Merge tag 'driver-core-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 1 Apr 2014 23:28:19 +0000 (16:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 1 Apr 2014 23:28:19 +0000 (16:28 -0700)
Pull driver core and sysfs updates from Greg KH:
 "Here's the big driver core / sysfs update for 3.15-rc1.

  Lots of kernfs updates to make it useful for other subsystems, and a
  few other tiny driver core patches.

  All have been in linux-next for a while"

* tag 'driver-core-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (42 commits)
  Revert "sysfs, driver-core: remove unused {sysfs|device}_schedule_callback_owner()"
  kernfs: cache atomic_write_len in kernfs_open_file
  numa: fix NULL pointer access and memory leak in unregister_one_node()
  Revert "driver core: synchronize device shutdown"
  kernfs: fix off by one error.
  kernfs: remove duplicate dir.c at the top dir
  x86: align x86 arch with generic CPU modalias handling
  cpu: add generic support for CPU feature based module autoloading
  sysfs: create bin_attributes under the requested group
  driver core: unexport static function create_syslog_header
  firmware: use power efficient workqueue for unloading and aborting fw load
  firmware: give a protection when map page failed
  firmware: google memconsole driver fixes
  firmware: fix google/gsmi duplicate efivars_sysfs_init()
  drivers/base: delete non-required instances of include <linux/init.h>
  kernfs: fix kernfs_node_from_dentry()
  ACPI / platform: drop redundant ACPI_HANDLE check
  kernfs: fix hash calculation in kernfs_rename_ns()
  kernfs: add CONFIG_KERNFS
  sysfs, kobject: add sysfs wrapper for kernfs_enable_ns()
  ...

2878 files changed:
Documentation/ABI/testing/sysfs-devices-power
Documentation/ABI/testing/sysfs-power
Documentation/DocBook/Makefile
Documentation/DocBook/w1.tmpl [new file with mode: 0644]
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/PCI/pci-iov-howto.txt
Documentation/RCU/RTFP.txt
Documentation/RCU/checklist.txt
Documentation/arm64/memory.txt
Documentation/connector/cn_test.c
Documentation/cpu-freq/core.txt
Documentation/cpu-freq/cpu-drivers.txt
Documentation/device-mapper/cache.txt
Documentation/device-mapper/thin-provisioning.txt
Documentation/devices.txt
Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
Documentation/devicetree/bindings/arm/marvell,dove.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/ata/apm-xgene.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
Documentation/devicetree/bindings/i2c/trivial-devices.txt
Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/s2mpa01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/s2mps11.txt
Documentation/devicetree/bindings/mfd/tps65910.txt
Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
Documentation/devicetree/bindings/misc/atmel-ssc.txt
Documentation/devicetree/bindings/misc/sram.txt
Documentation/devicetree/bindings/net/micrel-ks8851.txt
Documentation/devicetree/bindings/net/opencores-ethoc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt [deleted file]
Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
Documentation/devicetree/bindings/powerpc/fsl/ifc.txt [deleted file]
Documentation/devicetree/bindings/regulator/gpio-regulator.txt
Documentation/devicetree/bindings/regulator/pfuze100.txt
Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
Documentation/devicetree/bindings/sound/armada-370db-audio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs42xx8.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/da9055.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
Documentation/devicetree/bindings/sound/eukrea-tlv320.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,esai.txt
Documentation/devicetree/bindings/sound/fsl,spdif.txt
Documentation/devicetree/bindings/sound/mvebu-audio.txt
Documentation/devicetree/bindings/sound/pcm512x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/sirf-audio-codec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/sirf-audio-port.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/sirf-audio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tdm-slot.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic31xx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic32x4.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/widgets.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/efm32-spi.txt
Documentation/devicetree/bindings/spi/qcom,spi-qup.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/sh-hspi.txt
Documentation/devicetree/bindings/spi/sh-msiof.txt
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
Documentation/devicetree/bindings/spi/spi-rspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-sun4i.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-sun6i.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spmi/spmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
Documentation/devicetree/bindings/timer/ti,keystone-timer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
Documentation/fmc/fmc-write-eeprom.txt
Documentation/hwmon/adc128d818 [new file with mode: 0644]
Documentation/hwmon/lm95245
Documentation/hwmon/ltc2945 [new file with mode: 0644]
Documentation/hwmon/ltc2978
Documentation/hwmon/ltc4260 [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/kernel-per-CPU-kthreads.txt
Documentation/memory-barriers.txt
Documentation/networking/can.txt
Documentation/networking/netlink_mmap.txt
Documentation/networking/packet_mmap.txt
Documentation/networking/timestamping.txt
Documentation/power/pm_qos_interface.txt
Documentation/spi/spidev
Documentation/spi/spidev_fdx.c
Documentation/spi/spidev_test.c
Documentation/sysctl/kernel.txt
Documentation/trace/events-power.txt
Documentation/w1/masters/ds2490
Documentation/w1/w1.netlink
Documentation/watchdog/watchdog-parameters.txt
Documentation/x86/boot.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/Kbuild
arch/alpha/include/asm/cputime.h [deleted file]
arch/alpha/kernel/pci.c
arch/arc/include/asm/Kbuild
arch/arc/mm/cache_arc700.c
arch/arm/Kconfig
arch/arm/boot/compressed/.gitignore
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/keystone-clocks.dtsi
arch/arm/boot/dts/omap3-gta04.dts
arch/arm/boot/dts/omap3-igep0020.dts
arch/arm/boot/dts/omap3-igep0030.dts
arch/arm/boot/dts/r8a7791.dtsi
arch/arm/boot/dts/sama5d36.dtsi
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a10s.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/boot/dts/zynq-7000.dtsi
arch/arm/configs/tegra_defconfig
arch/arm/include/asm/Kbuild
arch/arm/include/asm/memory.h
arch/arm/include/asm/topology.h
arch/arm/kernel/bios32.c
arch/arm/kernel/head-common.S
arch/arm/kernel/head.S
arch/arm/kernel/process.c
arch/arm/kernel/smp.c
arch/arm/kernel/smp_twd.c
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-imx/pm-imx6q.c
arch/arm/mach-mmp/pm-mmp2.c
arch/arm/mach-mmp/pm-pxa910.c
arch/arm/mach-omap1/ams-delta-fiq.c
arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/dpll3xxx.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-sa1100/include/mach/collie.h
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-bockw.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-spear/spear1310.c
arch/arm/mach-spear/spear1340.c
arch/arm/mach-u300/Makefile
arch/arm/mach-u300/timer.c [deleted file]
arch/arm/mach-zynq/Kconfig
arch/arm/mach-zynq/common.c
arch/arm/mm/dump.c
arch/arm64/Kconfig
arch/arm64/boot/dts/apm-storm.dtsi
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/barrier.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/compat.h
arch/arm64/include/asm/cpufeature.h [new file with mode: 0644]
arch/arm64/include/asm/debug-monitors.h
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/hwcap.h
arch/arm64/include/asm/io.h
arch/arm64/include/asm/irqflags.h
arch/arm64/include/asm/kgdb.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/psci.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/tlb.h
arch/arm64/include/asm/topology.h [new file with mode: 0644]
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/uapi/asm/Kbuild
arch/arm64/include/uapi/asm/perf_regs.h [new file with mode: 0644]
arch/arm64/kernel/Makefile
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/head.S
arch/arm64/kernel/kgdb.c [new file with mode: 0644]
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/perf_regs.c [new file with mode: 0644]
arch/arm64/kernel/process.c
arch/arm64/kernel/psci.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/smp_spin_table.c
arch/arm64/kernel/topology.c [new file with mode: 0644]
arch/arm64/kernel/vdso.c
arch/arm64/kvm/hyp-init.S
arch/arm64/mm/cache.S
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/init.c
arch/arm64/mm/proc.S
arch/avr32/boards/mimc200/Makefile
arch/avr32/boards/mimc200/fram.c [deleted file]
arch/avr32/include/asm/Kbuild
arch/avr32/include/asm/bugs.h
arch/avr32/include/asm/processor.h
arch/avr32/kernel/cpu.c
arch/avr32/mm/cache.c
arch/blackfin/include/asm/Kbuild
arch/blackfin/include/asm/irq.h
arch/c6x/include/asm/Kbuild
arch/c6x/include/asm/cache.h
arch/cris/include/asm/Kbuild
arch/cris/include/asm/bitops.h
arch/cris/include/asm/cputime.h [deleted file]
arch/frv/include/asm/Kbuild
arch/frv/include/asm/cputime.h [deleted file]
arch/frv/mb93090-mb00/pci-frv.c
arch/hexagon/include/asm/Kbuild
arch/ia64/configs/generic_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/hp/common/sba_iommu.c
arch/ia64/include/asm/Kbuild
arch/ia64/include/asm/pci.h
arch/ia64/include/asm/topology.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/time.c
arch/ia64/kernel/uncached.c
arch/ia64/pci/fixup.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/msi_sn.c
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/cputime.h [deleted file]
arch/m68k/Kconfig
arch/m68k/amiga/cia.c
arch/m68k/atari/ataints.c
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/include/asm/Kbuild
arch/m68k/kernel/head.S
arch/m68k/kernel/ints.c
arch/metag/include/asm/Kbuild
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/cputime.h [deleted file]
arch/microblaze/pci/pci-common.c
arch/mips/Kconfig
arch/mips/alchemy/board-gpr.c
arch/mips/alchemy/board-mtx1.c
arch/mips/bcm47xx/board.c
arch/mips/bcm47xx/nvram.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/include/asm/Kbuild
arch/mips/include/asm/asmmacro.h
arch/mips/include/asm/fpu.h
arch/mips/include/asm/ftrace.h
arch/mips/include/asm/syscall.h
arch/mips/include/asm/topology.h
arch/mips/include/asm/unistd.h
arch/mips/include/uapi/asm/inst.h
arch/mips/kernel/ftrace.c
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/rtlx-cmp.c
arch/mips/kernel/rtlx-mt.c
arch/mips/kernel/smtc.c
arch/mips/math-emu/cp1emu.c
arch/mips/mti-malta/malta-amon.c
arch/mips/mti-malta/malta-int.c
arch/mips/pci/msi-octeon.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sibyte/sb1250/smp.c
arch/mn10300/include/asm/Kbuild
arch/mn10300/include/asm/cputime.h [deleted file]
arch/mn10300/kernel/cevt-mn10300.c
arch/mn10300/kernel/mn10300-serial.c
arch/mn10300/kernel/mn10300-watchdog.c
arch/mn10300/kernel/smp.c
arch/mn10300/unit-asb2364/irq-fpga.c
arch/openrisc/include/asm/Kbuild
arch/parisc/include/asm/Kbuild
arch/parisc/include/asm/page.h
arch/parisc/include/asm/spinlock.h
arch/parisc/include/uapi/asm/unistd.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/Kbuild
arch/powerpc/include/asm/fsl_ifc.h [deleted file]
arch/powerpc/include/asm/topology.h
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/reloc_64.S
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/oprofile/op_model_cell.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/ehv_pic.c
arch/powerpc/sysdev/fsl_ifc.c [deleted file]
arch/s390/Kconfig
arch/s390/appldata/appldata_os.c
arch/s390/configs/default_defconfig
arch/s390/configs/gcov_defconfig
arch/s390/configs/performance_defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/defconfig
arch/s390/hypfs/hypfs_vm.c
arch/s390/include/asm/Kbuild
arch/s390/include/asm/airq.h
arch/s390/include/asm/bitops.h
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/checksum.h
arch/s390/include/asm/compat.h
arch/s390/include/asm/futex.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/sclp.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/uaccess.h
arch/s390/include/uapi/asm/ptrace.h
arch/s390/kernel/Makefile
arch/s390/kernel/compat_exec_domain.c [deleted file]
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_linux.h
arch/s390/kernel/compat_signal.c
arch/s390/kernel/compat_wrapper.S [deleted file]
arch/s390/kernel/compat_wrapper.c [new file with mode: 0644]
arch/s390/kernel/early.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/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/topology.c
arch/s390/kvm/diag.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/lib/Makefile
arch/s390/lib/find.c
arch/s390/lib/uaccess.h
arch/s390/lib/uaccess_mvcos.c
arch/s390/lib/uaccess_pt.c
arch/s390/mm/maccess.c
arch/s390/mm/pgtable.c
arch/s390/pci/pci.c
arch/s390/pci/pci_debug.c
arch/score/include/asm/Kbuild
arch/score/include/asm/cputime.h [deleted file]
arch/sh/Kconfig
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/drivers/pci/pci.c
arch/sh/include/asm/Kbuild
arch/sh/include/cpu-sh2/cpu/cache.h
arch/sh/include/cpu-sh2a/cpu/cache.h
arch/sh/include/cpu-sh3/cpu/cache.h
arch/sh/include/cpu-sh4/cpu/cache.h
arch/sh/kernel/cpu/init.c
arch/sh/kernel/idle.c
arch/sh/kernel/irq.c
arch/sh/mm/cache-debugfs.c
arch/sh/mm/cache-sh2.c
arch/sh/mm/cache-sh2a.c
arch/sh/mm/cache-sh4.c
arch/sh/mm/cache-shx3.c
arch/sh/mm/cache.c
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/smp_64.h
arch/sparc/include/asm/topology_64.h
arch/sparc/kernel/leon_pci.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/prom_64.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/syscalls.S
arch/sparc/kernel/time_64.c
arch/sparc/mm/tsb.c
arch/tile/include/asm/Kbuild
arch/tile/kernel/pci_gx.c
arch/um/include/asm/Kbuild
arch/unicore32/include/asm/Kbuild
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/eboot.h
arch/x86/boot/compressed/efi_stub_64.S
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/cpucheck.c
arch/x86/boot/header.S
arch/x86/boot/tools/build.c
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/include/asm/Kbuild
arch/x86/include/asm/apic.h
arch/x86/include/asm/barrier.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/cputime.h [deleted file]
arch/x86/include/asm/efi.h
arch/x86/include/asm/floppy.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/io.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nmi.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/unistd.h
arch/x86/include/asm/xsave.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/amd_nb.c
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/apic_noop.c
arch/x86/kernel/apic/apic_numachip.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/es7000_32.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/summit_32.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/crash.c
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/hpet.c
arch/x86/kernel/i387.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/module.c
arch/x86/kernel/nmi.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/time.c
arch/x86/kernel/tsc.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/svm.c
arch/x86/lib/hash.c
arch/x86/lib/memcpy_32.c
arch/x86/lib/msr.c
arch/x86/mm/dump_pagetables.c
arch/x86/mm/fault.c
arch/x86/mm/pageattr.c
arch/x86/mm/srat.c
arch/x86/net/bpf_jit.S
arch/x86/pci/acpi.c
arch/x86/pci/amd_bus.c
arch/x86/pci/bus_numa.c
arch/x86/pci/common.c
arch/x86/pci/fixup.c
arch/x86/pci/irq.c
arch/x86/pci/legacy.c
arch/x86/pci/numaq_32.c
arch/x86/pci/visws.c
arch/x86/platform/efi/Makefile
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_32.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/efi/efi_stub_64.S
arch/x86/platform/efi/efi_thunk_64.S [new file with mode: 0644]
arch/x86/platform/ts5500/ts5500.c
arch/x86/um/asm/barrier.h
arch/x86/vdso/Makefile
arch/x86/xen/mmu.c
arch/x86/xen/spinlock.c
arch/xtensa/include/asm/Kbuild
arch/xtensa/kernel/irq.c
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-mq-cpu.c
block/blk-mq.c
block/blk-mq.h
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/ac.c
drivers/acpi/acpi_cmos_rtc.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_pad.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/accommon.h
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acdispat.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/acopcode.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acresrc.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/amlresrc.h
drivers/acpi/acpica/dsargs.c
drivers/acpi/acpica/dscontrol.c
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dsmthdat.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/dswscope.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evglock.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evgpeutil.c
drivers/acpi/acpica/evhandler.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evsci.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdebug.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfield.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exnames.c
drivers/acpi/acpica/exoparg1.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exoparg3.c
drivers/acpi/acpica/exoparg6.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exresnte.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/exstorob.c
drivers/acpi/acpica/exsystem.c
drivers/acpi/acpica/exutils.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/acpica/hwesleep.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwpci.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwvalid.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/hwxfsleep.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsarguments.c
drivers/acpi/acpica/nsconvert.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nsdumpdv.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsinit.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nsparse.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsprepkg.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/psargs.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psobject.c
drivers/acpi/acpica/psopcode.c
drivers/acpi/acpica/psopinfo.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/psscope.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psutils.c
drivers/acpi/acpica/pswalk.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/rsaddr.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsdumpinfo.c
drivers/acpi/acpica/rsinfo.c
drivers/acpi/acpica/rsio.c
drivers/acpi/acpica/rsirq.c
drivers/acpi/acpica/rslist.c
drivers/acpi/acpica/rsmemory.c
drivers/acpi/acpica/rsmisc.c
drivers/acpi/acpica/rsserial.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbprint.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/tbxfload.c
drivers/acpi/acpica/tbxfroot.c
drivers/acpi/acpica/utaddress.c
drivers/acpi/acpica/utalloc.c
drivers/acpi/acpica/utbuffer.c
drivers/acpi/acpica/utcache.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdecode.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/uterror.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utexcep.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utlock.c
drivers/acpi/acpica/utmath.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utobject.c
drivers/acpi/acpica/utosi.c
drivers/acpi/acpica/utownerid.c
drivers/acpi/acpica/utpredef.c
drivers/acpi/acpica/utresrc.c
drivers/acpi/acpica/utstate.c
drivers/acpi/acpica/utstring.c
drivers/acpi/acpica/uttrack.c
drivers/acpi/acpica/utxface.c
drivers/acpi/acpica/utxferror.c
drivers/acpi/acpica/utxfinit.c
drivers/acpi/acpica/utxfmutex.c
drivers/acpi/apei/Kconfig
drivers/acpi/battery.c
drivers/acpi/battery.h [new file with mode: 0644]
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/container.c
drivers/acpi/device_pm.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/fan.c
drivers/acpi/glue.c
drivers/acpi/internal.h
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/acpi/pci_root.c
drivers/acpi/power.c
drivers/acpi/processor_core.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_perflib.c
drivers/acpi/resource.c
drivers/acpi/sbs.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/tables.c
drivers/acpi/thermal.c
drivers/acpi/utils.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/acard-ahci.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_da850.c [new file with mode: 0644]
drivers/ata/ahci_imx.c
drivers/ata/ahci_platform.c
drivers/ata/ahci_st.c [new file with mode: 0644]
drivers/ata/ahci_sunxi.c [new file with mode: 0644]
drivers/ata/ahci_xgene.c [new file with mode: 0644]
drivers/ata/ata_generic.c
drivers/ata/libahci.c
drivers/ata/libahci_platform.c [new file with mode: 0644]
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-zpodd.c
drivers/ata/pata_acpi.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_atiixp.c
drivers/ata/pata_atp867x.c
drivers/ata/pata_cmd640.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cs5535.c
drivers/ata/pata_cs5536.c
drivers/ata/pata_cypress.c
drivers/ata/pata_efar.c
drivers/ata/pata_ep93xx.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_imx.c
drivers/ata/pata_it8213.c
drivers/ata/pata_it821x.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_legacy.c
drivers/ata/pata_marvell.c
drivers/ata/pata_mpiix.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ninja32.c
drivers/ata/pata_ns87410.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_opti.c
drivers/ata/pata_optidma.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_piccolo.c
drivers/ata/pata_platform.c
drivers/ata/pata_pxa.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rdc.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_scc.c
drivers/ata/pata_sch.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/pdc_adma.c
drivers/ata/sata_dwc_460ex.c
drivers/ata/sata_highbank.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_sx4.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/base/devres.c
drivers/base/power/Makefile
drivers/base/power/domain.c
drivers/base/power/main.c
drivers/base/power/power.h
drivers/base/power/qos.c
drivers/base/power/runtime.c
drivers/base/power/sysfs.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-mmio.c
drivers/base/regmap/regmap-spmi.c
drivers/base/regmap/regmap.c
drivers/block/aoe/aoecmd.c
drivers/block/floppy.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/nvme-core.c
drivers/block/rbd.c
drivers/block/zram/zram_drv.c
drivers/bus/mvebu-mbus.c
drivers/char/agp/frontend.c
drivers/char/agp/generic.c
drivers/char/agp/intel-gtt.c
drivers/char/agp/sgi-agp.c
drivers/char/hw_random/bcm2835-rng.c
drivers/char/hw_random/core.c
drivers/char/hw_random/exynos-rng.c
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/nomadik-rng.c
drivers/char/hw_random/octeon-rng.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/mem.c
drivers/char/mwave/3780i.c
drivers/char/tile-srom.c
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_i2c_stm_st33.c
drivers/clk/at91/clk-master.c
drivers/clk/clk-nomadik.c
drivers/clk/clk.c
drivers/clk/keystone/gate.c
drivers/clk/mvebu/armada-370.c
drivers/clk/mvebu/armada-xp.c
drivers/clk/mvebu/dove.c
drivers/clk/mvebu/kirkwood.c
drivers/clk/shmobile/clk-rcar-gen2.c
drivers/clk/tegra/clk-divider.c
drivers/clk/tegra/clk-id.h
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk-tegra114.c
drivers/clk/tegra/clk-tegra124.c
drivers/clk/tegra/clk-tegra20.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/cadence_ttc_timer.c
drivers/clocksource/exynos_mct.c
drivers/clocksource/sun4i_timer.c
drivers/clocksource/time-armada-370-xp.c
drivers/clocksource/time-orion.c
drivers/clocksource/timer-keystone.c [new file with mode: 0644]
drivers/clocksource/timer-u300.c [new file with mode: 0644]
drivers/clocksource/vf_pit_timer.c
drivers/connector/cn_proc.c
drivers/connector/connector.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/arm_big_little.c
drivers/cpufreq/blackfin-cpufreq.c
drivers/cpufreq/cpufreq-cpu0.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/cris-artpec3-cpufreq.c
drivers/cpufreq/cris-etraxfs-cpufreq.c
drivers/cpufreq/davinci-cpufreq.c
drivers/cpufreq/e_powersaver.c
drivers/cpufreq/elanfreq.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/exynos5440-cpufreq.c
drivers/cpufreq/freq_table.c
drivers/cpufreq/ia64-acpi-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.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
drivers/cpufreq/powernow-k6.c
drivers/cpufreq/powernow-k7.c
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/ppc-corenet-cpufreq.c
drivers/cpufreq/ppc_cbe_cpufreq.c
drivers/cpufreq/pxa2xx-cpufreq.c
drivers/cpufreq/pxa3xx-cpufreq.c
drivers/cpufreq/s5pv210-cpufreq.c
drivers/cpufreq/sc520_freq.c
drivers/cpufreq/sh-cpufreq.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/speedstep-ich.c
drivers/cpufreq/speedstep-smi.c
drivers/cpufreq/tegra-cpufreq.c
drivers/cpuidle/cpuidle-powernv.c
drivers/cpuidle/cpuidle-pseries.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/driver.c
drivers/cpuidle/governors/menu.c
drivers/devfreq/devfreq.c
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/amd8111_edac.c
drivers/edac/e752x_edac.c
drivers/edac/i3200_edac.c
drivers/edac/i5100_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i7core_edac.c
drivers/edac/i82875p_edac.c
drivers/edac/mce_amd.c
drivers/edac/mpc85xx_edac.c
drivers/edac/sb_edac.c
drivers/extcon/Kconfig
drivers/extcon/Makefile
drivers/extcon/extcon-class.c
drivers/extcon/extcon-gpio.c
drivers/extcon/extcon-palmas.c
drivers/extcon/of_extcon.c [deleted file]
drivers/firewire/core-device.c
drivers/firewire/net.c
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/firmware/dcdbas.c
drivers/firmware/efi/efi-stub-helper.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efivars.c
drivers/fmc/fmc-core.c
drivers/fmc/fmc-sdb.c
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/bochs/Kconfig
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/gma500/Kconfig
drivers/gpu/drm/gma500/mmu.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_smc.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-prodikeys.c
drivers/hid/hid-sony.c
drivers/hid/hidraw.c
drivers/hv/Makefile
drivers/hv/channel.c
drivers/hv/hv_balloon.c
drivers/hv/hv_fcopy.c [new file with mode: 0644]
drivers/hv/hv_kvp.c
drivers/hv/hv_snapshot.c
drivers/hv/hv_util.c
drivers/hv/hyperv_vmbus.h
drivers/hv/ring_buffer.c
drivers/hv/vmbus_drv.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adc128d818.c [new file with mode: 0644]
drivers/hwmon/coretemp.c
drivers/hwmon/emc2103.c
drivers/hwmon/hwmon.c
drivers/hwmon/iio_hwmon.c
drivers/hwmon/jz4740-hwmon.c
drivers/hwmon/lm95241.c
drivers/hwmon/lm95245.c
drivers/hwmon/ltc2945.c [new file with mode: 0644]
drivers/hwmon/ltc4215.c
drivers/hwmon/ltc4222.c [new file with mode: 0644]
drivers/hwmon/ltc4245.c
drivers/hwmon/ltc4260.c [new file with mode: 0644]
drivers/hwmon/max1668.c
drivers/hwmon/max6639.c
drivers/hwmon/max6650.c
drivers/hwmon/pmbus/ltc2978.c
drivers/hwmon/smm665.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-cpm.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/men_z188_adc.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/input/evdev.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/misc/da9052_onkey.c
drivers/input/mouse/cypress_ps2.c
drivers/input/mouse/synaptics.c
drivers/input/mousedev.c
drivers/input/touchscreen/st1232.c
drivers/iommu/amd_iommu_types.h
drivers/irqchip/Makefile
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-bcm2835.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-mmp.c
drivers/irqchip/irq-moxart.c
drivers/irqchip/irq-orion.c
drivers/irqchip/irq-sirfsoc.c
drivers/irqchip/irq-sun4i.c
drivers/irqchip/irq-sunxi-nmi.c [new file with mode: 0644]
drivers/irqchip/irq-vic.c
drivers/irqchip/irq-vt8500.c
drivers/irqchip/irq-xtensa-mx.c
drivers/irqchip/irq-zevio.c
drivers/irqchip/irqchip.c
drivers/isdn/capi/Kconfig
drivers/mcb/Kconfig [new file with mode: 0644]
drivers/mcb/Makefile [new file with mode: 0644]
drivers/mcb/mcb-core.c [new file with mode: 0644]
drivers/mcb/mcb-internal.h [new file with mode: 0644]
drivers/mcb/mcb-parse.c [new file with mode: 0644]
drivers/mcb/mcb-pci.c [new file with mode: 0644]
drivers/md/Kconfig
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-target.c
drivers/md/dm-log-userspace-transfer.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin-metadata.h
drivers/md/dm-thin.c
drivers/md/persistent-data/Kconfig
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/media/pci/cx18/cx18-alsa-main.c
drivers/media/pci/cx23885/cx23885-alsa.c
drivers/media/pci/cx25821/cx25821-alsa.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/ivtv/ivtv-alsa-main.c
drivers/media/pci/saa7134/saa7134-alsa.c
drivers/media/usb/cx231xx/cx231xx-audio.c
drivers/media/usb/em28xx/em28xx-audio.c
drivers/media/usb/stk1160/stk1160-ac97.c
drivers/media/usb/tlg2300/pd-alsa.c
drivers/media/usb/tm6000/tm6000-alsa.c
drivers/memory/Kconfig
drivers/memory/Makefile
drivers/memory/fsl_ifc.c [new file with mode: 0644]
drivers/memory/ti-aemif.c [new file with mode: 0644]
drivers/message/i2o/iop.c
drivers/mfd/arizona-core.c
drivers/mfd/sec-core.c
drivers/mfd/sec-irq.c
drivers/mfd/wm5102-tables.c
drivers/misc/Kconfig
drivers/misc/ad525x_dpot.c
drivers/misc/apds9802als.c
drivers/misc/atmel-ssc.c
drivers/misc/bmp085.c
drivers/misc/carma/carma-fpga.c
drivers/misc/ds1682.c
drivers/misc/eeprom/at25.c
drivers/misc/eeprom/eeprom.c
drivers/misc/eeprom/eeprom_93xx46.c
drivers/misc/eeprom/max6875.c
drivers/misc/eeprom/sunxi_sid.c
drivers/misc/genwqe/card_debugfs.c
drivers/misc/hmc6352.c
drivers/misc/isl29003.c
drivers/misc/isl29020.c
drivers/misc/lattice-ecp3-config.c
drivers/misc/lis3lv02d/lis3lv02d.c
drivers/misc/lis3lv02d/lis3lv02d_i2c.c
drivers/misc/lis3lv02d/lis3lv02d_spi.c
drivers/misc/lkdtm.c
drivers/misc/mei/Kconfig
drivers/misc/mei/Makefile
drivers/misc/mei/amthif.c
drivers/misc/mei/bus.c
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/debugfs.c
drivers/misc/mei/hbm.c
drivers/misc/mei/hbm.h
drivers/misc/mei/hw-me.c
drivers/misc/mei/hw-me.h
drivers/misc/mei/hw-txe-regs.h [new file with mode: 0644]
drivers/misc/mei/hw-txe.c [new file with mode: 0644]
drivers/misc/mei/hw-txe.h [new file with mode: 0644]
drivers/misc/mei/hw.h
drivers/misc/mei/init.c
drivers/misc/mei/interrupt.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/nfc.c
drivers/misc/mei/pci-me.c
drivers/misc/mei/pci-txe.c [new file with mode: 0644]
drivers/misc/mei/wd.c
drivers/misc/mic/card/mic_device.h
drivers/misc/mic/host/mic_device.h
drivers/misc/mic/host/mic_intr.c
drivers/misc/pch_phub.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/misc/sram.c
drivers/misc/ti-st/st_core.c
drivers/misc/ti_dac7512.c
drivers/misc/tsl2550.c
drivers/misc/vmw_vmci/vmci_guest.c
drivers/mmc/host/dw_mmc.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/sh_flctl.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bonding.h
drivers/net/can/flexcan.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic.h
drivers/net/ethernet/broadcom/cnic_defs.h
drivers/net/ethernet/broadcom/cnic_if.h
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/brocade/bna/bfa_ioc.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmveth.h
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/micrel/ks8851.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/at86rf230.c
drivers/net/ifb.c
drivers/net/macvlan.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/tun.c
drivers/net/usb/Makefile
drivers/net/usb/ax88179_178a.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c [deleted file]
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/iwlwifi/dvm/sta.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mwifiex/11ac.c
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/ti/wl1251/rx.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/of/base.c
drivers/parport/share.c
drivers/pci/Makefile
drivers/pci/bus.c
drivers/pci/host-bridge.c
drivers/pci/host/Kconfig
drivers/pci/host/pci-imx6.c
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-rcar-gen2.c
drivers/pci/host/pcie-designware.c
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_acpi.c
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/iov.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/rom.c
drivers/pci/search.c
drivers/pci/setup-res.c
drivers/pcmcia/sa11xx_base.c
drivers/pcmcia/yenta_socket.c
drivers/pinctrl/Kconfig
drivers/pinctrl/devicetree.c
drivers/pinctrl/mvebu/Kconfig
drivers/pinctrl/mvebu/Makefile
drivers/pinctrl/mvebu/pinctrl-armada-370.c
drivers/pinctrl/mvebu/pinctrl-armada-375.c [new file with mode: 0644]
drivers/pinctrl/mvebu/pinctrl-armada-38x.c [new file with mode: 0644]
drivers/pinctrl/mvebu/pinctrl-armada-xp.c
drivers/pinctrl/mvebu/pinctrl-dove.c
drivers/pinctrl/mvebu/pinctrl-kirkwood.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/mvebu/pinctrl-mvebu.h
drivers/pinctrl/pinctrl-adi2-bf54x.c
drivers/pinctrl/pinctrl-adi2-bf60x.c
drivers/pinctrl/pinctrl-adi2.c
drivers/pinctrl/pinctrl-adi2.h
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-baytrail.c
drivers/pinctrl/pinctrl-capri.c
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-imx.c
drivers/pinctrl/pinctrl-msm.c
drivers/pinctrl/pinctrl-msm.h
drivers/pinctrl/pinctrl-msm8x74.c
drivers/pinctrl/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-samsung.c
drivers/pinctrl/pinctrl-samsung.h
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/pinctrl-sunxi-pins.h
drivers/pinctrl/pinctrl-sunxi.c
drivers/pinctrl/pinctrl-sunxi.h
drivers/pinctrl/pinctrl-tegra.c
drivers/pinctrl/pinctrl-tegra.h
drivers/pinctrl/pinctrl-tegra114.c
drivers/pinctrl/pinctrl-tegra124.c
drivers/pinctrl/pinctrl-tegra20.c
drivers/pinctrl/pinctrl-tegra30.c
drivers/pinctrl/sh-pfc/pfc-r8a7790.c
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sirf/pinctrl-atlas6.c
drivers/pinctrl/sirf/pinctrl-prima2.c
drivers/pinctrl/sirf/pinctrl-sirf.c
drivers/platform/x86/Kconfig
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pnp/pnpacpi/rsparser.c
drivers/pnp/pnpbios/bioscalls.c
drivers/powercap/intel_rapl.c
drivers/ps3/ps3-vuart.c
drivers/rapidio/devices/tsi721.h
drivers/rapidio/devices/tsi721_dma.c
drivers/regulator/88pm800.c
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/aat2870-regulator.c
drivers/regulator/act8865-regulator.c
drivers/regulator/anatop-regulator.c
drivers/regulator/arizona-ldo1.c
drivers/regulator/arizona-micsupp.c
drivers/regulator/as3711-regulator.c
drivers/regulator/as3722-regulator.c
drivers/regulator/bcm590xx-regulator.c [new file with mode: 0644]
drivers/regulator/core.c
drivers/regulator/da9052-regulator.c
drivers/regulator/da9055-regulator.c
drivers/regulator/da9063-regulator.c
drivers/regulator/da9210-regulator.c
drivers/regulator/db8500-prcmu.c
drivers/regulator/dbx500-prcmu.c
drivers/regulator/dummy.c
drivers/regulator/fan53555.c
drivers/regulator/fixed.c
drivers/regulator/gpio-regulator.c
drivers/regulator/helpers.c
drivers/regulator/lp3971.c
drivers/regulator/lp872x.c
drivers/regulator/max14577.c
drivers/regulator/max1586.c
drivers/regulator/max77686.c
drivers/regulator/max77693.c
drivers/regulator/max8649.c
drivers/regulator/max8660.c
drivers/regulator/max8907-regulator.c
drivers/regulator/max8925-regulator.c
drivers/regulator/max8952.c
drivers/regulator/max8973-regulator.c
drivers/regulator/max8997.c
drivers/regulator/max8998.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/pfuze100-regulator.c
drivers/regulator/rc5t583-regulator.c
drivers/regulator/s2mpa01.c [new file with mode: 0644]
drivers/regulator/s2mps11.c
drivers/regulator/s5m8767.c
drivers/regulator/st-pwm.c [new file with mode: 0644]
drivers/regulator/ti-abb-regulator.c
drivers/regulator/tps51632-regulator.c
drivers/regulator/tps62360-regulator.c
drivers/regulator/tps6507x-regulator.c
drivers/regulator/tps65090-regulator.c
drivers/regulator/tps65217-regulator.c
drivers/regulator/tps65218-regulator.c [new file with mode: 0644]
drivers/regulator/tps6524x-regulator.c
drivers/regulator/tps6586x-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/regulator/tps80031-regulator.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-isink.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8994-regulator.c
drivers/rtc/rtc-s3c.c
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/raw3270.c
drivers/s390/char/raw3270.h
drivers/s390/char/sclp_early.c
drivers/s390/cio/airq.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cio.c
drivers/s390/cio/device.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/atari_scsi.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2fc/bnx2fc_tgt.c
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/isci/host.h
drivers/scsi/isci/port_config.c
drivers/scsi/isci/task.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/storvsc_drv.c
drivers/spi/Kconfig
drivers/spi/Makefile
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-hsspi.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-bfin-sport.c
drivers/spi/spi-bfin-v3.c
drivers/spi/spi-bfin5xx.c
drivers/spi/spi-bitbang.c
drivers/spi/spi-butterfly.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-efm32.c
drivers/spi/spi-ep93xx.c
drivers/spi/spi-falcon.c
drivers/spi/spi-fsl-dspi.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-octeon.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-pxadma.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-qup.c [new file with mode: 0644]
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c24xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sc18is602.c
drivers/spi/spi-sh-hspi.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sh-sci.c
drivers/spi/spi-sirf.c
drivers/spi/spi-sun4i.c [new file with mode: 0644]
drivers/spi/spi-sun6i.c [new file with mode: 0644]
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi-ti-ssp.c [deleted file]
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi-txx9.c
drivers/spi/spi-xcomm.c
drivers/spi/spi-xilinx.c
drivers/spi/spi-xtensa-xtfpga.c [new file with mode: 0644]
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/spmi/Kconfig [new file with mode: 0644]
drivers/spmi/Makefile [new file with mode: 0644]
drivers/spmi/spmi-pmic-arb.c [new file with mode: 0644]
drivers/spmi/spmi.c [new file with mode: 0644]
drivers/staging/cxt1e1/linux.c
drivers/staging/fwserial/fwserial.c
drivers/staging/fwserial/fwserial.h
drivers/staging/line6/audio.c
drivers/staging/line6/midi.c
drivers/staging/line6/pcm.c
drivers/staging/media/go7007/snd-go7007.c
drivers/staging/media/solo6x10/solo6x10-g723.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/target_core_sbc.c
drivers/thermal/Kconfig
drivers/thermal/thermal_core.c
drivers/thermal/x86_pkg_temp_thermal.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sunhv.c
drivers/tty/serial/sunsab.c
drivers/tty/serial/sunsu.c
drivers/tty/serial/sunzilog.c
drivers/tty/tty_ldsem.c
drivers/usb/core/config.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/gadget/f_midi.c
drivers/usb/gadget/f_uac2.c
drivers/usb/host/xhci.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/net.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/hyperv_fb.c
drivers/video/output.c [deleted file]
drivers/video/uvesafb.c
drivers/vme/bridges/vme_ca91cx42.c
drivers/vme/bridges/vme_tsi148.c
drivers/w1/masters/Kconfig
drivers/w1/masters/ds2490.c
drivers/w1/masters/mxc_w1.c
drivers/w1/masters/w1-gpio.c
drivers/w1/slaves/Kconfig
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
drivers/w1/w1.h
drivers/w1/w1_family.c
drivers/w1/w1_family.h
drivers/w1/w1_int.c
drivers/w1/w1_io.c
drivers/w1/w1_netlink.c
drivers/w1/w1_netlink.h
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/acquirewdt.c
drivers/watchdog/advantechwdt.c
drivers/watchdog/ar7_wdt.c
drivers/watchdog/at32ap700x_wdt.c
drivers/watchdog/ath79_wdt.c
drivers/watchdog/bcm2835_wdt.c
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/bcm63xx_wdt.c
drivers/watchdog/cpu5wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9055_wdt.c
drivers/watchdog/davinci_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/geodewdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/ib700wdt.c
drivers/watchdog/ibmasr.c
drivers/watchdog/indydog.c
drivers/watchdog/intel_scu_watchdog.c
drivers/watchdog/it87_wdt.c
drivers/watchdog/jz4740_wdt.c
drivers/watchdog/max63xx_wdt.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mtx-1_wdt.c
drivers/watchdog/nuc900_wdt.c
drivers/watchdog/of_xilinx_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pcwd_usb.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/rdc321x_wdt.c
drivers/watchdog/retu_wdt.c
drivers/watchdog/riowd.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sc520_wdt.c
drivers/watchdog/shwdt.c
drivers/watchdog/softdog.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/stmp3xxx_rtc_wdt.c
drivers/watchdog/sunxi_wdt.c
drivers/watchdog/tegra_wdt.c [new file with mode: 0644]
drivers/watchdog/ts72xx_wdt.c
drivers/watchdog/w83697hf_wdt.c
drivers/watchdog/wdt285.c
drivers/watchdog/wdt_pci.c
drivers/watchdog/wm831x_wdt.c
drivers/xen/balloon.c
drivers/xen/events/events_2l.c
drivers/xen/events/events_base.c
drivers/xen/events/events_fifo.c
drivers/xen/xen-acpi-cpuhotplug.c
drivers/xen/xen-acpi-memhotplug.c
drivers/xen/xen-acpi-pad.c
fs/afs/internal.h
fs/afs/rxrpc.c
fs/anon_inodes.c
fs/bio-integrity.c
fs/cifs/cifsglob.h
fs/cifs/file.c
fs/cifs/transport.c
fs/compat.c
fs/compat_binfmt_elf.c
fs/compat_ioctl.c
fs/dcache.c
fs/efivarfs/file.c
fs/exec.c
fs/ext4/inode.c
fs/file.c
fs/file_table.c
fs/hfsplus/catalog.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/options.c
fs/mount.h
fs/namei.c
fs/namespace.c
fs/nfs/delegation.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfsd/vfs.c
fs/ocfs2/file.c
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/stackglue.c
fs/open.c
fs/pnode.c
fs/pnode.h
fs/proc/base.c
fs/proc/page.c
fs/proc/stat.c
fs/proc/uptime.c
fs/read_write.c
fs/timerfd.c
include/acpi/acbuffer.h
include/acpi/acconfig.h
include/acpi/acexcep.h
include/acpi/acnames.h
include/acpi/acoutput.h
include/acpi/acpi.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpi_numa.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/acrestyp.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl2.h
include/acpi/actbl3.h
include/acpi/actypes.h
include/acpi/platform/acenv.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-generic/bitops/const_hweight.h
include/asm-generic/cputime_jiffies.h
include/asm-generic/cputime_nsecs.h
include/asm-generic/mcs_spinlock.h [new file with mode: 0644]
include/asm-generic/pgtable.h
include/asm-generic/rwsem.h
include/dt-bindings/clock/tegra124-car.h
include/dt-bindings/sound/tlv320aic31xx-micbias.h [new file with mode: 0644]
include/dt-bindings/spmi/spmi.h [new file with mode: 0644]
include/kvm/arm_vgic.h
include/linux/acpi.h
include/linux/ahci_platform.h
include/linux/atmel-ssc.h
include/linux/audit.h
include/linux/bitops.h
include/linux/blk-mq.h
include/linux/clk/ti.h
include/linux/clockchips.h
include/linux/compat.h
include/linux/connector.h
include/linux/cpufreq.h
include/linux/cputime.h [new file with mode: 0644]
include/linux/device.h
include/linux/efi.h
include/linux/extcon.h
include/linux/extcon/of_extcon.h [deleted file]
include/linux/file.h
include/linux/firewire.h
include/linux/fmc-sdb.h
include/linux/fs.h
include/linux/fsl_ifc.h [new file with mode: 0644]
include/linux/ftrace_event.h
include/linux/futex.h
include/linux/gfp.h
include/linux/hardirq.h
include/linux/hrtimer.h
include/linux/huge_mm.h
include/linux/hyperv.h
include/linux/init.h
include/linux/interrupt.h
include/linux/io.h
include/linux/ioport.h
include/linux/irq.h
include/linux/irq_work.h
include/linux/kernel.h
include/linux/kernel_stat.h
include/linux/kexec.h
include/linux/libata.h
include/linux/linkage.h
include/linux/lockdep.h
include/linux/mcb.h [new file with mode: 0644]
include/linux/mfd/arizona/registers.h
include/linux/mfd/samsung/core.h
include/linux/mfd/samsung/irq.h
include/linux/mfd/samsung/rtc.h
include/linux/mfd/samsung/s2mpa01.h [new file with mode: 0644]
include/linux/mfd/samsung/s2mps14.h [new file with mode: 0644]
include/linux/mfd/samsung/s5m8767.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/mutex.h
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/nfs_xdr.h
include/linux/nvme.h
include/linux/of.h
include/linux/pci-acpi.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/platform_data/adau1977.h [new file with mode: 0644]
include/linux/platform_data/asoc-s3c.h
include/linux/platform_data/asoc-s3c24xx_simtec.h
include/linux/platform_data/davinci_asp.h
include/linux/platform_data/spi-s3c64xx.h
include/linux/pm.h
include/linux/pm_qos.h
include/linux/pm_runtime.h
include/linux/rculist.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/regmap.h
include/linux/regulator/driver.h
include/linux/regulator/pfuze100.h
include/linux/rmap.h
include/linux/sched.h
include/linux/sched/prio.h [new file with mode: 0644]
include/linux/sched/rt.h
include/linux/security.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/spi/spi.h
include/linux/spi/spi_bitbang.h
include/linux/spmi.h [new file with mode: 0644]
include/linux/srcu.h
include/linux/syscalls.h
include/linux/torture.h [new file with mode: 0644]
include/linux/tracepoint.h
include/linux/usb/cdc_ncm.h
include/linux/usb/usbnet.h
include/linux/video_output.h [deleted file]
include/linux/workqueue.h
include/net/if_inet6.h
include/net/ip_tunnels.h
include/net/sock.h
include/net/tcp.h
include/net/xfrm.h
include/scsi/libsas.h
include/sound/core.h
include/sound/emu10k1.h
include/sound/hwdep.h
include/sound/pcm.h
include/sound/rawmidi.h
include/sound/rcar_snd.h
include/sound/simple_card.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/target/iscsi/iscsi_transport.h
include/trace/events/hswadsp.h [new file with mode: 0644]
include/trace/events/intel-sst.h [new file with mode: 0644]
include/trace/events/power.h
include/trace/events/sunrpc.h
include/trace/ftrace.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/Kbuild
include/uapi/linux/hyperv.h [new file with mode: 0644]
include/uapi/linux/spi/spidev.h
init/Kconfig
init/main.c
ipc/compat.c
ipc/compat_mq.c
ipc/msg.c
kernel/Makefile
kernel/audit.c
kernel/audit.h
kernel/auditfilter.c
kernel/cgroup.c
kernel/compat.c
kernel/cpu/Makefile [deleted file]
kernel/cpu/idle.c [deleted file]
kernel/cpuset.c
kernel/debug/debug_core.c
kernel/events/core.c
kernel/extable.c
kernel/fork.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/chip.c
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/proc.c
kernel/irq_work.c
kernel/kexec.c
kernel/ksysfs.c
kernel/locking/Makefile
kernel/locking/lockdep.c
kernel/locking/locktorture.c [new file with mode: 0644]
kernel/locking/mcs_spinlock.c [new file with mode: 0644]
kernel/locking/mcs_spinlock.h [new file with mode: 0644]
kernel/locking/mutex-debug.c
kernel/locking/mutex.c
kernel/locking/rtmutex.c
kernel/locking/rwsem-xadd.c
kernel/module.c
kernel/notifier.c
kernel/panic.c
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/qos.c
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/wakelock.c
kernel/profile.c
kernel/ptrace.c
kernel/rcu/Makefile
kernel/rcu/rcu.h
kernel/rcu/rcutorture.c [new file with mode: 0644]
kernel/rcu/srcu.c
kernel/rcu/tiny.c
kernel/rcu/tiny_plugin.h
kernel/rcu/torture.c [deleted file]
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_plugin.h
kernel/rcu/tree_trace.c
kernel/rcu/update.c
kernel/resource.c
kernel/sched/Makefile
kernel/sched/auto_group.c
kernel/sched/clock.c
kernel/sched/core.c
kernel/sched/cpudeadline.c
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/idle.c [new file with mode: 0644]
kernel/sched/idle_task.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stop_task.c
kernel/softirq.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/time/Kconfig
kernel/time/Makefile
kernel/time/clockevents.c
kernel/time/ntp.c
kernel/time/tick-broadcast-hrtimer.c [new file with mode: 0644]
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/timekeeping.c
kernel/time/timekeeping_debug.c
kernel/timer.c
kernel/torture.c [new file with mode: 0644]
kernel/trace/ring_buffer_benchmark.c
kernel/trace/trace.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
kernel/trace/trace_export.c
kernel/trace/trace_irqsoff.c
kernel/tracepoint.c
kernel/workqueue.c
lib/Kconfig.debug
lib/dma-debug.c
lib/fonts/Kconfig
lib/radix-tree.c
lib/random32.c
lib/string.c
lib/vsprintf.c
mm/Kconfig
mm/compaction.c
mm/fremap.c
mm/huge_memory.c
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/mempolicy.c
mm/migrate.c
mm/mmu_context.c
mm/page_alloc.c
mm/percpu.c
mm/process_vm_access.c
mm/rmap.c
mm/swap.c
net/8021q/vlan.c
net/8021q/vlan_dev.c
net/bridge/br_device.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_vlan.c
net/can/raw.c
net/compat.c
net/core/dev.c
net/core/neighbour.c
net/core/netpoll.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/hsr/hsr_framereg.c
net/ipv4/af_inet.c
net/ipv4/gre_demux.c
net/ipv4/inet_fragment.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ipmr.c
net/ipv4/netfilter/nf_nat_snmp_basic.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/ipv6/exthdrs_core.c
net/ipv6/exthdrs_offload.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/ping.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/udp_offload.c
net/key/af_key.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/mesh_ps.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_nat_core.c
net/netfilter/nfnetlink_queue_core.c
net/netfilter/nft_meta.c
net/netfilter/nft_payload.c
net/netfilter/nft_reject_inet.c
net/netlink/af_netlink.c
net/nfc/nci/core.c
net/openvswitch/datapath.c
net/openvswitch/flow.c
net/sched/sch_api.c
net/sched/sch_fq.c
net/sched/sch_tbf.c
net/sctp/associola.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/socket.c
net/tipc/bearer.c
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/handler.c
net/tipc/name_table.c
net/tipc/netlink.c
net/tipc/ref.c
net/tipc/server.c
net/tipc/server.h
net/tipc/socket.c
net/tipc/subscr.c
net/unix/af_unix.c
net/wireless/core.c
net/wireless/reg.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/Kbuild.include
scripts/Makefile.build
scripts/gcc-ld [new file with mode: 0644]
scripts/gen_initramfs_list.sh
scripts/ld-version.sh [new file with mode: 0755]
scripts/mod/modpost.c
scripts/mod/modpost.h
security/capability.c
security/keys/compat.c
security/keys/keyring.c
security/security.c
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/include/xfrm.h
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/selinux/xfrm.c
sound/aoa/aoa.h
sound/aoa/codecs/onyx.c
sound/aoa/codecs/tas.c
sound/aoa/codecs/toonie.c
sound/aoa/core/alsa.c
sound/arm/aaci.c
sound/arm/pxa2xx-ac97.c
sound/atmel/abdac.c
sound/atmel/ac97c.c
sound/core/compress_offload.c
sound/core/control.c
sound/core/control_compat.c
sound/core/device.c
sound/core/hrtimer.c
sound/core/hwdep.c
sound/core/info.c
sound/core/init.c
sound/core/isadma.c
sound/core/memalloc.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/pcm_timer.c
sound/core/rawmidi.c
sound/core/rtctimer.c
sound/core/seq/oss/seq_oss.c
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/oss/seq_oss_init.c
sound/core/seq/oss/seq_oss_ioctl.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_synth.c
sound/core/seq/oss/seq_oss_timer.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_device.c
sound/core/seq/seq_dummy.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_lock.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_midi_emul.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_timer.c
sound/core/seq/seq_virmidi.c
sound/core/sound.c
sound/core/sound_oss.c
sound/core/timer.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/mts64.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_synth.c
sound/drivers/pcsp/pcsp.c
sound/drivers/pcsp/pcsp_input.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/firewire/dice.c
sound/firewire/isight.c
sound/firewire/scs1x.c
sound/firewire/speakers.c
sound/i2c/other/ak4113.c
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1848/ad1848.c
sound/isa/adlib.c
sound/isa/als100.c
sound/isa/azt2320.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/mips/au1x00.c
sound/mips/hal2.c
sound/mips/sgio2audio.c
sound/oss/pas2.h
sound/oss/pas2_card.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ac97_pcm.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/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/aw2/aw2-alsa.c
sound/pci/aw2/aw2-saa7146.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca_midi.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/cs5535audio/cs5535audio_olpc.c
sound/pci/cs5535audio/cs5535audio_pcm.c
sound/pci/cs5535audio/cs5535audio_pm.c
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio_dsp.c
sound/pci/echoaudio/midi.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1_patch.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emumpu401.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/io.c
sound/pci/emu10k1/irq.c
sound/pci/emu10k1/memory.c
sound/pci/emu10k1/p16v.c
sound/pci/emu10k1/voice.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_controller.c [new file with mode: 0644]
sound/pci/hda/hda_controller.h [new file with mode: 0644]
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_i915.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_priv.h [new file with mode: 0644]
sound/pci/hda/hda_sysfs.c [new file with mode: 0644]
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/hda/thinkpad_helper.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/delta.c
sound/pci/ice1712/ews.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/prodigy192.c
sound/pci/ice1712/quartet.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/lola/lola_clock.c
sound/pci/lola/lola_mixer.c
sound/pci/lola/lola_pcm.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx_core.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/mixart/mixart_core.c
sound/pci/mixart/mixart_hwdep.c
sound/pci/mixart/mixart_mixer.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/xonar_dg.c
sound/pci/oxygen/xonar_hdmi.c
sound/pci/oxygen/xonar_lib.c
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr_core.c
sound/pci/pcxhr/pcxhr_hwdep.c
sound/pci/pcxhr/pcxhr_mix22.c
sound/pci/pcxhr/pcxhr_mixer.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/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/vx222/vx222_ops.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/powermac.c
sound/ppc/snd_ps3.c
sound/sh/aica.c
sound/sh/sh_dac_audio.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/blackfin/Kconfig
sound/soc/cirrus/Kconfig
sound/soc/cirrus/snappercl15.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x-i2c.c [new file with mode: 0644]
sound/soc/codecs/ad193x-spi.c [new file with mode: 0644]
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1977-i2c.c [new file with mode: 0644]
sound/soc/codecs/adau1977-spi.c [new file with mode: 0644]
sound/soc/codecs/adau1977.c [new file with mode: 0644]
sound/soc/codecs/adau1977.h [new file with mode: 0644]
sound/soc/codecs/adav801.c [new file with mode: 0644]
sound/soc/codecs/adav803.c [new file with mode: 0644]
sound/soc/codecs/adav80x.c
sound/soc/codecs/adav80x.h
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/ak4671.h
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.c
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/cs42xx8-i2c.c [new file with mode: 0644]
sound/soc/codecs/cs42xx8.c [new file with mode: 0644]
sound/soc/codecs/cs42xx8.h [new file with mode: 0644]
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da732x.h
sound/soc/codecs/da9055.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/max9768.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98090.h
sound/soc/codecs/max98095.c
sound/soc/codecs/max9850.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/ml26124.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/pcm1792a.c
sound/soc/codecs/pcm512x-i2c.c [new file with mode: 0644]
sound/soc/codecs/pcm512x-spi.c [new file with mode: 0644]
sound/soc/codecs/pcm512x.c [new file with mode: 0644]
sound/soc/codecs/pcm512x.h [new file with mode: 0644]
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/si476x.c
sound/soc/codecs/sirf-audio-codec.c [new file with mode: 0644]
sound/soc/codecs/sirf-audio-codec.h [new file with mode: 0644]
sound/soc/codecs/sn95031.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/ssm2602-i2c.c [new file with mode: 0644]
sound/soc/codecs/ssm2602-spi.c [new file with mode: 0644]
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm2602.h
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta529.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tlv320aic23-i2c.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic23-spi.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic23.h
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic31xx.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic31xx.h [new file with mode: 0644]
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/edma-pcm.c [new file with mode: 0644]
sound/soc/davinci/edma-pcm.h [new file with mode: 0644]
sound/soc/fsl/Kconfig
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_utils.c
sound/soc/fsl/fsl_utils.h
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/Makefile
sound/soc/intel/byt-rt5640.c [new file with mode: 0644]
sound/soc/intel/haswell.c [new file with mode: 0644]
sound/soc/intel/mfld_machine.c
sound/soc/intel/sst-acpi.c [new file with mode: 0644]
sound/soc/intel/sst-baytrail-dsp.c [new file with mode: 0644]
sound/soc/intel/sst-baytrail-ipc.c [new file with mode: 0644]
sound/soc/intel/sst-baytrail-ipc.h [new file with mode: 0644]
sound/soc/intel/sst-baytrail-pcm.c [new file with mode: 0644]
sound/soc/intel/sst-dsp-priv.h [new file with mode: 0644]
sound/soc/intel/sst-dsp.c [new file with mode: 0644]
sound/soc/intel/sst-dsp.h [new file with mode: 0644]
sound/soc/intel/sst-firmware.c [new file with mode: 0644]
sound/soc/intel/sst-haswell-dsp.c [new file with mode: 0644]
sound/soc/intel/sst-haswell-ipc.c [new file with mode: 0644]
sound/soc/intel/sst-haswell-ipc.h [new file with mode: 0644]
sound/soc/intel/sst-haswell-pcm.c [new file with mode: 0644]
sound/soc/intel/sst-mfld-dsp.h [new file with mode: 0644]
sound/soc/intel/sst-mfld-platform.c [new file with mode: 0644]
sound/soc/intel/sst-mfld-platform.h [new file with mode: 0644]
sound/soc/intel/sst_dsp.h [deleted file]
sound/soc/intel/sst_platform.c [deleted file]
sound/soc/intel/sst_platform.h [deleted file]
sound/soc/kirkwood/Kconfig
sound/soc/kirkwood/Makefile
sound/soc/kirkwood/armada-370-db.c [new file with mode: 0644]
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/omap/Kconfig
sound/soc/omap/ams-delta.c
sound/soc/omap/n810.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/rx51.c
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/poodle.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/pxa/zylonite.c
sound/soc/s6000/s6105-ipcam.c
sound/soc/samsung/Kconfig
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/tobermory.c
sound/soc/sh/fsi.c
sound/soc/sh/migor.c
sound/soc/sh/rcar/Makefile
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/scu.c [deleted file]
sound/soc/sh/rcar/src.c [new file with mode: 0644]
sound/soc/sh/rcar/ssi.c
sound/soc/sirf/Kconfig [new file with mode: 0644]
sound/soc/sirf/Makefile [new file with mode: 0644]
sound/soc/sirf/sirf-audio-port.c [new file with mode: 0644]
sound/soc/sirf/sirf-audio-port.h [new file with mode: 0644]
sound/soc/sirf/sirf-audio.c [new file with mode: 0644]
sound/soc/soc-cache.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-io.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/spear/spdif_out.c
sound/soc/tegra/Kconfig
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra20_ac97.h
sound/soc/tegra/tegra20_das.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_wm9712.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/spi/at73c213.c
sound/usb/6fire/chip.c
sound/usb/6fire/comm.c
sound/usb/6fire/control.c
sound/usb/6fire/firmware.c
sound/usb/6fire/midi.c
sound/usb/6fire/pcm.c
sound/usb/caiaq/device.c
sound/usb/card.c
sound/usb/clock.c
sound/usb/endpoint.c
sound/usb/format.c
sound/usb/hiface/chip.c
sound/usb/midi.c
sound/usb/misc/ua101.c
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks.c
sound/usb/stream.c
sound/usb/usbaudio.h
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2y.h
sound/usb/usx2y/usbusx2yaudio.c
sound/usb/usx2y/usx2yhwdeppcm.c
tools/Makefile
tools/hv/Makefile [new file with mode: 0644]
tools/hv/hv_fcopy_daemon.c [new file with mode: 0644]
tools/hv/hv_vss_daemon.c
tools/include/linux/hash.h [new file with mode: 0644]
tools/lib/api/Makefile
tools/lib/api/fs/fs.c [new file with mode: 0644]
tools/lib/api/fs/fs.h [new file with mode: 0644]
tools/lib/lockdep/Makefile
tools/lib/lockdep/preload.c
tools/lib/lockdep/run_tests.sh [changed mode: 0644->0755]
tools/lib/lockdep/uinclude/asm/hash.h [new file with mode: 0644]
tools/lib/lockdep/uinclude/linux/rcu.h
tools/net/Makefile
tools/perf/Documentation/perf-mem.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/arch/arm/Makefile
tools/perf/arch/arm/util/unwind-libunwind.c [new file with mode: 0644]
tools/perf/arch/arm/util/unwind.c [deleted file]
tools/perf/arch/x86/Makefile
tools/perf/arch/x86/include/perf_regs.h
tools/perf/arch/x86/tests/dwarf-unwind.c [new file with mode: 0644]
tools/perf/arch/x86/tests/regs_load.S [new file with mode: 0644]
tools/perf/arch/x86/util/unwind-libdw.c [new file with mode: 0644]
tools/perf/arch/x86/util/unwind-libunwind.c [new file with mode: 0644]
tools/perf/arch/x86/util/unwind.c [deleted file]
tools/perf/bench/bench.h
tools/perf/bench/futex-hash.c [new file with mode: 0644]
tools/perf/bench/futex-requeue.c [new file with mode: 0644]
tools/perf/bench/futex-wake.c [new file with mode: 0644]
tools/perf/bench/futex.h [new file with mode: 0644]
tools/perf/bench/numa.c
tools/perf/builtin-bench.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kvm.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/config/feature-checks/test-all.c
tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c [new file with mode: 0644]
tools/perf/design.txt
tools/perf/perf-completion.sh
tools/perf/perf.h
tools/perf/tests/builtin-test.c
tools/perf/tests/dwarf-unwind.c [new file with mode: 0644]
tools/perf/tests/hists_link.c
tools/perf/tests/make
tools/perf/tests/parse-events.c
tools/perf/tests/sample-parsing.c
tools/perf/tests/tests.h
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/annotate.c
tools/perf/util/cpumap.c
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/fs.c [deleted file]
tools/perf/util/fs.h [deleted file]
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/include/linux/hash.h [deleted file]
tools/perf/util/include/linux/kernel.h
tools/perf/util/include/linux/list.h
tools/perf/util/include/linux/magic.h [deleted file]
tools/perf/util/include/linux/prefetch.h [deleted file]
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.h
tools/perf/util/parse-options.c
tools/perf/util/parse-options.h
tools/perf/util/perf_regs.c [new file with mode: 0644]
tools/perf/util/perf_regs.h
tools/perf/util/pmu.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/python-ext-sources
tools/perf/util/record.c
tools/perf/util/session.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/trace-event-parse.c
tools/perf/util/unwind-libdw.c [new file with mode: 0644]
tools/perf/util/unwind-libdw.h [new file with mode: 0644]
tools/perf/util/unwind-libunwind.c [new file with mode: 0644]
tools/perf/util/unwind.c [deleted file]
tools/perf/util/unwind.h
tools/perf/util/util.c
tools/testing/selftests/ipc/msgque.c
tools/testing/selftests/rcutorture/bin/functions.sh
tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh [new file with mode: 0755]
tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh [new file with mode: 0755]
tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh [deleted file]
tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh [new file with mode: 0755]
tools/testing/selftests/rcutorture/bin/kvm.sh
tools/testing/selftests/rcutorture/configs/CFLIST [deleted file]
tools/testing/selftests/rcutorture/configs/SRCU-N [deleted file]
tools/testing/selftests/rcutorture/configs/SRCU-N.boot [deleted file]
tools/testing/selftests/rcutorture/configs/SRCU-P [deleted file]
tools/testing/selftests/rcutorture/configs/SRCU-P.boot [deleted file]
tools/testing/selftests/rcutorture/configs/TINY01 [deleted file]
tools/testing/selftests/rcutorture/configs/TINY02 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE01 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE01.boot [deleted file]
tools/testing/selftests/rcutorture/configs/TREE02 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE03 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE04 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE04.boot [deleted file]
tools/testing/selftests/rcutorture/configs/TREE05 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE05.boot [deleted file]
tools/testing/selftests/rcutorture/configs/TREE06 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE07 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE08 [deleted file]
tools/testing/selftests/rcutorture/configs/TREE08-T [deleted file]
tools/testing/selftests/rcutorture/configs/TREE09 [deleted file]
tools/testing/selftests/rcutorture/configs/lock/BUSTED [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/CFLIST [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/CFcommon [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/LOCK01 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/BUSTED [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/CFLIST [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/CFcommon [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/SRCU-N [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/SRCU-P [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TINY01 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TINY02 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE01 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE02 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE03 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE04 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE05 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE06 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE07 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE08 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE08-T [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/TREE09 [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh [new file with mode: 0644]
tools/testing/selftests/rcutorture/configs/v0.0/CFLIST [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/CFLIST [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/CFLIST [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/CFLIST [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH [deleted file]
tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh [deleted file]
tools/testing/selftests/rcutorture/configs/ver_functions.sh [deleted file]
tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt [deleted file]
tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt [new file with mode: 0644]
virt/kvm/kvm_main.c

index efe449bdf811db7a1c9f74f38a0371d2c0dd692e..7dbf96b724edb7c2035e358c5736a1bea03c6bb5 100644 (file)
@@ -187,7 +187,7 @@ Description:
                Not all drivers support this attribute.  If it isn't supported,
                attempts to read or write it will yield I/O errors.
 
-What:          /sys/devices/.../power/pm_qos_latency_us
+What:          /sys/devices/.../power/pm_qos_resume_latency_us
 Date:          March 2012
 Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
@@ -205,6 +205,31 @@ Description:
                This attribute has no effect on system-wide suspend/resume and
                hibernation.
 
+What:          /sys/devices/.../power/pm_qos_latency_tolerance_us
+Date:          January 2014
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               The /sys/devices/.../power/pm_qos_latency_tolerance_us attribute
+               contains the PM QoS active state latency tolerance limit for the
+               given device in microseconds.  That is the maximum memory access
+               latency the device can suffer without any visible adverse
+               effects on user space functionality.  If that value is the
+               string "any", the latency does not matter to user space at all,
+               but hardware should not be allowed to set the latency tolerance
+               for the device automatically.
+
+               Reading "auto" from this file means that the maximum memory
+               access latency for the device may be determined automatically
+               by the hardware as needed.  Writing "auto" to it allows the
+               hardware to be switched to this mode if there are no other
+               latency tolerance requirements from the kernel side.
+
+               This attribute is only present if the feature controlled by it
+               is supported by the hardware.
+
+               This attribute has no effect on runtime suspend and resume of
+               devices and on system-wide suspend/resume and hibernation.
+
 What:          /sys/devices/.../power/pm_qos_no_power_off
 Date:          September 2012
 Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
index 205a7387844106804de496ec9b3a8c372b725977..64c9276e94218ce2379172afdd98c795bf1fab11 100644 (file)
@@ -12,8 +12,9 @@ Contact:      Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
                The /sys/power/state file controls the system power state.
                Reading from this file returns what states are supported,
-               which is hard-coded to 'standby' (Power-On Suspend), 'mem'
-               (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
+               which is hard-coded to 'freeze' (Low-Power Idle), 'standby'
+               (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk'
+               (Suspend-to-Disk).
 
                Writing to this file one of these strings causes the system to
                transition into that state. Please see the file
index 0f9c6ff41aac5206eb470ef07d68553d067022f0..8d96ebf524e96e0f001dc999b1734b7b97feda4e 100644 (file)
@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
-           tracepoint.xml drm.xml media_api.xml
+           tracepoint.xml drm.xml media_api.xml w1.xml
 
 include $(srctree)/Documentation/DocBook/media/Makefile
 
diff --git a/Documentation/DocBook/w1.tmpl b/Documentation/DocBook/w1.tmpl
new file mode 100644 (file)
index 0000000..b0228d4
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="w1id">
+  <bookinfo>
+    <title>W1: Dallas' 1-wire bus</title>
+
+    <authorgroup>
+      <author>
+        <firstname>David</firstname>
+        <surname>Fries</surname>
+        <affiliation>
+          <address>
+            <email>David@Fries.net</email>
+          </address>
+        </affiliation>
+      </author>
+
+    </authorgroup>
+
+    <copyright>
+      <year>2013</year>
+      <!--
+      <holder></holder>
+      -->
+    </copyright>
+
+    <legalnotice>
+      <para>
+        This documentation is free software; you can redistribute
+        it and/or modify it under the terms of the GNU General Public
+        License version 2.
+      </para>
+
+      <para>
+        This program is distributed in the hope that it will be
+        useful, but WITHOUT ANY WARRANTY; without even the implied
+        warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+        For more details see the file COPYING in the source
+        distribution of Linux.
+      </para>
+    </legalnotice>
+  </bookinfo>
+
+  <toc></toc>
+
+  <chapter id="w1_internal">
+    <title>W1 API internal to the kernel</title>
+
+    <sect1 id="w1_internal_api">
+      <title>W1 API internal to the kernel</title>
+      <sect2 id="w1.h">
+        <title>drivers/w1/w1.h</title>
+        <para>W1 core functions.</para>
+!Idrivers/w1/w1.h
+      </sect2>
+
+      <sect2 id="w1.c">
+        <title>drivers/w1/w1.c</title>
+        <para>W1 core functions.</para>
+!Idrivers/w1/w1.c
+      </sect2>
+
+      <sect2 id="w1_family.h">
+        <title>drivers/w1/w1_family.h</title>
+        <para>Allows registering device family operations.</para>
+!Idrivers/w1/w1_family.h
+      </sect2>
+
+      <sect2 id="w1_family.c">
+        <title>drivers/w1/w1_family.c</title>
+        <para>Allows registering device family operations.</para>
+!Edrivers/w1/w1_family.c
+      </sect2>
+
+      <sect2 id="w1_int.c">
+        <title>drivers/w1/w1_int.c</title>
+        <para>W1 internal initialization for master devices.</para>
+!Edrivers/w1/w1_int.c
+      </sect2>
+
+      <sect2 id="w1_netlink.h">
+        <title>drivers/w1/w1_netlink.h</title>
+        <para>W1 external netlink API structures and commands.</para>
+!Idrivers/w1/w1_netlink.h
+      </sect2>
+
+      <sect2 id="w1_io.c">
+        <title>drivers/w1/w1_io.c</title>
+        <para>W1 input/output.</para>
+!Edrivers/w1/w1_io.c
+!Idrivers/w1/w1_io.c
+      </sect2>
+
+    </sect1>
+
+
+  </chapter>
+
+</book>
index 06741e9259850d43eaac5d287da48fa284992255..d0056a4e9c53fc9e455ec5eaad518074dbc5b152 100644 (file)
                   return err;
           }
 
-          snd_card_set_dev(card, &pci->dev);
-
           *rchip = chip;
           return 0;
   }
           }
 
           /* (2) */
-          err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+          err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                             0, &card);
           if (err < 0)
                   return err;
 
   struct snd_card *card;
   int err;
   ....
-  err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+  err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                     0, &card);
 ]]>
             </programlisting>
           </informalexample>
 
       <para>
         As mentioned above, to create a card instance, call
-      <function>snd_card_create()</function>.
+      <function>snd_card_new()</function>.
 
         <informalexample>
           <programlisting>
 <![CDATA[
   struct snd_card *card;
   int err;
-  err = snd_card_create(index, id, module, extra_size, &card);
+  err = snd_card_new(&pci->dev, index, id, module, extra_size, &card);
 ]]>
           </programlisting>
         </informalexample>
       </para>
 
       <para>
-        The function takes five arguments, the card-index number, the
-        id string, the module pointer (usually
+        The function takes six arguments: the parent device pointer,
+        the card-index number, the id string, the module pointer (usually
         <constant>THIS_MODULE</constant>),
         the size of extra-data space, and the pointer to return the
         card instance.  The extra_size argument is used to
         allocate card-&gt;private_data for the
         chip-specific data.  Note that these data
-        are allocated by <function>snd_card_create()</function>.
+        are allocated by <function>snd_card_new()</function>.
+      </para>
+
+      <para>
+       The first argument, the pointer of struct
+       <structname>device</structname>, specifies the parent device.
+       For PCI devices, typically &amp;pci-&gt; is passed there.
       </para>
     </section>
 
       </para>
 
       <section id="card-management-chip-specific-snd-card-new">
-        <title>1. Allocating via <function>snd_card_create()</function>.</title>
+        <title>1. Allocating via <function>snd_card_new()</function>.</title>
         <para>
           As mentioned above, you can pass the extra-data-length
-         to the 4th argument of <function>snd_card_create()</function>, i.e.
+         to the 5th argument of <function>snd_card_new()</function>, i.e.
 
           <informalexample>
             <programlisting>
 <![CDATA[
-  err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                        sizeof(struct mychip), &card);
+  err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                     sizeof(struct mychip), &card);
 ]]>
             </programlisting>
           </informalexample>
 
         <para>
           After allocating a card instance via
-          <function>snd_card_create()</function> (with
+          <function>snd_card_new()</function> (with
           <constant>0</constant> on the 4th arg), call
           <function>kzalloc()</function>. 
 
 <![CDATA[
   struct snd_card *card;
   struct mychip *chip;
-  err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+  err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                     0, &card);
   .....
   chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 ]]>
                   return err;
           }
 
-          snd_card_set_dev(card, &pci->dev);
-
           *rchip = chip;
           return 0;
   }        
 
     </section>
 
-    <section id="pci-resource-device-struct">
-      <title>Registration of Device Struct</title>
-      <para>
-       At some point, typically after calling <function>snd_device_new()</function>,
-       you need to register the struct <structname>device</structname> of the chip
-       you're handling for udev and co.  ALSA provides a macro for compatibility with
-       older kernels.  Simply call like the following:
-        <informalexample>
-          <programlisting>
-<![CDATA[
-  snd_card_set_dev(card, &pci->dev);
-]]>
-          </programlisting>
-        </informalexample>
-       so that it stores the PCI's device pointer to the card.  This will be
-       referred by ALSA core functions later when the devices are registered.
-      </para>
-      <para>
-       In the case of non-PCI, pass the proper device struct pointer of the BUS
-       instead.  (In the case of legacy ISA without PnP, you don't have to do
-       anything.)
-      </para>
-    </section>
-
     <section id="pci-resource-entries">
       <title>PCI Entries</title>
       <para>
@@ -5740,7 +5721,8 @@ struct _snd_pcm_runtime {
           struct mychip *chip;
           int err;
           ....
-          err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+          err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                             0, &card);
           ....
           chip = kzalloc(sizeof(*chip), GFP_KERNEL);
           ....
@@ -5752,7 +5734,7 @@ struct _snd_pcm_runtime {
       </informalexample>
 
        When you created the chip data with
-       <function>snd_card_create()</function>, it's anyway accessible
+       <function>snd_card_new()</function>, it's anyway accessible
        via <structfield>private_data</structfield> field.
 
       <informalexample>
@@ -5766,8 +5748,8 @@ struct _snd_pcm_runtime {
           struct mychip *chip;
           int err;
           ....
-          err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                                sizeof(struct mychip), &card);
+          err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct mychip), &card);
           ....
           chip = card->private_data;
           ....
index 86551cc72e034fc48e63c54c6e662954ca857372..2d91ae25198295dc8559d2ef8d00cae1b5314989 100644 (file)
@@ -68,10 +68,6 @@ To disable SR-IOV capability:
        echo  0 > \
         /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
 
-To notify SR-IOV core of Virtual Function Migration:
-(a) In the driver:
-       irqreturn_t pci_sriov_migration(struct pci_dev *dev);
-
 3.2 Usage example
 
 Following piece of code illustrates the usage of the SR-IOV API.
index 273e654d7d086531ae958e16af780d7a0d1404d1..2f0fcb2112d271b01ba74b16a4c65c82caebb009 100644 (file)
@@ -31,6 +31,14 @@ has lapsed, so this approach may be used in non-GPL software, if desired.
 (In contrast, implementation of RCU is permitted only in software licensed
 under either GPL or LGPL.  Sorry!!!)
 
+In 1987, Rashid et al. described lazy TLB-flush [RichardRashid87a].
+At first glance, this has nothing to do with RCU, but nevertheless
+this paper helped inspire the update-side batching used in the later
+RCU implementation in DYNIX/ptx.  In 1988, Barbara Liskov published
+a description of Argus that noted that use of out-of-date values can
+be tolerated in some situations.  Thus, this paper provides some early
+theoretical justification for use of stale data.
+
 In 1990, Pugh [Pugh90] noted that explicitly tracking which threads
 were reading a given data structure permitted deferred free to operate
 in the presence of non-terminating threads.  However, this explicit
@@ -41,11 +49,11 @@ providing a fine-grained locking design, however, it would be interesting
 to see how much of the performance advantage reported in 1990 remains
 today.
 
-At about this same time, Adams [Adams91] described ``chaotic relaxation'',
-where the normal barriers between successive iterations of convergent
-numerical algorithms are relaxed, so that iteration $n$ might use
-data from iteration $n-1$ or even $n-2$.  This introduces error,
-which typically slows convergence and thus increases the number of
+At about this same time, Andrews [Andrews91textbook] described ``chaotic
+relaxation'', where the normal barriers between successive iterations
+of convergent numerical algorithms are relaxed, so that iteration $n$
+might use data from iteration $n-1$ or even $n-2$.  This introduces
+error, which typically slows convergence and thus increases the number of
 iterations required.  However, this increase is sometimes more than made
 up for by a reduction in the number of expensive barrier operations,
 which are otherwise required to synchronize the threads at the end
@@ -55,7 +63,8 @@ is thus inapplicable to most data structures in operating-system kernels.
 
 In 1992, Henry (now Alexia) Massalin completed a dissertation advising
 parallel programmers to defer processing when feasible to simplify
-synchronization.  RCU makes extremely heavy use of this advice.
+synchronization [HMassalinPhD].  RCU makes extremely heavy use of
+this advice.
 
 In 1993, Jacobson [Jacobson93] verbally described what is perhaps the
 simplest deferred-free technique: simply waiting a fixed amount of time
@@ -90,27 +99,29 @@ mechanism, which is quite similar to RCU [Gamsa99].  These operating
 systems made pervasive use of RCU in place of "existence locks", which
 greatly simplifies locking hierarchies and helps avoid deadlocks.
 
-2001 saw the first RCU presentation involving Linux [McKenney01a]
-at OLS.  The resulting abundance of RCU patches was presented the
-following year [McKenney02a], and use of RCU in dcache was first
-described that same year [Linder02a].
+The year 2000 saw an email exchange that would likely have
+led to yet another independent invention of something like RCU
+[RustyRussell2000a,RustyRussell2000b].  Instead, 2001 saw the first
+RCU presentation involving Linux [McKenney01a] at OLS.  The resulting
+abundance of RCU patches was presented the following year [McKenney02a],
+and use of RCU in dcache was first described that same year [Linder02a].
 
 Also in 2002, Michael [Michael02b,Michael02a] presented "hazard-pointer"
 techniques that defer the destruction of data structures to simplify
 non-blocking synchronization (wait-free synchronization, lock-free
 synchronization, and obstruction-free synchronization are all examples of
-non-blocking synchronization).  In particular, this technique eliminates
-locking, reduces contention, reduces memory latency for readers, and
-parallelizes pipeline stalls and memory latency for writers.  However,
-these techniques still impose significant read-side overhead in the
-form of memory barriers.  Researchers at Sun worked along similar lines
-in the same timeframe [HerlihyLM02].  These techniques can be thought
-of as inside-out reference counts, where the count is represented by the
-number of hazard pointers referencing a given data structure rather than
-the more conventional counter field within the data structure itself.
-The key advantage of inside-out reference counts is that they can be
-stored in immortal variables, thus allowing races between access and
-deletion to be avoided.
+non-blocking synchronization).  The corresponding journal article appeared
+in 2004 [MagedMichael04a].  This technique eliminates locking, reduces
+contention, reduces memory latency for readers, and parallelizes pipeline
+stalls and memory latency for writers.  However, these techniques still
+impose significant read-side overhead in the form of memory barriers.
+Researchers at Sun worked along similar lines in the same timeframe
+[HerlihyLM02].  These techniques can be thought of as inside-out reference
+counts, where the count is represented by the number of hazard pointers
+referencing a given data structure rather than the more conventional
+counter field within the data structure itself.  The key advantage
+of inside-out reference counts is that they can be stored in immortal
+variables, thus allowing races between access and deletion to be avoided.
 
 By the same token, RCU can be thought of as a "bulk reference count",
 where some form of reference counter covers all reference by a given CPU
@@ -123,8 +134,10 @@ can be thought of in other terms as well.
 
 In 2003, the K42 group described how RCU could be used to create
 hot-pluggable implementations of operating-system functions [Appavoo03a].
-Later that year saw a paper describing an RCU implementation of System
-V IPC [Arcangeli03], and an introduction to RCU in Linux Journal
+Later that year saw a paper describing an RCU implementation
+of System V IPC [Arcangeli03] (following up on a suggestion by
+Hugh Dickins [Dickins02a] and an implementation by Mingming Cao
+[MingmingCao2002IPCRCU]), and an introduction to RCU in Linux Journal
 [McKenney03a].
 
 2004 has seen a Linux-Journal article on use of RCU in dcache
@@ -383,6 +396,21 @@ for Programming Languages and Operating Systems}"
 }
 }
 
+@phdthesis{HMassalinPhD
+,author="H. Massalin"
+,title="Synthesis: An Efficient Implementation of Fundamental Operating
+System Services"
+,school="Columbia University"
+,address="New York, NY"
+,year="1992"
+,annotation={
+       Mondo optimizing compiler.
+       Wait-free stuff.
+       Good advice: defer work to avoid synchronization.  See page 90
+               (PDF page 106), Section 5.4, fourth bullet point.
+}
+}
+
 @unpublished{Jacobson93
 ,author="Van Jacobson"
 ,title="Avoid Read-Side Locking Via Delayed Free"
@@ -671,6 +699,20 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
 [Viewed October 18, 2004]"
 }
 
+@conference{Michael02b
+,author="Maged M. Michael"
+,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM
+Symposium on Parallel
+Algorithms and Architecture}"
+,pages="73-82"
+,annotation={
+Like the title says...
+}
+}
+
 @Conference{Linder02a
 ,Author="Hanna Linder and Dipankar Sarma and Maneesh Soni"
 ,Title="Scalability of the Directory Entry Cache"
@@ -727,6 +769,24 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 }
 }
 
+@conference{Michael02a
+,author="Maged M. Michael"
+,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic
+Reads and Writes"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM
+Symposium on Principles of Distributed Computing}"
+,pages="21-30"
+,annotation={
+       Each thread keeps an array of pointers to items that it is
+       currently referencing.  Sort of an inside-out garbage collection
+       mechanism, but one that requires the accessing code to explicitly
+       state its needs.  Also requires read-side memory barriers on
+       most architectures.
+}
+}
+
 @unpublished{Dickins02a
 ,author="Hugh Dickins"
 ,title="Use RCU for System-V IPC"
@@ -735,6 +795,17 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 ,note="private communication"
 }
 
+@InProceedings{HerlihyLM02
+,author={Maurice Herlihy and Victor Luchangco and Mark Moir}
+,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized,
+Lock-Free Data Structures"
+,booktitle={Proceedings of 16\textsuperscript{th} International
+Symposium on Distributed Computing}
+,year=2002
+,month="October"
+,pages="339-353"
+}
+
 @unpublished{Sarma02b
 ,Author="Dipankar Sarma"
 ,Title="Some dcache\_rcu benchmark numbers"
@@ -749,6 +820,19 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 }
 }
 
+@unpublished{MingmingCao2002IPCRCU
+,Author="Mingming Cao"
+,Title="[PATCH]updated ipc lock patch"
+,month="October"
+,year="2002"
+,note="Available:
+\url{https://lkml.org/lkml/2002/10/24/262}
+[Viewed February 15, 2014]"
+,annotation={
+       Mingming Cao's patch to introduce RCU to SysV IPC.
+}
+}
+
 @unpublished{LinusTorvalds2003a
 ,Author="Linus Torvalds"
 ,Title="Re: {[PATCH]} small fixes in brlock.h"
@@ -982,6 +1066,23 @@ Realtime Applications"
 }
 }
 
+@article{MagedMichael04a
+,author="Maged M. Michael"
+,title="Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects"
+,Year="2004"
+,Month="June"
+,journal="IEEE Transactions on Parallel and Distributed Systems"
+,volume="15"
+,number="6"
+,pages="491-504"
+,url="Available:
+\url{http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf}
+[Viewed March 1, 2005]"
+,annotation={
+       New canonical hazard-pointer citation.
+}
+}
+
 @phdthesis{PaulEdwardMcKenneyPhD
 ,author="Paul E. McKenney"
 ,title="Exploiting Deferred Destruction:
index 91266193b8f49e840709db77d75f8357428b2806..9d10d1db16a53ffc464c484cc7fe1b7ef2a1e864 100644 (file)
@@ -256,10 +256,10 @@ over a rather long period of time, but improvements are always welcome!
                variations on this theme.
 
        b.      Limiting update rate.  For example, if updates occur only
-               once per hour, then no explicit rate limiting is required,
-               unless your system is already badly broken.  The dcache
-               subsystem takes this approach -- updates are guarded
-               by a global lock, limiting their rate.
+               once per hour, then no explicit rate limiting is
+               required, unless your system is already badly broken.
+               Older versions of the dcache subsystem take this approach,
+               guarding updates with a global lock, limiting their rate.
 
        c.      Trusted update -- if updates can only be done manually by
                superuser or some other trusted user, then it might not
@@ -268,7 +268,8 @@ over a rather long period of time, but improvements are always welcome!
                the machine.
 
        d.      Use call_rcu_bh() rather than call_rcu(), in order to take
-               advantage of call_rcu_bh()'s faster grace periods.
+               advantage of call_rcu_bh()'s faster grace periods.  (This
+               is only a partial solution, though.)
 
        e.      Periodically invoke synchronize_rcu(), permitting a limited
                number of updates per grace period.
@@ -276,6 +277,13 @@ over a rather long period of time, but improvements are always welcome!
        The same cautions apply to call_rcu_bh(), call_rcu_sched(),
        call_srcu(), and kfree_rcu().
 
+       Note that although these primitives do take action to avoid memory
+       exhaustion when any given CPU has too many callbacks, a determined
+       user could still exhaust memory.  This is especially the case
+       if a system with a large number of CPUs has been configured to
+       offload all of its RCU callbacks onto a single CPU, or if the
+       system has relatively little free memory.
+
 9.     All RCU list-traversal primitives, which include
        rcu_dereference(), list_for_each_entry_rcu(), and
        list_for_each_safe_rcu(), must be either within an RCU read-side
index 5e054bfe4dde8e30e178c073d19c8c2b520a7e0f..85e24c4f215c45136eb3393763dc802b007ac408 100644 (file)
@@ -35,11 +35,13 @@ ffffffbc00000000    ffffffbdffffffff           8GB          vmemmap
 
 ffffffbe00000000       ffffffbffbbfffff          ~8GB          [guard, future vmmemap]
 
-ffffffbffbc00000       ffffffbffbdfffff           2MB          earlyprintk device
+ffffffbffa000000       ffffffbffaffffff          16MB          PCI I/O space
+
+ffffffbffb000000       ffffffbffbbfffff          12MB          [guard]
 
-ffffffbffbe00000       ffffffbffbe0ffff          64KB          PCI I/O space
+ffffffbffbc00000       ffffffbffbdfffff           2MB          earlyprintk device
 
-ffffffbffbe10000       ffffffbcffffffff          ~2MB          [guard]
+ffffffbffbe00000       ffffffbffbffffff           2MB          [guard]
 
 ffffffbffc000000       ffffffbfffffffff          64MB          modules
 
@@ -60,11 +62,13 @@ fffffdfc00000000    fffffdfdffffffff           8GB          vmemmap
 
 fffffdfe00000000       fffffdfffbbfffff          ~8GB          [guard, future vmmemap]
 
-fffffdfffbc00000       fffffdfffbdfffff           2MB          earlyprintk device
+fffffdfffa000000       fffffdfffaffffff          16MB          PCI I/O space
+
+fffffdfffb000000       fffffdfffbbfffff          12MB          [guard]
 
-fffffdfffbe00000       fffffdfffbe0ffff          64KB          PCI I/O space
+fffffdfffbc00000       fffffdfffbdfffff           2MB          earlyprintk device
 
-fffffdfffbe10000       fffffdfffbffffff          ~2MB          [guard]
+fffffdfffbe00000       fffffdfffbffffff           2MB          [guard]
 
 fffffdfffc000000       fffffdffffffffff          64MB          modules
 
index adcca0368d602ff4cb54c10365aa4b3651a4e79b..d12cc944b69621e44b77a7a6f6abc8d3e6b76bb4 100644 (file)
@@ -145,7 +145,7 @@ static void cn_test_timer_func(unsigned long __data)
 
                memcpy(m + 1, data, m->len);
 
-               cn_netlink_send(m, 0, GFP_ATOMIC);
+               cn_netlink_send(m, 0, 0, GFP_ATOMIC);
                kfree(m);
        }
 
index ce0666e5103682a766caff09a4af75513c38f77f..0060d76b445f3e42d89bf0a47d15440c2cd440e7 100644 (file)
@@ -92,7 +92,3 @@ values:
 cpu    - number of the affected CPU
 old    - old frequency
 new    - new frequency
-
-If the cpufreq core detects the frequency has changed while the system
-was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
-second argument.
index 8b1a4451422e747a2278c0ba48ed4ca58e131ba3..48da5fdcb9f11b5671859a63e61ce2c9f40bab03 100644 (file)
@@ -61,7 +61,13 @@ target_index         -       See below on the differences.
 
 And optionally
 
-cpufreq_driver.exit -          A pointer to a per-CPU cleanup function.
+cpufreq_driver.exit -          A pointer to a per-CPU cleanup
+                               function called during CPU_POST_DEAD
+                               phase of cpu hotplug process.
+
+cpufreq_driver.stop_cpu -      A pointer to a per-CPU stop function
+                               called during CPU_DOWN_PREPARE phase of
+                               cpu hotplug process.
 
 cpufreq_driver.resume -                A pointer to a per-CPU resume function
                                which is called with interrupts disabled
index e6b72d35515123ad0aff423999aeef359183bb3d..68c0f517c60edb1ab7a61e990720c7c8f097bb16 100644 (file)
@@ -124,12 +124,11 @@ the default being 204800 sectors (or 100MB).
 Updating on-disk metadata
 -------------------------
 
-On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
-written.  If no such requests are made then commits will occur every
-second.  This means the cache behaves like a physical disk that has a
-write cache (the same is true of the thin-provisioning target).  If
-power is lost you may lose some recent writes.  The metadata should
-always be consistent in spite of any crash.
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second.  This
+means the cache behaves like a physical disk that has a volatile write
+cache.  If power is lost you may lose some recent writes.  The metadata
+should always be consistent in spite of any crash.
 
 The 'dirty' state for a cache block changes far too frequently for us
 to keep updating it on the fly.  So we treat it as a hint.  In normal
index 8a7a3d46e0daa00d6f87315648b7cb292e8c05b4..05a27e9442bd4e5c4d3e618a6a0594e55466b192 100644 (file)
@@ -116,6 +116,35 @@ Resuming a device with a new table itself triggers an event so the
 userspace daemon can use this to detect a situation where a new table
 already exceeds the threshold.
 
+A low water mark for the metadata device is maintained in the kernel and
+will trigger a dm event if free space on the metadata device drops below
+it.
+
+Updating on-disk metadata
+-------------------------
+
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second.  This
+means the thin-provisioning target behaves like a physical disk that has
+a volatile write cache.  If power is lost you may lose some recent
+writes.  The metadata should always be consistent in spite of any crash.
+
+If data space is exhausted the pool will either error or queue IO
+according to the configuration (see: error_if_no_space).  If metadata
+space is exhausted or a metadata operation fails: the pool will error IO
+until the pool is taken offline and repair is performed to 1) fix any
+potential inconsistencies and 2) clear the flag that imposes repair.
+Once the pool's metadata device is repaired it may be resized, which
+will allow the pool to return to normal operation.  Note that if a pool
+is flagged as needing repair, the pool's data and metadata devices
+cannot be resized until repair is performed.  It should also be noted
+that when the pool's metadata space is exhausted the current metadata
+transaction is aborted.  Given that the pool will cache IO whose
+completion may have already been acknowledged to upper IO layers
+(e.g. filesystem) it is strongly suggested that consistency checks
+(e.g. fsck) be performed on those layers when repair of the pool is
+required.
+
 Thin provisioning
 -----------------
 
@@ -258,10 +287,9 @@ ii) Status
        should register for the event and then check the target's status.
 
     held metadata root:
-       The location, in sectors, of the metadata root that has been
+       The location, in blocks, of the metadata root that has been
        'held' for userspace read access.  '-' indicates there is no
-       held root.  This feature is not yet implemented so '-' is
-       always returned.
+       held root.
 
     discard_passdown|no_discard_passdown
        Whether or not discards are actually being passed down to the
index 10378cc48374cf8ffde068d4ce329ce5b5cbb205..087d2122b204fd919d66a6df71b1d38e96a81133 100644 (file)
@@ -410,6 +410,7 @@ Your cooperation is appreciated.
                194 = /dev/zkshim       Zero-Knowledge network shim control
                195 = /dev/elographics/e2201    Elographics touchscreen E271-2201
                196 = /dev/vfio/vfio    VFIO userspace driver interface
+               197 = /dev/pxa3xx-gcu   PXA3xx graphics controller unit driver
                198 = /dev/sexec        Signed executable interface
                199 = /dev/scanners/cuecat :CueCat barcode scanner
                200 = /dev/net/tun      TAP/TUN network device
@@ -451,6 +452,7 @@ Your cooperation is appreciated.
                236 = /dev/mapper/control       Device-Mapper control device
                237 = /dev/loop-control Loopback control device
                238 = /dev/vhost-net    Host kernel accelerator for virtio net
+               239 = /dev/uhid         User-space I/O driver support for HID subsystem
 
                240-254                 Reserved for local use
                255                     Reserved for MISC_DYNAMIC_MINOR
index d74091a8a3bfd243490d83faedd452ec9a2c426c..5fc03134a9996473e4fe3ce1cd895b49da5b96f1 100644 (file)
@@ -1,4 +1,4 @@
-Marvell Armada 370 and Armada XP Interrupt Controller
+Marvell Armada 370, 375, 38x, XP Interrupt Controller
 -----------------------------------------------------
 
 Required properties:
@@ -16,7 +16,13 @@ Required properties:
   automatically map to the interrupt controller registers of the
   current CPU)
 
+Optional properties:
 
+- interrupts: If defined, then it indicates that this MPIC is
+  connected as a slave to another interrupt controller. This is
+  typically the case on Armada 375 and Armada 38x, where the MPIC is
+  connected as a slave to the Cortex-A9 GIC. The provided interrupt
+  indicate to which GIC interrupt the MPIC output is connected.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/arm/marvell,dove.txt b/Documentation/devicetree/bindings/arm/marvell,dove.txt
new file mode 100644 (file)
index 0000000..aaaf64c
--- /dev/null
@@ -0,0 +1,22 @@
+Marvell Dove Platforms Device Tree Bindings
+-----------------------------------------------
+
+Boards with a Marvell Dove SoC shall have the following properties:
+
+Required root node property:
+- compatible: must contain "marvell,dove";
+
+* Global Configuration registers
+
+Global Configuration registers of Dove SoC are shared by a syscon node.
+
+Required properties:
+- compatible: must contain "marvell,dove-global-config" and "syscon".
+- reg: base address and size of the Global Configuration registers.
+
+Example:
+
+gconf: global-config@e802c {
+       compatible = "marvell,dove-global-config", "syscon";
+       reg = <0xe802c 0x14>;
+};
index 89de1564950ce64cf2bdb1e087da04e2043a0db6..48b285ffa3a650e7d0adb028e7f577617b2dff9c 100644 (file)
@@ -4,17 +4,33 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
 Each SATA controller should have its own node.
 
 Required properties:
-- compatible        : compatible list, contains "snps,spear-ahci"
+- compatible        : compatible list, one of "snps,spear-ahci",
+                      "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+                      "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci"
+                      "fsl,imx6q-ahci" or "snps,dwc-ahci"
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
 Optional properties:
 - dma-coherent      : Present if dma operations are coherent
+- clocks            : a list of phandle + clock specifier pairs
+- target-supply     : regulator for SATA target power
 
-Example:
+"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
+- clocks            : must contain the sata, sata_ref and ahb clocks
+- clock-names       : must contain "ahb" for the ahb clock
+
+Examples:
         sata@ffe08000 {
                compatible = "snps,spear-ahci";
                reg = <0xffe08000 0x1000>;
                interrupts = <115>;
-
         };
+
+       ahci: sata@01c18000 {
+               compatible = "allwinner,sun4i-a10-ahci";
+               reg = <0x01c18000 0x1000>;
+               interrupts = <56>;
+               clocks = <&pll6 0>, <&ahb_gates 25>;
+               target-supply = <&reg_ahci_5v>;
+       };
diff --git a/Documentation/devicetree/bindings/ata/apm-xgene.txt b/Documentation/devicetree/bindings/ata/apm-xgene.txt
new file mode 100644 (file)
index 0000000..7bcfbf5
--- /dev/null
@@ -0,0 +1,76 @@
+* APM X-Gene 6.0 Gb/s SATA host controller nodes
+
+SATA host controller nodes are defined to describe on-chip Serial ATA
+controllers. Each SATA controller (pair of ports) have its own node.
+
+Required properties:
+- compatible           : Shall contain:
+  * "apm,xgene-ahci"
+- reg                  : First memory resource shall be the AHCI memory
+                         resource.
+                         Second memory resource shall be the host controller
+                         core memory resource.
+                         Third memory resource shall be the host controller
+                         diagnostic memory resource.
+                         4th memory resource shall be the host controller
+                         AXI memory resource.
+                         5th optional memory resource shall be the host
+                         controller MUX memory resource if required.
+- interrupts           : Interrupt-specifier for SATA host controller IRQ.
+- clocks               : Reference to the clock entry.
+- phys                 : A list of phandles + phy-specifiers, one for each
+                         entry in phy-names.
+- phy-names            : Should contain:
+  * "sata-phy" for the SATA 6.0Gbps PHY
+
+Optional properties:
+- status               : Shall be "ok" if enabled or "disabled" if disabled.
+                         Default is "ok".
+
+Example:
+               sataclk: sataclk {
+                       compatible = "fixed-clock";
+                       #clock-cells = <1>;
+                       clock-frequency = <100000000>;
+                       clock-output-names = "sataclk";
+               };
+
+               phy2: phy@1f22a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f22a000 0x0 0x100>;
+                       #phy-cells = <1>;
+               };
+
+               phy3: phy@1f23a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f23a000 0x0 0x100>;
+                       #phy-cells = <1>;
+               };
+
+               sata2: sata@1a400000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a400000 0x0 0x1000>,
+                             <0x0 0x1f220000 0x0 0x1000>,
+                             <0x0 0x1f22d000 0x0 0x1000>,
+                             <0x0 0x1f22e000 0x0 0x1000>,
+                             <0x0 0x1f227000 0x0 0x1000>;
+                       interrupts = <0x0 0x87 0x4>;
+                       status = "ok";
+                       clocks = <&sataclk 0>;
+                       phys = <&phy2 0>;
+                       phy-names = "sata-phy";
+               };
+
+               sata3: sata@1a800000 {
+                       compatible = "apm,xgene-ahci-pcie";
+                       reg = <0x0 0x1a800000 0x0 0x1000>,
+                             <0x0 0x1f230000 0x0 0x1000>,
+                             <0x0 0x1f23d000 0x0 0x1000>,
+                             <0x0 0x1f23e000 0x0 0x1000>,
+                             <0x0 0x1f237000 0x0 0x1000>;
+                       interrupts = <0x0 0x88 0x4>;
+                       status = "ok";
+                       clocks = <&sataclk 0>;
+                       phys = <&phy3 0>;
+                       phy-names = "sata-phy";
+               };
index a6a352c2771e74da0064ec9ce93a87c44ce2fe07..5992dceec7af7d1e9d1ac8f329b831d48e409d87 100644 (file)
@@ -21,9 +21,9 @@ Required Properties:
     must appear in the same order as the output clocks.
   - #clock-cells: Must be 1
   - clock-output-names: The name of the clocks as free-form strings
-  - renesas,indices: Indices of the gate clocks into the group (0 to 31)
+  - renesas,clock-indices: Indices of the gate clocks into the group (0 to 31)
 
-The clocks, clock-output-names and renesas,indices properties contain one
+The clocks, clock-output-names and renesas,clock-indices properties contain one
 entry per gate clock. The MSTP groups are sparsely populated. Unimplemented
 gate clocks must not be declared.
 
index 1a1ac2e560e94a083c5df71fa9bad004e12df7ab..f47e56bcf78d49bea32e9b259cd09a44638f4e81 100644 (file)
@@ -18,6 +18,7 @@ atmel,24c02           i2c serial eeprom  (24cxx)
 atmel,at97sc3204t      i2c trusted platform module (TPM)
 capella,cm32181                CM32181: Ambient Light Sensor
 catalyst,24c32         i2c serial eeprom
+cirrus,cs42l51         Cirrus Logic CS42L51 audio codec
 dallas,ds1307          64 x 8, Serial, I2C Real-Time Clock
 dallas,ds1338          I2C RTC with 56-Byte NV RAM
 dallas,ds1339          I2C Serial Real-Time Clock
index 32cec4b26cd08f69e5380c05234b4c0fb50bc9e4..b290ca150d30eabb5bd25ac64ff8efb682caab47 100644 (file)
@@ -2,7 +2,7 @@ Allwinner Sunxi Interrupt Controller
 
 Required properties:
 
-- compatible : should be "allwinner,sun4i-ic"
+- compatible : should be "allwinner,sun4i-a10-ic"
 - reg : Specifies base physical address and size of the registers.
 - interrupt-controller : Identifies the node as an interrupt controller
 - #interrupt-cells : Specifies the number of cells needed to encode an
@@ -11,7 +11,7 @@ Required properties:
 Example:
 
 intc: interrupt-controller {
-       compatible = "allwinner,sun4i-ic";
+       compatible = "allwinner,sun4i-a10-ic";
        reg = <0x01c20400 0x400>;
        interrupt-controller;
        #interrupt-cells = <1>;
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
new file mode 100644 (file)
index 0000000..d1c5cda
--- /dev/null
@@ -0,0 +1,27 @@
+Allwinner Sunxi NMI Controller
+==============================
+
+Required properties:
+
+- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
+  "allwinner,sun6i-a31-sc-nmi"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 2. The first cell is the IRQ number, the
+  second cell the trigger type as defined in interrupt.txt in this directory.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the interrupt line (NMI) which is handled by
+  the interrupt controller in the parent controller's notation. This value
+  shall be the NMI.
+
+Example:
+
+sc-nmi-intc@01c00030 {
+       compatible = "allwinner,sun7i-a20-sc-nmi";
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       reg = <0x01c00030 0x0c>;
+       interrupt-parent = <&gic>;
+       interrupts = <0 0 4>;
+};
diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt
new file mode 100644 (file)
index 0000000..d5e3704
--- /dev/null
@@ -0,0 +1,79 @@
+Integrated Flash Controller
+
+Properties:
+- name : Should be ifc
+- compatible : should contain "fsl,ifc". The version of the integrated
+               flash controller can be found in the IFC_REV register at
+               offset zero.
+
+- #address-cells : Should be either two or three.  The first cell is the
+                   chipselect number, and the remaining cells are the
+                   offset into the chipselect.
+- #size-cells : Either one or two, depending on how large each chipselect
+                can be.
+- reg : Offset and length of the register set for the device
+- interrupts: IFC may have one or two interrupts.  If two interrupt
+              specifiers are present, the first is the "common"
+              interrupt (CM_EVTER_STAT), and the second is the NAND
+              interrupt (NAND_EVTER_STAT).  If there is only one,
+              that interrupt reports both types of event.
+
+
+- ranges : Each range corresponds to a single chipselect, and covers
+           the entire access window as configured.
+
+Child device nodes describe the devices connected to IFC such as NOR (e.g.
+cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices
+like FPGAs, CPLDs, etc.
+
+Example:
+
+       ifc@ffe1e000 {
+               compatible = "fsl,ifc", "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0x0 0xffe1e000 0 0x2000>;
+               interrupts = <16 2 19 2>;
+
+               /* NOR, NAND Flashes and CPLD on board */
+               ranges = <0x0 0x0 0x0 0xee000000 0x02000000
+                         0x1 0x0 0x0 0xffa00000 0x00010000
+                         0x3 0x0 0x0 0xffb00000 0x00020000>;
+
+               flash@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x0 0x2000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       partition@0 {
+                               /* 32MB for user data */
+                               reg = <0x0 0x02000000>;
+                               label = "NOR Data";
+                       };
+               };
+
+               flash@1,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,ifc-nand";
+                       reg = <0x1 0x0 0x10000>;
+
+                       partition@0 {
+                               /* This location must not be altered  */
+                               /* 1MB for u-boot Bootloader Image */
+                               reg = <0x0 0x00100000>;
+                               label = "NAND U-Boot Image";
+                               read-only;
+                       };
+               };
+
+               cpld@3,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,p1010rdb-cpld";
+                       reg = <0x3 0x0 0x000001f>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt
new file mode 100644 (file)
index 0000000..9592717
--- /dev/null
@@ -0,0 +1,210 @@
+* Device tree bindings for Texas instruments AEMIF controller
+
+The Async External Memory Interface (EMIF16/AEMIF) controller is intended to
+provide a glue-less interface to a variety of asynchronous memory devices like
+ASRA M, NOR and NAND memory. A total of 256M bytes of any of these memories
+can be accessed at any given time via four chip selects with 64M byte access
+per chip select. Synchronous memories such as DDR1 SD RAM, SDR SDRAM
+and Mobile SDR are not supported.
+
+Documentation:
+Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
+OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf
+Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
+
+Required properties:
+
+- compatible:          "ti,davinci-aemif"
+                       "ti,keystone-aemif"
+                       "ti,da850-aemif"
+
+- reg:                 contains offset/length value for AEMIF control registers
+                       space.
+
+- #address-cells:      Must be 2. The partition number has to be encoded in the
+                       first address cell and it may accept values 0..N-1
+                       (N - total number of partitions). It's recommended to
+                       assign N-1 number for the control partition. The second
+                       cell is the offset into the partition.
+
+- #size-cells:         Must be set to 1.
+
+- ranges:              Contains memory regions. There are two types of
+                       ranges/partitions:
+                       - CS-specific partition/range. If continuous, must be
+                       set up to reflect the memory layout for 4 chipselects,
+                       if not then additional range/partition can be added and
+                       child device can select the proper one.
+                       - control partition which is common for all CS
+                       interfaces.
+
+- clocks:              the clock feeding the controller clock. Required only
+                       if clock tree data present in device tree.
+                       See clock-bindings.txt
+
+- clock-names:         clock name. It has to be "aemif". Required only if clock
+                       tree data present in device tree, in another case don't
+                       use it.
+                       See clock-bindings.txt
+
+- clock-ranges:                Empty property indicating that child nodes can inherit
+                       named clocks. Required only if clock tree data present
+                       in device tree.
+                       See clock-bindings.txt
+
+
+Child chip-select (cs) nodes contain the memory devices nodes connected to
+such as NOR (e.g. cfi-flash) and NAND (ti,davinci-nand, see davinci-nand.txt).
+There might be board specific devices like FPGAs.
+
+Required child cs node properties:
+
+- #address-cells:      Must be 2.
+
+- #size-cells:         Must be 1.
+
+- ranges:              Empty property indicating that child nodes can inherit
+                       memory layout.
+
+- clock-ranges:                Empty property indicating that child nodes can inherit
+                       named clocks. Required only if clock tree data present
+                       in device tree.
+
+- ti,cs-chipselect:    number of chipselect. Indicates on the aemif driver
+                       which chipselect is used for accessing the memory. For
+                       compatibles "ti,davinci-aemif" and "ti,keystone-aemif"
+                       it can be in range [0-3]. For compatible
+                       "ti,da850-aemif" range is [2-5].
+
+Optional child cs node properties:
+
+- ti,cs-bus-width:             width of the asynchronous device's data bus
+                               8 or 16 if not preset 8
+
+- ti,cs-select-strobe-mode:    enable/disable select strobe mode
+                               In select strobe mode chip select behaves as
+                               the strobe and is active only during the strobe
+                               period. If present then enable.
+
+- ti,cs-extended-wait-mode:    enable/disable extended wait mode
+                               if set, the controller monitors the EMIFWAIT pin
+                               mapped to that chip select to determine if the
+                               device wants to extend the strobe period. If
+                               present then enable.
+
+- ti,cs-min-turnaround-ns:     minimum turn around time, ns
+                               Time between the end of one asynchronous memory
+                               access and the start of another asynchronous
+                               memory access. This delay is not incurred
+                               between a read followed by read or a write
+                               followed by a write to same chip select.
+
+- ti,cs-read-setup-ns:         read setup width, ns
+                               Time between the beginning of a memory cycle
+                               and the activation of read strobe.
+                               Minimum value is 1 (0 treated as 1).
+
+- ti,cs-read-strobe-ns:                read strobe width, ns
+                               Time between the activation and deactivation of
+                               the read strobe.
+                               Minimum value is 1 (0 treated as 1).
+
+- ti,cs-read-hold-ns:          read hold width, ns
+                               Time between the deactivation of the read
+                               strobe and the end of the cycle (which may be
+                               either an address change or the deactivation of
+                               the chip select signal.
+                               Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-setup-ns:                write setup width, ns
+                               Time between the beginning of a memory cycle
+                               and the activation of write strobe.
+                               Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-strobe-ns:       write strobe width, ns
+                               Time between the activation and deactivation of
+                               the write strobe.
+                               Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-hold-ns:         write hold width, ns
+                               Time between the deactivation of the write
+                               strobe and the end of the cycle (which may be
+                               either an address change or the deactivation of
+                               the chip select signal.
+                               Minimum value is 1 (0 treated as 1).
+
+If any of the above parameters are absent, current parameter value will be taken
+from the corresponding HW reg.
+
+Example for aemif, davinci nand and nor flash chip select shown below.
+
+memory-controller@21000A00 {
+       compatible = "ti,davinci-aemif";
+       #address-cells = <2>;
+       #size-cells = <1>;
+       clocks = <&clkaemif 0>;
+       clock-names = "aemif";
+       clock-ranges;
+       reg = <0x21000A00 0x00000100>;
+       ranges = <0 0 0x70000000 0x10000000
+                 1 0 0x21000A00 0x00000100>;
+                 /*
+                  * Partition0: CS-specific memory range which is
+                  * implemented as continuous physical memory region
+                  * Partition1: control memory range
+                  */
+
+       nand:cs2 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               clock-ranges;
+               ranges;
+
+               ti,cs-chipselect = <2>;
+               /* all timings in nanoseconds */
+               ti,cs-min-turnaround-ns = <0>;
+               ti,cs-read-hold-ns = <7>;
+               ti,cs-read-strobe-ns = <42>;
+               ti,cs-read-setup-ns = <14>;
+               ti,cs-write-hold-ns = <7>;
+               ti,cs-write-strobe-ns = <42>;
+               ti,cs-write-setup-ns = <14>;
+
+               nand@0,0x8000000 {
+                       compatible = "ti,davinci-nand";
+                       reg = <0 0x8000000 0x4000000
+                              1 0x0000000 0x0000100>;
+                       /*
+                        * Partition0, offset 0x8000000, size 0x4000000
+                        * Partition1, offset 0x0000000, size 0x0000100
+                        */
+
+                       .. see davinci-nand.txt
+               };
+       };
+
+       nor:cs0 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               clock-ranges;
+               ranges;
+
+               ti,cs-chipselect = <0>;
+               /* all timings in nanoseconds */
+               ti,cs-min-turnaround-ns = <0>;
+               ti,cs-read-hold-ns = <8>;
+               ti,cs-read-strobe-ns = <40>;
+               ti,cs-read-setup-ns = <14>;
+               ti,cs-write-hold-ns = <7>;
+               ti,cs-write-strobe-ns = <40>;
+               ti,cs-write-setup-ns = <14>;
+               ti,cs-bus-width = <16>;
+
+               flash@0,0x0000000 {
+                       compatible = "cfi-flash";
+                       reg = <0 0x0000000 0x4000000>;
+
+                       ...
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mfd/s2mpa01.txt b/Documentation/devicetree/bindings/mfd/s2mpa01.txt
new file mode 100644 (file)
index 0000000..c13d3d8
--- /dev/null
@@ -0,0 +1,90 @@
+
+* Samsung S2MPA01 Voltage and Current Regulator
+
+The Samsung S2MPA01 is a multi-function device which includes high
+efficiency buck converters including Dual-Phase buck converter, various LDOs,
+and an RTC. It is interfaced to the host controller using an I2C interface.
+Each sub-block is addressed by the host system using different I2C slave
+addresses.
+
+Required properties:
+- compatible: Should be "samsung,s2mpa01-pmic".
+- reg: Specifies the I2C slave address of the PMIC block. It should be 0x66.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the interrupts from s2mpa01 are delivered to.
+- interrupts: An interrupt specifier for the sole interrupt generated by the
+  device.
+
+Optional nodes:
+- regulators: The regulators of s2mpa01 that have to be instantiated should be
+  included in a sub-node named 'regulators'. Regulator nodes and constraints
+  included in this sub-node use the standard regulator bindings which are
+  documented elsewhere.
+
+Properties for BUCK regulator nodes:
+- regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500
+  (default), 25000, or 50000. May be 0 for disabling the ramp delay on
+  BUCK{1,2,3,4}.
+
+ In the absence of the regulator-ramp-delay property, the default ramp
+ delay will be used.
+
+  NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set
+  for a particular group of BUCKs. So provide same regulator-ramp-delay=<value>.
+
+  The following BUCKs share ramp settings:
+  * 1 and 6
+  * 2 and 4
+  * 8, 9, and 10
+
+The following are the names of the regulators that the s2mpa01 PMIC block
+supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of s2mpa01.
+
+       - LDOn
+                 - valid values for n are 1 to 26
+                 - Example: LDO1, LD02, LDO26
+       - BUCKn
+                 - valid values for n are 1 to 10.
+                 - Example: BUCK1, BUCK2, BUCK9
+
+Example:
+
+       s2mpa01_pmic@66 {
+               compatible = "samsung,s2mpa01-pmic";
+               reg = <0x66>;
+
+               regulators {
+                       ldo1_reg: LDO1 {
+                               regulator-name = "VDD_ALIVE";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <1000000>;
+                       };
+
+                       ldo2_reg: LDO2 {
+                               regulator-name = "VDDQ_MMC2";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               regulator-always-on;
+                       };
+
+                       buck1_reg: BUCK1 {
+                               regulator-name = "vdd_mif";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       buck2_reg: BUCK2 {
+                               regulator-name = "vdd_arm";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-ramp-delay = <50000>;
+                       };
+               };
+       };
index 15ee89c3cc7b3406451c91038c3c4cb312ec5488..f69bec294f0200d55806109b0c70c94f7ae7c732 100644 (file)
@@ -1,5 +1,5 @@
 
-* Samsung S2MPS11 Voltage and Current Regulator
+* Samsung S2MPS11 and S2MPS14 Voltage and Current Regulator
 
 The Samsung S2MPS11 is a multi-function device which includes voltage and
 current regulators, RTC, charger controller and other sub-blocks. It is
@@ -7,7 +7,7 @@ interfaced to the host controller using an I2C interface. Each sub-block is
 addressed by the host system using different I2C slave addresses.
 
 Required properties:
-- compatible: Should be "samsung,s2mps11-pmic".
+- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic".
 - reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
 
 Optional properties:
@@ -59,10 +59,14 @@ supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
 as per the datasheet of s2mps11.
 
        - LDOn
-                 - valid values for n are 1 to 38
+                 - valid values for n are:
+                       - S2MPS11: 1 to 38
+                       - S2MPS14: 1 to 25
                  - Example: LDO1, LD02, LDO28
        - BUCKn
-                 - valid values for n are 1 to 10.
+                 - valid values for n are:
+                       - S2MPS11: 1 to 10
+                       - S2MPS14: 1 to 5
                  - Example: BUCK1, BUCK2, BUCK9
 
 Example:
index b4bd98af1cc7979ec1f6c7c6645173cd5c8b2d35..38833e63a59f901f79578f3ec7bba01227ec770d 100644 (file)
@@ -11,7 +11,7 @@ Required properties:
 - #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
+  Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
 - regulators: This is the list of child nodes that specify the regulator
   initialization data for defined regulators. Not all regulators for the given
   device need to be present. The definition for each of these nodes is defined
index 68ba37295565262d05807c1ba8ac0f7933395725..fabdf64a5737cc637b59f5612df2f82310619e3a 100644 (file)
@@ -1,12 +1,12 @@
 Allwinner sunxi-sid
 
 Required properties:
-- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-a20-sid".
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
 - reg: Should contain registers location and length
 
 Example for sun4i:
        sid@01c23800 {
-               compatible = "allwinner,sun4i-sid";
+               compatible = "allwinner,sun4i-a10-sid";
                reg = <0x01c23800 0x10>
        };
 
index 60960b2755f435f473a9dbb5569b2f845c25cd39..efc98ea1f23d28e18f64b0f0331a8b2e3da0c4ff 100644 (file)
@@ -17,6 +17,14 @@ Required properties for devices compatible with "atmel,at91sam9g45-ssc":
   See Documentation/devicetree/bindings/dma/atmel-dma.txt for details.
 - dma-names: Must be "tx", "rx".
 
+Optional properties:
+  - atmel,clk-from-rk-pin: bool property.
+     - When SSC works in slave mode, according to the hardware design, the
+       clock can get from TK pin, and also can get from RK pin. So, add
+       this parameter to choose where the clock from.
+     - By default the clock is from TK pin, if the clock from RK pin, this
+       property is needed.
+
 Examples:
 - PDC transfer:
 ssc0: ssc@fffbc000 {
index 4d0a00e453a82bcaab289888ad7391178bf1e041..36cbe5aea990ae77ab6212feb8e4aa27275c022b 100644 (file)
@@ -8,9 +8,44 @@ Required properties:
 
 - reg : SRAM iomem address range
 
+Reserving sram areas:
+---------------------
+
+Each child of the sram node specifies a region of reserved memory. Each
+child node should use a 'reg' property to specify a specific range of
+reserved memory.
+
+Following the generic-names recommended practice, node names should
+reflect the purpose of the node. Unit address (@<address>) should be
+appended to the name.
+
+Required properties in the sram node:
+
+- #address-cells, #size-cells : should use the same values as the root node
+- ranges : standard definition, should translate from local addresses
+           within the sram to bus addresses
+
+Required properties in the area nodes:
+
+- reg : iomem address range, relative to the SRAM range
+
+Optional properties in the area nodes:
+
+- compatible : standard definition, should contain a vendor specific string
+               in the form <vendor>,[<device>-]<usage>
+
 Example:
 
 sram: sram@5c000000 {
        compatible = "mmio-sram";
        reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
+
+       #adress-cells = <1>;
+       #size-cells = <1>;
+       ranges = <0 0x5c000000 0x40000>;
+
+       smp-sram@100 {
+               compatible = "socvendor,smp-sram";
+               reg = <0x100 0x50>;
+       };
 };
index 11ace3c3d805f872990ad82f721af2d7c8bd86b7..4fc39276361132fe7450248e0ceb5216c151bf25 100644 (file)
@@ -7,3 +7,4 @@ Required properties:
 
 Optional properties:
 - local-mac-address : Ethernet mac address to use
+- vdd-supply:  supply for Ethernet mac
diff --git a/Documentation/devicetree/bindings/net/opencores-ethoc.txt b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
new file mode 100644 (file)
index 0000000..2dc127c
--- /dev/null
@@ -0,0 +1,22 @@
+* OpenCores MAC 10/100 Mbps
+
+Required properties:
+- compatible: Should be "opencores,ethoc".
+- reg: two memory regions (address and length),
+  first region is for the device registers and descriptor rings,
+  second is for the device packet memory.
+- interrupts: interrupt for the device.
+
+Optional properties:
+- clocks: phandle to refer to the clk used as per
+  Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Examples:
+
+       enet0: ethoc@fd030000 {
+               compatible = "opencores,ethoc";
+               reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+               interrupts = <1>;
+               local-mac-address = [00 50 c2 13 6f 00];
+               clocks = <&osc>;
+        };
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
new file mode 100644 (file)
index 0000000..c119deb
--- /dev/null
@@ -0,0 +1,461 @@
+Broadcom BCM281xx Pin Controller
+
+This is a pin controller for the Broadcom BCM281xx SoC family, which includes
+BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
+
+=== Pin Controller Node ===
+
+Required Properties:
+
+- compatible:  Must be "brcm,bcm11351-pinctrl"
+- reg:         Base address of the PAD Controller register block and the size
+               of the block.
+
+For example, the following is the bare minimum node:
+
+       pinctrl@35004800 {
+               compatible = "brcm,bcm11351-pinctrl";
+               reg = <0x35004800 0x430>;
+       };
+
+As a pin controller device, in addition to the required properties, this node
+should also contain the pin configuration nodes that client devices reference,
+if any.
+
+=== Pin Configuration Node ===
+
+Each pin configuration node is a sub-node of the pin controller node and is a
+container of an arbitrary number of subnodes, called pin group nodes in this
+document.
+
+Please refer to the pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the definition of a
+"pin configuration node".
+
+=== Pin Group Node ===
+
+A pin group node specifies the desired pin mux and/or pin configuration for an
+arbitrary number of pins.  The name of the pin group node is optional and not
+used.
+
+A pin group node only affects the properties specified in the node, and has no
+effect on any properties that are omitted.
+
+The pin group node accepts a subset of the generic pin config properties. For
+details generic pin config properties, please refer to pinctrl-bindings.txt
+and <include/linux/pinctrl/pinconfig-generic.h>.
+
+Each pin controlled by this pin controller belong to one of three types:
+Standard, I2C, and HDMI.  Each type accepts a different set of pin config
+properties.  A list of pins and their types is provided below.
+
+Required Properties (applicable to all pins):
+
+- pins:                Multiple strings.  Specifies the name(s) of one or more pins to
+               be configured by this node.
+
+Optional Properties (for standard pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- input-schmitt-enable:                No arguments. Enable schmitt-trigger mode.
+- input-schmitt-disable:       No arguments. Disable schmitt-trigger mode.
+- bias-pull-up:                        No arguments. Pull up on pin.
+- bias-pull-down:              No arguments. Pull down on pin.
+- bias-disable:                        No arguments. Disable pin bias.
+- slew-rate:                   Integer. Meaning depends on configured pin mux:
+                               *_SCL or *_SDA:
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+                               IC_DM or IC_DP:
+                                       0: normal slew rate
+                                       1: fast slew rate
+                               Otherwise:
+                                       0: fast slew rate
+                                       1: normal slew rate
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+- drive-strength:              Integer. Drive strength in mA.  Valid values are
+                               2, 4, 6, 8, 10, 12, 14, 16 mA.
+
+Optional Properties (for I2C pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- bias-pull-up:                        Integer. Pull up strength in Ohm. There are 3
+                               pull-up resisitors (1.2k, 1.8k, 2.7k) available
+                               in parallel for I2C pins, so the valid values
+                               are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm.
+- bias-disable:                        No arguments. Disable pin bias.
+- slew-rate:                   Integer. Meaning depends on configured pin mux:
+                               *_SCL or *_SDA:
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+                               IC_DM or IC_DP:
+                                       0: normal slew rate
+                                       1: fast slew rate
+                               Otherwise:
+                                       0: fast slew rate
+                                       1: normal slew rate
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+
+Optional Properties (for HDMI pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- slew-rate:                   Integer. Controls slew rate.
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+
+Example:
+// pin controller node
+pinctrl@35004800 {
+       compatible = "brcmbcm11351-pinctrl";
+       reg = <0x35004800 0x430>;
+
+       // pin configuration node
+       dev_a_default: dev_a_active {
+               //group node defining 1 standard pin
+               grp_1 {
+                       pins            = "std_pin1";
+                       function        = "alt1";
+                       input-schmitt-enable;
+                       bias-disable;
+                       slew-rate       = <1>;
+                       drive-strength  = <4>;
+               };
+
+               // group node defining 2 I2C pins
+               grp_2 {
+                       pins            = "i2c_pin1", "i2c_pin2";
+                       function        = "alt2";
+                       bias-pull-up    = <720>;
+                       input-enable;
+               };
+
+               // group node defining 2 HDMI pins
+               grp_3 {
+                       pins            = "hdmi_pin1", "hdmi_pin2";
+                       function        = "alt3";
+                       slew-rate       = <1>;
+               };
+
+               // other pin group nodes
+               ...
+       };
+
+       // other pin configuration nodes
+       ...
+};
+
+In the example above, "dev_a_active" is a pin configuration node with a number
+of sub-nodes.  In the pin group node "grp_1", one pin, "std_pin1", is defined in
+the "pins" property.  Thus, the remaining properties in the "grp_1" node applies
+only to this pin, including the following settings:
+ - setting pinmux to "alt1"
+ - enabling schmitt-trigger (hystersis) mode
+ - disabling pin bias
+ - setting the slew-rate to 1
+ - setting the drive strength to 4 mA
+Note that neither "input-enable" nor "input-disable" was specified - the pinctrl
+subsystem will therefore leave this property unchanged from whatever state it
+was in before applying these changes.
+
+The "pins" property in the pin group node "grp_2" specifies two pins -
+"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node,
+therefore, applies to both of these pins.  The properties include:
+ - setting pinmux to "alt2"
+ - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors
+   in parallel)
+ - enabling both pins' input
+"slew-rate" is not specified in this pin group node, so the slew-rate for these
+pins are left as-is.
+
+Finally, "grp_3" defines two HDMI pins.  The following properties are applied to
+both pins:
+ - setting pinmux to "alt3"
+ - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps
+   Highspeed mode
+The input is neither enabled or disabled, and is left untouched.
+
+=== Pin Names and Type ===
+
+The following are valid pin names and their pin types:
+
+       "adcsync",              Standard
+       "bat_rm",               Standard
+       "bsc1_scl",             I2C
+       "bsc1_sda",             I2C
+       "bsc2_scl",             I2C
+       "bsc2_sda",             I2C
+       "classgpwr",            Standard
+       "clk_cx8",              Standard
+       "clkout_0",             Standard
+       "clkout_1",             Standard
+       "clkout_2",             Standard
+       "clkout_3",             Standard
+       "clkreq_in_0",          Standard
+       "clkreq_in_1",          Standard
+       "cws_sys_req1",         Standard
+       "cws_sys_req2",         Standard
+       "cws_sys_req3",         Standard
+       "digmic1_clk",          Standard
+       "digmic1_dq",           Standard
+       "digmic2_clk",          Standard
+       "digmic2_dq",           Standard
+       "gpen13",               Standard
+       "gpen14",               Standard
+       "gpen15",               Standard
+       "gpio00",               Standard
+       "gpio01",               Standard
+       "gpio02",               Standard
+       "gpio03",               Standard
+       "gpio04",               Standard
+       "gpio05",               Standard
+       "gpio06",               Standard
+       "gpio07",               Standard
+       "gpio08",               Standard
+       "gpio09",               Standard
+       "gpio10",               Standard
+       "gpio11",               Standard
+       "gpio12",               Standard
+       "gpio13",               Standard
+       "gpio14",               Standard
+       "gps_pablank",          Standard
+       "gps_tmark",            Standard
+       "hdmi_scl",             HDMI
+       "hdmi_sda",             HDMI
+       "ic_dm",                Standard
+       "ic_dp",                Standard
+       "kp_col_ip_0",          Standard
+       "kp_col_ip_1",          Standard
+       "kp_col_ip_2",          Standard
+       "kp_col_ip_3",          Standard
+       "kp_row_op_0",          Standard
+       "kp_row_op_1",          Standard
+       "kp_row_op_2",          Standard
+       "kp_row_op_3",          Standard
+       "lcd_b_0",              Standard
+       "lcd_b_1",              Standard
+       "lcd_b_2",              Standard
+       "lcd_b_3",              Standard
+       "lcd_b_4",              Standard
+       "lcd_b_5",              Standard
+       "lcd_b_6",              Standard
+       "lcd_b_7",              Standard
+       "lcd_g_0",              Standard
+       "lcd_g_1",              Standard
+       "lcd_g_2",              Standard
+       "lcd_g_3",              Standard
+       "lcd_g_4",              Standard
+       "lcd_g_5",              Standard
+       "lcd_g_6",              Standard
+       "lcd_g_7",              Standard
+       "lcd_hsync",            Standard
+       "lcd_oe",               Standard
+       "lcd_pclk",             Standard
+       "lcd_r_0",              Standard
+       "lcd_r_1",              Standard
+       "lcd_r_2",              Standard
+       "lcd_r_3",              Standard
+       "lcd_r_4",              Standard
+       "lcd_r_5",              Standard
+       "lcd_r_6",              Standard
+       "lcd_r_7",              Standard
+       "lcd_vsync",            Standard
+       "mdmgpio0",             Standard
+       "mdmgpio1",             Standard
+       "mdmgpio2",             Standard
+       "mdmgpio3",             Standard
+       "mdmgpio4",             Standard
+       "mdmgpio5",             Standard
+       "mdmgpio6",             Standard
+       "mdmgpio7",             Standard
+       "mdmgpio8",             Standard
+       "mphi_data_0",          Standard
+       "mphi_data_1",          Standard
+       "mphi_data_2",          Standard
+       "mphi_data_3",          Standard
+       "mphi_data_4",          Standard
+       "mphi_data_5",          Standard
+       "mphi_data_6",          Standard
+       "mphi_data_7",          Standard
+       "mphi_data_8",          Standard
+       "mphi_data_9",          Standard
+       "mphi_data_10",         Standard
+       "mphi_data_11",         Standard
+       "mphi_data_12",         Standard
+       "mphi_data_13",         Standard
+       "mphi_data_14",         Standard
+       "mphi_data_15",         Standard
+       "mphi_ha0",             Standard
+       "mphi_hat0",            Standard
+       "mphi_hat1",            Standard
+       "mphi_hce0_n",          Standard
+       "mphi_hce1_n",          Standard
+       "mphi_hrd_n",           Standard
+       "mphi_hwr_n",           Standard
+       "mphi_run0",            Standard
+       "mphi_run1",            Standard
+       "mtx_scan_clk",         Standard
+       "mtx_scan_data",        Standard
+       "nand_ad_0",            Standard
+       "nand_ad_1",            Standard
+       "nand_ad_2",            Standard
+       "nand_ad_3",            Standard
+       "nand_ad_4",            Standard
+       "nand_ad_5",            Standard
+       "nand_ad_6",            Standard
+       "nand_ad_7",            Standard
+       "nand_ale",             Standard
+       "nand_cen_0",           Standard
+       "nand_cen_1",           Standard
+       "nand_cle",             Standard
+       "nand_oen",             Standard
+       "nand_rdy_0",           Standard
+       "nand_rdy_1",           Standard
+       "nand_wen",             Standard
+       "nand_wp",              Standard
+       "pc1",                  Standard
+       "pc2",                  Standard
+       "pmu_int",              Standard
+       "pmu_scl",              I2C
+       "pmu_sda",              I2C
+       "rfst2g_mtsloten3g",    Standard
+       "rgmii_0_rx_ctl",       Standard
+       "rgmii_0_rxc",          Standard
+       "rgmii_0_rxd_0",        Standard
+       "rgmii_0_rxd_1",        Standard
+       "rgmii_0_rxd_2",        Standard
+       "rgmii_0_rxd_3",        Standard
+       "rgmii_0_tx_ctl",       Standard
+       "rgmii_0_txc",          Standard
+       "rgmii_0_txd_0",        Standard
+       "rgmii_0_txd_1",        Standard
+       "rgmii_0_txd_2",        Standard
+       "rgmii_0_txd_3",        Standard
+       "rgmii_1_rx_ctl",       Standard
+       "rgmii_1_rxc",          Standard
+       "rgmii_1_rxd_0",        Standard
+       "rgmii_1_rxd_1",        Standard
+       "rgmii_1_rxd_2",        Standard
+       "rgmii_1_rxd_3",        Standard
+       "rgmii_1_tx_ctl",       Standard
+       "rgmii_1_txc",          Standard
+       "rgmii_1_txd_0",        Standard
+       "rgmii_1_txd_1",        Standard
+       "rgmii_1_txd_2",        Standard
+       "rgmii_1_txd_3",        Standard
+       "rgmii_gpio_0",         Standard
+       "rgmii_gpio_1",         Standard
+       "rgmii_gpio_2",         Standard
+       "rgmii_gpio_3",         Standard
+       "rtxdata2g_txdata3g1",  Standard
+       "rtxen2g_txdata3g2",    Standard
+       "rxdata3g0",            Standard
+       "rxdata3g1",            Standard
+       "rxdata3g2",            Standard
+       "sdio1_clk",            Standard
+       "sdio1_cmd",            Standard
+       "sdio1_data_0",         Standard
+       "sdio1_data_1",         Standard
+       "sdio1_data_2",         Standard
+       "sdio1_data_3",         Standard
+       "sdio4_clk",            Standard
+       "sdio4_cmd",            Standard
+       "sdio4_data_0",         Standard
+       "sdio4_data_1",         Standard
+       "sdio4_data_2",         Standard
+       "sdio4_data_3",         Standard
+       "sim_clk",              Standard
+       "sim_data",             Standard
+       "sim_det",              Standard
+       "sim_resetn",           Standard
+       "sim2_clk",             Standard
+       "sim2_data",            Standard
+       "sim2_det",             Standard
+       "sim2_resetn",          Standard
+       "sri_c",                Standard
+       "sri_d",                Standard
+       "sri_e",                Standard
+       "ssp_extclk",           Standard
+       "ssp0_clk",             Standard
+       "ssp0_fs",              Standard
+       "ssp0_rxd",             Standard
+       "ssp0_txd",             Standard
+       "ssp2_clk",             Standard
+       "ssp2_fs_0",            Standard
+       "ssp2_fs_1",            Standard
+       "ssp2_fs_2",            Standard
+       "ssp2_fs_3",            Standard
+       "ssp2_rxd_0",           Standard
+       "ssp2_rxd_1",           Standard
+       "ssp2_txd_0",           Standard
+       "ssp2_txd_1",           Standard
+       "ssp3_clk",             Standard
+       "ssp3_fs",              Standard
+       "ssp3_rxd",             Standard
+       "ssp3_txd",             Standard
+       "ssp4_clk",             Standard
+       "ssp4_fs",              Standard
+       "ssp4_rxd",             Standard
+       "ssp4_txd",             Standard
+       "ssp5_clk",             Standard
+       "ssp5_fs",              Standard
+       "ssp5_rxd",             Standard
+       "ssp5_txd",             Standard
+       "ssp6_clk",             Standard
+       "ssp6_fs",              Standard
+       "ssp6_rxd",             Standard
+       "ssp6_txd",             Standard
+       "stat_1",               Standard
+       "stat_2",               Standard
+       "sysclken",             Standard
+       "traceclk",             Standard
+       "tracedt00",            Standard
+       "tracedt01",            Standard
+       "tracedt02",            Standard
+       "tracedt03",            Standard
+       "tracedt04",            Standard
+       "tracedt05",            Standard
+       "tracedt06",            Standard
+       "tracedt07",            Standard
+       "tracedt08",            Standard
+       "tracedt09",            Standard
+       "tracedt10",            Standard
+       "tracedt11",            Standard
+       "tracedt12",            Standard
+       "tracedt13",            Standard
+       "tracedt14",            Standard
+       "tracedt15",            Standard
+       "txdata3g0",            Standard
+       "txpwrind",             Standard
+       "uartb1_ucts",          Standard
+       "uartb1_urts",          Standard
+       "uartb1_urxd",          Standard
+       "uartb1_utxd",          Standard
+       "uartb2_urxd",          Standard
+       "uartb2_utxd",          Standard
+       "uartb3_ucts",          Standard
+       "uartb3_urts",          Standard
+       "uartb3_urxd",          Standard
+       "uartb3_utxd",          Standard
+       "uartb4_ucts",          Standard
+       "uartb4_urts",          Standard
+       "uartb4_urxd",          Standard
+       "uartb4_utxd",          Standard
+       "vc_cam1_scl",          I2C
+       "vc_cam1_sda",          I2C
+       "vc_cam2_scl",          I2C
+       "vc_cam2_sda",          I2C
+       "vc_cam3_scl",          I2C
+       "vc_cam3_sda",          I2C
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt
deleted file mode 100644 (file)
index 9e9e9ef..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-Broadcom Capri Pin Controller
-
-This is a pin controller for the Broadcom BCM281xx SoC family, which includes
-BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
-
-=== Pin Controller Node ===
-
-Required Properties:
-
-- compatible:  Must be "brcm,capri-pinctrl".
-- reg:         Base address of the PAD Controller register block and the size
-               of the block.
-
-For example, the following is the bare minimum node:
-
-       pinctrl@35004800 {
-               compatible = "brcm,capri-pinctrl";
-               reg = <0x35004800 0x430>;
-       };
-
-As a pin controller device, in addition to the required properties, this node
-should also contain the pin configuration nodes that client devices reference,
-if any.
-
-=== Pin Configuration Node ===
-
-Each pin configuration node is a sub-node of the pin controller node and is a
-container of an arbitrary number of subnodes, called pin group nodes in this
-document.
-
-Please refer to the pinctrl-bindings.txt in this directory for details of the
-common pinctrl bindings used by client devices, including the definition of a
-"pin configuration node".
-
-=== Pin Group Node ===
-
-A pin group node specifies the desired pin mux and/or pin configuration for an
-arbitrary number of pins.  The name of the pin group node is optional and not
-used.
-
-A pin group node only affects the properties specified in the node, and has no
-effect on any properties that are omitted.
-
-The pin group node accepts a subset of the generic pin config properties. For
-details generic pin config properties, please refer to pinctrl-bindings.txt
-and <include/linux/pinctrl/pinconfig-generic.h>.
-
-Each pin controlled by this pin controller belong to one of three types:
-Standard, I2C, and HDMI.  Each type accepts a different set of pin config
-properties.  A list of pins and their types is provided below.
-
-Required Properties (applicable to all pins):
-
-- pins:                Multiple strings.  Specifies the name(s) of one or more pins to
-               be configured by this node.
-
-Optional Properties (for standard pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- input-schmitt-enable:                No arguments. Enable schmitt-trigger mode.
-- input-schmitt-disable:       No arguments. Disable schmitt-trigger mode.
-- bias-pull-up:                        No arguments. Pull up on pin.
-- bias-pull-down:              No arguments. Pull down on pin.
-- bias-disable:                        No arguments. Disable pin bias.
-- slew-rate:                   Integer. Meaning depends on configured pin mux:
-                               *_SCL or *_SDA:
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-                               IC_DM or IC_DP:
-                                       0: normal slew rate
-                                       1: fast slew rate
-                               Otherwise:
-                                       0: fast slew rate
-                                       1: normal slew rate
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-- drive-strength:              Integer. Drive strength in mA.  Valid values are
-                               2, 4, 6, 8, 10, 12, 14, 16 mA.
-
-Optional Properties (for I2C pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- bias-pull-up:                        Integer. Pull up strength in Ohm. There are 3
-                               pull-up resisitors (1.2k, 1.8k, 2.7k) available
-                               in parallel for I2C pins, so the valid values
-                               are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm.
-- bias-disable:                        No arguments. Disable pin bias.
-- slew-rate:                   Integer. Meaning depends on configured pin mux:
-                               *_SCL or *_SDA:
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-                               IC_DM or IC_DP:
-                                       0: normal slew rate
-                                       1: fast slew rate
-                               Otherwise:
-                                       0: fast slew rate
-                                       1: normal slew rate
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-
-Optional Properties (for HDMI pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- slew-rate:                   Integer. Controls slew rate.
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-
-Example:
-// pin controller node
-pinctrl@35004800 {
-       compatible = "brcm,capri-pinctrl";
-       reg = <0x35004800 0x430>;
-
-       // pin configuration node
-       dev_a_default: dev_a_active {
-               //group node defining 1 standard pin
-               grp_1 {
-                       pins            = "std_pin1";
-                       function        = "alt1";
-                       input-schmitt-enable;
-                       bias-disable;
-                       slew-rate       = <1>;
-                       drive-strength  = <4>;
-               };
-
-               // group node defining 2 I2C pins
-               grp_2 {
-                       pins            = "i2c_pin1", "i2c_pin2";
-                       function        = "alt2";
-                       bias-pull-up    = <720>;
-                       input-enable;
-               };
-
-               // group node defining 2 HDMI pins
-               grp_3 {
-                       pins            = "hdmi_pin1", "hdmi_pin2";
-                       function        = "alt3";
-                       slew-rate       = <1>;
-               };
-
-               // other pin group nodes
-               ...
-       };
-
-       // other pin configuration nodes
-       ...
-};
-
-In the example above, "dev_a_active" is a pin configuration node with a number
-of sub-nodes.  In the pin group node "grp_1", one pin, "std_pin1", is defined in
-the "pins" property.  Thus, the remaining properties in the "grp_1" node applies
-only to this pin, including the following settings:
- - setting pinmux to "alt1"
- - enabling schmitt-trigger (hystersis) mode
- - disabling pin bias
- - setting the slew-rate to 1
- - setting the drive strength to 4 mA
-Note that neither "input-enable" nor "input-disable" was specified - the pinctrl
-subsystem will therefore leave this property unchanged from whatever state it
-was in before applying these changes.
-
-The "pins" property in the pin group node "grp_2" specifies two pins -
-"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node,
-therefore, applies to both of these pins.  The properties include:
- - setting pinmux to "alt2"
- - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors
-   in parallel)
- - enabling both pins' input
-"slew-rate" is not specified in this pin group node, so the slew-rate for these
-pins are left as-is.
-
-Finally, "grp_3" defines two HDMI pins.  The following properties are applied to
-both pins:
- - setting pinmux to "alt3"
- - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps
-   Highspeed mode
-The input is neither enabled or disabled, and is left untouched.
-
-=== Pin Names and Type ===
-
-The following are valid pin names and their pin types:
-
-       "adcsync",              Standard
-       "bat_rm",               Standard
-       "bsc1_scl",             I2C
-       "bsc1_sda",             I2C
-       "bsc2_scl",             I2C
-       "bsc2_sda",             I2C
-       "classgpwr",            Standard
-       "clk_cx8",              Standard
-       "clkout_0",             Standard
-       "clkout_1",             Standard
-       "clkout_2",             Standard
-       "clkout_3",             Standard
-       "clkreq_in_0",          Standard
-       "clkreq_in_1",          Standard
-       "cws_sys_req1",         Standard
-       "cws_sys_req2",         Standard
-       "cws_sys_req3",         Standard
-       "digmic1_clk",          Standard
-       "digmic1_dq",           Standard
-       "digmic2_clk",          Standard
-       "digmic2_dq",           Standard
-       "gpen13",               Standard
-       "gpen14",               Standard
-       "gpen15",               Standard
-       "gpio00",               Standard
-       "gpio01",               Standard
-       "gpio02",               Standard
-       "gpio03",               Standard
-       "gpio04",               Standard
-       "gpio05",               Standard
-       "gpio06",               Standard
-       "gpio07",               Standard
-       "gpio08",               Standard
-       "gpio09",               Standard
-       "gpio10",               Standard
-       "gpio11",               Standard
-       "gpio12",               Standard
-       "gpio13",               Standard
-       "gpio14",               Standard
-       "gps_pablank",          Standard
-       "gps_tmark",            Standard
-       "hdmi_scl",             HDMI
-       "hdmi_sda",             HDMI
-       "ic_dm",                Standard
-       "ic_dp",                Standard
-       "kp_col_ip_0",          Standard
-       "kp_col_ip_1",          Standard
-       "kp_col_ip_2",          Standard
-       "kp_col_ip_3",          Standard
-       "kp_row_op_0",          Standard
-       "kp_row_op_1",          Standard
-       "kp_row_op_2",          Standard
-       "kp_row_op_3",          Standard
-       "lcd_b_0",              Standard
-       "lcd_b_1",              Standard
-       "lcd_b_2",              Standard
-       "lcd_b_3",              Standard
-       "lcd_b_4",              Standard
-       "lcd_b_5",              Standard
-       "lcd_b_6",              Standard
-       "lcd_b_7",              Standard
-       "lcd_g_0",              Standard
-       "lcd_g_1",              Standard
-       "lcd_g_2",              Standard
-       "lcd_g_3",              Standard
-       "lcd_g_4",              Standard
-       "lcd_g_5",              Standard
-       "lcd_g_6",              Standard
-       "lcd_g_7",              Standard
-       "lcd_hsync",            Standard
-       "lcd_oe",               Standard
-       "lcd_pclk",             Standard
-       "lcd_r_0",              Standard
-       "lcd_r_1",              Standard
-       "lcd_r_2",              Standard
-       "lcd_r_3",              Standard
-       "lcd_r_4",              Standard
-       "lcd_r_5",              Standard
-       "lcd_r_6",              Standard
-       "lcd_r_7",              Standard
-       "lcd_vsync",            Standard
-       "mdmgpio0",             Standard
-       "mdmgpio1",             Standard
-       "mdmgpio2",             Standard
-       "mdmgpio3",             Standard
-       "mdmgpio4",             Standard
-       "mdmgpio5",             Standard
-       "mdmgpio6",             Standard
-       "mdmgpio7",             Standard
-       "mdmgpio8",             Standard
-       "mphi_data_0",          Standard
-       "mphi_data_1",          Standard
-       "mphi_data_2",          Standard
-       "mphi_data_3",          Standard
-       "mphi_data_4",          Standard
-       "mphi_data_5",          Standard
-       "mphi_data_6",          Standard
-       "mphi_data_7",          Standard
-       "mphi_data_8",          Standard
-       "mphi_data_9",          Standard
-       "mphi_data_10",         Standard
-       "mphi_data_11",         Standard
-       "mphi_data_12",         Standard
-       "mphi_data_13",         Standard
-       "mphi_data_14",         Standard
-       "mphi_data_15",         Standard
-       "mphi_ha0",             Standard
-       "mphi_hat0",            Standard
-       "mphi_hat1",            Standard
-       "mphi_hce0_n",          Standard
-       "mphi_hce1_n",          Standard
-       "mphi_hrd_n",           Standard
-       "mphi_hwr_n",           Standard
-       "mphi_run0",            Standard
-       "mphi_run1",            Standard
-       "mtx_scan_clk",         Standard
-       "mtx_scan_data",        Standard
-       "nand_ad_0",            Standard
-       "nand_ad_1",            Standard
-       "nand_ad_2",            Standard
-       "nand_ad_3",            Standard
-       "nand_ad_4",            Standard
-       "nand_ad_5",            Standard
-       "nand_ad_6",            Standard
-       "nand_ad_7",            Standard
-       "nand_ale",             Standard
-       "nand_cen_0",           Standard
-       "nand_cen_1",           Standard
-       "nand_cle",             Standard
-       "nand_oen",             Standard
-       "nand_rdy_0",           Standard
-       "nand_rdy_1",           Standard
-       "nand_wen",             Standard
-       "nand_wp",              Standard
-       "pc1",                  Standard
-       "pc2",                  Standard
-       "pmu_int",              Standard
-       "pmu_scl",              I2C
-       "pmu_sda",              I2C
-       "rfst2g_mtsloten3g",    Standard
-       "rgmii_0_rx_ctl",       Standard
-       "rgmii_0_rxc",          Standard
-       "rgmii_0_rxd_0",        Standard
-       "rgmii_0_rxd_1",        Standard
-       "rgmii_0_rxd_2",        Standard
-       "rgmii_0_rxd_3",        Standard
-       "rgmii_0_tx_ctl",       Standard
-       "rgmii_0_txc",          Standard
-       "rgmii_0_txd_0",        Standard
-       "rgmii_0_txd_1",        Standard
-       "rgmii_0_txd_2",        Standard
-       "rgmii_0_txd_3",        Standard
-       "rgmii_1_rx_ctl",       Standard
-       "rgmii_1_rxc",          Standard
-       "rgmii_1_rxd_0",        Standard
-       "rgmii_1_rxd_1",        Standard
-       "rgmii_1_rxd_2",        Standard
-       "rgmii_1_rxd_3",        Standard
-       "rgmii_1_tx_ctl",       Standard
-       "rgmii_1_txc",          Standard
-       "rgmii_1_txd_0",        Standard
-       "rgmii_1_txd_1",        Standard
-       "rgmii_1_txd_2",        Standard
-       "rgmii_1_txd_3",        Standard
-       "rgmii_gpio_0",         Standard
-       "rgmii_gpio_1",         Standard
-       "rgmii_gpio_2",         Standard
-       "rgmii_gpio_3",         Standard
-       "rtxdata2g_txdata3g1",  Standard
-       "rtxen2g_txdata3g2",    Standard
-       "rxdata3g0",            Standard
-       "rxdata3g1",            Standard
-       "rxdata3g2",            Standard
-       "sdio1_clk",            Standard
-       "sdio1_cmd",            Standard
-       "sdio1_data_0",         Standard
-       "sdio1_data_1",         Standard
-       "sdio1_data_2",         Standard
-       "sdio1_data_3",         Standard
-       "sdio4_clk",            Standard
-       "sdio4_cmd",            Standard
-       "sdio4_data_0",         Standard
-       "sdio4_data_1",         Standard
-       "sdio4_data_2",         Standard
-       "sdio4_data_3",         Standard
-       "sim_clk",              Standard
-       "sim_data",             Standard
-       "sim_det",              Standard
-       "sim_resetn",           Standard
-       "sim2_clk",             Standard
-       "sim2_data",            Standard
-       "sim2_det",             Standard
-       "sim2_resetn",          Standard
-       "sri_c",                Standard
-       "sri_d",                Standard
-       "sri_e",                Standard
-       "ssp_extclk",           Standard
-       "ssp0_clk",             Standard
-       "ssp0_fs",              Standard
-       "ssp0_rxd",             Standard
-       "ssp0_txd",             Standard
-       "ssp2_clk",             Standard
-       "ssp2_fs_0",            Standard
-       "ssp2_fs_1",            Standard
-       "ssp2_fs_2",            Standard
-       "ssp2_fs_3",            Standard
-       "ssp2_rxd_0",           Standard
-       "ssp2_rxd_1",           Standard
-       "ssp2_txd_0",           Standard
-       "ssp2_txd_1",           Standard
-       "ssp3_clk",             Standard
-       "ssp3_fs",              Standard
-       "ssp3_rxd",             Standard
-       "ssp3_txd",             Standard
-       "ssp4_clk",             Standard
-       "ssp4_fs",              Standard
-       "ssp4_rxd",             Standard
-       "ssp4_txd",             Standard
-       "ssp5_clk",             Standard
-       "ssp5_fs",              Standard
-       "ssp5_rxd",             Standard
-       "ssp5_txd",             Standard
-       "ssp6_clk",             Standard
-       "ssp6_fs",              Standard
-       "ssp6_rxd",             Standard
-       "ssp6_txd",             Standard
-       "stat_1",               Standard
-       "stat_2",               Standard
-       "sysclken",             Standard
-       "traceclk",             Standard
-       "tracedt00",            Standard
-       "tracedt01",            Standard
-       "tracedt02",            Standard
-       "tracedt03",            Standard
-       "tracedt04",            Standard
-       "tracedt05",            Standard
-       "tracedt06",            Standard
-       "tracedt07",            Standard
-       "tracedt08",            Standard
-       "tracedt09",            Standard
-       "tracedt10",            Standard
-       "tracedt11",            Standard
-       "tracedt12",            Standard
-       "tracedt13",            Standard
-       "tracedt14",            Standard
-       "tracedt15",            Standard
-       "txdata3g0",            Standard
-       "txpwrind",             Standard
-       "uartb1_ucts",          Standard
-       "uartb1_urts",          Standard
-       "uartb1_urxd",          Standard
-       "uartb1_utxd",          Standard
-       "uartb2_urxd",          Standard
-       "uartb2_utxd",          Standard
-       "uartb3_ucts",          Standard
-       "uartb3_urts",          Standard
-       "uartb3_urxd",          Standard
-       "uartb3_utxd",          Standard
-       "uartb4_ucts",          Standard
-       "uartb4_urts",          Standard
-       "uartb4_urxd",          Standard
-       "uartb4_utxd",          Standard
-       "vc_cam1_scl",          I2C
-       "vc_cam1_sda",          I2C
-       "vc_cam2_scl",          I2C
-       "vc_cam2_sda",          I2C
-       "vc_cam3_scl",          I2C
-       "vc_cam3_sda",          I2C
index 01ef408e205f18ce5ac3c16b44e559f01f877f08..adda2a8d1d5298dcf3b35634d26a3022fc686a14 100644 (file)
@@ -5,6 +5,7 @@ part and usage.
 
 Required properties:
 - compatible: "marvell,88f6710-pinctrl"
+- reg: register specifier of MPP registers
 
 Available mpp pins/groups and functions:
 Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
new file mode 100644 (file)
index 0000000..7de0cda
--- /dev/null
@@ -0,0 +1,82 @@
+* Marvell Armada 375 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6720-pinctrl"
+- reg: register specifier of MPP registers
+
+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.
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, dev(ad2), spi0(cs1), spi1(cs1)
+mpp1          1        gpio, dev(ad3), spi0(mosi), spi1(mosi)
+mpp2          2        gpio, dev(ad4), ptp(eventreq), led(c0), audio(sdi)
+mpp3          3        gpio, dev(ad5), ptp(triggen), led(p3), audio(mclk)
+mpp4          4        gpio, dev(ad6), spi0(miso), spi1(miso)
+mpp5          5        gpio, dev(ad7), spi0(cs2), spi1(cs2)
+mpp6          6        gpio, dev(ad0), led(p1), audio(rclk)
+mpp7          7        gpio, dev(ad1), ptp(clk), led(p2), audio(extclk)
+mpp8          8        gpio, dev (bootcs), spi0(cs0), spi1(cs0)
+mpp9          9        gpio, nf(wen), spi0(sck), spi1(sck)
+mpp10        10        gpio, nf(ren), dram(vttctrl), led(c1)
+mpp11        11        gpio, dev(a0), led(c2), audio(sdo)
+mpp12        12        gpio, dev(a1), audio(bclk)
+mpp13        13        gpio, dev(readyn), pcie0(rstoutn), pcie1(rstoutn)
+mpp14        14        gpio, i2c0(sda), uart1(txd)
+mpp15        15        gpio, i2c0(sck), uart1(rxd)
+mpp16        16        gpio, uart0(txd)
+mpp17        17        gpio, uart0(rxd)
+mpp18        18        gpio, tdm(intn)
+mpp19        19        gpio, tdm(rstn)
+mpp20        20        gpio, tdm(pclk)
+mpp21        21        gpio, tdm(fsync)
+mpp22        22        gpio, tdm(drx)
+mpp23        23        gpio, tdm(dtx)
+mpp24        24        gpio, led(p0), ge1(rxd0), sd(cmd), uart0(rts)
+mpp25        25        gpio, led(p2), ge1(rxd1), sd(d0), uart0(cts)
+mpp26        26        gpio, pcie0(clkreq), ge1(rxd2), sd(d2), uart1(rts)
+mpp27        27        gpio, pcie1(clkreq), ge1(rxd3), sd(d1), uart1(cts)
+mpp28        28        gpio, led(p3), ge1(txctl), sd(clk)
+mpp29        29        gpio, pcie1(clkreq), ge1(rxclk), sd(d3)
+mpp30        30        gpio, ge1(txd0), spi1(cs0)
+mpp31        31        gpio, ge1(txd1), spi1(mosi)
+mpp32        32        gpio, ge1(txd2), spi1(sck), ptp(triggen)
+mpp33        33        gpio, ge1(txd3), spi1(miso)
+mpp34        34        gpio, ge1(txclkout), spi1(sck)
+mpp35        35        gpio, ge1(rxctl), spi1(cs1), spi0(cs2)
+mpp36        36        gpio, pcie0(clkreq)
+mpp37        37        gpio, pcie0(clkreq), tdm(intn), ge(mdc)
+mpp38        38        gpio, pcie1(clkreq), ge(mdio)
+mpp39        39        gpio, ref(clkout)
+mpp40        40        gpio, uart1(txd)
+mpp41        41        gpio, uart1(rxd)
+mpp42        42        gpio, spi1(cs2), led(c0)
+mpp43        43        gpio, sata0(prsnt), dram(vttctrl)
+mpp44        44        gpio, sata0(prsnt)
+mpp45        45        gpio, spi0(cs2), pcie0(rstoutn)
+mpp46        46        gpio, led(p0), ge0(txd0), ge1(txd0)
+mpp47        47        gpio, led(p1), ge0(txd1), ge1(txd1)
+mpp48        48        gpio, led(p2), ge0(txd2), ge1(txd2)
+mpp49        49        gpio, led(p3), ge0(txd3), ge1(txd3)
+mpp50        50        gpio, led(c0), ge0(rxd0), ge1(rxd0)
+mpp51        51        gpio, led(c1), ge0(rxd1), ge1(rxd1)
+mpp52        52        gpio, led(c2), ge0(rxd2), ge1(rxd2)
+mpp53        53        gpio, pcie1(rstoutn), ge0(rxd3), ge1(rxd3)
+mpp54        54        gpio, pcie0(rstoutn), ge0(rxctl), ge1(rxctl)
+mpp55        55        gpio, ge0(rxclk), ge1(rxclk)
+mpp56        56        gpio, ge0(txclkout), ge1(txclkout)
+mpp57        57        gpio, ge0(txctl), ge1(txctl)
+mpp58        58        gpio, led(c0)
+mpp59        59        gpio, led(c1)
+mpp60        60        gpio, uart1(txd), led(c2)
+mpp61        61        gpio, i2c1(sda), uart1(rxd), spi1(cs2), led(p0)
+mpp62        62        gpio, i2c1(sck), led(p1)
+mpp63        63        gpio, ptp(triggen), led(p2)
+mpp64        64        gpio, dram(vttctrl), led(p3)
+mpp65        65        gpio, sata1(prsnt)
+mpp66        66        gpio, ptp(eventreq), spi1(cs3)
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
new file mode 100644 (file)
index 0000000..b17c968
--- /dev/null
@@ -0,0 +1,80 @@
+* Marvell Armada 380/385 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6810-pinctrl", "marvell,88f6820-pinctrl" or
+  "marvell,88f6828-pinctrl" depending on the specific variant of the
+  SoC being used.
+- reg: register specifier of MPP registers
+
+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.
+
+name          pins     functions
+================================================================================
+mpp0          0        gpio, ua0(rxd)
+mpp1          1        gpio, ua0(txd)
+mpp2          2        gpio, i2c0(sck)
+mpp3          3        gpio, i2c0(sda)
+mpp4          4        gpio, ge(mdc), ua1(txd), ua0(rts)
+mpp5          5        gpio, ge(mdio), ua1(rxd), ua0(cts)
+mpp6          6        gpio, ge0(txclkout), ge0(crs), dev(cs3)
+mpp7          7        gpio, ge0(txd0), dev(ad9)
+mpp8          8        gpio, ge0(txd1), dev(ad10)
+mpp9          9        gpio, ge0(txd2), dev(ad11)
+mpp10         10       gpio, ge0(txd3), dev(ad12)
+mpp11         11       gpio, ge0(txctl), dev(ad13)
+mpp12         12       gpio, ge0(rxd0), pcie0(rstout), pcie1(rstout) [1], spi0(cs1), dev(ad14)
+mpp13         13       gpio, ge0(rxd1), pcie0(clkreq), pcie1(clkreq) [1], spi0(cs2), dev(ad15)
+mpp14         14       gpio, ge0(rxd2), ptp(clk), m(vtt_ctrl), spi0(cs3), dev(wen1)
+mpp15         15       gpio, ge0(rxd3), ge(mdc slave), pcie0(rstout), spi0(mosi), pcie1(rstout) [1]
+mpp16         16       gpio, ge0(rxctl), ge(mdio slave), m(decc_err), spi0(miso), pcie0(clkreq)
+mpp17         17       gpio, ge0(rxclk), ptp(clk), ua1(rxd), spi0(sck), sata1(prsnt)
+mpp18         18       gpio, ge0(rxerr), ptp(trig_gen), ua1(txd), spi0(cs0), pcie1(rstout) [1]
+mpp19         19       gpio, ge0(col), ptp(event_req), pcie0(clkreq), sata1(prsnt), ua0(cts)
+mpp20         20       gpio, ge0(txclk), ptp(clk), pcie1(rstout) [1], sata0(prsnt), ua0(rts)
+mpp21         21       gpio, spi0(cs1), ge1(rxd0), sata0(prsnt), sd0(cmd), dev(bootcs)
+mpp22         22       gpio, spi0(mosi), dev(ad0)
+mpp23         23       gpio, spi0(sck), dev(ad2)
+mpp24         24       gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready)
+mpp25         25       gpio, spi0(cs0), ua0(rts), ua1(txd), sd0(d5), dev(cs0)
+mpp26         26       gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1)
+mpp27         27       gpio, spi0(cs3), ge1(txclkout), i2c1(sda), sd0(d7), dev(cs2)
+mpp28         28       gpio, ge1(txd0), sd0(clk), dev(ad5)
+mpp29         29       gpio, ge1(txd1), dev(ale0)
+mpp30         30       gpio, ge1(txd2), dev(oen)
+mpp31         31       gpio, ge1(txd3), dev(ale1)
+mpp32         32       gpio, ge1(txctl), dev(wen0)
+mpp33         33       gpio, m(decc_err), dev(ad3)
+mpp34         34       gpio, dev(ad1)
+mpp35         35       gpio, ref(clk_out1), dev(a1)
+mpp36         36       gpio, ptp(trig_gen), dev(a0)
+mpp37         37       gpio, ptp(clk), ge1(rxclk), sd0(d3), dev(ad8)
+mpp38         38       gpio, ptp(event_req), ge1(rxd1), ref(clk_out0), sd0(d0), dev(ad4)
+mpp39         39       gpio, i2c1(sck), ge1(rxd2), ua0(cts), sd0(d1), dev(a2)
+mpp40         40       gpio, i2c1(sda), ge1(rxd3), ua0(rts), sd0(d2), dev(ad6)
+mpp41         41       gpio, ua1(rxd), ge1(rxctl), ua0(cts), spi1(cs3), dev(burst/last)
+mpp42         42       gpio, ua1(txd), ua0(rts), dev(ad7)
+mpp43         43       gpio, pcie0(clkreq), m(vtt_ctrl), m(decc_err), pcie0(rstout), dev(clkout)
+mpp44         44       gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [3], pcie0(rstout)
+mpp45         45       gpio, ref(clk_out0), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
+mpp46         46       gpio, ref(clk_out1), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
+mpp47         47       gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], spi1(cs2), sata3(prsnt) [2]
+mpp48         48       gpio, sata0(prsnt), m(vtt_ctrl), tdm2c(pclk), audio(mclk), sd0(d4)
+mpp49         49       gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm2c(fsync), audio(lrclk), sd0(d5)
+mpp50         50       gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(drx), audio(extclk), sd0(cmd)
+mpp51         51       gpio, tdm2c(dtx), audio(sdo), m(decc_err)
+mpp52         52       gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(intn), audio(sdi), sd0(d6)
+mpp53         53       gpio, sata1(prsnt), sata0(prsnt), tdm2c(rstn), audio(bclk), sd0(d7)
+mpp54         54       gpio, sata0(prsnt), sata1(prsnt), pcie0(rstout), pcie1(rstout) [1], sd0(d3)
+mpp55         55       gpio, ua1(cts), ge(mdio), pcie1(clkreq) [1], spi1(cs1), sd0(d0)
+mpp56         56       gpio, ua1(rts), ge(mdc), m(decc_err), spi1(mosi)
+mpp57         57       gpio, spi1(sck), sd0(clk)
+mpp58         58       gpio, pcie1(clkreq) [1], i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1)
+mpp59         59       gpio, pcie0(rstout), i2c1(sda), pcie1(rstout) [1], spi1(cs0), sd0(d2)
+
+[1]: only available on 88F6820 and 88F6828
+[2]: only available on 88F6828
index bfa0a2e5e0cb929d91f666537fe45a99199005d0..373dbccd7ab0e7c5b4905b7c700e8fada265be1a 100644 (file)
@@ -6,6 +6,7 @@ part and usage.
 Required properties:
 - compatible: "marvell,mv78230-pinctrl", "marvell,mv78260-pinctrl",
               "marvell,mv78460-pinctrl"
+- reg: register specifier of MPP registers
 
 This driver supports all Armada XP variants, i.e. mv78230, mv78260, and mv78460.
 
index 50ec3512a292c3cbfc8a2ab4aba5c005c10ad2db..cf52477cc7ee3affd5527ccfeaef0fd841e80cff 100644 (file)
@@ -6,6 +6,7 @@ part and usage.
 Required properties:
 - compatible: "marvell,dove-pinctrl"
 - clocks: (optional) phandle of pdma clock
+- reg: register specifiers of MPP, MPP4, and PMU MPP registers
 
 Available mpp pins/groups and functions:
 Note: brackets (x) are not part of the mpp name for marvell,function and given
index 95daf6335c3796e2256ddb94e3e21190cf0c1b35..730444a9a4de8a3aba0e6be2864f974b4f5da1a5 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
               "marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl",
               "marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl"
               "marvell,98dx4122-pinctrl"
+- reg: register specifier of MPP registers
 
 This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x.
 It also support the 88f6281-based variant in the 98dx412x Bobcat SoCs.
index 0a26c3aa4e6d0ccc20ad78c981f52fb4733e14aa..0c09f4eb2af09db6aa785d6c6ea70f0086de6240 100644 (file)
@@ -37,7 +37,7 @@ uart1: serial@12100 {
 
 pinctrl: pinctrl@d0200 {
        compatible = "marvell,dove-pinctrl";
-       reg = <0xd0200 0x20>;
+       reg = <0xd0200 0x14>, <0xd0440 0x04>, <0xd802c 0x08>;
 
        pmx_uart1_sw: pmx-uart1-sw {
                marvell,pins = "mpp_uart1";
index bc0dfdfdb14860577483963c01979b3f8b18ffbd..66dcaa9efd7401916d3ec8cc9e03c9ebaff50a22 100644 (file)
@@ -63,6 +63,13 @@ Optional properties:
                /* input, enable bits, disable bits, mask */
                pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
 
+- pinctrl-single,low-power-mode : array of value that are used to configure
+  low power mode of this pin. For some silicons, the low power mode will
+  control the output of the pin when the pad including the pin enter low
+  power mode.
+               /* low power mode value, mask */
+               pinctrl-single,low-power-mode = <0x288 0x388>;
+
 - pinctrl-single,gpio-range : list of value that are used to configure a GPIO
   range. They're value of subnode phandle, pin base in pinctrl device, pin
   number in this range, GPIO function value of this GPIO range.
index 05bf82a07dfdea5c51a1fdf0c09a9a9b8ef95e37..4bd5be0e5e7dd51eaf7cf23a92a2bf884dd264f1 100644 (file)
@@ -11,18 +11,68 @@ 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)
+GPIO bank can have one of the two possible types of interrupt-wirings.
+
+First type is via irqmux, single interrupt is used by multiple gpio banks. This
+reduces number of overall interrupts numbers required. All these banks belong to
+a single pincontroller.
+                 _________
+                |         |----> [gpio-bank (n)    ]
+                |         |----> [gpio-bank (n + 1)]
+       [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
+                |         |----> [gpio-bank (...  )]
+                |_________|----> [gpio-bank (n + 7)]
+
+Second type has a dedicated interrupt per gpio bank.
+
+       [irqN]----> [gpio-bank (n)]
+
+
+Pin controller node:
+Required properties:
 - 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,syscfg            : Should be a phandle of the syscfg node.
 - 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.
+- ranges : defines mapping between pin controller node (parent) to gpio-bank
+  node (children).
+
+Optional properties:
+- interrupts   : Interrupt number of the irqmux. If the interrupt is shared
+  with other gpio banks via irqmux.
+  a irqline and gpio banks.
+- reg          : irqmux memory resource. If irqmux is present.
+- reg-names    : irqmux resource should be named as "irqmux".
+
+GPIO controller/bank node.
+Required properties:
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells    : Should be one. The first cell is the pin number.
+- st,bank-name   : Should be a name string for this bank as specified in
+  datasheet.
+
+Optional properties:
+- interrupts   : Interrupt number for this gpio bank. If there is a dedicated
+  interrupt wired up for this gpio bank.
+
+- interrupt-controller : Indicates this device is a interrupt controller. GPIO
+  bank can be an interrupt controller iff one of the interrupt type either via
+irqmux or a dedicated interrupt per bank is specified.
+
+- #interrupt-cells: the value of this property should be 2.
+     - First Cell: represents the external gpio interrupt number local to the
+       gpio interrupt space of the controller.
+     - Second Cell: flags to identify the type of the interrupt
+       - 1 = rising edge triggered
+       - 2 = falling edge triggered
+       - 3 = rising and falling edge triggered
+       - 4 = high level triggered
+       - 8 = low level triggered
+for related macros look in:
+include/dt-bindings/interrupt-controller/irq.h
 
 Example:
        pin-controller-sbc {
@@ -30,10 +80,17 @@ Example:
                #size-cells     = <1>;
                compatible      = "st,stih415-sbc-pinctrl";
                st,syscfg       = <&syscfg_sbc>;
+               reg             = <0xfe61f080 0x4>;
+               reg-names       = "irqmux";
+               interrupts      = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts-names = "irqmux";
                ranges          = <0 0xfe610000 0x5000>;
+
                PIO0: gpio@fe610000 {
                        gpio-controller;
                        #gpio-cells     = <1>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                        reg             = <0 0x100>;
                        st,bank-name    = "PIO0";
                };
@@ -105,6 +162,10 @@ pin-controller {
 
 sdhci0:sdhci@fe810000{
        ...
+       interrupt-parent = <&PIO3>;
+       #interrupt-cells = <2>;
+       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; /* Interrupt line via PIO3-3 */
+       interrupts-names = "card-detect";
        pinctrl-names = "default";
        pinctrl-0       = <&pinctrl_mmc>;
 };
index 4c352be5dd615a463ae56bde90af1b321307a2eb..9fb89e3f61eac0b6794e32ccded19ff9671c200c 100644 (file)
@@ -1,7 +1,7 @@
 Qualcomm MSM8974 TLMM block
 
 Required properties:
-- compatible: "qcom,msm8x74-pinctrl"
+- compatible: "qcom,msm8974-pinctrl"
 - reg: Should be the base address and length of the TLMM block.
 - interrupts: Should be the parent IRQ of the TLMM block.
 - interrupt-controller: Marks the device node as an interrupt controller.
@@ -42,14 +42,14 @@ Non-empty subnodes must specify the 'pins' property.
 Note that not all properties are valid for all pins.
 
 
-Valid values for qcom,pins are:
+Valid values for pins are:
   gpio0-gpio145
     Supports mux, bias and drive-strength
 
   sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data
     Supports bias and drive-strength
 
-Valid values for qcom,function are:
+Valid values for function are:
   blsp_i2c2, blsp_i2c6, blsp_i2c11, blsp_spi1, blsp_uart2, blsp_uart8, slimbus
 
   (Note that this is not yet the complete list of functions)
@@ -73,18 +73,18 @@ Example:
 
                uart2_default: uart2_default {
                        mux {
-                               qcom,pins = "gpio4", "gpio5";
-                               qcom,function = "blsp_uart2";
+                               pins = "gpio4", "gpio5";
+                               function = "blsp_uart2";
                        };
 
                        tx {
-                               qcom,pins = "gpio4";
+                               pins = "gpio4";
                                drive-strength = <4>;
                                bias-disable;
                        };
 
                        rx {
-                               qcom,pins = "gpio5";
+                               pins = "gpio5";
                                drive-strength = <2>;
                                bias-pull-up;
                        };
index 257677de3e6badac3a185f8c897126d777d48b49..2b32783ba8210dda7fd78b231c512a9e672d694a 100644 (file)
@@ -16,6 +16,7 @@ Required Properties:
   - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
   - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
   - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
+  - "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller.
   - "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller.
 
 - reg: Base address of the pin controller hardware module and length of
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
deleted file mode 100644 (file)
index d5e3704..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-Integrated Flash Controller
-
-Properties:
-- name : Should be ifc
-- compatible : should contain "fsl,ifc". The version of the integrated
-               flash controller can be found in the IFC_REV register at
-               offset zero.
-
-- #address-cells : Should be either two or three.  The first cell is the
-                   chipselect number, and the remaining cells are the
-                   offset into the chipselect.
-- #size-cells : Either one or two, depending on how large each chipselect
-                can be.
-- reg : Offset and length of the register set for the device
-- interrupts: IFC may have one or two interrupts.  If two interrupt
-              specifiers are present, the first is the "common"
-              interrupt (CM_EVTER_STAT), and the second is the NAND
-              interrupt (NAND_EVTER_STAT).  If there is only one,
-              that interrupt reports both types of event.
-
-
-- ranges : Each range corresponds to a single chipselect, and covers
-           the entire access window as configured.
-
-Child device nodes describe the devices connected to IFC such as NOR (e.g.
-cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices
-like FPGAs, CPLDs, etc.
-
-Example:
-
-       ifc@ffe1e000 {
-               compatible = "fsl,ifc", "simple-bus";
-               #address-cells = <2>;
-               #size-cells = <1>;
-               reg = <0x0 0xffe1e000 0 0x2000>;
-               interrupts = <16 2 19 2>;
-
-               /* NOR, NAND Flashes and CPLD on board */
-               ranges = <0x0 0x0 0x0 0xee000000 0x02000000
-                         0x1 0x0 0x0 0xffa00000 0x00010000
-                         0x3 0x0 0x0 0xffb00000 0x00020000>;
-
-               flash@0,0 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "cfi-flash";
-                       reg = <0x0 0x0 0x2000000>;
-                       bank-width = <2>;
-                       device-width = <1>;
-
-                       partition@0 {
-                               /* 32MB for user data */
-                               reg = <0x0 0x02000000>;
-                               label = "NOR Data";
-                       };
-               };
-
-               flash@1,0 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "fsl,ifc-nand";
-                       reg = <0x1 0x0 0x10000>;
-
-                       partition@0 {
-                               /* This location must not be altered  */
-                               /* 1MB for u-boot Bootloader Image */
-                               reg = <0x0 0x00100000>;
-                               label = "NAND U-Boot Image";
-                               read-only;
-                       };
-               };
-
-               cpld@3,0 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "fsl,p1010rdb-cpld";
-                       reg = <0x3 0x0 0x000001f>;
-               };
-       };
index 63c659800c0320a9b08a8878fcb3ab327f270d9f..e5cac1e0ca8a734d43549ad125a837beef457e13 100644 (file)
@@ -8,8 +8,12 @@ Required properties:
 Optional properties:
 - enable-gpio          : GPIO to use to enable/disable the regulator.
 - gpios                        : GPIO group used to control voltage.
+- gpios-states         : gpios pin's initial states array. 0: LOW, 1: HIGH.
+                         defualt is LOW if nothing is specified.
 - startup-delay-us     : Startup time in microseconds.
 - enable-active-high   : Polarity of GPIO is active high (default is low).
+- regulator-type       : Specifies what is being regulated, must be either
+                         "voltage" or "current", defaults to current.
 
 Any property defined as part of the core regulator binding defined in
 regulator.txt can also be used.
index fc989b2e8057b3ced0b306ac53befb4a3edc1f81..34ef5d16d0f1697c51b6759b8a572f33d6b85894 100644 (file)
@@ -1,7 +1,7 @@
 PFUZE100 family of regulators
 
 Required properties:
-- compatible: "fsl,pfuze100"
+- compatible: "fsl,pfuze100" or "fsl,pfuze200"
 - reg: I2C slave address
 
 Required child node:
@@ -10,11 +10,14 @@ Required child node:
   Documentation/devicetree/bindings/regulator/regulator.txt.
 
   The valid names for regulators are:
+  --PFUZE100
   sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
+  --PFUZE200
+  sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6
 
 Each regulator is defined using the standard binding for regulators.
 
-Example:
+Example 1: PFUZE100
 
        pmic: pfuze100@08 {
                compatible = "fsl,pfuze100";
@@ -113,3 +116,92 @@ Example:
                        };
                };
        };
+
+
+Example 2: PFUZE200
+
+       pmic: pfuze200@08 {
+               compatible = "fsl,pfuze200";
+               reg = <0x08>;
+
+               regulators {
+                       sw1a_reg: sw1ab {
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3a_reg: sw3a {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3b_reg: sw3b {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vgen1 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen2_reg: vgen2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen3_reg: vgen3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vgen4_reg: vgen4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen5_reg: vgen5 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vgen6 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+               };
+       };
index fc6b38f035bd4b8a4e369e67d6eb25bb4d87edf9..d290988ed975fee4883ff6a49a0e5d79ae82feee 100644 (file)
@@ -69,13 +69,16 @@ sub-node should be of the format as listed below.
                };
        };
 The above regulator entries are defined in regulator bindings documentation
-except op_mode description.
+except these properties:
        - op_mode: describes the different operating modes of the LDO's with
                power mode change in SOC. The different possible values are,
                0 - always off mode
                1 - on in normal mode
                2 - low power mode
                3 - suspend mode
+       - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one
+               GPIO controlling this regulator (enable/disable); This is
+               valid only for buck9.
 
 The following are the names of the regulators that the s5m8767 pmic block
 supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
@@ -148,5 +151,13 @@ Example:
                                regulator-always-on;
                                regulator-boot-on;
                        };
+
+                       vemmc_reg: BUCK9 {
+                               regulator-name = "VMEM_VDD_2.8V";
+                               regulator-min-microvolt = <2800000>;
+                               regulator-max-microvolt = <2800000>;
+                               op_mode = <3>; /* Standby Mode */
+                               s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>;
+                       };
                };
        };
index 2e57a33e9029a39fa80c2da517e7d4bb8df4aa4d..c58db75f959e601fcf326a0637d79617253a8206 100644 (file)
@@ -4,10 +4,14 @@ Required Properties:
 - compatible: Should be one of:
   - "ti,abb-v1" for older SoCs like OMAP3
   - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5
+  - "ti,abb-v3" for a generic definition where setup and control registers are
+     provided (example: DRA7)
 - 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
+  - "base-address"     - contains base address of ABB module (ti,abb-v1,ti,abb-v2)
+  - "control-address"  - contains control register address of ABB module (ti,abb-v3)
+  - "setup-address"    - contains setup register address of ABB module (ti,abb-v3)
   - "int-address"      - contains address of interrupt register for ABB module
   (also see Optional properties)
 - #address-cell: should be 0
diff --git a/Documentation/devicetree/bindings/sound/armada-370db-audio.txt b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
new file mode 100644 (file)
index 0000000..bf984d2
--- /dev/null
@@ -0,0 +1,27 @@
+Device Tree bindings for the Armada 370 DB audio
+================================================
+
+These Device Tree bindings are used to describe the audio complex
+found on the Armada 370 DB platform.
+
+Mandatory properties:
+
+ * compatible: must be "marvell,a370db-audio"
+
+ * marvell,audio-controller: a phandle that points to the audio
+   controller of the Armada 370 SoC.
+
+ * marvell,audio-codec: a set of three phandles that points to:
+
+    1/ the analog audio codec connected to the Armada 370 SoC
+    2/ the S/PDIF transceiver
+    3/ the S/PDIF receiver
+
+Example:
+
+       sound {
+             compatible = "marvell,a370db-audio";
+             marvell,audio-controller = <&audio_controller>;
+             marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
+             status = "okay";
+       };
diff --git a/Documentation/devicetree/bindings/sound/cs42xx8.txt b/Documentation/devicetree/bindings/sound/cs42xx8.txt
new file mode 100644 (file)
index 0000000..f631fbc
--- /dev/null
@@ -0,0 +1,28 @@
+CS42448/CS42888 audio CODEC
+
+Required properties:
+
+  - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
+
+  - reg : the I2C address of the device for I2C
+
+  - clocks : a list of phandles + clock-specifiers, one for each entry in
+    clock-names
+
+  - clock-names : must contain "mclk"
+
+  - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
+    as covered in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+
+codec: cs42888@48 {
+       compatible = "cirrus,cs42888";
+       reg = <0x48>;
+       clocks = <&codec_mclk 0>;
+       clock-names = "mclk";
+       VA-supply = <&reg_audio>;
+       VD-supply = <&reg_audio>;
+       VLS-supply = <&reg_audio>;
+       VLC-supply = <&reg_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/da9055.txt b/Documentation/devicetree/bindings/sound/da9055.txt
new file mode 100644 (file)
index 0000000..ed1b7cc
--- /dev/null
@@ -0,0 +1,22 @@
+* Dialog DA9055 Audio CODEC
+
+DA9055 provides Audio CODEC support (I2C only).
+
+The Audio CODEC device in DA9055 has it's own I2C address which is configurable,
+so the device is instantiated separately from the PMIC (MFD) device.
+
+For details on accompanying PMIC I2C device, see the following:
+Documentation/devicetree/bindings/mfd/da9055.txt
+
+Required properties:
+
+  - compatible: "dlg,da9055-codec"
+  - reg: Specifies the I2C slave address
+
+
+Example:
+
+       codec: da9055-codec@1a {
+               compatible = "dlg,da9055-codec";
+               reg = <0x1a>;
+       };
index 865178d5cdf34cd615042234cf5f475c05e9c8db..963e100514c27d892069d1d504e70f249f620b2a 100644 (file)
@@ -5,12 +5,19 @@ Required properties:
 - ti,model : The user-visible name of this sound complex.
 - ti,audio-codec : The phandle of the TLV320AIC3x audio codec
 - ti,mcasp-controller : The phandle of the McASP controller
-- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
 - ti,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 codec's pins, and the jacks on the board:
 
+Optional properties:
+- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec.
+- clocks : Reference to the master clock
+- clock-names : The clock should be named "mclk"
+- Either codec-clock-rate or the codec-clock reference has to be defined. If
+  the both are defined the driver attempts to set referenced clock to the
+  defined rate and takes the rate from the clock reference.
+
   Board connectors:
 
   * Headphone Jack
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
new file mode 100644 (file)
index 0000000..0d7985c
--- /dev/null
@@ -0,0 +1,21 @@
+Audio complex for Eukrea boards with tlv320aic23 codec.
+
+Required properties:
+- compatible : "eukrea,asoc-tlv320"
+- eukrea,model : The user-visible name of this sound complex.
+- ssi-controller : The phandle of the SSI controller.
+- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
+- fsl,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 = "eukrea,asoc-tlv320";
+               eukrea,model = "imx51-eukrea-tlv320aic23";
+               ssi-controller = <&ssi2>;
+               fsl,mux-int-port = <2>;
+               fsl,mux-ext-port = <3>;
+       };
index d7b99fa637b59f713ef659563f476443f7df8a15..aeb8c4a0b88d4de37d17e97238d6beb16c6fd20e 100644 (file)
@@ -34,6 +34,10 @@ Required properties:
     that ESAI would work in the synchronous mode, which means all the settings
     for Receiving would be duplicated from Transmition related registers.
 
+  - big-endian : If this property is absent, the native endian mode will
+    be in use as default, or the big endian mode will be in use for all the
+    device registers.
+
 Example:
 
 esai: esai@02024000 {
@@ -46,5 +50,6 @@ esai: esai@02024000 {
        dma-names = "rx", "tx";
        fsl,fifo-depth = <128>;
        fsl,esai-synchronous;
+       big-endian;
        status = "disabled";
 };
index f2ae335670f5ebb34d467f396a0a1b4ac3b3a69c..3e9e82c8eab328a3427713de5ea5be3031533c51 100644 (file)
@@ -29,6 +29,10 @@ Required properties:
                        can also be referred to TxClk_Source
                        bit of register SPDIF_STC.
 
+   - big-endian : If this property is absent, the native endian mode will
+   be in use as default, or the big endian mode will be in use for all the
+   device registers.
+
 Example:
 
 spdif: spdif@02004000 {
@@ -50,5 +54,6 @@ spdif: spdif@02004000 {
                "rxtx5", "rxtx6",
                "rxtx7";
 
+       big-endian;
        status = "okay";
 };
index f0062c5871b4d1d525af5dac77fa85a2398a83ec..cb8c07c81ce4498e77a94003ae16bfb9ec9b2e5c 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
 - compatible:
   "marvell,kirkwood-audio" for Kirkwood platforms
   "marvell,dove-audio" for Dove platforms
+  "marvell,armada370-audio" for Armada 370 platforms
 
 - reg: physical base address of the controller and length of memory mapped
   region.
diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt
new file mode 100644 (file)
index 0000000..faff75e
--- /dev/null
@@ -0,0 +1,30 @@
+PCM512x audio CODECs
+
+These devices support both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+
+  - compatible : One of "ti,pcm5121" or "ti,pcm5122"
+
+  - reg : the I2C address of the device for I2C, the chip select
+          number for SPI.
+
+  - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the
+    device, as covered in bindings/regulator/regulator.txt
+
+Optional properties:
+
+  - clocks : A clock specifier for the clock connected as SCLK.  If this
+    is absent the device will be configured to clock from BCLK.
+
+Example:
+
+       pcm5122: pcm5122@4c {
+               compatible = "ti,pcm5122";
+               reg = <0x4c>;
+
+               AVDD-supply = <&reg_3v3_analog>;
+               DVDD-supply = <&reg_1v8>;
+               CPVDD-supply = <&reg_3v3>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
new file mode 100644 (file)
index 0000000..a44e917
--- /dev/null
@@ -0,0 +1,105 @@
+Renesas R-Car sound
+
+Required properties:
+- compatible                   : "renesas,rcar_sound-gen1" if generation1
+                                 "renesas,rcar_sound-gen2" if generation2
+- reg                          : Should contain the register physical address.
+                                 required register is
+                                  SRU/ADG/SSI      if generation1
+                                  SRU/ADG/SSIU/SSI if generation2
+- rcar_sound,ssi               : Should contain SSI feature.
+                                 The number of SSI subnode should be same as HW.
+                                 see below for detail.
+- rcar_sound,src               : Should contain SRC feature.
+                                 The number of SRC subnode should be same as HW.
+                                 see below for detail.
+- rcar_sound,dai               : DAI contents.
+                                 The number of DAI subnode should be same as HW.
+                                 see below for detail.
+
+SSI subnode properties:
+- interrupts                   : Should contain SSI interrupt for PIO transfer
+- shared-pin                   : if shared clock pin
+
+SRC subnode properties:
+no properties at this point
+
+DAI subnode properties:
+- playback                     : list of playback modules
+- capture                      : list of capture  modules
+
+Example:
+
+rcar_sound: rcar_sound@0xffd90000 {
+       #sound-dai-cells = <1>;
+       compatible = "renesas,rcar_sound-gen2";
+       reg =   <0 0xec500000 0 0x1000>, /* SCU */
+               <0 0xec5a0000 0 0x100>,  /* ADG */
+               <0 0xec540000 0 0x1000>, /* SSIU */
+               <0 0xec541000 0 0x1280>; /* SSI */
+
+       rcar_sound,src {
+               src0: src@0 { };
+               src1: src@1 { };
+               src2: src@2 { };
+               src3: src@3 { };
+               src4: src@4 { };
+               src5: src@5 { };
+               src6: src@6 { };
+               src7: src@7 { };
+               src8: src@8 { };
+               src9: src@9 { };
+       };
+
+       rcar_sound,ssi {
+               ssi0: ssi@0 {
+                       interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi1: ssi@1 {
+                       interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi2: ssi@2 {
+                       interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi3: ssi@3 {
+                       interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi4: ssi@4 {
+                       interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi5: ssi@5 {
+                       interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi6: ssi@6 {
+                       interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi7: ssi@7 {
+                       interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi8: ssi@8 {
+                       interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
+               };
+               ssi9: ssi@9 {
+                       interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
+               };
+       };
+
+       rcar_sound,dai {
+               dai0 {
+                       playback = <&ssi5 &src5>;
+                       capture  = <&ssi6>;
+               };
+               dai1 {
+                       playback = <&ssi3>;
+               };
+               dai2 {
+                       capture  = <&ssi4>;
+               };
+               dai3 {
+                       playback = <&ssi7>;
+               };
+               dai4 {
+                       capture  = <&ssi8>;
+               };
+       };
+};
index 19c84df5fffa35d8a65adae8f39db947da969147..131aa2ad7f1a3120d6ebeef6492c466f87ab461b 100644 (file)
@@ -8,16 +8,26 @@ Required properties:
 
 Optional properties:
 
+- simple-audio-card,name               : User specified audio sound card name, one string
+                                         property.
 - simple-audio-card,format             : CPU/CODEC common audio format.
                                          "i2s", "right_j", "left_j" , "dsp_a"
                                          "dsp_b", "ac97", "pdm", "msb", "lsb"
+- simple-audio-card,widgets            : Please refer to widgets.txt.
 - simple-audio-card,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.
+- dai-tdm-slot-num                     : Please refer to tdm-slot.txt.
+- dai-tdm-slot-width                   : Please refer to tdm-slot.txt.
 
 Required subnodes:
 
+- simple-audio-card,dai-link           : container for the CPU and CODEC sub-nodes
+                                         This container may be omitted when the
+                                         card has only one DAI link.
+                                         See the examples.
+
 - simple-audio-card,cpu                        : CPU   sub-node
 - simple-audio-card,codec              : CODEC sub-node
 
@@ -38,15 +48,29 @@ Optional CPU/CODEC subnodes properties:
                                          clock node (= common clock), or "system-clock-frequency"
                                          (if system doens't support common clock)
 
-Example:
+Note:
+ * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
+   'frame-inversion', the simple card will use the settings of CODEC for both
+   CPU and CODEC sides as we need to keep the settings identical for both ends
+   of the link.
+
+Example 1 - single DAI link:
 
 sound {
        compatible = "simple-audio-card";
+       simple-audio-card,name = "VF610-Tower-Sound-Card";
        simple-audio-card,format = "left_j";
+       simple-audio-card,widgets =
+               "Microphone", "Microphone Jack",
+               "Headphone", "Headphone Jack",
+               "Speaker", "External Speaker";
        simple-audio-card,routing =
-               "MIC_IN", "Mic Jack",
+               "MIC_IN", "Microphone Jack",
                "Headphone Jack", "HP_OUT",
-               "Ext Spk", "LINE_OUT";
+               "External Speaker", "LINE_OUT";
+
+       dai-tdm-slot-num = <2>;
+       dai-tdm-slot-width = <8>;
 
        simple-audio-card,cpu {
                sound-dai = <&sh_fsi2 0>;
@@ -75,3 +99,38 @@ sh_fsi2: sh_fsi2@ec230000 {
        interrupt-parent = <&gic>;
        interrupts = <0 146 0x4>;
 };
+
+Example 2 - many DAI links:
+
+sound {
+       compatible = "simple-audio-card";
+       simple-audio-card,name = "Cubox Audio";
+       simple-audio-card,format = "i2s";
+
+       simple-audio-card,dai-link@0 {          /* I2S - HDMI */
+               simple-audio-card,cpu {
+                       sound-dai = <&audio1 0>;
+               };
+               simple-audio-card,codec {
+                       sound-dai = <&tda998x 0>;
+               };
+       };
+
+       simple-audio-card,dai-link@1 {          /* S/PDIF - HDMI */
+               simple-audio-card,cpu {
+                       sound-dai = <&audio1 1>;
+               };
+               simple-audio-card,codec {
+                       sound-dai = <&tda998x 1>;
+               };
+       };
+
+       simple-audio-card,dai-link@2 {          /* S/PDIF - S/PDIF */
+               simple-audio-card,cpu {
+                       sound-dai = <&audio1 1>;
+               };
+               simple-audio-card,codec {
+                       sound-dai = <&spdif_codec>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
new file mode 100644 (file)
index 0000000..062f5ec
--- /dev/null
@@ -0,0 +1,17 @@
+SiRF internal audio CODEC
+
+Required properties:
+
+  - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec"
+
+  - reg : the register address of the device.
+
+  - clocks: the clock of SiRF internal audio codec
+
+Example:
+
+audiocodec: audiocodec@b0040000 {
+       compatible = "sirf,atlas6-audio-codec";
+       reg = <0xb0040000 0x10000>;
+       clocks = <&clks 27>;
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-port.txt b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt
new file mode 100644 (file)
index 0000000..1f66de3
--- /dev/null
@@ -0,0 +1,20 @@
+* SiRF SoC audio port
+
+Required properties:
+- compatible: "sirf,audio-port"
+- reg: Base address and size entries:
+- dmas: List of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: Identifier string for each DMA request line in the dmas property.
+  These strings correspond 1:1 with the ordered pairs in dmas.
+
+  One of the DMA channels will be responsible for transmission (should be
+  named "tx") and one for reception (should be named "rx").
+
+Example:
+
+audioport: audioport@b0040000 {
+       compatible = "sirf,audio-port";
+       reg = <0xb0040000 0x10000>;
+       dmas = <&dmac1 3>, <&dmac1 8>;
+       dma-names = "rx", "tx";
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio.txt b/Documentation/devicetree/bindings/sound/sirf-audio.txt
new file mode 100644 (file)
index 0000000..c88882c
--- /dev/null
@@ -0,0 +1,41 @@
+* SiRF atlas6 and prima2 internal audio codec and port based audio setups
+
+Required properties:
+- compatible: "sirf,sirf-audio-card"
+- sirf,audio-platform: phandle for the platform node
+- sirf,audio-codec: phandle for the SiRF internal codec node
+
+Optional properties:
+- hp-pa-gpios: Need to be present if the board need control external
+  headphone amplifier.
+- spk-pa-gpios: Need to be present if the board need control external
+  speaker amplifier.
+- hp-switch-gpios: Need to be present if the board capable to detect jack
+  insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Ext Spk
+ * Line In
+ * Mic
+
+SiRF internal audio codec pins:
+ * HPOUTL
+ * HPOUTR
+ * SPKOUT
+ * Ext Mic
+ * Mic Bias
+
+Example:
+
+sound {
+               compatible = "sirf,sirf-audio-card";
+               sirf,audio-codec = <&audiocodec>;
+               sirf,audio-platform = <&audioport>;
+               hp-pa-gpios = <&gpio 44 0>;
+               spk-pa-gpios = <&gpio 46 0>;
+               hp-switch-gpios = <&gpio 45 0>;
+};
+
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
new file mode 100644 (file)
index 0000000..6a2c842
--- /dev/null
@@ -0,0 +1,20 @@
+TDM slot:
+
+This specifies audio DAI's TDM slot.
+
+TDM slot properties:
+dai-tdm-slot-num : Number of slots in use.
+dai-tdm-slot-width :  Width in bits for each slot.
+
+For instance:
+       dai-tdm-slot-num = <2>;
+       dai-tdm-slot-width = <8>;
+
+And for each spcified driver, there could be one .of_xlate_tdm_slot_mask()
+to specify a explicit mapping of the channels and the slots. If it's absent
+the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
+tx and rx masks.
+
+For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
+for an active slot as default, and the default active bits are at the LSB of
+the masks.
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
new file mode 100644 (file)
index 0000000..74c66de
--- /dev/null
@@ -0,0 +1,61 @@
+Texas Instruments - tlv320aic31xx Codec module
+
+The tlv320aic31xx serial control bus communicates through I2C protocols
+
+Required properties:
+
+- compatible - "string" - One of:
+    "ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp
+    "ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp
+    "ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP)
+    "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
+    "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
+    "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
+
+- reg - <int> -  I2C slave address
+
+
+Optional properties:
+
+- gpio-reset - gpio pin number used for codec reset
+- ai31xx-micbias-vg - MicBias Voltage setting
+        1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
+        2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
+        3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
+       If this node is not mentioned or if the value is unknown, then
+       micbias is set to 2.0V.
+- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
+  DVDD-supply : power supplies for the device as covered in
+  Documentation/devicetree/bindings/regulator/regulator.txt
+
+CODEC output pins:
+  * HPL
+  * HPR
+  * SPL, devices with stereo speaker amp
+  * SPR, devices with stereo speaker amp
+  * SPK, devices with mono speaker amp
+  * MICBIAS
+
+CODEC input pins:
+  * MIC1LP
+  * MIC1RP
+  * MIC1LM
+
+The pins can be used in referring sound node's audio-routing property.
+
+Example:
+#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+tlv320aic31xx: tlv320aic31xx@18 {
+       compatible = "ti,tlv320aic311x";
+       reg = <0x18>;
+
+       ai31xx-micbias-vg = <MICBIAS_OFF>;
+
+       HPVDD-supply = <&regulator>;
+       SPRVDD-supply = <&regulator>;
+       SPLVDD-supply = <&regulator>;
+       AVDD-supply = <&regulator>;
+       IOVDD-supply = <&regulator>;
+       DVDD-supply = <&regulator>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
new file mode 100644 (file)
index 0000000..5e2741a
--- /dev/null
@@ -0,0 +1,30 @@
+Texas Instruments - tlv320aic32x4 Codec module
+
+The tlv320aic32x4 serial control bus communicates through I2C protocols
+
+Required properties:
+ - compatible: Should be "ti,tlv320aic32x4"
+ - reg: I2C slave address
+ - supply-*: Required supply regulators are:
+    "iov" - digital IO power supply
+    "ldoin" - LDO power supply
+    "dv" - Digital core power supply
+    "av" - Analog core power supply
+    If you supply ldoin, dv and av are optional. Otherwise they are required
+   See regulator/regulator.txt for more information about the detailed binding
+   format.
+
+Optional properties:
+ - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
+ - clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
+   See clock/clock-bindings.txt for information about the detailed format.
+
+
+Example:
+
+codec: tlv320aic32x4@18 {
+       compatible = "ti,tlv320aic32x4";
+       reg = <0x18>;
+       clocks = <&clks 201>;
+       clock-names = "mclk";
+};
index 9d8ea14db49011cd95bb86d102461ece9abeca2d..5e6040c2c2e9c34019dceb93e439504e4e5af9ad 100644 (file)
@@ -6,7 +6,6 @@ Required properties:
 
 - compatible - "string" - One of:
     "ti,tlv320aic3x" - Generic TLV320AIC3x device
-    "ti,tlv320aic32x4" - TLV320AIC32x4
     "ti,tlv320aic33" - TLV320AIC33
     "ti,tlv320aic3007" - TLV320AIC3007
     "ti,tlv320aic3106" - TLV320AIC3106
diff --git a/Documentation/devicetree/bindings/sound/widgets.txt b/Documentation/devicetree/bindings/sound/widgets.txt
new file mode 100644 (file)
index 0000000..b6de5ba
--- /dev/null
@@ -0,0 +1,20 @@
+Widgets:
+
+This mainly specifies audio off-codec DAPM widgets.
+
+Each entry is a pair of strings in DT:
+
+       "template-wname", "user-supplied-wname"
+
+The "template-wname" being the template widget name and currently includes:
+"Microphone", "Line", "Headphone" and "Speaker".
+
+The "user-supplied-wname" being the user specified widget name.
+
+For instance:
+       simple-audio-widgets =
+               "Microphone", "Microphone Jack",
+               "Line", "Line In Jack",
+               "Line", "Line Out Jack",
+               "Headphone", "Headphone Jack",
+               "Speaker", "Speaker External";
index a590ca51be75ead37bcf1b16fba6047625a945b7..8f081c96a4fa96845edba3d060583ddc974bb239 100644 (file)
@@ -3,24 +3,24 @@
 Required properties:
 - #address-cells: see spi-bus.txt
 - #size-cells: see spi-bus.txt
-- compatible: should be "efm32,spi"
+- compatible: should be "energymicro,efm32-spi"
 - reg: Offset and length of the register set for the controller
 - interrupts: pair specifying rx and tx irq
 - clocks: phandle to the spi clock
 - cs-gpios: see spi-bus.txt
-- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
+- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
 
 Example:
 
 spi1: spi@0x4000c400 { /* USART1 */
        #address-cells = <1>;
        #size-cells = <0>;
-       compatible = "efm32,spi";
+       compatible = "energymicro,efm32-spi";
        reg = <0x4000c400 0x400>;
        interrupts = <15 16>;
        clocks = <&cmu 20>;
        cs-gpios = <&gpio 51 1>; // D3
-       location = <1>;
+       efm32,location = <1>;
        status = "ok";
 
        ks8851@0 {
diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
new file mode 100644 (file)
index 0000000..b82a268
--- /dev/null
@@ -0,0 +1,85 @@
+Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI)
+
+The QUP core is an AHB slave that provides a common data path (an output FIFO
+and an input FIFO) for serial peripheral interface (SPI) mini-core.
+
+SPI in master mode supports up to 50MHz, up to four chip selects, programmable
+data path from 4 bits to 32 bits and numerous protocol variants.
+
+Required properties:
+- compatible:     Should contain "qcom,spi-qup-v2.1.1" or "qcom,spi-qup-v2.2.1"
+- reg:            Should contain base register location and length
+- interrupts:     Interrupt number used by this controller
+
+- clocks:         Should contain the core clock and the AHB clock.
+- clock-names:    Should be "core" for the core clock and "iface" for the
+                  AHB clock.
+
+- #address-cells: Number of cells required to define a chip select
+                  address on the SPI bus. Should be set to 1.
+- #size-cells:    Should be zero.
+
+Optional properties:
+- spi-max-frequency: Specifies maximum SPI clock frequency,
+                     Units - Hz. Definition as per
+                     Documentation/devicetree/bindings/spi/spi-bus.txt
+
+SPI slave nodes must be children of the SPI master node and can contain
+properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+       spi_8: spi@f9964000 { /* BLSP2 QUP2 */
+
+               compatible = "qcom,spi-qup-v2";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0xf9964000 0x1000>;
+               interrupts = <0 102 0>;
+               spi-max-frequency = <19200000>;
+
+               clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+               clock-names = "core", "iface";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&spi8_default>;
+
+               device@0 {
+                       compatible = "arm,pl022-dummy";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0>; /* Chip select 0 */
+                       spi-max-frequency = <19200000>;
+                       spi-cpol;
+               };
+
+               device@1 {
+                       compatible = "arm,pl022-dummy";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <1>; /* Chip select 1 */
+                       spi-max-frequency = <9600000>;
+                       spi-cpha;
+               };
+
+               device@2 {
+                       compatible = "arm,pl022-dummy";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <2>; /* Chip select 2 */
+                       spi-max-frequency = <19200000>;
+                       spi-cpol;
+                       spi-cpha;
+               };
+
+               device@3 {
+                       compatible = "arm,pl022-dummy";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <3>; /* Chip select 3 */
+                       spi-max-frequency = <19200000>;
+                       spi-cpol;
+                       spi-cpha;
+                       spi-cs-high;
+               };
+       };
index 30b57b1c8a13d86633d06f465e1e00d67fcdfabc..319bad4af875862c9d1e862403500206817ce743 100644 (file)
@@ -1,7 +1,29 @@
 Renesas HSPI.
 
 Required properties:
-- compatible :         "renesas,hspi"
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by HSPI
+- compatible       : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
+                    Examples with soctypes are:
+                      - "renesas,hspi-r8a7778" (R-Car M1)
+                      - "renesas,hspi-r8a7779" (R-Car H1)
+- reg              : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+                    services interrupts for this device
+- interrupts       : Interrupt specifier
+- #address-cells   : Must be <1>
+- #size-cells      : Must be <0>
+
+Pinctrl properties might be needed, too.  See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+       hspi0: spi@fffc7000 {
+               compatible = "renesas,hspi-r8a7778", "renesas,hspi";
+               reg = <0xfffc7000 0x18>;
+               interrupt-parent = <&gic>;
+               interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
 
index e6222106ca36db62f36bc54d8e1385407bd156e9..f24baf3b6cc16fd9f6a26505ce2ceaeb930ccc6a 100644 (file)
@@ -1,12 +1,40 @@
 Renesas MSIOF spi controller
 
 Required properties:
-- compatible :         "renesas,sh-msiof" for SuperH or
-               "renesas,sh-mobile-msiof" for SH Mobile series
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by MSIOF
+- compatible           : "renesas,msiof-<soctype>" for SoCs,
+                        "renesas,sh-msiof" for SuperH, or
+                        "renesas,sh-mobile-msiof" for SH Mobile series.
+                        Examples with soctypes are:
+                        "renesas,msiof-r8a7790" (R-Car H2)
+                        "renesas,msiof-r8a7791" (R-Car M2)
+- reg                  : Offset and length of the register set for the device
+- interrupt-parent     : The phandle for the interrupt controller that
+                        services interrupts for this device
+- interrupts           : Interrupt specifier
+- #address-cells       : Must be <1>
+- #size-cells          : Must be <0>
 
 Optional properties:
-- num-cs               : total number of chip-selects
-- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
-- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+- clocks               : Must contain a reference to the functional clock.
+- num-cs               : Total number of chip-selects (default is 1)
+
+Optional properties, deprecated for soctype-specific bindings:
+- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
+                        (default is 64)
+- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+                        (default is 64, or 256 on R-Car H2 and M2)
+
+Pinctrl properties might be needed, too.  See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+       msiof0: spi@e6e20000 {
+               compatible = "renesas,msiof-r8a7791";
+               reg = <0 0xe6e20000 0 0x0064>;
+               interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
index a1fb3035a42bebf683e25bf4012a539fe8092a50..5376de40f10b562ba218651433be71508e4c560b 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
 - pinctrl-names: must contain a "default" entry.
 - spi-num-chipselects : the number of the chipselect signals.
 - bus-num : the slave chip chipselect signal number.
+- big-endian : if DSPI modudle is big endian, the bool will be set in node.
 Example:
 
 dspi0@4002c000 {
@@ -24,6 +25,7 @@ dspi0@4002c000 {
        bus-num = <0>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_dspi0_1>;
+       big-endian;
        status = "okay";
 
        sflash: at26df081a@0 {
diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt
new file mode 100644 (file)
index 0000000..d57d82a
--- /dev/null
@@ -0,0 +1,61 @@
+Device tree configuration for Renesas RSPI/QSPI driver
+
+Required properties:
+- compatible       : For Renesas Serial Peripheral Interface on legacy SH:
+                    "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
+                    For Renesas Serial Peripheral Interface on RZ/A1H:
+                    "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
+                    For Quad Serial Peripheral Interface on R-Car Gen2:
+                    "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
+                    Examples with soctypes are:
+                       - "renesas,rspi-sh7757" (SH)
+                       - "renesas,rspi-r7s72100" (RZ/A1H)
+                       - "renesas,qspi-r8a7790" (R-Car H2)
+                       - "renesas,qspi-r8a7791" (R-Car M2)
+- reg              : Address start and address range size of the device
+- interrupts       : A list of interrupt-specifiers, one for each entry in
+                    interrupt-names.
+                    If interrupt-names is not present, an interrupt specifier
+                    for a single muxed interrupt.
+- interrupt-names  : A list of interrupt names. Should contain (if present):
+                      - "error" for SPEI,
+                      - "rx" for SPRI,
+                      - "tx" to SPTI,
+                      - "mux" for a single muxed interrupt.
+- interrupt-parent : The phandle for the interrupt controller that
+                    services interrupts for this device.
+- num-cs          : Number of chip selects. Some RSPI cores have more than 1.
+- #address-cells   : Must be <1>
+- #size-cells      : Must be <0>
+
+Optional properties:
+- clocks           : Must contain a reference to the functional clock.
+
+Pinctrl properties might be needed, too.  See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Examples:
+
+       spi0: spi@e800c800 {
+               compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+               reg = <0xe800c800 0x24>;
+               interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 239 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 240 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "error", "rx", "tx";
+               interrupt-parent = <&gic>;
+               num-cs = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spi: spi@e6b10000 {
+               compatible = "renesas,qspi-r8a7791", "renesas,qspi";
+               reg = <0 0xe6b10000 0 0x2c>;
+               interrupt-parent = <&gic>;
+               interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
+               num-cs = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
new file mode 100644 (file)
index 0000000..de827f5
--- /dev/null
@@ -0,0 +1,24 @@
+Allwinner A10 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun4-a10-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+          needed:
+  - "ahb": the gated AHB parent clock
+  - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+
+Example:
+
+spi1: spi@01c06000 {
+       compatible = "allwinner,sun4i-a10-spi";
+       reg = <0x01c06000 0x1000>;
+       interrupts = <11>;
+       clocks = <&ahb_gates 21>, <&spi1_clk>;
+       clock-names = "ahb", "mod";
+       status = "disabled";
+       #address-cells = <1>;
+       #size-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
new file mode 100644 (file)
index 0000000..21de73d
--- /dev/null
@@ -0,0 +1,24 @@
+Allwinner A31 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun6i-a31-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+          needed:
+  - "ahb": the gated AHB parent clock
+  - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+- resets: phandle to the reset controller asserting this device in
+          reset
+
+Example:
+
+spi1: spi@01c69000 {
+       compatible = "allwinner,sun6i-a31-spi";
+       reg = <0x01c69000 0x1000>;
+       interrupts = <0 66 4>;
+       clocks = <&ahb1_gates 21>, <&spi1_clk>;
+       clock-names = "ahb", "mod";
+       resets = <&ahb1_rst 21>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
new file mode 100644 (file)
index 0000000..b6ebe2b
--- /dev/null
@@ -0,0 +1,9 @@
+Cadence Xtensa XTFPGA platform SPI controller.
+
+This simple SPI master controller is built into xtfpga bitstreams and is used
+to control daughterboard audio codec.
+
+Required properties:
+- compatible: should be "cdns,xtfpga-spi".
+- reg: physical base address of the controller and length of memory mapped
+  region.
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
new file mode 100644 (file)
index 0000000..715d099
--- /dev/null
@@ -0,0 +1,61 @@
+Qualcomm SPMI Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on the Snapdragon 800 Series.  It is an SPMI
+controller with wrapping arbitration logic to allow for multiple on-chip
+devices to control a single SPMI master.
+
+The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+to slave devices.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+generic interrupt controller binding documentation.
+
+Required properties:
+- compatible : should be "qcom,spmi-pmic-arb".
+- reg-names  : must contain:
+     "core" - core registers
+     "intr" - interrupt controller registers
+     "cnfg" - configuration registers
+- reg : address + size pairs describing the PMIC arb register sets; order must
+        correspond with the order of entries in reg-names
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+- qcom,ee : indicates the active Execution Environment identifier (0-5)
+- qcom,channel : which of the PMIC Arb provided channels to use for accesses (0-5)
+- interrupts : interrupt list for the PMIC Arb controller, must contain a
+               single interrupt entry for the peripheral interrupt
+- interrupt-names : corresponding interrupt names for the interrupts
+                    listed in the 'interrupts' property, must contain:
+     "periph_irq" - summary interrupt for PMIC peripherals
+- interrupt-controller : boolean indicator that the PMIC arbiter is an interrupt controller
+- #interrupt-cells :  must be set to 4. Interrupts are specified as a 4-tuple:
+    cell 1: slave ID for the requested interrupt (0-15)
+    cell 2: peripheral ID for requested interrupt (0-255)
+    cell 3: the requested peripheral interrupt (0-7)
+    cell 4: interrupt flags indicating level-sense information, as defined in
+            dt-bindings/interrupt-controller/irq.h
+
+Example:
+
+       spmi {
+               compatible = "qcom,spmi-pmic-arb";
+               reg-names = "core", "intr", "cnfg";
+               reg = <0xfc4cf000 0x1000>,
+                     <0xfc4cb000 0x1000>,
+                     <0xfc4ca000 0x1000>;
+
+               interrupt-names = "periph_irq";
+               interrupts = <0 190 0>;
+
+               qcom,ee = <0>;
+               qcom,channel = <0>;
+
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               interrupt-controller;
+               #interrupt-cells = <4>;
+       };
diff --git a/Documentation/devicetree/bindings/spmi/spmi.txt b/Documentation/devicetree/bindings/spmi/spmi.txt
new file mode 100644 (file)
index 0000000..462a42f
--- /dev/null
@@ -0,0 +1,41 @@
+System Power Management Interface (SPMI) Controller
+
+This document defines a generic set of bindings for use by SPMI controllers.  A
+controller is modelled in device tree as a node with zero or more child nodes,
+each representing a unique slave on the bus.
+
+Required properties:
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+
+Child nodes:
+
+An SPMI controller node can contain zero or more child nodes representing slave
+devices on the bus.  Child 'reg' properties are specified as an address, type
+pair.  The address must be in the range 0-15 (4 bits).  The type must be one of
+SPMI_USID (0) or SPMI_GSID (1) for Unique Slave ID or Group Slave ID respectively.
+These are the identifiers "statically assigned by the system integrator", as
+per the SPMI spec.
+
+Each child node must have one and only one 'reg' entry of type SPMI_USID.
+
+#include <dt-bindings/spmi/spmi.h>
+
+       spmi@.. {
+               compatible = "...";
+               reg = <...>;
+
+               #address-cells = <2>;
+               #size-cells <0>;
+
+               child@0 {
+                       compatible = "...";
+                       reg = <0 SPMI_USID>;
+               };
+
+               child@7 {
+                       compatible = "...";
+                       reg = <7 SPMI_USID
+                              3 SPMI_GSID>;
+               };
+       };
index 48aeb7884ed3733ae46e757cf9ee5da4b1063a51..5c2e23574ca025aea14151eb4243052c4cf14901 100644 (file)
@@ -2,7 +2,7 @@ Allwinner A1X SoCs Timer Controller
 
 Required properties:
 
-- compatible : should be "allwinner,sun4i-timer"
+- compatible : should be "allwinner,sun4i-a10-timer"
 - reg : Specifies base physical address and size of the registers.
 - interrupts : The interrupt of the first timer
 - clocks: phandle to the source clock (usually a 24 MHz fixed clock)
@@ -10,7 +10,7 @@ Required properties:
 Example:
 
 timer {
-       compatible = "allwinner,sun4i-timer";
+       compatible = "allwinner,sun4i-a10-timer";
        reg = <0x01c20c00 0x400>;
        interrupts = <22>;
        clocks = <&osc>;
diff --git a/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt b/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt
new file mode 100644 (file)
index 0000000..5fbe361
--- /dev/null
@@ -0,0 +1,29 @@
+* Device tree bindings for Texas instruments Keystone timer
+
+This document provides bindings for the 64-bit timer in the KeyStone
+architecture devices. The timer can be configured as a general-purpose 64-bit
+timer, dual general-purpose 32-bit timers. When configured as dual 32-bit
+timers, each half can operate in conjunction (chain mode) or independently
+(unchained mode) of each other.
+
+It is global timer is a free running up-counter and can generate interrupt
+when the counter reaches preset counter values.
+
+Documentation:
+http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
+
+Required properties:
+
+- compatible : should be "ti,keystone-timer".
+- reg : specifies base physical address and count of the registers.
+- interrupts : interrupt generated by the timer.
+- clocks : the clock feeding the timer clock.
+
+Example:
+
+timer@22f0000 {
+       compatible = "ti,keystone-timer";
+       reg = <0x022f0000 0x80>;
+       interrupts = <GIC_SPI 110 IRQ_TYPE_EDGE_RISING>;
+       clocks = <&clktimer15>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
new file mode 100644 (file)
index 0000000..6d63782
--- /dev/null
@@ -0,0 +1,23 @@
+Xilinx AXI/PLB soft-core watchdog Device Tree Bindings
+---------------------------------------------------------
+
+Required properties:
+- compatible           : Should be "xlnx,xps-timebase-wdt-1.00.a" or
+                         "xlnx,xps-timebase-wdt-1.01.a".
+- reg                  : Physical base address and size
+
+Optional properties:
+- clock-frequency      : Frequency of clock in Hz
+- xlnx,wdt-enable-once : 0 - Watchdog can be restarted
+                         1 - Watchdog can be enabled just once
+- xlnx,wdt-interval    : Watchdog timeout interval in 2^<val> clock cycles,
+                         <val> is integer from 8 to 31.
+
+Example:
+axi-timebase-wdt@40100000 {
+       clock-frequency = <50000000>;
+       compatible = "xlnx,xps-timebase-wdt-1.00.a";
+       reg = <0x40100000 0x10000>;
+       xlnx,wdt-enable-once = <0x0>;
+       xlnx,wdt-interval = <0x1b>;
+} ;
index e39cb266c8f4cb3a62c1cf8575293f2c39e8a791..b8f75c51453a6463573835187a0c49d9a9fb8d11 100644 (file)
@@ -2,13 +2,13 @@ Allwinner SoCs Watchdog timer
 
 Required properties:
 
-- compatible : should be "allwinner,<soc-family>-wdt", the currently supported
-  SoC families being sun4i and sun6i
+- compatible : should be either "allwinner,sun4i-a10-wdt" or
+               "allwinner,sun6i-a31-wdt"
 - reg : Specifies base physical address and size of the registers.
 
 Example:
 
 wdt: watchdog@01c20c90 {
-       compatible = "allwinner,sun4i-wdt";
+       compatible = "allwinner,sun4i-a10-wdt";
        reg = <0x01c20c90 0x10>;
 };
index 44a3bc678bf0cb148c4f99dcc3f5f021bdf13fe4..e0a9712156aafa9929d5868a1aee83d55f3a11b6 100644 (file)
@@ -9,7 +9,12 @@ Overwriting the EEPROM is not something you should do daily, and it is
 expected to only happen during manufacturing. For this reason, the
 module makes it unlikely for the random user to change a working EEPROM.
 
-The module takes the following measures:
+However, since the EEPROM may include application-specific information
+other than the identification, later versions of this packages added
+write-support through sysfs. See *note Accessing the EEPROM::.
+
+To avoid damaging the EEPROM content, the module takes the following
+measures:
 
    * It accepts a `file=' argument (within /lib/firmware) and if no
      such argument is received, it doesn't write anything to EEPROM
@@ -70,56 +75,24 @@ first time.
         [  132.899872]  fake-fmc: Product name: FmcDelay1ns4cha
 
 
-Writing to the EEPROM
+Accessing the EEPROM
 =====================
 
-Once you have created a binary file for your EEPROM, you can write it
-to the storage medium using the fmc-write-eeprom (See *note
-fmc-write-eeprom::, while relying on a carrier driver.  The procedure
-here shown here uses the SPEC driver
-(`http://www.ohwr.org/projects/spec-sw').
-
-The example assumes no driver is already loaded (actually, I unloaded
-them by hand as everything loads automatically at boot time after you
-installed the modules), and shows kernel messages together with
-commands. Here the prompt is spusa.root# and two SPEC cards are plugged
-in the system.
-
-     spusa.root# insmod fmc.ko
-     spusa.root# insmod spec.ko
-     [13972.382818] spec 0000:02:00.0:  probe for device 0002:0000
-     [13972.392773] spec 0000:02:00.0: got file "fmc/spec-init.bin", 1484404 (0x16a674) bytes
-     [13972.591388] spec 0000:02:00.0: FPGA programming successful
-     [13972.883011] spec 0000:02:00.0: EEPROM has no FRU information
-     [13972.888719] spec 0000:02:00.0: No device_id filled, using index
-     [13972.894676] spec 0000:02:00.0: No mezzanine_name found
-     [13972.899863] /home/rubini/wip/spec-sw/kernel/spec-gpio.c - spec_gpio_init
-     [13972.906578] spec 0000:04:00.0:  probe for device 0004:0000
-     [13972.916509] spec 0000:04:00.0: got file "fmc/spec-init.bin", 1484404 (0x16a674) bytes
-     [13973.115096] spec 0000:04:00.0: FPGA programming successful
-     [13973.401798] spec 0000:04:00.0: EEPROM has no FRU information
-     [13973.407474] spec 0000:04:00.0: No device_id filled, using index
-     [13973.413417] spec 0000:04:00.0: No mezzanine_name found
-     [13973.418600] /home/rubini/wip/spec-sw/kernel/spec-gpio.c - spec_gpio_init
-     spusa.root# ls /sys/bus/fmc/devices
-     fmc-0000  fmc-0001
-     spusa.root# insmod fmc-write-eeprom.ko busid=0x0200 file=fdelay-eeprom.bin
-     [14103.966259] spec 0000:02:00.0: Matching an generic driver (no ID)
-     [14103.975519] spec 0000:02:00.0: programming 6155 bytes
-     [14126.373762] spec 0000:02:00.0: write_eeprom: success
-     [14126.378770] spec 0000:04:00.0: Matching an generic driver (no ID)
-     [14126.384903] spec 0000:04:00.0: fmc_write_eeprom: no filename given: not programming
-     [14126.392600] fmc_write_eeprom: probe of fmc-0001 failed with error -2
-
-Reading back the EEPROM
-=======================
-
-In order to read back the binary content of the EEPROM of your
-mezzanine device, the bus creates a read-only sysfs file called eeprom
-for each mezzanine it knows about:
-
-   spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
-   -r--r--r-- 1 root root 8192 Apr  9 16:53 FmcDelay1ns4cha-f001/eeprom
-   -r--r--r-- 1 root root 8192 Apr  9 17:19 fake-design-for-testing-f002/eeprom
-   -r--r--r-- 1 root root 8192 Apr  9 17:19 fake-design-for-testing-f003/eeprom
-   -r--r--r-- 1 root root 8192 Apr  9 17:19 fmc-f004/eeprom
+The bus creates a sysfs binary file called eeprom for each mezzanine it
+knows about:
+
+        spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
+        -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcAdc100m14b4cha-0800/eeprom
+        -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDelay1ns4cha-0200/eeprom
+        -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDio5cha-0400/eeprom
+
+Everybody can read the files and the superuser can also modify it, but
+the operation may on the carrier driver, if the carrier is unable to
+access the I2C bus.  For example, the spec driver can access the bus
+only with its golden gateware: after a mezzanine driver reprogrammed
+the FPGA with a custom circuit, the carrier is unable to access the
+EEPROM and returns ENOTSUPP.
+
+An alternative way to write the EEPROM is the mezzanine driver
+fmc-write-eeprom (See *note fmc-write-eeprom::), but the procedure is
+more complex.
diff --git a/Documentation/hwmon/adc128d818 b/Documentation/hwmon/adc128d818
new file mode 100644 (file)
index 0000000..39c9500
--- /dev/null
@@ -0,0 +1,47 @@
+Kernel driver adc128d818
+========================
+
+Supported chips:
+  * Texas Instruments ADC818D818
+    Prefix: 'adc818d818'
+    Addresses scanned: I2C 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f
+    Datasheet: Publicly available at the TI website
+               http://www.ti.com/
+
+Author: Guenter Roeck
+
+Description
+-----------
+
+This driver implements support for the Texas Instruments ADC128D818.
+It is described as 'ADC System Monitor with Temperature Sensor'.
+
+The ADC128D818 implements one temperature sensor and seven voltage sensors.
+
+Temperatures are measured in degrees Celsius. There is one set of limits.
+When the HOT Temperature Limit is crossed, this will cause an alarm that will
+be reasserted until the temperature drops below the HOT Hysteresis.
+Measurements are guaranteed between -55 and +125 degrees. The temperature
+measurement has a resolution of 0.5 degrees; the limits have a resolution
+of 1 degree.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 2.55 volts, with a resolution
+of 0.625 mV.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared by the time the alarm is read. The driver
+caches the alarm status for each sensor until it is at least reported
+once, to ensure that alarms are reported to user space.
+
+The ADC128D818 only updates its values approximately once per second;
+reading it more often will do no harm, but will return 'old' values.
+
+In addition to the scanned address list, the chip can also be configured for
+addresses 0x35 to 0x37. Those addresses are not scanned. You have to instantiate
+the driver explicitly if the chip is configured for any of those addresses in
+your system.
index cbd8aeab7124e07f48dcad74be6972996b417e32..77eaf2812d25d71009e545de8716acfd2bc93542 100644 (file)
@@ -24,8 +24,12 @@ is given within a range of -127 to +127.875 degrees. Remote temperatures are
 given within a range of -127 to +255 degrees. Resolution depends on
 temperature input and range.
 
-Each sensor has its own critical limit, but the hysteresis is common to all
-two channels.
+Each sensor has its own critical limit. Additionally, there is a relative
+hysteresis value common to both critical limits. To make life easier to
+user-space applications, two absolute values are exported, one for each
+channel, but these values are of course linked. Only the local hysteresis
+can be set from user-space, and the same delta applies to the remote
+hysteresis.
 
 The lm95245 driver can change its update interval to a fixed set of values.
 It will round up to the next selectable interval. See the datasheet for exact
diff --git a/Documentation/hwmon/ltc2945 b/Documentation/hwmon/ltc2945
new file mode 100644 (file)
index 0000000..f8d0f7f
--- /dev/null
@@ -0,0 +1,84 @@
+Kernel driver ltc2945
+=====================
+
+Supported chips:
+  * Linear Technology LTC2945
+    Prefix: 'ltc2945'
+    Addresses scanned: -
+    Datasheet:
+        http://cds.linear.com/docs/en/datasheet/2945fa.pdf
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The LTC2945  is a rail-to-rail system monitor that measures current, voltage,
+and power consumption.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC2945 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC2945 at address 0x10
+on I2C bus #1:
+$ modprobe ltc2945
+$ echo ltc2945 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+in1_input              VIN voltage (mV). Voltage is measured either at
+                       SENSE+ or VDD pin depending on chip configuration.
+in1_min                        Undervoltage threshold
+in1_max                        Overvoltage threshold
+in1_lowest             Lowest measured voltage
+in1_highest            Highest measured voltage
+in1_reset_history      Write 1 to reset in1 history
+in1_min_alarm          Undervoltage alarm
+in1_max_alarm          Overvoltage alarm
+
+in2_input              ADIN voltage (mV)
+in2_min                        Undervoltage threshold
+in2_max                        Overvoltage threshold
+in2_lowest             Lowest measured voltage
+in2_highest            Highest measured voltage
+in2_reset_history      Write 1 to reset in2 history
+in2_min_alarm          Undervoltage alarm
+in2_max_alarm          Overvoltage alarm
+
+curr1_input            SENSE current (mA)
+curr1_min              Undercurrent threshold
+curr1_max              Overcurrent threshold
+curr1_lowest           Lowest measured current
+curr1_highest          Highest measured current
+curr1_reset_history    Write 1 to reset curr1 history
+curr1_min_alarm                Undercurrent alarm
+curr1_max_alarm                Overcurrent alarm
+
+power1_input           Power (in uW). Power is calculated based on SENSE+/VDD
+                       voltage or ADIN voltage depending on chip configuration.
+power1_min             Low lower threshold
+power1_max             High power threshold
+power1_input_lowest    Historical minimum power use
+power1_input_highest   Historical maximum power use
+power1_reset_history   Write 1 to reset power1 history
+power1_min_alarm       Low power alarm
+power1_max_alarm       High power alarm
index a0546fc42273bb7fcdad6389c7afcdded4171ec2..686c078bb0e08192b6cba325c9f33638c1c0667c 100644 (file)
@@ -23,6 +23,10 @@ Supported chips:
     Prefix: 'ltc3883'
     Addresses scanned: -
     Datasheet: http://www.linear.com/product/ltc3883
+  * Linear Technology LTM4676
+    Prefix: 'ltm4676'
+    Addresses scanned: -
+    Datasheet: http://www.linear.com/product/ltm4676
 
 Author: Guenter Roeck <linux@roeck-us.net>
 
@@ -33,7 +37,8 @@ Description
 LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
 monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880 is a dual
 output poly-phase step-down DC/DC controller. LTC3883 is a single phase
-step-down DC/DC controller.
+step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule
+regulator.
 
 
 Usage Notes
@@ -75,7 +80,7 @@ in[N]_label           "vout[1-8]".
                        LTC2974: N=2-5
                        LTC2977: N=2-9
                        LTC2978: N=2-9
-                       LTC3880: N=2-3
+                       LTC3880, LTM4676: N=2-3
                        LTC3883: N=2
 in[N]_input            Measured output voltage.
 in[N]_min              Minimum output voltage.
@@ -95,7 +100,7 @@ temp[N]_input                Measured temperature.
                        and temp5 reports the chip temperature.
                        On LTC2977 and LTC2978, only one temperature measurement
                        is supported and reports the chip temperature.
-                       On LTC3880, temp1 and temp2 report external
+                       On LTC3880 and LTM4676, temp1 and temp2 report external
                        temperatures, and temp3 reports the chip temperature.
                        On LTC3883, temp1 reports an external temperature,
                        and temp2 reports the chip temperature.
@@ -123,11 +128,11 @@ power[N]_label            "pout[1-4]".
                        LTC2974: N=1-4
                        LTC2977: Not supported
                        LTC2978: Not supported
-                       LTC3880: N=1-2
+                       LTC3880, LTM4676: N=1-2
                        LTC3883: N=2
 power[N]_input         Measured output power.
 
-curr1_label            "iin". LTC3880 and LTC3883 only.
+curr1_label            "iin". LTC3880, LTC3883, and LTM4676 only.
 curr1_input            Measured input current.
 curr1_max              Maximum input current.
 curr1_max_alarm                Input current high alarm.
@@ -138,7 +143,7 @@ curr[N]_label               "iout[1-4]".
                        LTC2974: N=1-4
                        LTC2977: not supported
                        LTC2978: not supported
-                       LTC3880: N=2-3
+                       LTC3880, LTM4676: N=2-3
                        LTC3883: N=2
 curr[N]_input          Measured output current.
 curr[N]_max            Maximum output current.
diff --git a/Documentation/hwmon/ltc4260 b/Documentation/hwmon/ltc4260
new file mode 100644 (file)
index 0000000..c4ff4ad
--- /dev/null
@@ -0,0 +1,56 @@
+Kernel driver ltc4260
+=====================
+
+Supported chips:
+  * Linear Technology LTC4260
+    Prefix: 'ltc4260'
+    Addresses scanned: -
+    Datasheet:
+        http://cds.linear.com/docs/en/datasheet/4260fc.pdf
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The LTC4260 Hot Swap controller allows a board to be safely inserted
+and removed from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4260 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4260 at address 0x10
+on I2C bus #1:
+$ modprobe ltc4260
+$ echo ltc4260 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+in1_input              SOURCE voltage (mV)
+in1_min_alarm          Undervoltage alarm
+in1_max_alarm          Overvoltage alarm
+
+in2_input              ADIN voltage (mV)
+in2_alarm              Power bad alarm
+
+curr1_input            SENSE current (mA)
+curr1_alarm            SENSE overcurrent alarm
index 7116fda7077ffce993b0d2456869934ab8c3ee09..121d5fcbd94aa200d219ef36d6445169fd24ebd7 100644 (file)
@@ -231,6 +231,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        acpi_no_auto_ssdt       [HW,ACPI] Disable automatic loading of SSDT
 
+       acpica_no_return_repair [HW, ACPI]
+                       Disable AML predefined validation mechanism
+                       This mechanism can repair the evaluation result to make
+                       the return objects more ACPI specification compliant.
+                       This option is useful for developers to identify the
+                       root cause of an AML interpreter issue when the issue
+                       has something to do with the repair mechanism.
+
        acpi_os_name=   [HW,ACPI] Tell ACPI BIOS the name of the OS
                        Format: To spoof as Windows 98: ="Microsoft Windows"
 
@@ -1011,6 +1019,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        parameter will force ia64_sal_cache_flush to call
                        ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
 
+       forcepae [X86-32]
+                       Forcefully enable Physical Address Extension (PAE).
+                       Many Pentium M systems disable PAE but may have a
+                       functionally usable PAE implementation.
+                       Warning: use of this parameter will taint the kernel
+                       and may cause unknown problems.
+
        ftrace=[tracer]
                        [FTRACE] will set and start the specified tracer
                        as early as possible in order to facilitate early
@@ -2053,8 +2068,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        IOAPICs that may be present in the system.
 
        nokaslr         [X86]
-                       Disable kernel base offset ASLR (Address Space
-                       Layout Randomization) if built into the kernel.
+                       Disable kernel and module base offset ASLR (Address
+                       Space Layout Randomization) if built into the kernel.
 
        noautogroup     Disable scheduler automatic task group creation.
 
index 827104fb9364cf60df2359e45c3336f61d4568c5..f3cd299fcc41203f9fe73ad16cd70aa77a421ef3 100644 (file)
@@ -162,7 +162,18 @@ 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
+2.     A given workqueue can be made visible in the sysfs filesystem
+       by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
+       Such a workqueue can be confined to a given subset of the
+       CPUs using the /sys/devices/virtual/workqueue/*/cpumask sysfs
+       files.  The set of WQ_SYSFS workqueues can be displayed using
+       "ls sys/devices/virtual/workqueue".  That said, the workqueues
+       maintainer would like to caution people against indiscriminately
+       sprinkling WQ_SYSFS across all the workqueues.  The reason for
+       caution is that it is easy to add WQ_SYSFS, but because sysfs is
+       part of the formal user/kernel API, it can be nearly impossible
+       to remove it, even if its addition was a mistake.
+3.     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
index 102dc19c411980d0aa17beeb12f0bcdd38447e29..11c1d2049662cc7cff72193e87707a46ad77eca0 100644 (file)
@@ -608,26 +608,30 @@ as follows:
        b = p;  /* BUG: Compiler can reorder!!! */
        do_something();
 
-The solution is again ACCESS_ONCE(), which preserves the ordering between
-the load from variable 'a' and the store to variable 'b':
+The solution is again ACCESS_ONCE() and barrier(), which preserves the
+ordering between the load from variable 'a' and the store to variable 'b':
 
        q = ACCESS_ONCE(a);
        if (q) {
+               barrier();
                ACCESS_ONCE(b) = p;
                do_something();
        } else {
+               barrier();
                ACCESS_ONCE(b) = p;
                do_something_else();
        }
 
-You could also use barrier() to prevent the compiler from moving
-the stores to variable 'b', but barrier() would not prevent the
-compiler from proving to itself that a==1 always, so ACCESS_ONCE()
-is also needed.
+The initial ACCESS_ONCE() is required to prevent the compiler from
+proving the value of 'a', and the pair of barrier() invocations are
+required to prevent the compiler from pulling the two identical stores
+to 'b' out from the legs of the "if" statement.
 
 It is important to note that control dependencies absolutely require a
 a conditional.  For example, the following "optimized" version of
-the above example breaks ordering:
+the above example breaks ordering, which is why the barrier() invocations
+are absolutely required if you have identical stores in both legs of
+the "if" statement:
 
        q = ACCESS_ONCE(a);
        ACCESS_ONCE(b) = p;  /* BUG: No ordering vs. load from a!!! */
@@ -643,9 +647,11 @@ It is of course legal for the prior load to be part of the conditional,
 for example, as follows:
 
        if (ACCESS_ONCE(a) > 0) {
+               barrier();
                ACCESS_ONCE(b) = q / 2;
                do_something();
        } else {
+               barrier();
                ACCESS_ONCE(b) = q / 3;
                do_something_else();
        }
@@ -659,9 +665,11 @@ the needed conditional.  For example:
 
        q = ACCESS_ONCE(a);
        if (q % MAX) {
+               barrier();
                ACCESS_ONCE(b) = p;
                do_something();
        } else {
+               barrier();
                ACCESS_ONCE(b) = p;
                do_something_else();
        }
@@ -723,8 +731,13 @@ In summary:
       use smb_rmb(), smp_wmb(), or, in the case of prior stores and
       later loads, smp_mb().
 
+  (*) If both legs of the "if" statement begin with identical stores
+      to the same variable, a barrier() statement is required at the
+      beginning of each leg of the "if" statement.
+
   (*) Control dependencies require at least one run-time conditional
-      between the prior load and the subsequent store.  If the compiler
+      between the prior load and the subsequent store, and this
+      conditional must involve the prior load.  If the compiler
       is able to optimize the conditional away, it will have also
       optimized away the ordering.  Careful use of ACCESS_ONCE() can
       help to preserve the needed conditional.
@@ -1249,6 +1262,23 @@ The ACCESS_ONCE() function can prevent any number of optimizations that,
 while perfectly safe in single-threaded code, can be fatal in concurrent
 code.  Here are some examples of these sorts of optimizations:
 
+ (*) The compiler is within its rights to reorder loads and stores
+     to the same variable, and in some cases, the CPU is within its
+     rights to reorder loads to the same variable.  This means that
+     the following code:
+
+       a[0] = x;
+       a[1] = x;
+
+     Might result in an older value of x stored in a[1] than in a[0].
+     Prevent both the compiler and the CPU from doing this as follows:
+
+       a[0] = ACCESS_ONCE(x);
+       a[1] = ACCESS_ONCE(x);
+
+     In short, ACCESS_ONCE() provides cache coherence for accesses from
+     multiple CPUs to a single variable.
+
  (*) The compiler is within its rights to merge successive loads from
      the same variable.  Such merging can cause the compiler to "optimize"
      the following code:
@@ -1644,12 +1674,12 @@ for each construct.  These operations all imply certain barriers:
      Memory operations issued after the ACQUIRE will be completed after the
      ACQUIRE operation has completed.
 
-     Memory operations issued before the ACQUIRE may be completed after the
-     ACQUIRE operation has completed.  An smp_mb__before_spinlock(), combined
-     with a following ACQUIRE, orders prior loads against subsequent stores and
-     stores and prior stores against subsequent stores.  Note that this is
-     weaker than smp_mb()!  The smp_mb__before_spinlock() primitive is free on
-     many architectures.
+     Memory operations issued before the ACQUIRE may be completed after
+     the ACQUIRE operation has completed.  An smp_mb__before_spinlock(),
+     combined with a following ACQUIRE, orders prior loads against
+     subsequent loads and stores and also orders prior stores against
+     subsequent stores.  Note that this is weaker than smp_mb()!  The
+     smp_mb__before_spinlock() primitive is free on many architectures.
 
  (2) RELEASE operation implication:
 
@@ -1694,24 +1724,21 @@ may occur as:
 
        ACQUIRE M, STORE *B, STORE *A, RELEASE M
 
-This same reordering can of course occur if the lock's ACQUIRE and RELEASE are
-to the same lock variable, but only from the perspective of another CPU not
-holding that lock.
-
-In short, a RELEASE followed by an ACQUIRE may -not- be assumed to be a full
-memory barrier because it is possible for a preceding RELEASE to pass a
-later ACQUIRE from the viewpoint of the CPU, but not from the viewpoint
-of the compiler.  Note that deadlocks cannot be introduced by this
-interchange because if such a deadlock threatened, the RELEASE would
-simply complete.
-
-If it is necessary for a RELEASE-ACQUIRE pair to produce a full barrier, the
-ACQUIRE can be followed by an smp_mb__after_unlock_lock() invocation.  This
-will produce a full barrier if either (a) the RELEASE and the ACQUIRE are
-executed by the same CPU or task, or (b) the RELEASE and ACQUIRE act on the
-same variable.  The smp_mb__after_unlock_lock() primitive is free on many
-architectures.  Without smp_mb__after_unlock_lock(), the critical sections
-corresponding to the RELEASE and the ACQUIRE can cross:
+When the ACQUIRE and RELEASE are a lock acquisition and release,
+respectively, this same reordering can occur if the lock's ACQUIRE and
+RELEASE are to the same lock variable, but only from the perspective of
+another CPU not holding that lock.  In short, a ACQUIRE followed by an
+RELEASE may -not- be assumed to be a full memory barrier.
+
+Similarly, the reverse case of a RELEASE followed by an ACQUIRE does not
+imply a full memory barrier.  If it is necessary for a RELEASE-ACQUIRE
+pair to produce a full barrier, the ACQUIRE can be followed by an
+smp_mb__after_unlock_lock() invocation.  This will produce a full barrier
+if either (a) the RELEASE and the ACQUIRE are executed by the same
+CPU or task, or (b) the RELEASE and ACQUIRE act on the same variable.
+The smp_mb__after_unlock_lock() primitive is free on many architectures.
+Without smp_mb__after_unlock_lock(), the CPU's execution of the critical
+sections corresponding to the RELEASE and the ACQUIRE can cross, so that:
 
        *A = a;
        RELEASE M
@@ -1722,7 +1749,36 @@ could occur as:
 
        ACQUIRE N, STORE *B, STORE *A, RELEASE M
 
-With smp_mb__after_unlock_lock(), they cannot, so that:
+It might appear that this reordering could introduce a deadlock.
+However, this cannot happen because if such a deadlock threatened,
+the RELEASE would simply complete, thereby avoiding the deadlock.
+
+       Why does this work?
+
+       One key point is that we are only talking about the CPU doing
+       the reordering, not the compiler.  If the compiler (or, for
+       that matter, the developer) switched the operations, deadlock
+       -could- occur.
+
+       But suppose the CPU reordered the operations.  In this case,
+       the unlock precedes the lock in the assembly code.  The CPU
+       simply elected to try executing the later lock operation first.
+       If there is a deadlock, this lock operation will simply spin (or
+       try to sleep, but more on that later).  The CPU will eventually
+       execute the unlock operation (which preceded the lock operation
+       in the assembly code), which will unravel the potential deadlock,
+       allowing the lock operation to succeed.
+
+       But what if the lock is a sleeplock?  In that case, the code will
+       try to enter the scheduler, where it will eventually encounter
+       a memory barrier, which will force the earlier unlock operation
+       to complete, again unraveling the deadlock.  There might be
+       a sleep-unlock race, but the locking primitive needs to resolve
+       such races properly in any case.
+
+With smp_mb__after_unlock_lock(), the two critical sections cannot overlap.
+For example, with the following code, the store to *A will always be
+seen by other CPUs before the store to *B:
 
        *A = a;
        RELEASE M
@@ -1730,13 +1786,18 @@ With smp_mb__after_unlock_lock(), they cannot, so that:
        smp_mb__after_unlock_lock();
        *B = b;
 
-will always occur as either of the following:
+The operations will always occur in one of the following orders:
 
-       STORE *A, RELEASE, ACQUIRE, STORE *B
-       STORE *A, ACQUIRE, RELEASE, STORE *B
+       STORE *A, RELEASE, ACQUIRE, smp_mb__after_unlock_lock(), STORE *B
+       STORE *A, ACQUIRE, RELEASE, smp_mb__after_unlock_lock(), STORE *B
+       ACQUIRE, STORE *A, RELEASE, smp_mb__after_unlock_lock(), STORE *B
 
 If the RELEASE and ACQUIRE were instead both operating on the same lock
-variable, only the first of these two alternatives can occur.
+variable, only the first of these alternatives can occur.  In addition,
+the more strongly ordered systems may rule out some of the above orders.
+But in any case, as noted earlier, the smp_mb__after_unlock_lock()
+ensures that the store to *A will always be seen as happening before
+the store to *B.
 
 Locks and semaphores may not provide any guarantee of ordering on UP compiled
 systems, and so cannot be counted on in such a situation to actually achieve
@@ -2757,7 +2818,7 @@ in that order, but, without intervention, the sequence may have almost any
 combination of elements combined or discarded, provided the program's view of
 the world remains consistent.  Note that ACCESS_ONCE() is -not- optional
 in the above example, as there are architectures where a given CPU might
-interchange successive loads to the same location.  On such architectures,
+reorder successive loads to the same location.  On such architectures,
 ACCESS_ONCE() does whatever is necessary to prevent this, for example, on
 Itanium the volatile casts used by ACCESS_ONCE() cause GCC to emit the
 special ld.acq and st.rel instructions that prevent such reordering.
index f3089d4235153b6fa03aaf5c8d09c81043bba996..0cbe6ec22d6ff1d6a3c739f05ae61f4dc24781ec 100644 (file)
@@ -554,12 +554,6 @@ solution for a couple of reasons:
   not specified in the struct can_frame and therefore it is only valid in
   CANFD_MTU sized CAN FD frames.
 
-  As long as the payload length is <=8 the received CAN frames from CAN FD
-  capable CAN devices can be received and read by legacy sockets too. When
-  user-generated CAN FD frames have a payload length <=8 these can be send
-  by legacy CAN network interfaces too. Sending CAN FD frames with payload
-  length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
-
   Implementation hint for new CAN applications:
 
   To build a CAN FD aware application use struct canfd_frame as basic CAN
index b26122973525f81e691f2ef05e7069647d6b7e19..c6af4bac5aa8f914a83305831e10f285c1699fb2 100644 (file)
@@ -226,9 +226,9 @@ Ring setup:
        void *rx_ring, *tx_ring;
 
        /* Configure ring parameters */
-       if (setsockopt(fd, NETLINK_RX_RING, &req, sizeof(req)) < 0)
+       if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0)
                exit(1);
-       if (setsockopt(fd, NETLINK_TX_RING, &req, sizeof(req)) < 0)
+       if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0)
                exit(1)
 
        /* Calculate size of each individual ring */
index 1404674c0a0282af7d077cf55a5da076875bd2ed..6fea79efb4cbfd31cc1d0155aef320b94b89da9e 100644 (file)
@@ -453,7 +453,7 @@ TP_STATUS_COPY        : This flag indicates that the frame (and associated
                         enabled previously with setsockopt() and 
                         the PACKET_COPY_THRESH option. 
 
-                        The number of frames than can be buffered to 
+                        The number of frames that can be buffered to
                         be read with recvfrom is limited like a normal socket.
                         See the SO_RCVBUF option in the socket (7) man page.
 
index 661d3c316a17721d787a8a601f3e9c8356e957be..048c92b487f6a50b552cf12d47abe4212ba66f36 100644 (file)
@@ -21,26 +21,38 @@ has such a feature).
 
 SO_TIMESTAMPING:
 
-Instructs the socket layer which kind of information is wanted. The
-parameter is an integer with some of the following bits set. Setting
-other bits is an error and doesn't change the current state.
-
-SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamp in hardware
-SOF_TIMESTAMPING_TX_SOFTWARE:  if SOF_TIMESTAMPING_TX_HARDWARE is off or
-                               fails, then do it in software
-SOF_TIMESTAMPING_RX_HARDWARE:  return the original, unmodified time stamp
-                               as generated by the hardware
-SOF_TIMESTAMPING_RX_SOFTWARE:  if SOF_TIMESTAMPING_RX_HARDWARE is off or
-                               fails, then do it in software
-SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
-SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
-                               the system time base
-SOF_TIMESTAMPING_SOFTWARE:     return system time stamp generated in
-                               software
-
-SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
-SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
-following control message:
+Instructs the socket layer which kind of information should be collected
+and/or reported.  The parameter is an integer with some of the following
+bits set. Setting other bits is an error and doesn't change the current
+state.
+
+Four of the bits are requests to the stack to try to generate
+timestamps.  Any combination of them is valid.
+
+SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamps in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE:  try to obtain send time stamps in software
+SOF_TIMESTAMPING_RX_HARDWARE:  try to obtain receive time stamps in hardware
+SOF_TIMESTAMPING_RX_SOFTWARE:  try to obtain receive time stamps in software
+
+The other three bits control which timestamps will be reported in a
+generated control message.  If none of these bits are set or if none of
+the set bits correspond to data that is available, then the control
+message will not be generated:
+
+SOF_TIMESTAMPING_SOFTWARE:     report systime if available
+SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available
+SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+
+It is worth noting that timestamps may be collected for reasons other
+than being requested by a particular socket with
+SOF_TIMESTAMPING_[TR]X_(HARD|SOFT)WARE.  For example, most drivers that
+can generate hardware receive timestamps ignore
+SOF_TIMESTAMPING_RX_HARDWARE.  It is still a good idea to set that flag
+in case future drivers pay attention.
+
+If timestamps are reported, they will appear in a control message with
+cmsg_level==SOL_SOCKET, cmsg_type==SO_TIMESTAMPING, and a payload like
+this:
 
 struct scm_timestamping {
        struct timespec systime;
index 483632087788db0532718d2a26ab2283c379c38d..a5da5c7e7128bce8ff79beb019444c861fa1b68a 100644 (file)
@@ -88,17 +88,19 @@ node.
 
 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.
+For each device, there are three lists of PM QoS requests. Two of them are
+maintained along with the aggregated targets of resume latency and active
+state latency tolerance (in microseconds) and the third one 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.
+The target values of resume latency and active state latency tolerance are
+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.
 
-Note: the aggregated target value is implemented as an atomic variable so that
-reading the aggregated value does not require any locking mechanism.
+Note: The aggregated target values are implemented in such a way that reading
+the aggregated value does not require any locking mechanism.
 
 
 From kernel mode the use of this interface is the following:
@@ -132,19 +134,21 @@ The meaning of the return values is as follows:
        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)
+int dev_pm_qos_add_ancestor_request(dev, handle, type, value)
 Add a PM QoS request for the first direct ancestor of the given device whose
-power.ignore_children flag is unset.
+power.ignore_children flag is unset (for DEV_PM_QOS_RESUME_LATENCY requests)
+or whose power.set_latency_tolerance callback pointer is not NULL (for
+DEV_PM_QOS_LATENCY_TOLERANCE requests).
 
 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.
+Add a request to the device's PM QoS list of resume 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.
+PM QoS list of resume 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
@@ -163,7 +167,7 @@ a per-device notification tree and a global notification tree.
 int dev_pm_qos_add_notifier(device, notifier):
 Adds a notification callback function for the device.
 The callback is called when the aggregated value of the device constraints list
-is changed.
+is changed (for resume latency device PM QoS only).
 
 int dev_pm_qos_remove_notifier(device, notifier):
 Removes the notification callback function for the device.
@@ -171,14 +175,48 @@ Removes the notification callback function for the device.
 int dev_pm_qos_add_global_notifier(notifier):
 Adds a notification callback function in the global notification tree of the
 framework.
-The callback is called when the aggregated value for any device is changed.
+The callback is called when the aggregated value for any device is changed
+(for resume latency device PM QoS only).
 
 int dev_pm_qos_remove_global_notifier(notifier):
 Removes the notification callback function from the global notification tree
 of the framework.
 
 
-From user mode:
-No API for user space access to the per-device latency constraints is provided
-yet - still under discussion.
-
+Active state latency tolerance
+
+This device PM QoS type is used to support systems in which hardware may switch
+to energy-saving operation modes on the fly.  In those systems, if the operation
+mode chosen by the hardware attempts to save energy in an overly aggressive way,
+it may cause excess latencies to be visible to software, causing it to miss
+certain protocol requirements or target frame or sample rates etc.
+
+If there is a latency tolerance control mechanism for a given device available
+to software, the .set_latency_tolerance callback in that device's dev_pm_info
+structure should be populated.  The routine pointed to by it is should implement
+whatever is necessary to transfer the effective requirement value to the
+hardware.
+
+Whenever the effective latency tolerance changes for the device, its
+.set_latency_tolerance() callback will be executed and the effective value will
+be passed to it.  If that value is negative, which means that the list of
+latency tolerance requirements for the device is empty, the callback is expected
+to switch the underlying hardware latency tolerance control mechanism to an
+autonomous mode if available.  If that value is PM_QOS_LATENCY_ANY, in turn, and
+the hardware supports a special "no requirement" setting, the callback is
+expected to use it.  That allows software to prevent the hardware from
+automatically updating the device's latency tolerance in response to its power
+state changes (e.g. during transitions from D3cold to D0), which generally may
+be done in the autonomous latency tolerance control mode.
+
+If .set_latency_tolerance() is present for the device, sysfs attribute
+pm_qos_latency_tolerance_us will be present in the devivce's power directory.
+Then, user space can use that attribute to specify its latency tolerance
+requirement for the device, if any.  Writing "any" to it means "no requirement,
+but do not let the hardware control latency tolerance" and writing "auto" to it
+allows the hardware to be switched to the autonomous mode if there are no other
+requirements from the kernel side in the device's list.
+
+Kernel code can use the functions described above along with the
+DEV_PM_QOS_LATENCY_TOLERANCE device PM QoS type to add, remove and update
+latency tolerance requirements for devices.
index ed2da5e5b28a4490a3b03787b02df66d083692be..3d14035b1766994b537fb273d20dffc92d9554d9 100644 (file)
@@ -85,6 +85,12 @@ settings for data transfer parameters:
        SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
        (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
        sample on trailing edge iff this is set) flags.
+       Note that this request is limited to SPI mode flags that fit in a
+       single byte.
+
+    SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
+       which will return (RD) or assign (WR) the full SPI transfer mode,
+       not limited to the bits that fit in one byte.
 
     SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
        which will return (RD) or assign (WR) the bit justification used to
index 36ec0774ca0b0e17dc9454378bc472189e901620..0ea3e51292fcbbbdb5010084f1e0c041d1048c8b 100644 (file)
@@ -78,10 +78,10 @@ static void do_msg(int fd, int len)
 
 static void dumpstat(const char *name, int fd)
 {
-       __u8    mode, lsb, bits;
-       __u32   speed;
+       __u8    lsb, bits;
+       __u32   mode, speed;
 
-       if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+       if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
                perror("SPI rd_mode");
                return;
        }
@@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd)
                return;
        }
 
-       printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+       printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
                name, mode, bits, lsb ? "(lsb first) " : "", speed);
 }
 
index 16feda9014692a87a4996bf51d759ab9e7500ee5..3a2f9d59edabf9d7858a1fff178fc722971dafd3 100644 (file)
@@ -30,7 +30,7 @@ static void pabort(const char *s)
 }
 
 static const char *device = "/dev/spidev1.1";
-static uint8_t mode;
+static uint32_t mode;
 static uint8_t bits = 8;
 static uint32_t speed = 500000;
 static uint16_t delay;
@@ -57,6 +57,21 @@ static void transfer(int fd)
                .bits_per_word = bits,
        };
 
+       if (mode & SPI_TX_QUAD)
+               tr.tx_nbits = 4;
+       else if (mode & SPI_TX_DUAL)
+               tr.tx_nbits = 2;
+       if (mode & SPI_RX_QUAD)
+               tr.rx_nbits = 4;
+       else if (mode & SPI_RX_DUAL)
+               tr.rx_nbits = 2;
+       if (!(mode & SPI_LOOP)) {
+               if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
+                       tr.rx_buf = 0;
+               else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
+                       tr.tx_buf = 0;
+       }
+
        ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
        if (ret < 1)
                pabort("can't send spi message");
@@ -81,7 +96,11 @@ static void print_usage(const char *prog)
             "  -O --cpol     clock polarity\n"
             "  -L --lsb      least significant bit first\n"
             "  -C --cs-high  chip select active high\n"
-            "  -3 --3wire    SI/SO signals shared\n");
+            "  -3 --3wire    SI/SO signals shared\n"
+            "  -N --no-cs    no chip select\n"
+            "  -R --ready    slave pulls low to pause\n"
+            "  -2 --dual     dual transfer\n"
+            "  -4 --quad     quad transfer\n");
        exit(1);
 }
 
@@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[])
                        { "3wire",   0, 0, '3' },
                        { "no-cs",   0, 0, 'N' },
                        { "ready",   0, 0, 'R' },
+                       { "dual",    0, 0, '2' },
+                       { "quad",    0, 0, '4' },
                        { NULL, 0, 0, 0 },
                };
                int c;
 
-               c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
+               c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
 
                if (c == -1)
                        break;
@@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[])
                case 'R':
                        mode |= SPI_READY;
                        break;
+               case '2':
+                       mode |= SPI_TX_DUAL;
+                       break;
+               case '4':
+                       mode |= SPI_TX_QUAD;
+                       break;
                default:
                        print_usage(argv[0]);
                        break;
                }
        }
+       if (mode & SPI_LOOP) {
+               if (mode & SPI_TX_DUAL)
+                       mode |= SPI_RX_DUAL;
+               if (mode & SPI_TX_QUAD)
+                       mode |= SPI_RX_QUAD;
+       }
 }
 
 int main(int argc, char *argv[])
@@ -168,11 +201,11 @@ int main(int argc, char *argv[])
        /*
         * spi mode
         */
-       ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+       ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
        if (ret == -1)
                pabort("can't set spi mode");
 
-       ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+       ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
        if (ret == -1)
                pabort("can't get spi mode");
 
@@ -198,7 +231,7 @@ int main(int argc, char *argv[])
        if (ret == -1)
                pabort("can't get max speed hz");
 
-       printf("spi mode: %d\n", mode);
+       printf("spi mode: 0x%x\n", mode);
        printf("bits per word: %d\n", bits);
        printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
 
index e55124e7c40cd0eef8afb92c34913cd68c42faac..ec8be46bf48da2146cbf2689a6aa51a315e1f2f4 100644 (file)
@@ -320,10 +320,11 @@ This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
 
 ==============================================================
 
-hung_task_warning:
+hung_task_warnings:
 
 The maximum number of warnings to report. During a check interval
-When this value is reached, no more the warnings will be reported.
+if a hung task is detected, this value is decreased by 1.
+When this value reaches 0, no more warnings will be reported.
 This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
 
 -1: report an infinite number of warnings.
@@ -441,8 +442,7 @@ feature should be disabled. Otherwise, if the system overhead from the
 feature is too high then the rate the kernel samples for NUMA hinting
 faults may be controlled by the numa_balancing_scan_period_min_ms,
 numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms,
-numa_balancing_scan_size_mb, numa_balancing_settle_count sysctls and
-numa_balancing_migrate_deferred.
+numa_balancing_scan_size_mb, and numa_balancing_settle_count sysctls.
 
 ==============================================================
 
@@ -483,13 +483,6 @@ rate for each task.
 numa_balancing_scan_size_mb is how many megabytes worth of pages are
 scanned for a given scan.
 
-numa_balancing_migrate_deferred is how many page migrations get skipped
-unconditionally, after a page migration is skipped because a page is shared
-with other tasks. This reduces page migration overhead, and determines
-how much stronger the "move task near its memory" policy scheduler becomes,
-versus the "move memory near its task" memory management policy, for workloads
-with shared memory.
-
 ==============================================================
 
 osrelease, ostype & version:
index 3bd33b8dc7c460f71885b169077f3df9ec2adaac..21d514ced212436ea70aa5a218e20a5f8407523e 100644 (file)
@@ -92,5 +92,5 @@ 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 second parameter gives the request type (e.g. "DEV_PM_QOS_RESUME_LATENCY").
 The third parameter is value to be added/updated/removed.
index 28176def3d6f3430c0b2c71c6be9d6b180914cf9..3e091151dd80251363b99746be61c41362ee5e0a 100644 (file)
@@ -21,8 +21,6 @@ Notes and limitations.
 - The weak pullup current is a minimum of 0.9mA and maximum of 6.0mA.
 - The 5V strong pullup is supported with a minimum of 5.9mA and a
   maximum of 30.4 mA.  (From DS2490.pdf)
-- While the ds2490 supports a hardware search the code doesn't take
-  advantage of it (in tested case it only returned first device).
 - The hardware will detect when devices are attached to the bus on the
   next bus (reset?) operation, however only a message is printed as
   the core w1 code doesn't make use of the information.  Connecting
index f59a31965d50a38221ecd305e039d0f6319a03c7..927a52cc05197d68a37bf9b1d05e77c48b321a43 100644 (file)
@@ -5,8 +5,8 @@ Message types.
 =============
 
 There are three types of messages between w1 core and userspace:
-1. Events. They are generated each time new master or slave device
-       found either due to automatic or requested search.
+1. Events. They are generated each time new master or slave device
+       is found either due to automatic or requested search.
 2. Userspace commands.
 3. Replies to userspace commands.
 
@@ -131,7 +131,7 @@ of the w1_netlink_cmd structure and cn_msg.len will be equal to the sum
 of the sizeof(struct w1_netlink_msg) and sizeof(struct w1_netlink_cmd).
 If reply is generated for master or root command (which do not have
 w1_netlink_cmd attached), reply will contain only cn_msg and w1_netlink_msg
-structires.
+structures.
 
 w1_netlink_msg.status field will carry positive error value
 (EINVAL for example) or zero in case of success.
@@ -160,7 +160,7 @@ procedure is started to select given device.
 Then all requested in w1_netlink_msg operations are performed one by one.
 If command requires reply (like read command) it is sent on command completion.
 
-When all commands (w1_netlink_cmd) are processed muster device is unlocked
+When all commands (w1_netlink_cmd) are processed master device is unlocked
 and next w1_netlink_msg header processing started.
 
 
index f9492fed41043816eb8954ca7a56a941ea3e0235..692791cc674c44f20398c8b8f64bd652d6ea9f12 100644 (file)
@@ -150,6 +150,8 @@ nowayout: Disable watchdog shutdown on close
 -------------------------------------------------
 it87_wdt:
 nogameport: Forbid the activation of game port, default=0
+nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if
+system resets despite watchdog daemon running, default=0
 exclusive: Watchdog exclusive device open, default=1
 timeout: Watchdog timeout in seconds, default=60
 testmode: Watchdog test mode (1 = no reboot), default=0
@@ -325,6 +327,11 @@ soft_noboot: Softdog action, set to 1 to ignore reboots, 0 to reboot
 stmp3xxx_wdt:
 heartbeat: Watchdog heartbeat period in seconds from 1 to 4194304, default 19
 -------------------------------------------------
+tegra_wdt:
+heartbeat: Watchdog heartbeats in seconds. (default = 120)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
 ts72xx_wdt:
 timeout: Watchdog timeout in seconds. (1 <= timeout <= 8, default=8)
 nowayout: Disable watchdog shutdown on close
index cb81741d3b0bd92b70aa87918e632edd0bfef3f1..a75e3adaa39da277fb89150fb1d31daf8d1296ef 100644 (file)
@@ -182,7 +182,7 @@ Offset      Proto   Name            Meaning
 0226/1 2.02+(3 ext_loader_ver  Extended boot loader version
 0227/1 2.02+(3 ext_loader_type Extended boot loader ID
 0228/4 2.02+   cmd_line_ptr    32-bit pointer to the kernel command line
-022C/4 2.03+   ramdisk_max     Highest legal initrd address
+022C/4 2.03+   initrd_addr_max Highest legal initrd address
 0230/4 2.05+   kernel_alignment Physical addr alignment required for kernel
 0234/1 2.05+   relocatable_kernel Whether kernel is relocatable or not
 0235/1 2.10+   min_alignment   Minimum alignment, as a power of two
@@ -534,7 +534,7 @@ Protocol:   2.02+
   zero, the kernel will assume that your boot loader does not support
   the 2.02+ protocol.
 
-Field name:    ramdisk_max
+Field name:    initrd_addr_max
 Type:          read
 Offset/size:   0x22c/4
 Protocol:      2.03+
index c6d0e93eff62d700443b93dff01120d36d2ce52a..4a2ea1a168b20a683997bacf17bc8956a57481c9 100644 (file)
@@ -73,7 +73,8 @@ Descriptions of section entries:
        L: Mailing list that is relevant to this area
        W: Web-page with status/info
        Q: Patchwork web based patch tracking system site
-       T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit, topgit.
+       T: SCM tree type and location.
+          Type is one of: git, hg, quilt, stgit, topgit
        S: Status, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
@@ -241,8 +242,8 @@ S:  Maintained
 F:     drivers/platform/x86/acer-wmi.c
 
 ACPI
-M:     Len Brown <lenb@kernel.org>
 M:     Rafael J. Wysocki <rjw@rjwysocki.net>
+M:     Len Brown <lenb@kernel.org>
 L:     linux-acpi@vger.kernel.org
 W:     https://01.org/linux-acpi
 Q:     https://patchwork.kernel.org/project/linux-acpi/list/
@@ -473,7 +474,7 @@ F:  net/rxrpc/af_rxrpc.c
 
 AGPGART DRIVER
 M:     David Airlie <airlied@linux.ie>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T:     git git://people.freedesktop.org/~airlied/linux (part of drm maint)
 S:     Maintained
 F:     drivers/char/agp/
 F:     include/linux/agp*
@@ -910,11 +911,11 @@ F:        arch/arm/include/asm/hardware/dec21285.h
 F:     arch/arm/mach-footbridge/
 
 ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-M:     Shawn Guo <shawn.guo@linaro.org>
+M:     Shawn Guo <shawn.guo@freescale.com>
 M:     Sascha Hauer <kernel@pengutronix.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-T:     git git://git.linaro.org/people/shawnguo/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
 F:     arch/arm/mach-imx/
 F:     arch/arm/boot/dts/imx*
 F:     arch/arm/configs/imx*_defconfig
@@ -1319,6 +1320,7 @@ M:        Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     arch/arm/mach-u300/
+F:     drivers/clocksource/timer-u300.c
 F:     drivers/i2c/busses/i2c-stu300.c
 F:     drivers/rtc/rtc-coh901331.c
 F:     drivers/watchdog/coh901327_wdt.c
@@ -1612,11 +1614,11 @@ S:      Maintained
 F:     drivers/net/wireless/atmel*
 
 ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
-M:      Bradley Grove <linuxdrivers@attotech.com>
-L:      linux-scsi@vger.kernel.org
-W:      http://www.attotech.com
-S:      Supported
-F:      drivers/scsi/esas2r
+M:     Bradley Grove <linuxdrivers@attotech.com>
+L:     linux-scsi@vger.kernel.org
+W:     http://www.attotech.com
+S:     Supported
+F:     drivers/scsi/esas2r
 
 AUDIT SUBSYSTEM
 M:     Eric Paris <eparis@redhat.com>
@@ -1737,6 +1739,7 @@ F:        include/uapi/linux/bfs_fs.h
 BLACKFIN ARCHITECTURE
 M:     Steven Miao <realmz6@gmail.com>
 L:     adi-buildroot-devel@lists.sourceforge.net
+T:     git git://git.code.sf.net/p/adi-linux/code
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     arch/blackfin/
@@ -1830,8 +1833,8 @@ F:        net/bluetooth/
 F:     include/net/bluetooth/
 
 BONDING DRIVER
-M:     Jay Vosburgh <fubar@us.ibm.com>
-M:     Veaceslav Falico <vfalico@redhat.com>
+M:     Jay Vosburgh <j.vosburgh@gmail.com>
+M:     Veaceslav Falico <vfalico@gmail.com>
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
@@ -2159,7 +2162,7 @@ F:        Documentation/zh_CN/
 
 CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
 M:     Peter Chen <Peter.Chen@freescale.com>
-T:     git://github.com/hzpeterchen/linux-usb.git
+T:     git git://github.com/hzpeterchen/linux-usb.git
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/chipidea/
@@ -2179,9 +2182,9 @@ S:        Supported
 F:     drivers/net/ethernet/cisco/enic/
 
 CISCO VIC LOW LATENCY NIC DRIVER
-M:      Upinder Malhi <umalhi@cisco.com>
-S:      Supported
-F:      drivers/infiniband/hw/usnic
+M:     Upinder Malhi <umalhi@cisco.com>
+S:     Supported
+F:     drivers/infiniband/hw/usnic
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
 M:     Hartley Sweeten <hsweeten@visionengravers.com>
@@ -2201,6 +2204,13 @@ L:       alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Odd Fixes
 F:     sound/soc/codecs/cs4270*
 
+CIRRUS LOGIC AUDIO CODEC DRIVERS
+M:     Brian Austin <brian.austin@cirrus.com>
+M:     Paul Handrigan <Paul.Handrigan@cirrus.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/codecs/cs*
+
 CLEANCACHE API
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     linux-kernel@vger.kernel.org
@@ -2378,20 +2388,20 @@ F:      drivers/cpufreq/arm_big_little.c
 F:     drivers/cpufreq/arm_big_little_dt.c
 
 CPUIDLE DRIVER - ARM BIG LITTLE
-M:      Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-M:      Daniel Lezcano <daniel.lezcano@linaro.org>
-L:      linux-pm@vger.kernel.org
-L:      linux-arm-kernel@lists.infradead.org
-T:      git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-S:      Maintained
-F:      drivers/cpuidle/cpuidle-big_little.c
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M:     Daniel Lezcano <daniel.lezcano@linaro.org>
+L:     linux-pm@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+S:     Maintained
+F:     drivers/cpuidle/cpuidle-big_little.c
 
 CPUIDLE DRIVERS
 M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Daniel Lezcano <daniel.lezcano@linaro.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
 F:     drivers/cpuidle/*
 F:     include/linux/cpuidle.h
 
@@ -2458,9 +2468,9 @@ S:        Maintained
 F:     sound/pci/cs5535audio/
 
 CW1200 WLAN driver
-M:     Solomon Peachy <pizza@shaftnet.org>
-S:     Maintained
-F:     drivers/net/wireless/cw1200/
+M:     Solomon Peachy <pizza@shaftnet.org>
+S:     Maintained
+F:     drivers/net/wireless/cw1200/
 
 CX18 VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
@@ -2799,9 +2809,9 @@ S:        Supported
 F:     drivers/acpi/dock.c
 
 DOCUMENTATION
-M:     Rob Landley <rob@landley.net>
+M:     Randy Dunlap <rdunlap@infradead.org>
 L:     linux-doc@vger.kernel.org
-T:     TBD
+T:     quilt http://www.infradead.org/~rdunlap/Doc/patches/
 S:     Maintained
 F:     Documentation/
 
@@ -3095,6 +3105,8 @@ F:        fs/ecryptfs/
 
 EDAC-CORE
 M:     Doug Thompson <dougthompson@xmission.com>
+M:     Borislav Petkov <bp@alien8.de>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Supported
@@ -3653,8 +3665,8 @@ S:        Maintained
 F:     fs/freevxfs/
 
 FREEZER
-M:     Pavel Machek <pavel@ucw.cz>
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/freezing-of-tasks.txt
@@ -4018,8 +4030,8 @@ S:        Maintained
 F:     drivers/video/hgafb.c
 
 HIBERNATION (aka Software Suspend, aka swsusp)
-M:     Pavel Machek <pavel@ucw.cz>
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     arch/x86/power/
@@ -4541,6 +4553,7 @@ M:        Greg Rose <gregory.v.rose@intel.com>
 M:     Alex Duyck <alexander.h.duyck@intel.com>
 M:     John Ronciak <john.ronciak@intel.com>
 M:     Mitch Williams <mitch.a.williams@intel.com>
+M:     Linux NICS <linux.nics@intel.com>
 L:     e1000-devel@lists.sourceforge.net
 W:     http://www.intel.com/support/feedback.htm
 W:     http://e1000.sourceforge.net/
@@ -4558,6 +4571,7 @@ F:        Documentation/networking/ixgbevf.txt
 F:     Documentation/networking/i40e.txt
 F:     Documentation/networking/i40evf.txt
 F:     drivers/net/ethernet/intel/
+F:     drivers/net/ethernet/intel/*/
 
 INTEL-MID GPIO DRIVER
 M:     David Cohen <david.a.cohen@linux.intel.com>
@@ -4914,7 +4928,7 @@ F:        drivers/staging/ktap/
 KCONFIG
 M:     "Yann E. MORIN" <yann.morin.1998@free.fr>
 L:     linux-kbuild@vger.kernel.org
-T:     git://gitorious.org/linux-kconfig/linux-kconfig
+T:     git git://gitorious.org/linux-kconfig/linux-kconfig
 S:     Maintained
 F:     Documentation/kbuild/kconfig-language.txt
 F:     scripts/kconfig/
@@ -5471,11 +5485,11 @@ S:      Maintained
 F:     drivers/media/tuners/m88ts2022*
 
 MA901 MASTERKIT USB FM RADIO DRIVER
-M:      Alexey Klimov <klimov.linux@gmail.com>
-L:      linux-media@vger.kernel.org
-T:      git git://linuxtv.org/media_tree.git
-S:      Maintained
-F:      drivers/media/radio/radio-ma901.c
+M:     Alexey Klimov <klimov.linux@gmail.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/radio/radio-ma901.c
 
 MAC80211
 M:     Johannes Berg <johannes@sipsolutions.net>
@@ -5636,7 +5650,7 @@ F:        drivers/scsi/megaraid/
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
 M:     Amir Vadai <amirv@mellanox.com>
-L:     netdev@vger.kernel.org
+L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
@@ -5677,11 +5691,17 @@ F:      include/linux/mtd/
 F:     include/uapi/mtd/
 
 MEN A21 WATCHDOG DRIVER
-M:     Johannes Thumshirn <johannes.thumshirn@men.de>
+M:     Johannes Thumshirn <johannes.thumshirn@men.de>
 L:     linux-watchdog@vger.kernel.org
 S:     Supported
 F:     drivers/watchdog/mena21_wdt.c
 
+MEN CHAMELEON BUS (mcb)
+M:     Johannes Thumshirn <johannes.thumshirn@men.de>
+S:     Supported
+F:     drivers/mcb/
+F:     include/linux/mcb.h
+
 METAG ARCHITECTURE
 M:     James Hogan <james.hogan@imgtec.com>
 L:     linux-metag@vger.kernel.org
@@ -5733,20 +5753,20 @@ L:      linux-rdma@vger.kernel.org
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-T:     git://openfabrics.org/~eli/connect-ib.git
+T:     git git://openfabrics.org/~eli/connect-ib.git
 S:     Supported
 F:     drivers/net/ethernet/mellanox/mlx5/core/
 F:     include/linux/mlx5/
 
 Mellanox MLX5 IB driver
-M:      Eli Cohen <eli@mellanox.com>
-L:      linux-rdma@vger.kernel.org
-W:      http://www.mellanox.com
-Q:      http://patchwork.kernel.org/project/linux-rdma/list/
-T:      git://openfabrics.org/~eli/connect-ib.git
-S:      Supported
-F:      include/linux/mlx5/
-F:      drivers/infiniband/hw/mlx5/
+M:     Eli Cohen <eli@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+T:     git git://openfabrics.org/~eli/connect-ib.git
+S:     Supported
+F:     include/linux/mlx5/
+F:     drivers/infiniband/hw/mlx5/
 
 MODULE SUPPORT
 M:     Rusty Russell <rusty@rustcorp.com.au>
@@ -5998,6 +6018,9 @@ F:        include/linux/netdevice.h
 F:     include/uapi/linux/in.h
 F:     include/uapi/linux/net.h
 F:     include/uapi/linux/netdevice.h
+F:     tools/net/
+F:     tools/testing/selftests/net/
+F:     lib/random32.c
 
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
@@ -6171,6 +6194,12 @@ S:       Supported
 F:     drivers/block/nvme*
 F:     include/linux/nvme.h
 
+NXP TDA998X DRM DRIVER
+M:     Russell King <rmk+kernel@arm.linux.org.uk>
+S:     Supported
+F:     drivers/gpu/drm/i2c/tda998x_drv.c
+F:     include/drm/i2c/tda998x.h
+
 OMAP SUPPORT
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
@@ -7390,10 +7419,26 @@ W:      http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 F:     arch/s390/
 F:     drivers/s390/
-F:     block/partitions/ibm.c
 F:     Documentation/s390/
 F:     Documentation/DocBook/s390*
 
+S390 COMMON I/O LAYER
+M:     Sebastian Ott <sebott@linux.vnet.ibm.com>
+M:     Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+S:     Supported
+F:     drivers/s390/cio/
+
+S390 DASD DRIVER
+M:     Stefan Weinhuber <wein@de.ibm.com>
+M:     Stefan Haberland <stefan.haberland@de.ibm.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+S:     Supported
+F:     drivers/s390/block/dasd*
+F:     block/partitions/ibm.c
+
 S390 NETWORK DRIVERS
 M:     Ursula Braun <ursula.braun@de.ibm.com>
 M:     Frank Blaschka <blaschka@linux.vnet.ibm.com>
@@ -7403,6 +7448,15 @@ W:       http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 F:     drivers/s390/net/
 
+S390 PCI SUBSYSTEM
+M:     Sebastian Ott <sebott@linux.vnet.ibm.com>
+M:     Gerald Schaefer <gerald.schaefer@de.ibm.com>
+L:     linux-s390@vger.kernel.org
+W:     http://www.ibm.com/developerworks/linux/linux390/
+S:     Supported
+F:     arch/s390/pci/
+F:     drivers/pci/hotplug/s390_pci_hpc.c
+
 S390 ZCRYPT DRIVER
 M:     Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com>
 M:     linux390@de.ibm.com
@@ -8412,9 +8466,9 @@ F:        arch/sh/
 F:     drivers/sh/
 
 SUSPEND TO RAM
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Len Brown <len.brown@intel.com>
 M:     Pavel Machek <pavel@ucw.cz>
-M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/
@@ -8700,17 +8754,17 @@ S:      Maintained
 F:     drivers/media/radio/radio-raremono.c
 
 THERMAL
-M:      Zhang Rui <rui.zhang@intel.com>
-M:      Eduardo Valentin <eduardo.valentin@ti.com>
-L:      linux-pm@vger.kernel.org
-T:      git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
-T:      git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
-Q:      https://patchwork.kernel.org/project/linux-pm/list/
-S:      Supported
-F:      drivers/thermal/
-F:      include/linux/thermal.h
-F:      include/linux/cpu_cooling.h
-F:      Documentation/devicetree/bindings/thermal/
+M:     Zhang Rui <rui.zhang@intel.com>
+M:     Eduardo Valentin <eduardo.valentin@ti.com>
+L:     linux-pm@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
+Q:     https://patchwork.kernel.org/project/linux-pm/list/
+S:     Supported
+F:     drivers/thermal/
+F:     include/linux/thermal.h
+F:     include/linux/cpu_cooling.h
+F:     Documentation/devicetree/bindings/thermal/
 
 THINGM BLINK(1) USB RGB LED DRIVER
 M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -9768,6 +9822,12 @@ L:       linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/tty/serial/uartlite.c
 
+XTENSA XTFPGA PLATFORM SUPPORT
+M:     Max Filippov <jcmvbkbc@gmail.com>
+L:     linux-xtensa@linux-xtensa.org
+S:     Maintained
+F:     drivers/spi/spi-xtensa-xtfpga.c
+
 YAM DRIVER FOR AX.25
 M:     Jean-Paul Roubelat <jpr@f6fbb.org>
 L:     linux-hams@vger.kernel.org
@@ -9812,7 +9872,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
 L:     mjpeg-users@lists.sourceforge.net
 L:     linux-media@vger.kernel.org
 W:     http://mjpeg.sourceforge.net/driver-zoran/
-T:     Mercurial http://linuxtv.org/hg/v4l-dvb
+T:     hg http://linuxtv.org/hg/v4l-dvb
 S:     Odd Fixes
 F:     drivers/media/pci/zoran/
 
index 78209ee1f9811724f2ccc79b023fe2c7ad321105..e5ac8a62e6e57c855c4da06e3d80c2438fccee48 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 14
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION =
 NAME = Shuffling Zombie Juror
 
 # *DOCUMENTATION*
index a73a8e208a4ae00154c0e1adb6ef4a3f311ebcb6..96e54bed50889e4fe62c71ac6125ac6fe0dad5f2 100644 (file)
@@ -1,7 +1,9 @@
 
-generic-y += clkdev.h
 
+generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
 generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/alpha/include/asm/cputime.h b/arch/alpha/include/asm/cputime.h
deleted file mode 100644 (file)
index 19577fd..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_CPUTIME_H
-#define __ALPHA_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __ALPHA_CPUTIME_H */
index edb4e0097b75eff056ea89d37146ec2fe77eadc7..076c35cd6cde7c2d782a46fe3942b8962369230e 100644 (file)
@@ -254,12 +254,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
        }
 }
 
-int
-pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       return pci_enable_resources(dev, mask);
-}
-
 /*
  *  If we set up a device for bus mastering, we need to check the latency
  *  timer as certain firmware forgets to set it properly, as seen
index 0d3362991c316efd8236933c178523565c3f29ad..e76fd79f32b0126ee2e83dfaa5ba05d3d4c98452 100644 (file)
@@ -1,15 +1,15 @@
 generic-y += auxvec.h
 generic-y += barrier.h
-generic-y += bugs.h
 generic-y += bitsperlong.h
+generic-y += bugs.h
 generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += device.h
 generic-y += div64.h
 generic-y += emergency-restart.h
 generic-y += errno.h
-generic-y += fcntl.h
 generic-y += fb.h
+generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += hardirq.h
 generic-y += hash.h
@@ -22,6 +22,7 @@ generic-y += kmap_types.h
 generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += msgbuf.h
 generic-y += param.h
@@ -30,6 +31,7 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sembuf.h
@@ -48,4 +50,3 @@ generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
-generic-y += preempt.h
index 6b58c1de757744feac1d0ae54ec1fdd0693fc500..400c663b21c2bf075e977a8ccf3016fb7e03b5a6 100644 (file)
@@ -282,7 +282,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
 #else
        /* if V-P const for loop, PTAG can be written once outside loop */
        if (full_page_op)
-               write_aux_reg(ARC_REG_DC_PTAG, paddr);
+               write_aux_reg(aux_tag, paddr);
 #endif
 
        while (num_lines-- > 0) {
@@ -296,7 +296,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
                write_aux_reg(aux_cmd, vaddr);
                vaddr += L1_CACHE_BYTES;
 #else
-               write_aux_reg(aux, paddr);
+               write_aux_reg(aux_cmd, paddr);
                paddr += L1_CACHE_BYTES;
 #endif
        }
index e254198177914ca13050f37519a6ca43e0da596d..15949459611f194376dafcdebaf569f8ef141dc5 100644 (file)
@@ -1578,6 +1578,7 @@ config BL_SWITCHER_DUMMY_IF
 
 choice
        prompt "Memory split"
+       depends on MMU
        default VMSPLIT_3G
        help
          Select the desired split between kernel and user memory.
@@ -1595,6 +1596,7 @@ endchoice
 
 config PAGE_OFFSET
        hex
+       default PHYS_OFFSET if !MMU
        default 0x40000000 if VMSPLIT_1G
        default 0x80000000 if VMSPLIT_2G
        default 0xC0000000
@@ -1903,6 +1905,7 @@ config XEN
        depends on ARM && AEABI && OF
        depends on CPU_V7 && !CPU_V6
        depends on !GENERIC_ATOMIC64
+       depends on MMU
        select ARM_PSCI
        select SWIOTLB_XEN
        select ARCH_DMA_ADDR_T_64BIT
index 47279aa96a6a48fd1945ae9faa7584d49f24a355..0714e0334e33c9790b221d03859574b2f4e774ad 100644 (file)
@@ -1,4 +1,5 @@
 ashldi3.S
+bswapsdi2.S
 font.c
 lib1funcs.S
 hyp-stub.S
index e491b82f8d67099ce25b4d1f08cdc6777bf55d7f..792fde1b7f752a93ffa42f2e5f8c7083dc1bb55c 100644 (file)
        };
 
        pinctrl@35004800 {
-               compatible = "brcm,capri-pinctrl";
+               compatible = "brcm,bcm11351-pinctrl";
                reg = <0x35004800 0x430>;
        };
 
index 2363593e1050b7b84b4705878fc10cb653b33cca..ef58d1c24313541a068436c5e590378120c6bb3b 100644 (file)
@@ -612,7 +612,7 @@ clocks {
                compatible = "ti,keystone,psc-clock";
                clocks = <&chipclk13>;
                clock-output-names = "vcp-3";
-               reg = <0x0235000a8 0xb00>, <0x02350060 0x400>;
+               reg = <0x023500a8 0xb00>, <0x02350060 0x400>;
                reg-names = "control", "domain";
                domain-id = <24>;
        };
index c551e4af4d83712f67b69b260be16434523305d9..d3b253bbc8856a9ba0a2f1810c1860f875931462 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "OMAP3 GTA04";
-       compatible = "ti,omap3-gta04", "ti,omap3";
+       compatible = "ti,omap3-gta04", "ti,omap36xx", "ti,omap3";
 
        cpus {
                cpu@0 {
index 25a2b5f652fd1949ceac364ec8a154436aba05e4..f2779ac75872a4a44e2d03402fab7b6fe1a4b66b 100644 (file)
@@ -14,7 +14,7 @@
 
 / {
        model = "IGEPv2 (TI OMAP AM/DM37x)";
-       compatible = "isee,omap3-igep0020", "ti,omap3";
+       compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
 
        leds {
                pinctrl-names = "default";
index 145c58cfc8ac1d3c322f2a2ad44abac2734bbb30..2793749eb1ba460dcf8736fc964aef7b87b05d1a 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "IGEP COM MODULE (TI OMAP AM/DM37x)";
-       compatible = "isee,omap3-igep0030", "ti,omap3";
+       compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
 
        leds {
                pinctrl-names = "default";
index 19c65509a22d8b10cc48e667fb747bdda0d6ee1e..3b075dd19b51ce7c28eb2b243c075a5a7e2be56a 100644 (file)
                                R8A7791_CLK_MSIOF1 R8A7791_CLK_SCIFB2
                        >;
                        clock-output-names =
-                               "scifa2", "scifa1", "scifa0", "misof2", "scifb0",
+                               "scifa2", "scifa1", "scifa0", "msiof2", "scifb0",
                                "scifb1", "msiof1", "scifb2";
                };
                mstp3_clks: mstp3_clks@e615013c {
index 6c31c26e6cc09511b9e4cd11b12dc946ecea8aeb..db58cad6acd32633b88bf88a0589885bfa58ed9b 100644 (file)
@@ -8,8 +8,8 @@
  */
 #include "sama5d3.dtsi"
 #include "sama5d3_can.dtsi"
-#include "sama5d3_emac.dtsi"
 #include "sama5d3_gmac.dtsi"
+#include "sama5d3_emac.dtsi"
 #include "sama5d3_lcd.dtsi"
 #include "sama5d3_mci2.dtsi"
 #include "sama5d3_tcb1.dtsi"
index 10666ca8aee1c49cd35ef7373a0298df27816ae3..7753be0c86d7cd8c4a6aca932bc17bb932971a10 100644 (file)
                };
 
                intc: interrupt-controller@01c20400 {
-                       compatible = "allwinner,sun4i-ic";
+                       compatible = "allwinner,sun4i-a10-ic";
                        reg = <0x01c20400 0x400>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                };
 
                timer@01c20c00 {
-                       compatible = "allwinner,sun4i-timer";
+                       compatible = "allwinner,sun4i-a10-timer";
                        reg = <0x01c20c00 0x90>;
                        interrupts = <22>;
                        clocks = <&osc24M>;
                };
 
                sid: eeprom@01c23800 {
-                       compatible = "allwinner,sun4i-sid";
+                       compatible = "allwinner,sun4i-a10-sid";
                        reg = <0x01c23800 0x10>;
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 64961595e8d63cafaaaf2373ce6e5a580a7e6879..ee17b1c379e319fb852cc47099abe8ca2a61af83 100644 (file)
                };
 
                intc: interrupt-controller@01c20400 {
-                       compatible = "allwinner,sun4i-ic";
+                       compatible = "allwinner,sun4i-a10-ic";
                        reg = <0x01c20400 0x400>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                };
 
                timer@01c20c00 {
-                       compatible = "allwinner,sun4i-timer";
+                       compatible = "allwinner,sun4i-a10-timer";
                        reg = <0x01c20c00 0x90>;
                        interrupts = <22>;
                        clocks = <&osc24M>;
                };
 
                sid: eeprom@01c23800 {
-                       compatible = "allwinner,sun4i-sid";
+                       compatible = "allwinner,sun4i-a10-sid";
                        reg = <0x01c23800 0x10>;
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 320335abfccd763118408f3f836c0fba39ca6f69..3490ef9ec6034b8d4fb0a100bca11152f1a5133d 100644 (file)
                ranges;
 
                intc: interrupt-controller@01c20400 {
-                       compatible = "allwinner,sun4i-ic";
+                       compatible = "allwinner,sun4i-a10-ic";
                        reg = <0x01c20400 0x400>;
                        interrupt-controller;
                        #interrupt-cells = <1>;
                };
 
                timer@01c20c00 {
-                       compatible = "allwinner,sun4i-timer";
+                       compatible = "allwinner,sun4i-a10-timer";
                        reg = <0x01c20c00 0x90>;
                        interrupts = <22>;
                        clocks = <&osc24M>;
                };
 
                sid: eeprom@01c23800 {
-                       compatible = "allwinner,sun4i-sid";
+                       compatible = "allwinner,sun4i-a10-sid";
                        reg = <0x01c23800 0x10>;
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 5256ad9be52c691022ce99e81b679b012f766350..38d43febda4c0f2721c249fe89ea69a4bc6ca63b 100644 (file)
                #size-cells = <1>;
                ranges;
 
+               nmi_intc: interrupt-controller@01f00c0c {
+                       compatible = "allwinner,sun6i-a31-sc-nmi";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       reg = <0x01f00c0c 0x38>;
+                       interrupts = <0 32 4>;
+               };
+
                pio: pinctrl@01c20800 {
                        compatible = "allwinner,sun6i-a31-pinctrl";
                        reg = <0x01c20800 0x400>;
                };
 
                timer@01c20c00 {
-                       compatible = "allwinner,sun4i-timer";
+                       compatible = "allwinner,sun4i-a10-timer";
                        reg = <0x01c20c00 0xa0>;
                        interrupts = <0 18 4>,
                                     <0 19 4>,
index 9ff09484847b9ca8cf0eb58ed4f6ad859f5273ad..cadcf2f9881d460fd9fbdc6e40d072a8610bf8d6 100644 (file)
                #size-cells = <1>;
                ranges;
 
+               nmi_intc: interrupt-controller@01c00030 {
+                       compatible = "allwinner,sun7i-a20-sc-nmi";
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       reg = <0x01c00030 0x0c>;
+                       interrupts = <0 0 4>;
+               };
+
                emac: ethernet@01c0b000 {
                        compatible = "allwinner,sun4i-a10-emac";
                        reg = <0x01c0b000 0x1000>;
                };
 
                timer@01c20c00 {
-                       compatible = "allwinner,sun4i-timer";
+                       compatible = "allwinner,sun4i-a10-timer";
                        reg = <0x01c20c00 0x90>;
                        interrupts = <0 22 4>,
                                     <0 23 4>,
                rtc: rtc@01c20d00 {
                        compatible = "allwinner,sun7i-a20-rtc";
                        reg = <0x01c20d00 0x20>;
-                       interrupts = <0 24 1>;
+                       interrupts = <0 24 4>;
                };
 
                sid: eeprom@01c23800 {
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <0 29 4>;
                };
                hstimer@01c60000 {
                        compatible = "allwinner,sun7i-a20-hstimer";
                        reg = <0x01c60000 0x1000>;
-                       interrupts = <0 81 1>,
-                                    <0 82 1>,
-                                    <0 83 1>,
-                                    <0 84 1>;
+                       interrupts = <0 81 4>,
+                                    <0 82 4>,
+                                    <0 83 4>,
+                                    <0 84 4>;
                        clocks = <&ahb_gates 28>;
                };
 
index 8b67b19392eca7ac1359dfe1db0ec4a16e5d1ade..789d0bacc11025ac2c333be1bb29748dcdeec3d2 100644 (file)
                        device_type = "cpu";
                        reg = <0>;
                        clocks = <&clkc 3>;
+                       operating-points = <
+                               /* kHz    uV */
+                               666667  1000000
+                               333334  1000000
+                               222223  1000000
+                       >;
                };
 
                cpu@1 {
index 00fe9e9710fd77e4a11c4c9c8c6c03534d5e6690..27d69b558c5de2caf1be2b9ac79388ae997f562a 100644 (file)
@@ -204,7 +204,10 @@ CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_ONESHOT=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
index 3278afe2c3ab9014e2ed80904e5e6e98508e14f7..23e728ecf8ab3707403c811b6b43baead7198380 100644 (file)
@@ -7,16 +7,19 @@ generic-y += current.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += msgbuf.h
 generic-y += param.h
 generic-y += parport.h
 generic-y += poll.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += sections.h
 generic-y += segment.h
@@ -33,5 +36,3 @@ generic-y += termios.h
 generic-y += timex.h
 generic-y += trace_clock.h
 generic-y += unaligned.h
-generic-y += preempt.h
-generic-y += hash.h
index 8756e4bcdba0609ff789a4f1efaa551faa39ed98..4afb376d9c7c13d07ea81502e17ba53f0554c122 100644 (file)
  */
 #define UL(x) _AC(x, UL)
 
+/* PAGE_OFFSET - the virtual address of the start of the kernel image */
+#define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
+
 #ifdef CONFIG_MMU
 
 /*
- * PAGE_OFFSET - the virtual address of the start of the kernel image
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
  */
-#define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
 #define TASK_SIZE              (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M))
 #define TASK_UNMAPPED_BASE     ALIGN(TASK_SIZE / 3, SZ_16M)
 
 #define END_MEM                (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE)
 #endif
 
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET            PLAT_PHYS_OFFSET
-#endif
-
 /*
  * The module can be at any place in ram in nommu mode.
  */
index 58b8b84adcd2cf5f295e6869b68350f9dcadc798..2fe85fff5ccacd3dfe67d72c4b6fd5d65342e5e9 100644 (file)
@@ -20,9 +20,6 @@ extern struct cputopo_arm cpu_topology[NR_CPUS];
 #define topology_core_cpumask(cpu)     (&cpu_topology[cpu].core_sibling)
 #define topology_thread_cpumask(cpu)   (&cpu_topology[cpu].thread_sibling)
 
-#define mc_capable()   (cpu_topology[0].socket_id != -1)
-#define smt_capable()  (cpu_topology[0].thread_id != -1)
-
 void init_cpu_topology(void);
 void store_cpu_topology(unsigned int cpuid);
 const struct cpumask *cpu_coregroup_mask(int cpu);
index 317da88ae65b14f2bdd9145a3b552316f134c18a..d0d46786892cac86f5f8575f063d3637032292fd 100644 (file)
@@ -19,7 +19,7 @@
 static int debug_pci;
 
 /*
- * We can't use pci_find_device() here since we are
+ * We can't use pci_get_device() here since we are
  * called from interrupt context.
  */
 static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, int warn)
@@ -57,13 +57,10 @@ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, in
 
 void pcibios_report_status(u_int status_mask, int warn)
 {
-       struct list_head *l;
-
-       list_for_each(l, &pci_root_buses) {
-               struct pci_bus *bus = pci_bus_b(l);
+       struct pci_bus *bus;
 
+       list_for_each_entry(bus, &pci_root_buses, node)
                pcibios_bus_report_status(bus, status_mask, warn);
-       }
 }
 
 /*
index 47cd974e57ea3ca0de7e9feccd9e527c2ba39f1f..c96ecacb2021222936844a4807f39ef474965879 100644 (file)
@@ -177,6 +177,18 @@ __lookup_processor_type_data:
        .long   __proc_info_end
        .size   __lookup_processor_type_data, . - __lookup_processor_type_data
 
+__error_lpae:
+#ifdef CONFIG_DEBUG_LL
+       adr     r0, str_lpae
+       bl      printascii
+       b       __error
+str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n"
+#else
+       b       __error
+#endif
+       .align
+ENDPROC(__error_lpae)
+
 __error_p:
 #ifdef CONFIG_DEBUG_LL
        adr     r0, str_p1
index 914616e0bdcd0c0108376a9e5834e9cb73219b51..f5f381d915560818dcf0d2200731a90b0c7ae404 100644 (file)
@@ -102,7 +102,7 @@ ENTRY(stext)
        and     r3, r3, #0xf                    @ extract VMSA support
        cmp     r3, #5                          @ long-descriptor translation table format?
  THUMB( it     lo )                            @ force fixup-able long branch encoding
-       blo     __error_p                       @ only classic page table format
+       blo     __error_lpae                    @ only classic page table format
 #endif
 
 #ifndef CONFIG_XIP_KERNEL
index 92f7b15dd22121d4aa674fd78cd95cac8924c07f..adabeababeb03d5fc34efe76fa5c12d4eab90a5d 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/uaccess.h>
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
-#include <linux/cpuidle.h>
 #include <linux/leds.h>
 #include <linux/reboot.h>
 
@@ -133,7 +132,11 @@ EXPORT_SYMBOL_GPL(arm_pm_restart);
 
 void (*arm_pm_idle)(void);
 
-static void default_idle(void)
+/*
+ * Called from the core idle loop.
+ */
+
+void arch_cpu_idle(void)
 {
        if (arm_pm_idle)
                arm_pm_idle();
@@ -167,15 +170,6 @@ void arch_cpu_idle_dead(void)
 }
 #endif
 
-/*
- * Called from the core idle loop.
- */
-void arch_cpu_idle(void)
-{
-       if (cpuidle_idle_call())
-               default_idle();
-}
-
 /*
  * Called by kexec, immediately prior to machine_kexec().
  *
index b7b4c86e338b0264919152caee8bec654e2b7757..7c4fada440f0fd5d4cdfe575b972beba689e6985 100644 (file)
@@ -674,8 +674,7 @@ static int cpufreq_callback(struct notifier_block *nb,
        }
 
        if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
-           (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
                loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
                                                global_l_p_j_ref_freq,
                                                freq->new);
index 6591e26fc13f4eab5fcd3a7b1292a3ca7cf3bd92..dfc32130bc443ddc407d463b486109ba49632db2 100644 (file)
@@ -166,7 +166,7 @@ static int twd_cpufreq_transition(struct notifier_block *nb,
         * frequency.  The timer is local to a cpu, so cross-call to the
         * changing cpu.
         */
-       if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
+       if (state == CPUFREQ_POSTCHANGE)
                smp_call_function_single(freqs->cpu, twd_update_frequency,
                        NULL, 1);
 
index 2ab00434b2eb64405a2c4b75f315950cbe9663c0..85399c98f84a7f30657ecc57beb267d404593560 100644 (file)
@@ -472,7 +472,7 @@ static struct clk_lookup da850_clks[] = {
        CLK("spi_davinci.0",    NULL,           &spi0_clk),
        CLK("spi_davinci.1",    NULL,           &spi1_clk),
        CLK("vpif",             NULL,           &vpif_clk),
-       CLK("ahci",             NULL,           &sata_clk),
+       CLK("ahci_da850",               NULL,           &sata_clk),
        CLK("davinci-rproc.0",  NULL,           &dsp_clk),
        CLK("ehrpwm",           "fck",          &ehrpwm_clk),
        CLK("ehrpwm",           "tbclk",        &ehrpwm_tbclk),
index 0486cdf28c8d552205ff4285fe7d7476721cc2a6..56ea41d5f8491307ab89b3178365071cec34ee3d 100644 (file)
@@ -1020,111 +1020,29 @@ int __init da8xx_register_spi_bus(int instance, unsigned num_chipselect)
 }
 
 #ifdef CONFIG_ARCH_DAVINCI_DA850
-
 static struct resource da850_sata_resources[] = {
        {
                .start  = DA850_SATA_BASE,
                .end    = DA850_SATA_BASE + 0x1fff,
                .flags  = IORESOURCE_MEM,
        },
+       {
+               .start  = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG,
+               .end    = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG + 0x3,
+               .flags  = IORESOURCE_MEM,
+       },
        {
                .start  = IRQ_DA850_SATAINT,
                .flags  = IORESOURCE_IRQ,
        },
 };
 
-/* SATA PHY Control Register offset from AHCI base */
-#define SATA_P0PHYCR_REG       0x178
-
-#define SATA_PHY_MPY(x)                ((x) << 0)
-#define SATA_PHY_LOS(x)                ((x) << 6)
-#define SATA_PHY_RXCDR(x)      ((x) << 10)
-#define SATA_PHY_RXEQ(x)       ((x) << 13)
-#define SATA_PHY_TXSWING(x)    ((x) << 19)
-#define SATA_PHY_ENPLL(x)      ((x) << 31)
-
-static struct clk *da850_sata_clk;
-static unsigned long da850_sata_refclkpn;
-
-/* Supported DA850 SATA crystal frequencies */
-#define KHZ_TO_HZ(freq) ((freq) * 1000)
-static unsigned long da850_sata_xtal[] = {
-       KHZ_TO_HZ(300000),
-       KHZ_TO_HZ(250000),
-       0,                      /* Reserved */
-       KHZ_TO_HZ(187500),
-       KHZ_TO_HZ(150000),
-       KHZ_TO_HZ(125000),
-       KHZ_TO_HZ(120000),
-       KHZ_TO_HZ(100000),
-       KHZ_TO_HZ(75000),
-       KHZ_TO_HZ(60000),
-};
-
-static int da850_sata_init(struct device *dev, void __iomem *addr)
-{
-       int i, ret;
-       unsigned int val;
-
-       da850_sata_clk = clk_get(dev, NULL);
-       if (IS_ERR(da850_sata_clk))
-               return PTR_ERR(da850_sata_clk);
-
-       ret = clk_prepare_enable(da850_sata_clk);
-       if (ret)
-               goto err0;
-
-       /* Enable SATA clock receiver */
-       val = __raw_readl(DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
-       val &= ~BIT(0);
-       __raw_writel(val, DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
-
-       /* Get the multiplier needed for 1.5GHz PLL output */
-       for (i = 0; i < ARRAY_SIZE(da850_sata_xtal); i++)
-               if (da850_sata_xtal[i] == da850_sata_refclkpn)
-                       break;
-
-       if (i == ARRAY_SIZE(da850_sata_xtal)) {
-               ret = -EINVAL;
-               goto err1;
-       }
-
-       val = SATA_PHY_MPY(i + 1) |
-               SATA_PHY_LOS(1) |
-               SATA_PHY_RXCDR(4) |
-               SATA_PHY_RXEQ(1) |
-               SATA_PHY_TXSWING(3) |
-               SATA_PHY_ENPLL(1);
-
-       __raw_writel(val, addr + SATA_P0PHYCR_REG);
-
-       return 0;
-
-err1:
-       clk_disable_unprepare(da850_sata_clk);
-err0:
-       clk_put(da850_sata_clk);
-       return ret;
-}
-
-static void da850_sata_exit(struct device *dev)
-{
-       clk_disable_unprepare(da850_sata_clk);
-       clk_put(da850_sata_clk);
-}
-
-static struct ahci_platform_data da850_sata_pdata = {
-       .init   = da850_sata_init,
-       .exit   = da850_sata_exit,
-};
-
 static u64 da850_sata_dmamask = DMA_BIT_MASK(32);
 
 static struct platform_device da850_sata_device = {
-       .name   = "ahci",
+       .name   = "ahci_da850",
        .id     = -1,
        .dev    = {
-               .platform_data          = &da850_sata_pdata,
                .dma_mask               = &da850_sata_dmamask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
@@ -1134,9 +1052,8 @@ static struct platform_device da850_sata_device = {
 
 int __init da850_register_sata(unsigned long refclkpn)
 {
-       da850_sata_refclkpn = refclkpn;
-       if (!da850_sata_refclkpn)
-               return -EINVAL;
+       /* please see comment in drivers/ata/ahci_da850.c */
+       BUG_ON(refclkpn != 100 * 1000 * 1000);
 
        return platform_device_register(&da850_sata_device);
 }
index 7a9b98589db7260ea0c56deca6872b3667158c2a..29e3fe6a66696b858850ca2190eb0383a72c9a3a 100644 (file)
@@ -120,7 +120,7 @@ static void imx6q_enable_wb(bool enable)
 
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
 {
-       struct irq_desc *iomuxc_irq_desc;
+       struct irq_data *iomuxc_irq_data = irq_get_irq_data(32);
        u32 val = readl_relaxed(ccm_base + CLPCR);
 
        val &= ~BM_CLPCR_LPM;
@@ -167,10 +167,9 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
         * 3) Software should mask IRQ #32 right after CCM Low-Power mode
         *    is set (set bits 0-1 of CCM_CLPCR).
         */
-       iomuxc_irq_desc = irq_to_desc(32);
-       imx_gpc_irq_unmask(&iomuxc_irq_desc->irq_data);
+       imx_gpc_irq_unmask(iomuxc_irq_data);
        writel_relaxed(val, ccm_base + CLPCR);
-       imx_gpc_irq_mask(&iomuxc_irq_desc->irq_data);
+       imx_gpc_irq_mask(iomuxc_irq_data);
 
        return 0;
 }
index 461a191a32d248ba3e2715aa9f3cfb607d6df7d8..43b1a516957fdfc2cc32b75a0e284289ad6d73ec 100644 (file)
 
 int mmp2_set_wake(struct irq_data *d, unsigned int on)
 {
-       int irq = d->irq;
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long data = 0;
-
-       if (unlikely(irq >= nr_irqs)) {
-               pr_err("IRQ nubmers are out of boundary!\n");
-               return -EINVAL;
-       }
-
-       if (on) {
-               if (desc->action)
-                       desc->action->flags |= IRQF_NO_SUSPEND;
-       } else {
-               if (desc->action)
-                       desc->action->flags &= ~IRQF_NO_SUSPEND;
-       }
+       int irq = d->irq;
 
        /* enable wakeup sources */
        switch (irq) {
index 48981ca801a5527b8b2df375237d595ec98dc388..04c9daf9f8d767a7225631a7f36e443fae260d88 100644 (file)
 
 int pxa910_set_wake(struct irq_data *data, unsigned int on)
 {
-       int irq = data->irq;
-       struct irq_desc *desc = irq_to_desc(data->irq);
        uint32_t awucrm = 0, apcr = 0;
-
-       if (unlikely(irq >= nr_irqs)) {
-               pr_err("IRQ nubmers are out of boundary!\n");
-               return -EINVAL;
-       }
-
-       if (on) {
-               if (desc->action)
-                       desc->action->flags |= IRQF_NO_SUSPEND;
-       } else {
-               if (desc->action)
-                       desc->action->flags &= ~IRQF_NO_SUSPEND;
-       }
+       int irq = data->irq;
 
        /* setting wakeup sources */
        switch (irq) {
@@ -115,9 +101,11 @@ int pxa910_set_wake(struct irq_data *data, unsigned int on)
                if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
                        awucrm = MPMU_AWUCRM_WAKEUP(2);
                        apcr |= MPMU_APCR_SLPWP2;
-               } else
+               } else {
+                       /* FIXME: This should return a proper error code ! */
                        printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
                                irq);
+               }
        }
 
        if (on) {
index f12a12af35237d434d8186838717850965443d08..d1f12095f3155d37ac72e61bc73d9cf2b84dcc2e 100644 (file)
@@ -44,13 +44,10 @@ static unsigned int irq_counter[16];
 
 static irqreturn_t deferred_fiq(int irq, void *dev_id)
 {
-       struct irq_desc *irq_desc;
-       struct irq_chip *irq_chip = NULL;
        int gpio, irq_num, fiq_count;
+       struct irq_chip *irq_chip;
 
-       irq_desc = irq_to_desc(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
-       if (irq_desc)
-               irq_chip = irq_desc->irq_data.chip;
+       irq_chip = irq_get_chip(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
 
        /*
         * For each handled GPIO interrupt, keep calling its interrupt handler
index 3b05aea56d1f5636d5ff2e154513cf22349b3eec..11ed9152e665274793ee83f50881efc2d9fbdded 100644 (file)
@@ -433,7 +433,9 @@ static const struct clk_ops dpll4_m5x2_ck_ops = {
        .enable         = &omap2_dflt_clk_enable,
        .disable        = &omap2_dflt_clk_disable,
        .is_enabled     = &omap2_dflt_clk_is_enabled,
+       .set_rate       = &omap3_clkoutx2_set_rate,
        .recalc_rate    = &omap3_clkoutx2_recalc,
+       .round_rate     = &omap3_clkoutx2_round_rate,
 };
 
 static const struct clk_ops dpll4_m5x2_ck_3630_ops = {
index 4c158c838d4062e1eaee78ff770e4b9dc257146f..01fc710c81818e9d48e2b26ca8742b77b392ff1c 100644 (file)
@@ -23,6 +23,8 @@
 #include "prm.h"
 #include "clockdomain.h"
 
+#define MAX_CPUS       2
+
 /* Machine specific information */
 struct idle_statedata {
        u32 cpu_state;
@@ -48,11 +50,11 @@ static struct idle_statedata omap4_idle_data[] = {
        },
 };
 
-static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS];
-static struct clockdomain *cpu_clkdm[NR_CPUS];
+static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
+static struct clockdomain *cpu_clkdm[MAX_CPUS];
 
 static atomic_t abort_barrier;
-static bool cpu_done[NR_CPUS];
+static bool cpu_done[MAX_CPUS];
 static struct idle_statedata *state_ptr = &omap4_idle_data[0];
 
 /* Private functions */
index 3185ced807c952804d50199fd3ff7bc8ea68fb8f..3c418ea54bbe1a483ddc37759f0580ca7c949dd5 100644 (file)
@@ -623,6 +623,32 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
 
 /* Clock control for DPLL outputs */
 
+/* Find the parent DPLL for the given clkoutx2 clock */
+static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
+{
+       struct clk_hw_omap *pclk = NULL;
+       struct clk *parent;
+
+       /* Walk up the parents of clk, looking for a DPLL */
+       do {
+               do {
+                       parent = __clk_get_parent(hw->clk);
+                       hw = __clk_get_hw(parent);
+               } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
+               if (!hw)
+                       break;
+               pclk = to_clk_hw_omap(hw);
+       } while (pclk && !pclk->dpll_data);
+
+       /* clk does not have a DPLL as a parent?  error in the clock data */
+       if (!pclk) {
+               WARN_ON(1);
+               return NULL;
+       }
+
+       return pclk;
+}
+
 /**
  * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
  * @clk: DPLL output struct clk
@@ -637,27 +663,14 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        unsigned long rate;
        u32 v;
        struct clk_hw_omap *pclk = NULL;
-       struct clk *parent;
 
        if (!parent_rate)
                return 0;
 
-       /* Walk up the parents of clk, looking for a DPLL */
-       do {
-               do {
-                       parent = __clk_get_parent(hw->clk);
-                       hw = __clk_get_hw(parent);
-               } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
-               if (!hw)
-                       break;
-               pclk = to_clk_hw_omap(hw);
-       } while (pclk && !pclk->dpll_data);
+       pclk = omap3_find_clkoutx2_dpll(hw);
 
-       /* clk does not have a DPLL as a parent?  error in the clock data */
-       if (!pclk) {
-               WARN_ON(1);
+       if (!pclk)
                return 0;
-       }
 
        dd = pclk->dpll_data;
 
@@ -672,6 +685,55 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        return rate;
 }
 
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate)
+{
+       return 0;
+}
+
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       const struct dpll_data *dd;
+       u32 v;
+       struct clk_hw_omap *pclk = NULL;
+
+       if (!*prate)
+               return 0;
+
+       pclk = omap3_find_clkoutx2_dpll(hw);
+
+       if (!pclk)
+               return 0;
+
+       dd = pclk->dpll_data;
+
+       /* TYPE J does not have a clkoutx2 */
+       if (dd->flags & DPLL_J_TYPE) {
+               *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate);
+               return *prate;
+       }
+
+       WARN_ON(!dd->enable_mask);
+
+       v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
+       v >>= __ffs(dd->enable_mask);
+
+       /* If in bypass, the rate is fixed to the bypass rate*/
+       if (v != OMAP3XXX_EN_DPLL_LOCKED)
+               return *prate;
+
+       if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+               unsigned long best_parent;
+
+               best_parent = (rate / 2);
+               *prate = __clk_round_rate(__clk_get_parent(hw->clk),
+                               best_parent);
+       }
+
+       return *prate * 2;
+}
+
 /* OMAP3/4 non-CORE DPLL clkops */
 const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
        .allow_idle     = omap3_dpll_allow_idle,
index 42d81885c700c498babd2dd2e5d322e3af2c3f19..1f33f5db10d5a2dde0d90bd29f1eb6fce9b65995 100644 (file)
@@ -1946,30 +1946,32 @@ static int _ocp_softreset(struct omap_hwmod *oh)
        if (ret)
                goto dis_opt_clks;
 
-       _write_sysconfig(v, oh);
-       ret = _clear_softreset(oh, &v);
-       if (ret)
-               goto dis_opt_clks;
-
        _write_sysconfig(v, oh);
 
        if (oh->class->sysc->srst_udelay)
                udelay(oh->class->sysc->srst_udelay);
 
        c = _wait_softreset_complete(oh);
-       if (c == MAX_MODULE_SOFTRESET_WAIT)
+       if (c == MAX_MODULE_SOFTRESET_WAIT) {
                pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
                           oh->name, MAX_MODULE_SOFTRESET_WAIT);
-       else
+               ret = -ETIMEDOUT;
+               goto dis_opt_clks;
+       } else {
                pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
+       }
+
+       ret = _clear_softreset(oh, &v);
+       if (ret)
+               goto dis_opt_clks;
+
+       _write_sysconfig(v, oh);
 
        /*
         * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
         * _wait_target_ready() or _reset()
         */
 
-       ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
-
 dis_opt_clks:
        if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
                _disable_optional_clocks(oh);
index 18f333c440db3b72ff49577ef71d24b64dbcc916..810c205d668bfa5040ed2ad0458b412eb83b538e 100644 (file)
@@ -1365,11 +1365,10 @@ static struct omap_hwmod_class_sysconfig dra7xx_spinlock_sysc = {
        .rev_offs       = 0x0000,
        .sysc_offs      = 0x0010,
        .syss_offs      = 0x0014,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
        .sysc_fields    = &omap_hwmod_sysc_type1,
 };
 
index 3d5b24dcd9a41e2b7f4c16052bc2d931de74a0e4..c33e07e2f0d4e3d01b9e58e6347d4ca42ed81a18 100644 (file)
@@ -22,6 +22,8 @@
 #include "common-board-devices.h"
 #include "dss-common.h"
 #include "control.h"
+#include "omap-secure.h"
+#include "soc.h"
 
 struct pdata_init {
        const char *compatible;
@@ -169,6 +171,22 @@ static void __init am3517_evm_legacy_init(void)
        omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
        omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
 }
+
+static void __init nokia_n900_legacy_init(void)
+{
+       hsmmc2_internal_input_clk();
+
+       if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
+               if (IS_ENABLED(CONFIG_ARM_ERRATA_430973)) {
+                       pr_info("RX-51: Enabling ARM errata 430973 workaround\n");
+                       /* set IBE to 1 */
+                       rx51_secure_update_aux_cr(BIT(6), 0);
+               } else {
+                       pr_warning("RX-51: Not enabling ARM errata 430973 workaround\n");
+                       pr_warning("Thumb binaries may crash randomly without this workaround\n");
+               }
+       }
+}
 #endif /* CONFIG_ARCH_OMAP3 */
 
 #ifdef CONFIG_ARCH_OMAP4
@@ -239,6 +257,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #endif
 #ifdef CONFIG_ARCH_OMAP3
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata),
+       OF_DEV_AUXDATA("ti,omap3-padconf", 0x480025a0, "480025a0.pinmux", &pcs_pdata),
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002a00, "48002a00.pinmux", &pcs_pdata),
        /* Only on am3517 */
        OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
@@ -259,7 +278,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 static struct pdata_init pdata_quirks[] __initdata = {
 #ifdef CONFIG_ARCH_OMAP3
        { "compulab,omap3-sbc-t3730", omap3_sbc_t3730_legacy_init, },
-       { "nokia,omap3-n900", hsmmc2_internal_input_clk, },
+       { "nokia,omap3-n900", nokia_n900_legacy_init, },
        { "nokia,omap3-n9", hsmmc2_internal_input_clk, },
        { "nokia,omap3-n950", hsmmc2_internal_input_clk, },
        { "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
index 6334b96b4097b6977ae29047040bf6990aed06a7..280f3c58abe505c9047e6027071ec8bafd720c57 100644 (file)
@@ -183,11 +183,11 @@ void omap4_prminst_global_warm_sw_reset(void)
                                        OMAP4_PRM_RSTCTRL_OFFSET);
        v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
        omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
-                                OMAP4430_PRM_DEVICE_INST,
+                                dev_inst,
                                 OMAP4_PRM_RSTCTRL_OFFSET);
 
        /* OCP barrier */
        v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
-                                   OMAP4430_PRM_DEVICE_INST,
+                                   dev_inst,
                                    OMAP4_PRM_RSTCTRL_OFFSET);
 }
index 29905b127ad988b68ec02a09b441cb48e9c59704..41f27f667ca89ccebdf0bd9b54b63f34922eb60a 100644 (file)
@@ -885,9 +885,6 @@ static int viper_cpufreq_notifier(struct notifier_block *nb,
                        viper_set_core_cpu_voltage(freq->new, 0);
                }
                break;
-       case CPUFREQ_RESUMECHANGE:
-               viper_set_core_cpu_voltage(freq->new, 0);
-               break;
        default:
                /* ignore */
                break;
index f33679d2d3ee0a218d280972c5f409f0b561d41b..50e1d850ee2e01d6f29ee5004af4339f40c712b0 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __ASM_ARCH_COLLIE_H
 #define __ASM_ARCH_COLLIE_H
 
+#include "hardware.h" /* Gives GPIO_MAX */
+
 extern void locomolcd_power(int on);
 
 #define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
index 05fa505df5850d0de63d013e9ebdecfdea1461e4..f6db7dcae3f4dd044bc8ffea87cbd7779dd4602b 100644 (file)
@@ -24,17 +24,21 @@ comment "Renesas ARM SoCs System Type"
 
 config ARCH_EMEV2
        bool "Emma Mobile EV2"
+       select SYS_SUPPORTS_EM_STI
 
 config ARCH_R7S72100
        bool "RZ/A1H (R7S72100)"
+       select SYS_SUPPORTS_SH_MTU2
 
 config ARCH_R8A7790
        bool "R-Car H2 (R8A77900)"
        select RENESAS_IRQC
+       select SYS_SUPPORTS_SH_CMT
 
 config ARCH_R8A7791
        bool "R-Car M2 (R8A77910)"
        select RENESAS_IRQC
+       select SYS_SUPPORTS_SH_CMT
 
 comment "Renesas ARM SoCs Board Type"
 
@@ -68,6 +72,8 @@ config ARCH_SH7372
        select ARM_CPU_SUSPEND if PM || CPU_IDLE
        select CPU_V7
        select SH_CLK_CPG
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_TMU
 
 config ARCH_SH73A0
        bool "SH-Mobile AG5 (R8A73A00)"
@@ -77,6 +83,8 @@ config ARCH_SH73A0
        select I2C
        select SH_CLK_CPG
        select RENESAS_INTC_IRQPIN
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_TMU
 
 config ARCH_R8A73A4
        bool "R-Mobile APE6 (R8A73A40)"
@@ -87,6 +95,8 @@ config ARCH_R8A73A4
        select RENESAS_IRQC
        select ARCH_HAS_CPUFREQ
        select ARCH_HAS_OPP
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_TMU
 
 config ARCH_R8A7740
        bool "R-Mobile A1 (R8A77400)"
@@ -95,6 +105,8 @@ config ARCH_R8A7740
        select CPU_V7
        select SH_CLK_CPG
        select RENESAS_INTC_IRQPIN
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_TMU
 
 config ARCH_R8A7778
        bool "R-Car M1A (R8A77781)"
@@ -104,6 +116,7 @@ config ARCH_R8A7778
        select ARM_GIC
        select USB_ARCH_HAS_EHCI
        select USB_ARCH_HAS_OHCI
+       select SYS_SUPPORTS_SH_TMU
 
 config ARCH_R8A7779
        bool "R-Car H1 (R8A77790)"
@@ -114,6 +127,7 @@ config ARCH_R8A7779
        select USB_ARCH_HAS_EHCI
        select USB_ARCH_HAS_OHCI
        select RENESAS_INTC_IRQPIN
+       select SYS_SUPPORTS_SH_TMU
 
 config ARCH_R8A7790
        bool "R-Car H2 (R8A77900)"
@@ -123,6 +137,7 @@ config ARCH_R8A7790
        select MIGHT_HAVE_PCI
        select SH_CLK_CPG
        select RENESAS_IRQC
+       select SYS_SUPPORTS_SH_CMT
 
 config ARCH_R8A7791
        bool "R-Car M2 (R8A77910)"
@@ -132,6 +147,7 @@ config ARCH_R8A7791
        select MIGHT_HAVE_PCI
        select SH_CLK_CPG
        select RENESAS_IRQC
+       select SYS_SUPPORTS_SH_CMT
 
 config ARCH_EMEV2
        bool "Emma Mobile EV2"
@@ -141,6 +157,7 @@ config ARCH_EMEV2
        select MIGHT_HAVE_PCI
        select USE_OF
        select AUTO_ZRELADDR
+       select SYS_SUPPORTS_EM_STI
 
 config ARCH_R7S72100
        bool "RZ/A1H (R7S72100)"
@@ -148,6 +165,7 @@ config ARCH_R7S72100
        select ARM_GIC
        select CPU_V7
        select SH_CLK_CPG
+       select SYS_SUPPORTS_SH_MTU2
 
 comment "Renesas ARM SoCs Board Type"
 
@@ -321,24 +339,6 @@ config SHMOBILE_TIMER_HZ
          want to select a HZ value such as 128 that can evenly divide RCLK.
          A HZ value that does not divide evenly may cause timer drift.
 
-config SH_TIMER_CMT
-       bool "CMT timer driver"
-       default y
-       help
-         This enables build of the CMT timer driver.
-
-config SH_TIMER_TMU
-       bool "TMU timer driver"
-       default y
-       help
-         This enables build of the TMU timer driver.
-
-config EM_TIMER_STI
-       bool "STI timer driver"
-       default y
-       help
-         This enables build of the STI timer driver.
-
 endmenu
 
 endif
index 93533e2710a83927d1935799ce56410bb26d098f..9323854242ca10f8bf0f8f1956ae79828d4505a2 100644 (file)
@@ -988,14 +988,12 @@ static struct asoc_simple_card_info fsi_wm8978_info = {
        .card           = "FSI2A-WM8978",
        .codec          = "wm8978.0-001a",
        .platform       = "sh_fsi2",
-       .daifmt         = SND_SOC_DAIFMT_I2S,
+       .daifmt         = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
        .cpu_dai = {
                .name   = "fsia-dai",
-               .fmt    = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
        },
        .codec_dai = {
                .name   = "wm8978-hifi",
-               .fmt    = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
                .sysclk = 12288000,
        },
 };
index c475220545f2a1c11180330d99ba31fa97099f91..74c27d9d690092d62e0cfdc2f4a9e70797c9cada 100644 (file)
@@ -429,14 +429,12 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
                .card           = "SSI56-AK4643",
                .codec          = "ak4642-codec.0-0012",
                .platform       = "rcar_sound",
-               .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+               .daifmt         = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
                .cpu_dai = {
                        .name   = "rsnd-dai.0",
-                       .fmt    = SND_SOC_DAIFMT_CBS_CFS,
                },
                .codec_dai = {
                        .name   = "ak4642-hifi",
-                       .fmt    = SND_SOC_DAIFMT_CBM_CFM,
                        .sysclk = 11289600,
                },
        },
@@ -446,10 +444,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
                .card           = "SSI3-AK4554(playback)",
                .codec          = "ak4554-adc-dac.0",
                .platform       = "rcar_sound",
+               .daifmt         = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
                .cpu_dai = {
                        .name   = "rsnd-dai.1",
-                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
-                                 SND_SOC_DAIFMT_RIGHT_J,
                },
                .codec_dai = {
                        .name   = "ak4554-hifi",
@@ -461,10 +458,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
                .card           = "SSI4-AK4554(capture)",
                .codec          = "ak4554-adc-dac.0",
                .platform       = "rcar_sound",
+               .daifmt         = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
                .cpu_dai = {
                        .name   = "rsnd-dai.2",
-                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
-                                 SND_SOC_DAIFMT_LEFT_J,
                },
                .codec_dai = {
                        .name   = "ak4554-hifi",
@@ -476,10 +472,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
                .card           = "SSI7-AK4554(playback)",
                .codec          = "ak4554-adc-dac.1",
                .platform       = "rcar_sound",
+               .daifmt         = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
                .cpu_dai = {
                        .name   = "rsnd-dai.3",
-                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
-                                 SND_SOC_DAIFMT_RIGHT_J,
                },
                .codec_dai = {
                        .name   = "ak4554-hifi",
@@ -491,10 +486,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
                .card           = "SSI8-AK4554(capture)",
                .codec          = "ak4554-adc-dac.1",
                .platform       = "rcar_sound",
+               .daifmt         = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
                .cpu_dai = {
                        .name   = "rsnd-dai.4",
-                       .fmt    = SND_SOC_DAIFMT_CBM_CFM |
-                                 SND_SOC_DAIFMT_LEFT_J,
                },
                .codec_dai = {
                        .name   = "ak4554-hifi",
index bc40b853ffd3cff2204bdfdc283863a9577f51bc..03dc3ac84502edd8f83aa51820ef1a05f24f9648 100644 (file)
@@ -589,14 +589,12 @@ static struct asoc_simple_card_info fsi2_ak4648_info = {
        .card           = "FSI2A-AK4648",
        .codec          = "ak4642-codec.0-0012",
        .platform       = "sh_fsi2",
-       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
        .cpu_dai = {
                .name   = "fsia-dai",
-               .fmt    = SND_SOC_DAIFMT_CBS_CFS,
        },
        .codec_dai = {
                .name   = "ak4642-hifi",
-               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
                .sysclk = 11289600,
        },
 };
index 3aba0372f6305b7458e87dcffa9b27c8c515425e..0ff4d8e45cf7d9a2a7dc5974756b43d14256b1c8 100644 (file)
@@ -509,9 +509,9 @@ static struct asoc_simple_card_info fsi2_hdmi_info = {
        .card           = "FSI2B-HDMI",
        .codec          = "sh-mobile-hdmi",
        .platform       = "sh_fsi2",
+       .daifmt         = SND_SOC_DAIFMT_CBS_CFS,
        .cpu_dai = {
                .name   = "fsib-dai",
-               .fmt    = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
        },
        .codec_dai = {
                .name   = "sh_mobile_hdmi-hifi",
@@ -905,14 +905,12 @@ static struct asoc_simple_card_info fsi2_ak4643_info = {
        .card           = "FSI2A-AK4643",
        .codec          = "ak4642-codec.0-0013",
        .platform       = "sh_fsi2",
-       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
        .cpu_dai = {
                .name   = "fsia-dai",
-               .fmt    = SND_SOC_DAIFMT_CBS_CFS,
        },
        .codec_dai = {
                .name   = "ak4642-hifi",
-               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
                .sysclk = 11289600,
        },
 };
index 7ad003001ab7639e71b4df8309b73707a25df98e..824b12a56a422dc8c6b941b16746027305b80a98 100644 (file)
@@ -28,6 +28,7 @@
 static void __init spear1310_dt_init(void)
 {
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+       platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
 }
 
 static const char * const spear1310_dt_board_compat[] = {
index 3fb6834247298c32cbe2b82542f79a159cc6d74a..7b6bff7154e11ee81f6f5be1e962df81665e888c 100644 (file)
@@ -143,6 +143,7 @@ static void __init spear1340_dt_init(void)
 {
        of_platform_populate(NULL, of_default_bus_match_table,
                        spear1340_auxdata_lookup, NULL);
+       platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
 }
 
 static const char * const spear1340_dt_board_compat[] = {
index 0f362b64fb878c02a03d4647ba7076353631b926..3ec74ac95bc1c1087c04776c0c1b2e6176273f4f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel, U300 machine.
 #
 
-obj-y          := core.o timer.o
+obj-y          := core.o
 obj-m          :=
 obj-n          :=
 obj-           :=
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
deleted file mode 100644 (file)
index fe08fd3..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/timer.c
- *
- *
- * Copyright (C) 2007-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Timer COH 901 328, runs the OS timer interrupt.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/clockchips.h>
-#include <linux/clocksource.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/sched_clock.h>
-
-/* Generic stuff */
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-/*
- * APP side special timer registers
- * This timer contains four timers which can fire an interrupt each.
- * OS (operating system) timer @ 32768 Hz
- * DD (device driver) timer @ 1 kHz
- * GP1 (general purpose 1) timer @ 1MHz
- * GP2 (general purpose 2) timer @ 1MHz
- */
-
-/* Reset OS Timer 32bit (-/W) */
-#define U300_TIMER_APP_ROST                                    (0x0000)
-#define U300_TIMER_APP_ROST_TIMER_RESET                                (0x00000000)
-/* Enable OS Timer 32bit (-/W) */
-#define U300_TIMER_APP_EOST                                    (0x0004)
-#define U300_TIMER_APP_EOST_TIMER_ENABLE                       (0x00000000)
-/* Disable OS Timer 32bit (-/W) */
-#define U300_TIMER_APP_DOST                                    (0x0008)
-#define U300_TIMER_APP_DOST_TIMER_DISABLE                      (0x00000000)
-/* OS Timer Mode Register 32bit (-/W) */
-#define U300_TIMER_APP_SOSTM                                   (0x000c)
-#define U300_TIMER_APP_SOSTM_MODE_CONTINUOUS                   (0x00000000)
-#define U300_TIMER_APP_SOSTM_MODE_ONE_SHOT                     (0x00000001)
-/* OS Timer Status Register 32bit (R/-) */
-#define U300_TIMER_APP_OSTS                                    (0x0010)
-#define U300_TIMER_APP_OSTS_TIMER_STATE_MASK                   (0x0000000F)
-#define U300_TIMER_APP_OSTS_TIMER_STATE_IDLE                   (0x00000001)
-#define U300_TIMER_APP_OSTS_TIMER_STATE_ACTIVE                 (0x00000002)
-#define U300_TIMER_APP_OSTS_ENABLE_IND                         (0x00000010)
-#define U300_TIMER_APP_OSTS_MODE_MASK                          (0x00000020)
-#define U300_TIMER_APP_OSTS_MODE_CONTINUOUS                    (0x00000000)
-#define U300_TIMER_APP_OSTS_MODE_ONE_SHOT                      (0x00000020)
-#define U300_TIMER_APP_OSTS_IRQ_ENABLED_IND                    (0x00000040)
-#define U300_TIMER_APP_OSTS_IRQ_PENDING_IND                    (0x00000080)
-/* OS Timer Current Count Register 32bit (R/-) */
-#define U300_TIMER_APP_OSTCC                                   (0x0014)
-/* OS Timer Terminal Count Register 32bit (R/W) */
-#define U300_TIMER_APP_OSTTC                                   (0x0018)
-/* OS Timer Interrupt Enable Register 32bit (-/W) */
-#define U300_TIMER_APP_OSTIE                                   (0x001c)
-#define U300_TIMER_APP_OSTIE_IRQ_DISABLE                       (0x00000000)
-#define U300_TIMER_APP_OSTIE_IRQ_ENABLE                                (0x00000001)
-/* OS Timer Interrupt Acknowledge Register 32bit (-/W) */
-#define U300_TIMER_APP_OSTIA                                   (0x0020)
-#define U300_TIMER_APP_OSTIA_IRQ_ACK                           (0x00000080)
-
-/* Reset DD Timer 32bit (-/W) */
-#define U300_TIMER_APP_RDDT                                    (0x0040)
-#define U300_TIMER_APP_RDDT_TIMER_RESET                                (0x00000000)
-/* Enable DD Timer 32bit (-/W) */
-#define U300_TIMER_APP_EDDT                                    (0x0044)
-#define U300_TIMER_APP_EDDT_TIMER_ENABLE                       (0x00000000)
-/* Disable DD Timer 32bit (-/W) */
-#define U300_TIMER_APP_DDDT                                    (0x0048)
-#define U300_TIMER_APP_DDDT_TIMER_DISABLE                      (0x00000000)
-/* DD Timer Mode Register 32bit (-/W) */
-#define U300_TIMER_APP_SDDTM                                   (0x004c)
-#define U300_TIMER_APP_SDDTM_MODE_CONTINUOUS                   (0x00000000)
-#define U300_TIMER_APP_SDDTM_MODE_ONE_SHOT                     (0x00000001)
-/* DD Timer Status Register 32bit (R/-) */
-#define U300_TIMER_APP_DDTS                                    (0x0050)
-#define U300_TIMER_APP_DDTS_TIMER_STATE_MASK                   (0x0000000F)
-#define U300_TIMER_APP_DDTS_TIMER_STATE_IDLE                   (0x00000001)
-#define U300_TIMER_APP_DDTS_TIMER_STATE_ACTIVE                 (0x00000002)
-#define U300_TIMER_APP_DDTS_ENABLE_IND                         (0x00000010)
-#define U300_TIMER_APP_DDTS_MODE_MASK                          (0x00000020)
-#define U300_TIMER_APP_DDTS_MODE_CONTINUOUS                    (0x00000000)
-#define U300_TIMER_APP_DDTS_MODE_ONE_SHOT                      (0x00000020)
-#define U300_TIMER_APP_DDTS_IRQ_ENABLED_IND                    (0x00000040)
-#define U300_TIMER_APP_DDTS_IRQ_PENDING_IND                    (0x00000080)
-/* DD Timer Current Count Register 32bit (R/-) */
-#define U300_TIMER_APP_DDTCC                                   (0x0054)
-/* DD Timer Terminal Count Register 32bit (R/W) */
-#define U300_TIMER_APP_DDTTC                                   (0x0058)
-/* DD Timer Interrupt Enable Register 32bit (-/W) */
-#define U300_TIMER_APP_DDTIE                                   (0x005c)
-#define U300_TIMER_APP_DDTIE_IRQ_DISABLE                       (0x00000000)
-#define U300_TIMER_APP_DDTIE_IRQ_ENABLE                                (0x00000001)
-/* DD Timer Interrupt Acknowledge Register 32bit (-/W) */
-#define U300_TIMER_APP_DDTIA                                   (0x0060)
-#define U300_TIMER_APP_DDTIA_IRQ_ACK                           (0x00000080)
-
-/* Reset GP1 Timer 32bit (-/W) */
-#define U300_TIMER_APP_RGPT1                                   (0x0080)
-#define U300_TIMER_APP_RGPT1_TIMER_RESET                       (0x00000000)
-/* Enable GP1 Timer 32bit (-/W) */
-#define U300_TIMER_APP_EGPT1                                   (0x0084)
-#define U300_TIMER_APP_EGPT1_TIMER_ENABLE                      (0x00000000)
-/* Disable GP1 Timer 32bit (-/W) */
-#define U300_TIMER_APP_DGPT1                                   (0x0088)
-#define U300_TIMER_APP_DGPT1_TIMER_DISABLE                     (0x00000000)
-/* GP1 Timer Mode Register 32bit (-/W) */
-#define U300_TIMER_APP_SGPT1M                                  (0x008c)
-#define U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS                  (0x00000000)
-#define U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT                    (0x00000001)
-/* GP1 Timer Status Register 32bit (R/-) */
-#define U300_TIMER_APP_GPT1S                                   (0x0090)
-#define U300_TIMER_APP_GPT1S_TIMER_STATE_MASK                  (0x0000000F)
-#define U300_TIMER_APP_GPT1S_TIMER_STATE_IDLE                  (0x00000001)
-#define U300_TIMER_APP_GPT1S_TIMER_STATE_ACTIVE                        (0x00000002)
-#define U300_TIMER_APP_GPT1S_ENABLE_IND                                (0x00000010)
-#define U300_TIMER_APP_GPT1S_MODE_MASK                         (0x00000020)
-#define U300_TIMER_APP_GPT1S_MODE_CONTINUOUS                   (0x00000000)
-#define U300_TIMER_APP_GPT1S_MODE_ONE_SHOT                     (0x00000020)
-#define U300_TIMER_APP_GPT1S_IRQ_ENABLED_IND                   (0x00000040)
-#define U300_TIMER_APP_GPT1S_IRQ_PENDING_IND                   (0x00000080)
-/* GP1 Timer Current Count Register 32bit (R/-) */
-#define U300_TIMER_APP_GPT1CC                                  (0x0094)
-/* GP1 Timer Terminal Count Register 32bit (R/W) */
-#define U300_TIMER_APP_GPT1TC                                  (0x0098)
-/* GP1 Timer Interrupt Enable Register 32bit (-/W) */
-#define U300_TIMER_APP_GPT1IE                                  (0x009c)
-#define U300_TIMER_APP_GPT1IE_IRQ_DISABLE                      (0x00000000)
-#define U300_TIMER_APP_GPT1IE_IRQ_ENABLE                       (0x00000001)
-/* GP1 Timer Interrupt Acknowledge Register 32bit (-/W) */
-#define U300_TIMER_APP_GPT1IA                                  (0x00a0)
-#define U300_TIMER_APP_GPT1IA_IRQ_ACK                          (0x00000080)
-
-/* Reset GP2 Timer 32bit (-/W) */
-#define U300_TIMER_APP_RGPT2                                   (0x00c0)
-#define U300_TIMER_APP_RGPT2_TIMER_RESET                       (0x00000000)
-/* Enable GP2 Timer 32bit (-/W) */
-#define U300_TIMER_APP_EGPT2                                   (0x00c4)
-#define U300_TIMER_APP_EGPT2_TIMER_ENABLE                      (0x00000000)
-/* Disable GP2 Timer 32bit (-/W) */
-#define U300_TIMER_APP_DGPT2                                   (0x00c8)
-#define U300_TIMER_APP_DGPT2_TIMER_DISABLE                     (0x00000000)
-/* GP2 Timer Mode Register 32bit (-/W) */
-#define U300_TIMER_APP_SGPT2M                                  (0x00cc)
-#define U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS                  (0x00000000)
-#define U300_TIMER_APP_SGPT2M_MODE_ONE_SHOT                    (0x00000001)
-/* GP2 Timer Status Register 32bit (R/-) */
-#define U300_TIMER_APP_GPT2S                                   (0x00d0)
-#define U300_TIMER_APP_GPT2S_TIMER_STATE_MASK                  (0x0000000F)
-#define U300_TIMER_APP_GPT2S_TIMER_STATE_IDLE                  (0x00000001)
-#define U300_TIMER_APP_GPT2S_TIMER_STATE_ACTIVE                        (0x00000002)
-#define U300_TIMER_APP_GPT2S_ENABLE_IND                                (0x00000010)
-#define U300_TIMER_APP_GPT2S_MODE_MASK                         (0x00000020)
-#define U300_TIMER_APP_GPT2S_MODE_CONTINUOUS                   (0x00000000)
-#define U300_TIMER_APP_GPT2S_MODE_ONE_SHOT                     (0x00000020)
-#define U300_TIMER_APP_GPT2S_IRQ_ENABLED_IND                   (0x00000040)
-#define U300_TIMER_APP_GPT2S_IRQ_PENDING_IND                   (0x00000080)
-/* GP2 Timer Current Count Register 32bit (R/-) */
-#define U300_TIMER_APP_GPT2CC                                  (0x00d4)
-/* GP2 Timer Terminal Count Register 32bit (R/W) */
-#define U300_TIMER_APP_GPT2TC                                  (0x00d8)
-/* GP2 Timer Interrupt Enable Register 32bit (-/W) */
-#define U300_TIMER_APP_GPT2IE                                  (0x00dc)
-#define U300_TIMER_APP_GPT2IE_IRQ_DISABLE                      (0x00000000)
-#define U300_TIMER_APP_GPT2IE_IRQ_ENABLE                       (0x00000001)
-/* GP2 Timer Interrupt Acknowledge Register 32bit (-/W) */
-#define U300_TIMER_APP_GPT2IA                                  (0x00e0)
-#define U300_TIMER_APP_GPT2IA_IRQ_ACK                          (0x00000080)
-
-/* Clock request control register - all four timers */
-#define U300_TIMER_APP_CRC                                     (0x100)
-#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE                        (0x00000001)
-
-static void __iomem *u300_timer_base;
-
-struct u300_clockevent_data {
-       struct clock_event_device cevd;
-       unsigned ticks_per_jiffy;
-};
-
-/*
- * The u300_set_mode() function is always called first, if we
- * have oneshot timer active, the oneshot scheduling function
- * u300_set_next_event() is called immediately after.
- */
-static void u300_set_mode(enum clock_event_mode mode,
-                         struct clock_event_device *evt)
-{
-       struct u300_clockevent_data *cevdata =
-               container_of(evt, struct u300_clockevent_data, cevd);
-
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               /* Disable interrupts on GPT1 */
-               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
-                      u300_timer_base + U300_TIMER_APP_GPT1IE);
-               /* Disable GP1 while we're reprogramming it. */
-               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
-                      u300_timer_base + U300_TIMER_APP_DGPT1);
-               /*
-                * Set the periodic mode to a certain number of ticks per
-                * jiffy.
-                */
-               writel(cevdata->ticks_per_jiffy,
-                      u300_timer_base + U300_TIMER_APP_GPT1TC);
-               /*
-                * Set continuous mode, so the timer keeps triggering
-                * interrupts.
-                */
-               writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
-                      u300_timer_base + U300_TIMER_APP_SGPT1M);
-               /* Enable timer interrupts */
-               writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
-                      u300_timer_base + U300_TIMER_APP_GPT1IE);
-               /* Then enable the OS timer again */
-               writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
-                      u300_timer_base + U300_TIMER_APP_EGPT1);
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               /* Just break; here? */
-               /*
-                * The actual event will be programmed by the next event hook,
-                * so we just set a dummy value somewhere at the end of the
-                * universe here.
-                */
-               /* Disable interrupts on GPT1 */
-               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
-                      u300_timer_base + U300_TIMER_APP_GPT1IE);
-               /* Disable GP1 while we're reprogramming it. */
-               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
-                      u300_timer_base + U300_TIMER_APP_DGPT1);
-               /*
-                * Expire far in the future, u300_set_next_event() will be
-                * called soon...
-                */
-               writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC);
-               /* We run one shot per tick here! */
-               writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
-                      u300_timer_base + U300_TIMER_APP_SGPT1M);
-               /* Enable interrupts for this timer */
-               writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
-                      u300_timer_base + U300_TIMER_APP_GPT1IE);
-               /* Enable timer */
-               writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
-                      u300_timer_base + U300_TIMER_APP_EGPT1);
-               break;
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-               /* Disable interrupts on GP1 */
-               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
-                      u300_timer_base + U300_TIMER_APP_GPT1IE);
-               /* Disable GP1 */
-               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
-                      u300_timer_base + U300_TIMER_APP_DGPT1);
-               break;
-       case CLOCK_EVT_MODE_RESUME:
-               /* Ignore this call */
-               break;
-       }
-}
-
-/*
- * The app timer in one shot mode obviously has to be reprogrammed
- * in EXACTLY this sequence to work properly. Do NOT try to e.g. replace
- * the interrupt disable + timer disable commands with a reset command,
- * it will fail miserably. Apparently (and I found this the hard way)
- * the timer is very sensitive to the instruction order, though you don't
- * get that impression from the data sheet.
- */
-static int u300_set_next_event(unsigned long cycles,
-                              struct clock_event_device *evt)
-
-{
-       /* Disable interrupts on GPT1 */
-       writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
-              u300_timer_base + U300_TIMER_APP_GPT1IE);
-       /* Disable GP1 while we're reprogramming it. */
-       writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
-              u300_timer_base + U300_TIMER_APP_DGPT1);
-       /* Reset the General Purpose timer 1. */
-       writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
-              u300_timer_base + U300_TIMER_APP_RGPT1);
-       /* IRQ in n * cycles */
-       writel(cycles, u300_timer_base + U300_TIMER_APP_GPT1TC);
-       /*
-        * We run one shot per tick here! (This is necessary to reconfigure,
-        * the timer will tilt if you don't!)
-        */
-       writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
-              u300_timer_base + U300_TIMER_APP_SGPT1M);
-       /* Enable timer interrupts */
-       writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
-              u300_timer_base + U300_TIMER_APP_GPT1IE);
-       /* Then enable the OS timer again */
-       writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
-              u300_timer_base + U300_TIMER_APP_EGPT1);
-       return 0;
-}
-
-static struct u300_clockevent_data u300_clockevent_data = {
-       /* Use general purpose timer 1 as clock event */
-       .cevd = {
-               .name           = "GPT1",
-               /* Reasonably fast and accurate clock event */
-               .rating         = 300,
-               .features       = CLOCK_EVT_FEAT_PERIODIC |
-                       CLOCK_EVT_FEAT_ONESHOT,
-               .set_next_event = u300_set_next_event,
-               .set_mode       = u300_set_mode,
-       },
-};
-
-/* Clock event timer interrupt handler */
-static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = &u300_clockevent_data.cevd;
-       /* ACK/Clear timer IRQ for the APP GPT1 Timer */
-
-       writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
-               u300_timer_base + U300_TIMER_APP_GPT1IA);
-       evt->event_handler(evt);
-       return IRQ_HANDLED;
-}
-
-static struct irqaction u300_timer_irq = {
-       .name           = "U300 Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = u300_timer_interrupt,
-};
-
-/*
- * Override the global weak sched_clock symbol with this
- * local implementation which uses the clocksource to get some
- * better resolution when scheduling the kernel. We accept that
- * this wraps around for now, since it is just a relative time
- * stamp. (Inspired by OMAP implementation.)
- */
-
-static u64 notrace u300_read_sched_clock(void)
-{
-       return readl(u300_timer_base + U300_TIMER_APP_GPT2CC);
-}
-
-static unsigned long u300_read_current_timer(void)
-{
-       return readl(u300_timer_base + U300_TIMER_APP_GPT2CC);
-}
-
-static struct delay_timer u300_delay_timer;
-
-/*
- * This sets up the system timers, clock source and clock event.
- */
-static void __init u300_timer_init_of(struct device_node *np)
-{
-       unsigned int irq;
-       struct clk *clk;
-       unsigned long rate;
-
-       u300_timer_base = of_iomap(np, 0);
-       if (!u300_timer_base)
-               panic("could not ioremap system timer\n");
-
-       /* Get the IRQ for the GP1 timer */
-       irq = irq_of_parse_and_map(np, 2);
-       if (!irq)
-               panic("no IRQ for system timer\n");
-
-       pr_info("U300 GP1 timer @ base: %p, IRQ: %u\n", u300_timer_base, irq);
-
-       /* Clock the interrupt controller */
-       clk = of_clk_get(np, 0);
-       BUG_ON(IS_ERR(clk));
-       clk_prepare_enable(clk);
-       rate = clk_get_rate(clk);
-
-       u300_clockevent_data.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
-
-       sched_clock_register(u300_read_sched_clock, 32, rate);
-
-       u300_delay_timer.read_current_timer = &u300_read_current_timer;
-       u300_delay_timer.freq = rate;
-       register_current_timer_delay(&u300_delay_timer);
-
-       /*
-        * Disable the "OS" and "DD" timers - these are designed for Symbian!
-        * Example usage in cnh1601578 cpu subsystem pd_timer_app.c
-        */
-       writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE,
-               u300_timer_base + U300_TIMER_APP_CRC);
-       writel(U300_TIMER_APP_ROST_TIMER_RESET,
-               u300_timer_base + U300_TIMER_APP_ROST);
-       writel(U300_TIMER_APP_DOST_TIMER_DISABLE,
-               u300_timer_base + U300_TIMER_APP_DOST);
-       writel(U300_TIMER_APP_RDDT_TIMER_RESET,
-               u300_timer_base + U300_TIMER_APP_RDDT);
-       writel(U300_TIMER_APP_DDDT_TIMER_DISABLE,
-               u300_timer_base + U300_TIMER_APP_DDDT);
-
-       /* Reset the General Purpose timer 1. */
-       writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
-               u300_timer_base + U300_TIMER_APP_RGPT1);
-
-       /* Set up the IRQ handler */
-       setup_irq(irq, &u300_timer_irq);
-
-       /* Reset the General Purpose timer 2 */
-       writel(U300_TIMER_APP_RGPT2_TIMER_RESET,
-               u300_timer_base + U300_TIMER_APP_RGPT2);
-       /* Set this timer to run around forever */
-       writel(0xFFFFFFFFU, u300_timer_base + U300_TIMER_APP_GPT2TC);
-       /* Set continuous mode so it wraps around */
-       writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS,
-              u300_timer_base + U300_TIMER_APP_SGPT2M);
-       /* Disable timer interrupts */
-       writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE,
-               u300_timer_base + U300_TIMER_APP_GPT2IE);
-       /* Then enable the GP2 timer to use as a free running us counter */
-       writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
-               u300_timer_base + U300_TIMER_APP_EGPT2);
-
-       /* Use general purpose timer 2 as clock source */
-       if (clocksource_mmio_init(u300_timer_base + U300_TIMER_APP_GPT2CC,
-                       "GPT2", rate, 300, 32, clocksource_mmio_readl_up))
-               pr_err("timer: failed to initialize U300 clock source\n");
-
-       /* Configure and register the clockevent */
-       clockevents_config_and_register(&u300_clockevent_data.cevd, rate,
-                                       1, 0xffffffff);
-
-       /*
-        * TODO: init and register the rest of the timers too, they can be
-        * used by hrtimers!
-        */
-}
-
-CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer",
-                      u300_timer_init_of);
index 6b04260aa142da12e290b20aab00a35cc105d364..f03e75bd0b2b232f9afdfbbd4ea30e5da95a0adf 100644 (file)
@@ -2,6 +2,8 @@ config ARCH_ZYNQ
        bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7
        select ARM_AMBA
        select ARM_GIC
+       select ARCH_HAS_CPUFREQ
+       select ARCH_HAS_OPP
        select COMMON_CLK
        select CPU_V7
        select GENERIC_CLOCKEVENTS
@@ -13,6 +15,6 @@ config ARCH_ZYNQ
        select HAVE_SMP
        select SPARSE_IRQ
        select CADENCE_TTC_TIMER
-       select ARM_GLOBAL_TIMER
+       select ARM_GLOBAL_TIMER if !CPU_FREQ
        help
          Support for Xilinx Zynq ARM Cortex A9 Platform
index 8c09a8393fb63056a171e12351e3a52d35d5de4d..a39be8e8085607c49156af97a4ba46462e0dac26 100644 (file)
@@ -64,6 +64,8 @@ static struct platform_device zynq_cpuidle_device = {
  */
 static void __init zynq_init_machine(void)
 {
+       struct platform_device_info devinfo = { .name = "cpufreq-cpu0", };
+
        /*
         * 64KB way size, 8-way associativity, parity disabled
         */
@@ -72,6 +74,7 @@ static void __init zynq_init_machine(void)
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 
        platform_device_register(&zynq_cpuidle_device);
+       platform_device_register_full(&devinfo);
 }
 
 static void __init zynq_timer_init(void)
index 2b3a56414271e5e31323566676097b774fca9406..ef69152f9b52e473796829545bf5cf5d1e83926a 100644 (file)
@@ -264,6 +264,9 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
                        note_page(st, addr, 3, pmd_val(*pmd));
                else
                        walk_pte(st, pmd, addr);
+
+               if (SECTION_SIZE < PMD_SIZE && pmd_large(pmd[1]))
+                       note_page(st, addr + SECTION_SIZE, 3, pmd_val(pmd[1]));
        }
 }
 
index 27bbcfc7202a8df09f6ec35cd3939f0f5c26edfd..07aa3556952cd773adf64d1ff8d2e2a63f8e3faa 100644 (file)
@@ -16,6 +16,7 @@ config ARM64
        select DCACHE_WORD_ACCESS
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+       select GENERIC_CPU_AUTOPROBE
        select GENERIC_IOMAP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
@@ -26,6 +27,7 @@ config ARM64
        select GENERIC_TIME_VSYSCALL
        select HARDIRQS_SW_RESEND
        select HAVE_ARCH_JUMP_LABEL
+       select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DEBUG_BUGVERBOSE
        select HAVE_DEBUG_KMEMLEAK
@@ -38,6 +40,8 @@ config ARM64
        select HAVE_MEMBLOCK
        select HAVE_PATA_PLATFORM
        select HAVE_PERF_EVENTS
+       select HAVE_PERF_REGS
+       select HAVE_PERF_USER_STACK_DUMP
        select IRQ_DOMAIN
        select MODULES_USE_ELF_RELA
        select NO_BOOTMEM
@@ -73,7 +77,7 @@ config LOCKDEP_SUPPORT
 config TRACE_IRQFLAGS_SUPPORT
        def_bool y
 
-config RWSEM_GENERIC_SPINLOCK
+config RWSEM_XCHGADD_ALGORITHM
        def_bool y
 
 config GENERIC_HWEIGHT
@@ -85,7 +89,7 @@ config GENERIC_CSUM
 config GENERIC_CALIBRATE_DELAY
        def_bool y
 
-config ZONE_DMA32
+config ZONE_DMA
        def_bool y
 
 config ARCH_DMA_ADDR_T_64BIT
@@ -164,6 +168,22 @@ config SMP
 
          If you don't know what to do here, say N.
 
+config SCHED_MC
+       bool "Multi-core scheduler support"
+       depends on SMP
+       help
+         Multi-core scheduler support improves the CPU scheduler's decision
+         making when dealing with multi-core CPU chips at a cost of slightly
+         increased overhead in some places. If unsure say N here.
+
+config SCHED_SMT
+       bool "SMT scheduler support"
+       depends on SMP
+       help
+         Improves the CPU scheduler's decision making when dealing with
+         MultiThreading at a cost of slightly increased overhead in some
+         places. If unsure say N here.
+
 config NR_CPUS
        int "Maximum number of CPUs (2-32)"
        range 2 32
@@ -301,6 +321,16 @@ menu "CPU Power Management"
 
 source "drivers/cpuidle/Kconfig"
 
+source "drivers/cpufreq/Kconfig"
+
+endmenu
+
+menu "Power management options"
+
+source "kernel/power/Kconfig"
+
+source "drivers/cpufreq/Kconfig"
+
 endmenu
 
 source "net/Kconfig"
index d37d7369e260f3f7d2564711217f6d6ac19a859a..93f4b2dd92484863e8015da4a622a0c17745de5a 100644 (file)
                                reg-names = "csr-reg";
                                clock-output-names = "eth8clk";
                        };
+
+                       sataphy1clk: sataphy1clk@1f21c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f21c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sataphy1clk";
+                               status = "disabled";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x00>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x06>;
+                       };
+
+                       sataphy2clk: sataphy1clk@1f22c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f22c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sataphy2clk";
+                               status = "ok";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x3a>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x06>;
+                       };
+
+                       sataphy3clk: sataphy1clk@1f23c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f23c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sataphy3clk";
+                               status = "ok";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x3a>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x06>;
+                       };
+
+                       sata01clk: sata01clk@1f21c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f21c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sata01clk";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x05>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x39>;
+                       };
+
+                       sata23clk: sata23clk@1f22c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f22c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sata23clk";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x05>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x39>;
+                       };
+
+                       sata45clk: sata45clk@1f23c000 {
+                               compatible = "apm,xgene-device-clock";
+                               #clock-cells = <1>;
+                               clocks = <&socplldiv2 0>;
+                               reg = <0x0 0x1f23c000 0x0 0x1000>;
+                               reg-names = "csr-reg";
+                               clock-output-names = "sata45clk";
+                               csr-offset = <0x4>;
+                               csr-mask = <0x05>;
+                               enable-offset = <0x0>;
+                               enable-mask = <0x39>;
+                       };
                };
 
                serial0: serial@1c020000 {
                        interrupt-parent = <&gic>;
                        interrupts = <0x0 0x4c 0x4>;
                };
+
+               phy1: phy@1f21a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f21a000 0x0 0x100>;
+                       #phy-cells = <1>;
+                       clocks = <&sataphy1clk 0>;
+                       status = "disabled";
+                       apm,tx-boost-gain = <30 30 30 30 30 30>;
+                       apm,tx-eye-tuning = <2 10 10 2 10 10>;
+               };
+
+               phy2: phy@1f22a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f22a000 0x0 0x100>;
+                       #phy-cells = <1>;
+                       clocks = <&sataphy2clk 0>;
+                       status = "ok";
+                       apm,tx-boost-gain = <30 30 30 30 30 30>;
+                       apm,tx-eye-tuning = <1 10 10 2 10 10>;
+               };
+
+               phy3: phy@1f23a000 {
+                       compatible = "apm,xgene-phy";
+                       reg = <0x0 0x1f23a000 0x0 0x100>;
+                       #phy-cells = <1>;
+                       clocks = <&sataphy3clk 0>;
+                       status = "ok";
+                       apm,tx-boost-gain = <31 31 31 31 31 31>;
+                       apm,tx-eye-tuning = <2 10 10 2 10 10>;
+               };
+
+               sata1: sata@1a000000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a000000 0x0 0x1000>,
+                             <0x0 0x1f210000 0x0 0x1000>,
+                             <0x0 0x1f21d000 0x0 0x1000>,
+                             <0x0 0x1f21e000 0x0 0x1000>,
+                             <0x0 0x1f217000 0x0 0x1000>;
+                       interrupts = <0x0 0x86 0x4>;
+                       status = "disabled";
+                       clocks = <&sata01clk 0>;
+                       phys = <&phy1 0>;
+                       phy-names = "sata-phy";
+               };
+
+               sata2: sata@1a400000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a400000 0x0 0x1000>,
+                             <0x0 0x1f220000 0x0 0x1000>,
+                             <0x0 0x1f22d000 0x0 0x1000>,
+                             <0x0 0x1f22e000 0x0 0x1000>,
+                             <0x0 0x1f227000 0x0 0x1000>;
+                       interrupts = <0x0 0x87 0x4>;
+                       status = "ok";
+                       clocks = <&sata23clk 0>;
+                       phys = <&phy2 0>;
+                       phy-names = "sata-phy";
+               };
+
+               sata3: sata@1a800000 {
+                       compatible = "apm,xgene-ahci";
+                       reg = <0x0 0x1a800000 0x0 0x1000>,
+                             <0x0 0x1f230000 0x0 0x1000>,
+                             <0x0 0x1f23d000 0x0 0x1000>,
+                             <0x0 0x1f23e000 0x0 0x1000>;
+                       interrupts = <0x0 0x88 0x4>;
+                       status = "ok";
+                       clocks = <&sata45clk 0>;
+                       phys = <&phy3 0>;
+                       phy-names = "sata-phy";
+               };
        };
 };
index 71c53ecfcc3ae356f0c5d0bd4c593e3b7bef8b89..4bca4923fc0b7eef27e37532358fe7eb48aa1224 100644 (file)
@@ -12,6 +12,7 @@ generic-y += dma.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += ftrace.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -22,13 +23,16 @@ generic-y += kmap_types.h
 generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += msgbuf.h
 generic-y += mutex.h
 generic-y += pci.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
+generic-y += rwsem.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += segment.h
@@ -38,8 +42,8 @@ generic-y += shmbuf.h
 generic-y += sizes.h
 generic-y += socket.h
 generic-y += sockios.h
-generic-y += switch_to.h
 generic-y += swab.h
+generic-y += switch_to.h
 generic-y += termbits.h
 generic-y += termios.h
 generic-y += topology.h
@@ -49,5 +53,3 @@ generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 409ca370cfe2ddccd245efc3f3b0a20fe2360d49..66eb7648043bc9c1ba6383b0e2187a74c8dc8d5c 100644 (file)
@@ -25,6 +25,7 @@
 #define wfi()          asm volatile("wfi" : : : "memory")
 
 #define isb()          asm volatile("isb" : : : "memory")
+#define dmb(opt)       asm volatile("dmb sy" : : : "memory")
 #define dsb(opt)       asm volatile("dsb sy" : : : "memory")
 
 #define mb()           dsb()
index 889324981aa4f569a77e6a5385897b6493c85526..4c60e64a801c5cf3a3c5e379a3270ea3ff31eea5 100644 (file)
@@ -84,6 +84,13 @@ static inline void flush_cache_page(struct vm_area_struct *vma,
 {
 }
 
+/*
+ * Cache maintenance functions used by the DMA API. No to be used directly.
+ */
+extern void __dma_map_area(const void *, size_t, int);
+extern void __dma_unmap_area(const void *, size_t, int);
+extern void __dma_flush_range(const void *, const void *);
+
 /*
  * Copy user data from/to a page which is mapped into a different
  * processes address space.  Really, we want to allow our "user
index fda2704b3f9f9a49354e12dc6b55aaa81638cd5a..e71f81fe127a504838ba86c5290d99ce10b5411f 100644 (file)
@@ -228,7 +228,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
        return (u32)(unsigned long)uptr;
 }
 
-#define compat_user_stack_pointer() (current_pt_regs()->compat_sp)
+#define compat_user_stack_pointer() (user_stack_pointer(current_pt_regs()))
 
 static inline void __user *arch_compat_alloc_user_space(long len)
 {
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
new file mode 100644 (file)
index 0000000..cd4ac05
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_CPUFEATURE_H
+#define __ASM_CPUFEATURE_H
+
+#include <asm/hwcap.h>
+
+/*
+ * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
+ * in the kernel and for user space to keep track of which optional features
+ * are supported by the current system. So let's map feature 'x' to HWCAP_x.
+ * Note that HWCAP_x constants are bit fields so we need to take the log.
+ */
+
+#define MAX_CPU_FEATURES       (8 * sizeof(elf_hwcap))
+#define cpu_feature(x)         ilog2(HWCAP_ ## x)
+
+static inline bool cpu_have_feature(unsigned int num)
+{
+       return elf_hwcap & (1UL << num);
+}
+
+#endif
index 62314791570cbdda16b7e575c2aa7fc48ed5d45a..6e9b5b36921cce2d26276d12c5379514b420f2ff 100644 (file)
 #define DBG_ESR_EVT_HWWP       0x2
 #define DBG_ESR_EVT_BRK                0x6
 
+/*
+ * Break point instruction encoding
+ */
+#define BREAK_INSTR_SIZE               4
+
+/*
+ * ESR values expected for dynamic and compile time BRK instruction
+ */
+#define DBG_ESR_VAL_BRK(x)     (0xf2000000 | ((x) & 0xfffff))
+
+/*
+ * #imm16 values used for BRK instruction generation
+ * Allowed values for kgbd are 0x400 - 0x7ff
+ * 0x400: for dynamic BRK instruction
+ * 0x401: for compile time BRK instruction
+ */
+#define KGDB_DYN_DGB_BRK_IMM           0x400
+#define KDBG_COMPILED_DBG_BRK_IMM      0x401
+
+/*
+ * BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+#define AARCH64_BREAK_MON      0xd4200000
+
+/*
+ * Extract byte from BRK instruction
+ */
+#define KGDB_DYN_DGB_BRK_INS_BYTE(x) \
+       ((((AARCH64_BREAK_MON) & 0xffe0001f) >> (x * 8)) & 0xff)
+
+/*
+ * Extract byte from BRK #imm16
+ */
+#define KGBD_DYN_DGB_BRK_IMM_BYTE(x) \
+       (((((KGDB_DYN_DGB_BRK_IMM) & 0xffff) << 5) >> (x * 8)) & 0xff)
+
+#define KGDB_DYN_DGB_BRK_BYTE(x) \
+       (KGDB_DYN_DGB_BRK_INS_BYTE(x) | KGBD_DYN_DGB_BRK_IMM_BYTE(x))
+
+#define  KGDB_DYN_BRK_INS_BYTE0  KGDB_DYN_DGB_BRK_BYTE(0)
+#define  KGDB_DYN_BRK_INS_BYTE1  KGDB_DYN_DGB_BRK_BYTE(1)
+#define  KGDB_DYN_BRK_INS_BYTE2  KGDB_DYN_DGB_BRK_BYTE(2)
+#define  KGDB_DYN_BRK_INS_BYTE3  KGDB_DYN_DGB_BRK_BYTE(3)
+
+#define CACHE_FLUSH_IS_SAFE            1
+
 enum debug_el {
        DBG_ACTIVE_EL0 = 0,
        DBG_ACTIVE_EL1,
@@ -43,23 +90,6 @@ enum debug_el {
 #ifndef __ASSEMBLY__
 struct task_struct;
 
-#define local_dbg_save(flags)                                                  \
-       do {                                                                    \
-               typecheck(unsigned long, flags);                                \
-               asm volatile(                                                   \
-               "mrs    %0, daif                        // local_dbg_save\n"    \
-               "msr    daifset, #8"                                            \
-               : "=r" (flags) : : "memory");                                   \
-       } while (0)
-
-#define local_dbg_restore(flags)                                               \
-       do {                                                                    \
-               typecheck(unsigned long, flags);                                \
-               asm volatile(                                                   \
-               "msr    daif, %0                        // local_dbg_restore\n" \
-               : : "r" (flags) : "memory");                                    \
-       } while (0)
-
 #define DBG_ARCH_ID_RESERVED   0       /* In case of ptrace ABI updates. */
 
 #define DBG_HOOK_HANDLED       0
index fd0c0c0e447a657115c116f45bf9edd693b339a3..3a4572ec3273267c04334057b944739fe56d73e2 100644 (file)
@@ -30,6 +30,8 @@
 
 #define DMA_ERROR_CODE (~(dma_addr_t)0)
 extern struct dma_map_ops *dma_ops;
+extern struct dma_map_ops coherent_swiotlb_dma_ops;
+extern struct dma_map_ops noncoherent_swiotlb_dma_ops;
 
 static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
 {
@@ -47,6 +49,11 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
                return __generic_dma_ops(dev);
 }
 
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+       dev->archdata.dma_ops = ops;
+}
+
 #include <asm-generic/dma-mapping-common.h>
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
index 6cddbb0c9f5459cff851101fd3010ad74882a1ef..024c46183c3cc4bac07977ffcdade60c2567ea98 100644 (file)
 #define COMPAT_HWCAP_IDIV      (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
 #define COMPAT_HWCAP_EVTSTRM   (1 << 21)
 
+#define COMPAT_HWCAP2_AES      (1 << 0)
+#define COMPAT_HWCAP2_PMULL    (1 << 1)
+#define COMPAT_HWCAP2_SHA1     (1 << 2)
+#define COMPAT_HWCAP2_SHA2     (1 << 3)
+#define COMPAT_HWCAP2_CRC32    (1 << 4)
+
 #ifndef __ASSEMBLY__
 /*
  * This yields a mask that user programs can use to figure out what
@@ -41,7 +47,8 @@
 
 #ifdef CONFIG_COMPAT
 #define COMPAT_ELF_HWCAP       (compat_elf_hwcap)
-extern unsigned int compat_elf_hwcap;
+#define COMPAT_ELF_HWCAP2      (compat_elf_hwcap2)
+extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
 #endif
 
 extern unsigned long elf_hwcap;
index 4cc813eddacbebee4c84f864f103bb6492d7c193..7846a6bb08334dec2833ef8c09d60373a55fe3fa 100644 (file)
@@ -121,7 +121,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
  *  I/O port access primitives.
  */
 #define IO_SPACE_LIMIT         0xffff
-#define PCI_IOBASE             ((void __iomem *)(MODULES_VADDR - SZ_2M))
+#define PCI_IOBASE             ((void __iomem *)(MODULES_VADDR - SZ_32M))
 
 static inline u8 inb(unsigned long addr)
 {
index b2fcfbc51ecc4b0eaef6e4b20efd0f7afd2a9efd..11cc941bd107b5cb2457101ea15ac772e2eb699a 100644 (file)
@@ -90,5 +90,28 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
        return flags & PSR_I_BIT;
 }
 
+/*
+ * save and restore debug state
+ */
+#define local_dbg_save(flags)                                          \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               asm volatile(                                           \
+               "mrs    %0, daif                // local_dbg_save\n"    \
+               "msr    daifset, #8"                                    \
+               : "=r" (flags) : : "memory");                           \
+       } while (0)
+
+#define local_dbg_restore(flags)                                       \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               asm volatile(                                           \
+               "msr    daif, %0                // local_dbg_restore\n" \
+               : : "r" (flags) : "memory");                            \
+       } while (0)
+
+#define local_dbg_enable()     asm("msr        daifclr, #8" : : : "memory")
+#define local_dbg_disable()    asm("msr        daifset, #8" : : : "memory")
+
 #endif
 #endif
diff --git a/arch/arm64/include/asm/kgdb.h b/arch/arm64/include/asm/kgdb.h
new file mode 100644 (file)
index 0000000..3c8aafc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * AArch64 KGDB support
+ *
+ * Based on arch/arm/include/kgdb.h
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.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_KGDB_H
+#define __ARM_KGDB_H
+
+#include <linux/ptrace.h>
+#include <asm/debug-monitors.h>
+
+#ifndef        __ASSEMBLY__
+
+static inline void arch_kgdb_breakpoint(void)
+{
+       asm ("brk %0" : : "I" (KDBG_COMPILED_DBG_BRK_IMM));
+}
+
+extern void kgdb_handle_bus_error(void);
+extern int kgdb_fault_expected;
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * gdb is expecting the following registers layout.
+ *
+ * General purpose regs:
+ *     r0-r30: 64 bit
+ *     sp,pc : 64 bit
+ *     pstate  : 64 bit
+ *     Total: 34
+ * FPU regs:
+ *     f0-f31: 128 bit
+ *     Total: 32
+ * Extra regs
+ *     fpsr & fpcr: 32 bit
+ *     Total: 2
+ *
+ */
+
+#define _GP_REGS               34
+#define _FP_REGS               32
+#define _EXTRA_REGS            2
+/*
+ * general purpose registers size in bytes.
+ * pstate is only 4 bytes. subtract 4 bytes
+ */
+#define GP_REG_BYTES           (_GP_REGS * 8)
+#define DBG_MAX_REG_NUM                (_GP_REGS + _FP_REGS + _EXTRA_REGS)
+
+/*
+ * Size of I/O buffer for gdb packet.
+ * considering to hold all register contents, size is set
+ */
+
+#define BUFMAX                 2048
+
+/*
+ * Number of bytes required for gdb_regs buffer.
+ * _GP_REGS: 8 bytes, _FP_REGS: 16 bytes and _EXTRA_REGS: 4 bytes each
+ * GDB fails to connect for size beyond this with error
+ * "'g' packet reply is too long"
+ */
+
+#define NUMREGBYTES    ((_GP_REGS * 8) + (_FP_REGS * 16) + \
+                       (_EXTRA_REGS * 4))
+
+#endif /* __ASM_KGDB_H */
index 0eb39865537839c202879251fbb60f919328d58e..21ef48d32ff271fbdccba7f2df710b021f9db7e0 100644 (file)
 
 /* 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)
  * 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 VTCR_EL2_FLAGS         (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
 /*
  * 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 VTCR_EL2_FLAGS         (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
 
index b1d2e26c3c883e7259f0ab679efe33ffe2935429..f7af66b54cb216931f23718cc75754d269acefc4 100644 (file)
 #define PTE_HYP                        PTE_USER
 
 /*
- * 40-bit physical address supported.
+ * Highest possible physical address supported.
  */
-#define PHYS_MASK_SHIFT                (40)
+#define PHYS_MASK_SHIFT                (48)
 #define PHYS_MASK              ((UL(1) << PHYS_MASK_SHIFT) - 1)
 
 /*
 #define TCR_SHARED             ((UL(3) << 12) | (UL(3) << 28))
 #define TCR_TG0_64K            (UL(1) << 14)
 #define TCR_TG1_64K            (UL(1) << 30)
-#define TCR_IPS_40BIT          (UL(2) << 32)
 #define TCR_ASID16             (UL(1) << 36)
 #define TCR_TBI0               (UL(1) << 37)
 
index aa3917c8b62318aef9424735d560be305f3465d3..90c811f05a2e3279a8709211a770725141491dd7 100644 (file)
@@ -199,7 +199,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
        if (pte_valid_user(pte)) {
-               if (pte_exec(pte))
+               if (!pte_special(pte) && pte_exec(pte))
                        __sync_icache_dcache(pte, addr);
                if (pte_dirty(pte) && pte_write(pte))
                        pte_val(pte) &= ~PTE_RDONLY;
@@ -227,36 +227,36 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 
 #define __HAVE_ARCH_PTE_SPECIAL
 
-/*
- * Software PMD bits for THP
- */
+static inline pte_t pmd_pte(pmd_t pmd)
+{
+       return __pte(pmd_val(pmd));
+}
 
-#define PMD_SECT_DIRTY         (_AT(pmdval_t, 1) << 55)
-#define PMD_SECT_SPLITTING     (_AT(pmdval_t, 1) << 57)
+static inline pmd_t pte_pmd(pte_t pte)
+{
+       return __pmd(pte_val(pte));
+}
 
 /*
  * 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)
+#define pmd_trans_splitting(pmd)       pte_special(pmd_pte(pmd))
 #endif
 
-#define PMD_BIT_FUNC(fn,op) \
-static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+#define pmd_young(pmd)         pte_young(pmd_pte(pmd))
+#define pmd_wrprotect(pmd)     pte_pmd(pte_wrprotect(pmd_pte(pmd)))
+#define pmd_mksplitting(pmd)   pte_pmd(pte_mkspecial(pmd_pte(pmd)))
+#define pmd_mkold(pmd)         pte_pmd(pte_mkold(pmd_pte(pmd)))
+#define pmd_mkwrite(pmd)       pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+#define pmd_mkdirty(pmd)       pte_pmd(pte_mkdirty(pmd_pte(pmd)))
+#define pmd_mkyoung(pmd)       pte_pmd(pte_mkyoung(pmd_pte(pmd)))
+#define pmd_mknotpresent(pmd)  (__pmd(pmd_val(pmd) &= ~PMD_TYPE_MASK))
 
-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 __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd)         pte_write(pmd_pte(pmd))
 
 #define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
 
@@ -266,15 +266,6 @@ PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
 
 #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)
@@ -286,11 +277,9 @@ static inline int has_transparent_hugepage(void)
  * Mark the prot value as uncacheable and unbufferable.
  */
 #define pgprot_noncached(prot) \
-       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
 #define pgprot_writecombine(prot) \
-       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
-#define pgprot_dmacoherent(prot) \
-       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
 #define __HAVE_PHYS_MEM_ACCESS_PROT
 struct file;
 extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
@@ -383,6 +372,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
        return pte;
 }
 
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+       return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
+}
+
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
 
index e5312ea0ec1a59bdd92934926da81155a6ce3e12..d15ab8b463360869553f4ecfa4cc255d4c8455e3 100644 (file)
@@ -14,6 +14,6 @@
 #ifndef __ASM_PSCI_H
 #define __ASM_PSCI_H
 
-int psci_init(void);
+void psci_init(void);
 
 #endif /* __ASM_PSCI_H */
index 0e7fa49637359ab3cd4757565174d4e63f191cf0..c7ba261dd4b37b8b1ecb1a06d5a4fe7b583a3d92 100644 (file)
@@ -68,6 +68,7 @@
 
 /* Architecturally defined mapping between AArch32 and AArch64 registers */
 #define compat_usr(x)  regs[(x)]
+#define compat_fp      regs[11]
 #define compat_sp      regs[13]
 #define compat_lr      regs[14]
 #define compat_sp_hyp  regs[15]
@@ -132,7 +133,7 @@ struct pt_regs {
        (!((regs)->pstate & PSR_F_BIT))
 
 #define user_stack_pointer(regs) \
-       ((regs)->sp)
+       (!compat_user_mode(regs)) ? ((regs)->sp) : ((regs)->compat_sp)
 
 /*
  * Are the current registers suitable for user mode? (used to maintain
@@ -164,7 +165,7 @@ static inline int valid_user_regs(struct user_pt_regs *regs)
        return 0;
 }
 
-#define instruction_pointer(regs)      (regs)->pc
+#define instruction_pointer(regs)      ((unsigned long)(regs)->pc)
 
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
index 717031a762c27966aabc7786f6d2a900034b0b08..72cadf52ca807f181261b1599b25944374de5544 100644 (file)
 #ifndef __ASM_TLB_H
 #define __ASM_TLB_H
 
-#include <linux/pagemap.h>
-#include <linux/swap.h>
 
-#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
-
-#define MMU_GATHER_BUNDLE      8
-
-/*
- * TLB handling.  This allows us to remove pages from the page
- * tables, and efficiently handle the TLB issues.
- */
-struct mmu_gather {
-       struct mm_struct        *mm;
-       unsigned int            fullmm;
-       struct vm_area_struct   *vma;
-       unsigned long           start, end;
-       unsigned long           range_start;
-       unsigned long           range_end;
-       unsigned int            nr;
-       unsigned int            max;
-       struct page             **pages;
-       struct page             *local[MMU_GATHER_BUNDLE];
-};
+#include <asm-generic/tlb.h>
 
 /*
- * This is unnecessarily complex.  There's three ways the TLB shootdown
- * code is used:
+ * There's three ways the TLB shootdown code is used:
  *  1. Unmapping a range of vmas.  See zap_page_range(), unmap_region().
  *     tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
- *     tlb->vma will be non-NULL.
  *  2. Unmapping all vmas.  See exit_mmap().
  *     tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
- *     tlb->vma will be non-NULL.  Additionally, page tables will be freed.
+ *     Page tables will be freed.
  *  3. Unmapping argument pages.  See shift_arg_pages().
  *     tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
- *     tlb->vma will be NULL.
  */
 static inline void tlb_flush(struct mmu_gather *tlb)
 {
-       if (tlb->fullmm || !tlb->vma)
+       if (tlb->fullmm) {
                flush_tlb_mm(tlb->mm);
-       else if (tlb->range_end > 0) {
-               flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
-               tlb->range_start = TASK_SIZE;
-               tlb->range_end = 0;
+       } else if (tlb->end > 0) {
+               struct vm_area_struct vma = { .vm_mm = tlb->mm, };
+               flush_tlb_range(&vma, tlb->start, tlb->end);
+               tlb->start = TASK_SIZE;
+               tlb->end = 0;
        }
 }
 
 static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
 {
        if (!tlb->fullmm) {
-               if (addr < tlb->range_start)
-                       tlb->range_start = addr;
-               if (addr + PAGE_SIZE > tlb->range_end)
-                       tlb->range_end = addr + PAGE_SIZE;
-       }
-}
-
-static inline void __tlb_alloc_page(struct mmu_gather *tlb)
-{
-       unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
-
-       if (addr) {
-               tlb->pages = (void *)addr;
-               tlb->max = PAGE_SIZE / sizeof(struct page *);
+               tlb->start = min(tlb->start, addr);
+               tlb->end = max(tlb->end, addr + PAGE_SIZE);
        }
 }
 
-static inline void tlb_flush_mmu(struct mmu_gather *tlb)
-{
-       tlb_flush(tlb);
-       free_pages_and_swap_cache(tlb->pages, tlb->nr);
-       tlb->nr = 0;
-       if (tlb->pages == tlb->local)
-               __tlb_alloc_page(tlb);
-}
-
-static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-       tlb->mm = mm;
-       tlb->fullmm = !(start | (end+1));
-       tlb->start = start;
-       tlb->end = end;
-       tlb->vma = NULL;
-       tlb->max = ARRAY_SIZE(tlb->local);
-       tlb->pages = tlb->local;
-       tlb->nr = 0;
-       __tlb_alloc_page(tlb);
-}
-
-static inline void
-tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
-{
-       tlb_flush_mmu(tlb);
-
-       /* keep the page table cache within bounds */
-       check_pgt_cache();
-
-       if (tlb->pages != tlb->local)
-               free_pages((unsigned long)tlb->pages, 0);
-}
-
 /*
  * Memorize the range for the TLB flush.
  */
-static inline void
-tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
+static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
+                                         unsigned long addr)
 {
        tlb_add_flush(tlb, addr);
 }
@@ -137,38 +66,24 @@ tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
  * case where we're doing a full MM flush.  When we're doing a munmap,
  * the vmas are adjusted to only cover the region to be torn down.
  */
-static inline void
-tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+static inline void tlb_start_vma(struct mmu_gather *tlb,
+                                struct vm_area_struct *vma)
 {
        if (!tlb->fullmm) {
-               tlb->vma = vma;
-               tlb->range_start = TASK_SIZE;
-               tlb->range_end = 0;
+               tlb->start = TASK_SIZE;
+               tlb->end = 0;
        }
 }
 
-static inline void
-tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+static inline void tlb_end_vma(struct mmu_gather *tlb,
+                              struct vm_area_struct *vma)
 {
        if (!tlb->fullmm)
                tlb_flush(tlb);
 }
 
-static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
-{
-       tlb->pages[tlb->nr++] = page;
-       VM_BUG_ON(tlb->nr > tlb->max);
-       return tlb->max - tlb->nr;
-}
-
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
-{
-       if (!__tlb_remove_page(tlb, page))
-               tlb_flush_mmu(tlb);
-}
-
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
-       unsigned long addr)
+                                 unsigned long addr)
 {
        pgtable_page_dtor(pte);
        tlb_add_flush(tlb, addr);
@@ -184,16 +99,5 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
 }
 #endif
 
-#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)
-
-#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
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
new file mode 100644 (file)
index 0000000..0172e6d
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __ASM_TOPOLOGY_H
+#define __ASM_TOPOLOGY_H
+
+#ifdef CONFIG_SMP
+
+#include <linux/cpumask.h>
+
+struct cpu_topology {
+       int thread_id;
+       int core_id;
+       int cluster_id;
+       cpumask_t thread_sibling;
+       cpumask_t core_sibling;
+};
+
+extern struct cpu_topology cpu_topology[NR_CPUS];
+
+#define topology_physical_package_id(cpu)      (cpu_topology[cpu].cluster_id)
+#define topology_core_id(cpu)          (cpu_topology[cpu].core_id)
+#define topology_core_cpumask(cpu)     (&cpu_topology[cpu].core_sibling)
+#define topology_thread_cpumask(cpu)   (&cpu_topology[cpu].thread_sibling)
+
+#define mc_capable()   (cpu_topology[0].cluster_id != -1)
+#define smt_capable()  (cpu_topology[0].thread_id != -1)
+
+void init_cpu_topology(void);
+void store_cpu_topology(unsigned int cpuid);
+const struct cpumask *cpu_coregroup_mask(int cpu);
+
+#else
+
+static inline void init_cpu_topology(void) { }
+static inline void store_cpu_topology(unsigned int cpuid) { }
+
+#endif
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_ARM_TOPOLOGY_H */
index 6c0f684aca81ce2da8b71c18cf2fb659c62ceaab..3bf8f4e99a511c67a3a2d9c4a739929cedd5889f 100644 (file)
@@ -83,7 +83,7 @@ static inline void set_fs(mm_segment_t fs)
  * Returns 1 if the range is valid, 0 otherwise.
  *
  * This is equivalent to the following test:
- * (u65)addr + (u65)size < (u65)current->addr_limit
+ * (u65)addr + (u65)size <current->addr_limit
  *
  * This needs 65-bit arithmetic.
  */
@@ -91,7 +91,7 @@ static inline void set_fs(mm_segment_t fs)
 ({                                                                     \
        unsigned long flag, roksum;                                     \
        __chk_user_ptr(addr);                                           \
-       asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, cc"         \
+       asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls"         \
                : "=&r" (flag), "=&r" (roksum)                          \
                : "1" (addr), "Ir" (size),                              \
                  "r" (current_thread_info()->addr_limit)               \
index 82ce217e94cf07228e52ebbfae9e9bcdeb751de1..a4654c656a1eda3c07f682a8eda7acdfd8e18a31 100644 (file)
@@ -14,6 +14,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #ifdef CONFIG_COMPAT
+#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
 #define __ARCH_WANT_COMPAT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
index e4b78bdca19e81b373251cf228917d3a8eab0a60..942376d37d220fc359c6afc35ef3004c9a2074a2 100644 (file)
@@ -9,6 +9,7 @@ header-y += byteorder.h
 header-y += fcntl.h
 header-y += hwcap.h
 header-y += kvm_para.h
+header-y += perf_regs.h
 header-y += param.h
 header-y += ptrace.h
 header-y += setup.h
diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
new file mode 100644 (file)
index 0000000..172b831
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _ASM_ARM64_PERF_REGS_H
+#define _ASM_ARM64_PERF_REGS_H
+
+enum perf_event_arm_regs {
+       PERF_REG_ARM64_X0,
+       PERF_REG_ARM64_X1,
+       PERF_REG_ARM64_X2,
+       PERF_REG_ARM64_X3,
+       PERF_REG_ARM64_X4,
+       PERF_REG_ARM64_X5,
+       PERF_REG_ARM64_X6,
+       PERF_REG_ARM64_X7,
+       PERF_REG_ARM64_X8,
+       PERF_REG_ARM64_X9,
+       PERF_REG_ARM64_X10,
+       PERF_REG_ARM64_X11,
+       PERF_REG_ARM64_X12,
+       PERF_REG_ARM64_X13,
+       PERF_REG_ARM64_X14,
+       PERF_REG_ARM64_X15,
+       PERF_REG_ARM64_X16,
+       PERF_REG_ARM64_X17,
+       PERF_REG_ARM64_X18,
+       PERF_REG_ARM64_X19,
+       PERF_REG_ARM64_X20,
+       PERF_REG_ARM64_X21,
+       PERF_REG_ARM64_X22,
+       PERF_REG_ARM64_X23,
+       PERF_REG_ARM64_X24,
+       PERF_REG_ARM64_X25,
+       PERF_REG_ARM64_X26,
+       PERF_REG_ARM64_X27,
+       PERF_REG_ARM64_X28,
+       PERF_REG_ARM64_X29,
+       PERF_REG_ARM64_LR,
+       PERF_REG_ARM64_SP,
+       PERF_REG_ARM64_PC,
+       PERF_REG_ARM64_MAX,
+};
+#endif /* _ASM_ARM64_PERF_REGS_H */
index 2d4554b134100acbb6dab937326bdabcb12cd73e..7d811d9522bc4fca5e12b035460a56337b68f13e 100644 (file)
@@ -14,12 +14,14 @@ arm64-obj-y         := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o
 arm64-obj-$(CONFIG_MODULES)            += arm64ksyms.o module.o
-arm64-obj-$(CONFIG_SMP)                        += smp.o smp_spin_table.o
+arm64-obj-$(CONFIG_SMP)                        += smp.o smp_spin_table.o topology.o
+arm64-obj-$(CONFIG_PERF_EVENTS)                += perf_regs.o
 arm64-obj-$(CONFIG_HW_PERF_EVENTS)     += perf_event.o
-arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
+arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 arm64-obj-$(CONFIG_EARLY_PRINTK)       += early_printk.o
 arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)  += sleep.o suspend.o
 arm64-obj-$(CONFIG_JUMP_LABEL)         += jump_label.o
+arm64-obj-$(CONFIG_KGDB)               += kgdb.o
 
 obj-y                                  += $(arm64-obj-y) vdso/
 obj-m                                  += $(arm64-obj-m)
index 636ba8b6240b8042e9c49622297bbca74e140181..14ba23c6115367b962922e5decd3afabb59e789e 100644 (file)
@@ -137,7 +137,6 @@ void disable_debug_monitors(enum debug_el el)
 static void clear_os_lock(void *unused)
 {
        asm volatile("msr oslar_el1, %0" : : "r" (0));
-       isb();
 }
 
 static int os_lock_notify(struct notifier_block *self,
@@ -156,8 +155,9 @@ static struct notifier_block os_lock_nb = {
 static int debug_monitors_init(void)
 {
        /* Clear the OS lock. */
-       smp_call_function(clear_os_lock, NULL, 1);
-       clear_os_lock(NULL);
+       on_each_cpu(clear_os_lock, NULL, 1);
+       isb();
+       local_dbg_enable();
 
        /* Register hotplug handler. */
        register_cpu_notifier(&os_lock_nb);
@@ -189,7 +189,7 @@ static void clear_regs_spsr_ss(struct pt_regs *regs)
 
 /* EL1 Single Step Handler hooks */
 static LIST_HEAD(step_hook);
-DEFINE_RWLOCK(step_hook_lock);
+static DEFINE_RWLOCK(step_hook_lock);
 
 void register_step_hook(struct step_hook *hook)
 {
@@ -276,7 +276,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
  * Use reader/writer locks instead of plain spinlock.
  */
 static LIST_HEAD(break_hook);
-DEFINE_RWLOCK(break_hook_lock);
+static DEFINE_RWLOCK(break_hook_lock);
 
 void register_break_hook(struct break_hook *hook)
 {
index 0b281fffda5199dab76eeaa8f729609570fe6310..61035d6814cbcca9a7bb9be06e92e44446256f25 100644 (file)
@@ -384,26 +384,18 @@ ENDPROC(__calc_phys_offset)
  * Preserves:  tbl, flags
  * Corrupts:   phys, start, end, pstate
  */
-       .macro  create_block_map, tbl, flags, phys, start, end, idmap=0
+       .macro  create_block_map, tbl, flags, phys, start, end
        lsr     \phys, \phys, #BLOCK_SHIFT
-       .if     \idmap
-       and     \start, \phys, #PTRS_PER_PTE - 1        // table index
-       .else
        lsr     \start, \start, #BLOCK_SHIFT
        and     \start, \start, #PTRS_PER_PTE - 1       // table index
-       .endif
        orr     \phys, \flags, \phys, lsl #BLOCK_SHIFT  // table entry
-       .ifnc   \start,\end
        lsr     \end, \end, #BLOCK_SHIFT
        and     \end, \end, #PTRS_PER_PTE - 1           // table end index
-       .endif
 9999:  str     \phys, [\tbl, \start, lsl #3]           // store the entry
-       .ifnc   \start,\end
        add     \start, \start, #1                      // next entry
        add     \phys, \phys, #BLOCK_SIZE               // next block
        cmp     \start, \end
        b.ls    9999b
-       .endif
        .endm
 
 /*
@@ -435,9 +427,13 @@ __create_page_tables:
         * Create the identity mapping.
         */
        add     x0, x25, #PAGE_SIZE             // section table address
-       adr     x3, __turn_mmu_on               // virtual/physical address
+       ldr     x3, =KERNEL_START
+       add     x3, x3, x28                     // __pa(KERNEL_START)
        create_pgd_entry x25, x0, x3, x5, x6
-       create_block_map x0, x7, x3, x5, x5, idmap=1
+       ldr     x6, =KERNEL_END
+       mov     x5, x3                          // __pa(KERNEL_START)
+       add     x6, x6, x28                     // __pa(KERNEL_END)
+       create_block_map x0, x7, x3, x5, x6
 
        /*
         * Map the kernel image (starting with PHYS_OFFSET).
@@ -445,7 +441,7 @@ __create_page_tables:
        add     x0, x26, #PAGE_SIZE             // section table address
        mov     x5, #PAGE_OFFSET
        create_pgd_entry x26, x0, x5, x3, x6
-       ldr     x6, =KERNEL_END - 1
+       ldr     x6, =KERNEL_END
        mov     x3, x24                         // phys offset
        create_block_map x0, x7, x3, x5, x6
 
diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
new file mode 100644 (file)
index 0000000..75c9cf1
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * AArch64 KGDB support
+ *
+ * Based on arch/arm/kernel/kgdb.c
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.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/irq.h>
+#include <linux/kdebug.h>
+#include <linux/kgdb.h>
+#include <asm/traps.h>
+
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+       { "x0", 8, offsetof(struct pt_regs, regs[0])},
+       { "x1", 8, offsetof(struct pt_regs, regs[1])},
+       { "x2", 8, offsetof(struct pt_regs, regs[2])},
+       { "x3", 8, offsetof(struct pt_regs, regs[3])},
+       { "x4", 8, offsetof(struct pt_regs, regs[4])},
+       { "x5", 8, offsetof(struct pt_regs, regs[5])},
+       { "x6", 8, offsetof(struct pt_regs, regs[6])},
+       { "x7", 8, offsetof(struct pt_regs, regs[7])},
+       { "x8", 8, offsetof(struct pt_regs, regs[8])},
+       { "x9", 8, offsetof(struct pt_regs, regs[9])},
+       { "x10", 8, offsetof(struct pt_regs, regs[10])},
+       { "x11", 8, offsetof(struct pt_regs, regs[11])},
+       { "x12", 8, offsetof(struct pt_regs, regs[12])},
+       { "x13", 8, offsetof(struct pt_regs, regs[13])},
+       { "x14", 8, offsetof(struct pt_regs, regs[14])},
+       { "x15", 8, offsetof(struct pt_regs, regs[15])},
+       { "x16", 8, offsetof(struct pt_regs, regs[16])},
+       { "x17", 8, offsetof(struct pt_regs, regs[17])},
+       { "x18", 8, offsetof(struct pt_regs, regs[18])},
+       { "x19", 8, offsetof(struct pt_regs, regs[19])},
+       { "x20", 8, offsetof(struct pt_regs, regs[20])},
+       { "x21", 8, offsetof(struct pt_regs, regs[21])},
+       { "x22", 8, offsetof(struct pt_regs, regs[22])},
+       { "x23", 8, offsetof(struct pt_regs, regs[23])},
+       { "x24", 8, offsetof(struct pt_regs, regs[24])},
+       { "x25", 8, offsetof(struct pt_regs, regs[25])},
+       { "x26", 8, offsetof(struct pt_regs, regs[26])},
+       { "x27", 8, offsetof(struct pt_regs, regs[27])},
+       { "x28", 8, offsetof(struct pt_regs, regs[28])},
+       { "x29", 8, offsetof(struct pt_regs, regs[29])},
+       { "x30", 8, offsetof(struct pt_regs, regs[30])},
+       { "sp", 8, offsetof(struct pt_regs, sp)},
+       { "pc", 8, offsetof(struct pt_regs, pc)},
+       { "pstate", 8, offsetof(struct pt_regs, pstate)},
+       { "v0", 16, -1 },
+       { "v1", 16, -1 },
+       { "v2", 16, -1 },
+       { "v3", 16, -1 },
+       { "v4", 16, -1 },
+       { "v5", 16, -1 },
+       { "v6", 16, -1 },
+       { "v7", 16, -1 },
+       { "v8", 16, -1 },
+       { "v9", 16, -1 },
+       { "v10", 16, -1 },
+       { "v11", 16, -1 },
+       { "v12", 16, -1 },
+       { "v13", 16, -1 },
+       { "v14", 16, -1 },
+       { "v15", 16, -1 },
+       { "v16", 16, -1 },
+       { "v17", 16, -1 },
+       { "v18", 16, -1 },
+       { "v19", 16, -1 },
+       { "v20", 16, -1 },
+       { "v21", 16, -1 },
+       { "v22", 16, -1 },
+       { "v23", 16, -1 },
+       { "v24", 16, -1 },
+       { "v25", 16, -1 },
+       { "v26", 16, -1 },
+       { "v27", 16, -1 },
+       { "v28", 16, -1 },
+       { "v29", 16, -1 },
+       { "v30", 16, -1 },
+       { "v31", 16, -1 },
+       { "fpsr", 4, -1 },
+       { "fpcr", 4, -1 },
+};
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       if (regno >= DBG_MAX_REG_NUM || regno < 0)
+               return NULL;
+
+       if (dbg_reg_def[regno].offset != -1)
+               memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+                      dbg_reg_def[regno].size);
+       else
+               memset(mem, 0, dbg_reg_def[regno].size);
+       return dbg_reg_def[regno].name;
+}
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       if (regno >= DBG_MAX_REG_NUM || regno < 0)
+               return -EINVAL;
+
+       if (dbg_reg_def[regno].offset != -1)
+               memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+                      dbg_reg_def[regno].size);
+       return 0;
+}
+
+void
+sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
+{
+       struct pt_regs *thread_regs;
+
+       /* Initialize to zero */
+       memset((char *)gdb_regs, 0, NUMREGBYTES);
+       thread_regs = task_pt_regs(task);
+       memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
+}
+
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
+{
+       regs->pc = pc;
+}
+
+static int compiled_break;
+
+static void kgdb_arch_update_addr(struct pt_regs *regs,
+                               char *remcom_in_buffer)
+{
+       unsigned long addr;
+       char *ptr;
+
+       ptr = &remcom_in_buffer[1];
+       if (kgdb_hex2long(&ptr, &addr))
+               kgdb_arch_set_pc(regs, addr);
+       else if (compiled_break == 1)
+               kgdb_arch_set_pc(regs, regs->pc + 4);
+
+       compiled_break = 0;
+}
+
+int kgdb_arch_handle_exception(int exception_vector, int signo,
+                              int err_code, char *remcom_in_buffer,
+                              char *remcom_out_buffer,
+                              struct pt_regs *linux_regs)
+{
+       int err;
+
+       switch (remcom_in_buffer[0]) {
+       case 'D':
+       case 'k':
+               /*
+                * Packet D (Detach), k (kill). No special handling
+                * is required here. Handle same as c packet.
+                */
+       case 'c':
+               /*
+                * Packet c (Continue) to continue executing.
+                * Set pc to required address.
+                * Try to read optional parameter and set pc.
+                * If this was a compiled breakpoint, we need to move
+                * to the next instruction else we will just breakpoint
+                * over and over again.
+                */
+               kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
+               atomic_set(&kgdb_cpu_doing_single_step, -1);
+               kgdb_single_step =  0;
+
+               /*
+                * Received continue command, disable single step
+                */
+               if (kernel_active_single_step())
+                       kernel_disable_single_step();
+
+               err = 0;
+               break;
+       case 's':
+               /*
+                * Update step address value with address passed
+                * with step packet.
+                * On debug exception return PC is copied to ELR
+                * So just update PC.
+                * If no step address is passed, resume from the address
+                * pointed by PC. Do not update PC
+                */
+               kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
+               atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
+               kgdb_single_step =  1;
+
+               /*
+                * Enable single step handling
+                */
+               if (!kernel_active_single_step())
+                       kernel_enable_single_step(linux_regs);
+               err = 0;
+               break;
+       default:
+               err = -1;
+       }
+       return err;
+}
+
+static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+       kgdb_handle_exception(1, SIGTRAP, 0, regs);
+       return 0;
+}
+
+static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+       compiled_break = 1;
+       kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+       return 0;
+}
+
+static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+       kgdb_handle_exception(1, SIGTRAP, 0, regs);
+       return 0;
+}
+
+static struct break_hook kgdb_brkpt_hook = {
+       .esr_mask       = 0xffffffff,
+       .esr_val        = DBG_ESR_VAL_BRK(KGDB_DYN_DGB_BRK_IMM),
+       .fn             = kgdb_brk_fn
+};
+
+static struct break_hook kgdb_compiled_brkpt_hook = {
+       .esr_mask       = 0xffffffff,
+       .esr_val        = DBG_ESR_VAL_BRK(KDBG_COMPILED_DBG_BRK_IMM),
+       .fn             = kgdb_compiled_brk_fn
+};
+
+static struct step_hook kgdb_step_hook = {
+       .fn             = kgdb_step_brk_fn
+};
+
+static void kgdb_call_nmi_hook(void *ignored)
+{
+       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       local_irq_enable();
+       smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+       local_irq_disable();
+}
+
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+       struct pt_regs *regs = args->regs;
+
+       if (kgdb_handle_exception(1, args->signr, cmd, regs))
+               return NOTIFY_DONE;
+       return NOTIFY_STOP;
+}
+
+static int
+kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+       unsigned long flags;
+       int ret;
+
+       local_irq_save(flags);
+       ret = __kgdb_notify(ptr, cmd);
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+static struct notifier_block kgdb_notifier = {
+       .notifier_call  = kgdb_notify,
+       /*
+        * Want to be lowest priority
+        */
+       .priority       = -INT_MAX,
+};
+
+/*
+ * kgdb_arch_init - Perform any architecture specific initalization.
+ * This function will handle the initalization of any architecture
+ * specific callbacks.
+ */
+int kgdb_arch_init(void)
+{
+       int ret = register_die_notifier(&kgdb_notifier);
+
+       if (ret != 0)
+               return ret;
+
+       register_break_hook(&kgdb_brkpt_hook);
+       register_break_hook(&kgdb_compiled_brkpt_hook);
+       register_step_hook(&kgdb_step_hook);
+       return 0;
+}
+
+/*
+ * kgdb_arch_exit - Perform any architecture specific uninitalization.
+ * This function will handle the uninitalization of any architecture
+ * specific callbacks, for dynamic registration and unregistration.
+ */
+void kgdb_arch_exit(void)
+{
+       unregister_break_hook(&kgdb_brkpt_hook);
+       unregister_break_hook(&kgdb_compiled_brkpt_hook);
+       unregister_step_hook(&kgdb_step_hook);
+       unregister_die_notifier(&kgdb_notifier);
+}
+
+/*
+ * ARM instructions are always in LE.
+ * Break instruction is encoded in LE format
+ */
+struct kgdb_arch arch_kgdb_ops = {
+       .gdb_bpt_instr = {
+               KGDB_DYN_BRK_INS_BYTE0,
+               KGDB_DYN_BRK_INS_BYTE1,
+               KGDB_DYN_BRK_INS_BYTE2,
+               KGDB_DYN_BRK_INS_BYTE3,
+       }
+};
index 5b1cd792274a34cc620933e2258530b20cfdfa40..e868c72a79389c133559fc4c1599a197a33c195b 100644 (file)
@@ -1348,8 +1348,8 @@ early_initcall(init_hw_perf_events);
  * Callchain handling code.
  */
 struct frame_tail {
-       struct frame_tail   __user *fp;
-       unsigned long       lr;
+       struct frame_tail       __user *fp;
+       unsigned long           lr;
 } __attribute__((packed));
 
 /*
@@ -1386,22 +1386,80 @@ user_backtrace(struct frame_tail __user *tail,
        return buftail.fp;
 }
 
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct compat_frame_tail *)(xxx->fp)-1
+ *
+ * This code has been adapted from the ARM OProfile support.
+ */
+struct compat_frame_tail {
+       compat_uptr_t   fp; /* a (struct compat_frame_tail *) in compat mode */
+       u32             sp;
+       u32             lr;
+} __attribute__((packed));
+
+static struct compat_frame_tail __user *
+compat_user_backtrace(struct compat_frame_tail __user *tail,
+                     struct perf_callchain_entry *entry)
+{
+       struct compat_frame_tail buftail;
+       unsigned long err;
+
+       /* Also check accessibility of one struct frame_tail beyond */
+       if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+               return NULL;
+
+       pagefault_disable();
+       err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
+       pagefault_enable();
+
+       if (err)
+               return NULL;
+
+       perf_callchain_store(entry, buftail.lr);
+
+       /*
+        * Frame pointers should strictly progress back up the stack
+        * (towards higher addresses).
+        */
+       if (tail + 1 >= (struct compat_frame_tail __user *)
+                       compat_ptr(buftail.fp))
+               return NULL;
+
+       return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
+}
+
 void perf_callchain_user(struct perf_callchain_entry *entry,
                         struct pt_regs *regs)
 {
-       struct frame_tail __user *tail;
-
        if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
                /* We don't support guest os callchain now */
                return;
        }
 
        perf_callchain_store(entry, regs->pc);
-       tail = (struct frame_tail __user *)regs->regs[29];
 
-       while (entry->nr < PERF_MAX_STACK_DEPTH &&
-              tail && !((unsigned long)tail & 0xf))
-               tail = user_backtrace(tail, entry);
+       if (!compat_user_mode(regs)) {
+               /* AARCH64 mode */
+               struct frame_tail __user *tail;
+
+               tail = (struct frame_tail __user *)regs->regs[29];
+
+               while (entry->nr < PERF_MAX_STACK_DEPTH &&
+                      tail && !((unsigned long)tail & 0xf))
+                       tail = user_backtrace(tail, entry);
+       } else {
+               /* AARCH32 compat mode */
+               struct compat_frame_tail __user *tail;
+
+               tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
+
+               while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
+                       tail && !((unsigned long)tail & 0x3))
+                       tail = compat_user_backtrace(tail, entry);
+       }
 }
 
 /*
@@ -1429,6 +1487,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
        frame.fp = regs->regs[29];
        frame.sp = regs->sp;
        frame.pc = regs->pc;
+
        walk_stackframe(&frame, callchain_trace, entry);
 }
 
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
new file mode 100644 (file)
index 0000000..f2d6f0a
--- /dev/null
@@ -0,0 +1,44 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+       if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
+               return 0;
+
+       /*
+        * Compat (i.e. 32 bit) mode:
+        * - PC has been set in the pt_regs struct in kernel_entry,
+        * - Handle SP and LR here.
+        */
+       if (compat_user_mode(regs)) {
+               if ((u32)idx == PERF_REG_ARM64_SP)
+                       return regs->compat_sp;
+               if ((u32)idx == PERF_REG_ARM64_LR)
+                       return regs->compat_lr;
+       }
+
+       return regs->regs[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+       if (!mask || mask & REG_RESERVED)
+               return -EINVAL;
+
+       return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+       if (is_compat_thread(task_thread_info(task)))
+               return PERF_SAMPLE_REGS_ABI_32;
+       else
+               return PERF_SAMPLE_REGS_ABI_64;
+}
index 1c0a9be2ffa85ad87245ac5837c94149e246533a..6391485f342daaac57e207f129a62e28d169b114 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/kallsyms.h>
 #include <linux/init.h>
 #include <linux/cpu.h>
-#include <linux/cpuidle.h>
 #include <linux/elfcore.h>
 #include <linux/pm.h>
 #include <linux/tick.h>
@@ -72,8 +71,17 @@ static void setup_restart(void)
 
 void soft_restart(unsigned long addr)
 {
+       typedef void (*phys_reset_t)(unsigned long);
+       phys_reset_t phys_reset;
+
        setup_restart();
-       cpu_reset(addr);
+
+       /* Switch to the identity mapping */
+       phys_reset = (phys_reset_t)virt_to_phys(cpu_reset);
+       phys_reset(addr);
+
+       /* Should never get here */
+       BUG();
 }
 
 /*
@@ -94,10 +102,8 @@ void arch_cpu_idle(void)
         * This should do all the clock switching and wait for interrupt
         * tricks
         */
-       if (cpuidle_idle_call()) {
-               cpu_do_idle();
-               local_irq_enable();
-       }
+       cpu_do_idle();
+       local_irq_enable();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 4f97db3d73633294f6a6310e54e626972debc9a2..ea4828a4aa96729993d85145603ed45afba7ac03 100644 (file)
@@ -176,22 +176,20 @@ static const struct of_device_id psci_of_match[] __initconst = {
        {},
 };
 
-int __init psci_init(void)
+void __init psci_init(void)
 {
        struct device_node *np;
        const char *method;
        u32 id;
-       int err = 0;
 
        np = of_find_matching_node(NULL, psci_of_match);
        if (!np)
-               return -ENODEV;
+               return;
 
        pr_info("probing function IDs from device-tree\n");
 
        if (of_property_read_string(np, "method", &method)) {
                pr_warning("missing \"method\" property\n");
-               err = -ENXIO;
                goto out_put_node;
        }
 
@@ -201,7 +199,6 @@ int __init psci_init(void)
                invoke_psci_fn = __invoke_psci_fn_smc;
        } else {
                pr_warning("invalid \"method\" property: %s\n", method);
-               err = -EINVAL;
                goto out_put_node;
        }
 
@@ -227,7 +224,7 @@ int __init psci_init(void)
 
 out_put_node:
        of_node_put(np);
-       return err;
+       return;
 }
 
 #ifdef CONFIG_SMP
@@ -251,7 +248,7 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
 {
        int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
        if (err)
-               pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
+               pr_err("failed to boot CPU%d (%d)\n", cpu, err);
 
        return err;
 }
@@ -278,7 +275,7 @@ static void cpu_psci_cpu_die(unsigned int cpu)
 
        ret = psci_ops.cpu_off(state);
 
-       pr_crit("psci: unable to power off CPU%u (%d)\n", cpu, ret);
+       pr_crit("unable to power off CPU%u (%d)\n", cpu, ret);
 }
 #endif
 
index c8e9effe52e10f6b59d39de293aca7607f7d5bce..67da30741a1b64a73ce085739209d7bf085ac2e9 100644 (file)
@@ -69,6 +69,7 @@ EXPORT_SYMBOL_GPL(elf_hwcap);
                                 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
                                 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
 unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
+unsigned int compat_elf_hwcap2 __read_mostly;
 #endif
 
 static const char *cpu_name;
@@ -242,6 +243,38 @@ static void __init setup_processor(void)
        block = (features >> 16) & 0xf;
        if (block && !(block & 0x8))
                elf_hwcap |= HWCAP_CRC32;
+
+#ifdef CONFIG_COMPAT
+       /*
+        * ID_ISAR5_EL1 carries similar information as above, but pertaining to
+        * the Aarch32 32-bit execution state.
+        */
+       features = read_cpuid(ID_ISAR5_EL1);
+       block = (features >> 4) & 0xf;
+       if (!(block & 0x8)) {
+               switch (block) {
+               default:
+               case 2:
+                       compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL;
+               case 1:
+                       compat_elf_hwcap2 |= COMPAT_HWCAP2_AES;
+               case 0:
+                       break;
+               }
+       }
+
+       block = (features >> 8) & 0xf;
+       if (block && !(block & 0x8))
+               compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1;
+
+       block = (features >> 12) & 0xf;
+       if (block && !(block & 0x8))
+               compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2;
+
+       block = (features >> 16) & 0xf;
+       if (block && !(block & 0x8))
+               compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32;
+#endif
 }
 
 static void __init setup_machine_fdt(phys_addr_t dt_phys)
index 7cfb92a4ab66523212ec91392b6ee269fa0d97a9..f0a141dd5655817171605293d45429c740495661 100644 (file)
@@ -114,6 +114,11 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
        return ret;
 }
 
+static void smp_store_cpu_info(unsigned int cpuid)
+{
+       store_cpu_topology(cpuid);
+}
+
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
@@ -152,6 +157,8 @@ asmlinkage void secondary_start_kernel(void)
         */
        notify_cpu_starting(cpu);
 
+       smp_store_cpu_info(cpu);
+
        /*
         * OK, now it's safe to let the boot CPU continue.  Wait for
         * the CPU migration code to notice that the CPU is online
@@ -160,6 +167,7 @@ asmlinkage void secondary_start_kernel(void)
        set_cpu_online(cpu, true);
        complete(&cpu_running);
 
+       local_dbg_enable();
        local_irq_enable();
        local_async_enable();
 
@@ -390,6 +398,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        int err;
        unsigned int cpu, ncores = num_possible_cpus();
 
+       init_cpu_topology();
+
+       smp_store_cpu_info(smp_processor_id());
+
        /*
         * are we trying to boot more cores than exist?
         */
index 44c22805d2e2ad7e16895dc248bb9e861105fe07..7a530d2cc8077e7973938d1610d654644ae0ef1a 100644 (file)
@@ -128,7 +128,7 @@ static int smp_spin_table_cpu_boot(unsigned int cpu)
        return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
 }
 
-void smp_spin_table_cpu_postboot(void)
+static void smp_spin_table_cpu_postboot(void)
 {
        /*
         * Let the primary processor know we're out of the pen.
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
new file mode 100644 (file)
index 0000000..3e06b0b
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * arch/arm64/kernel/topology.c
+ *
+ * Copyright (C) 2011,2013,2014 Linaro Limited.
+ *
+ * Based on the arm32 version written by Vincent Guittot in turn based on
+ * arch/sh/kernel/topology.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/node.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+
+#include <asm/topology.h>
+
+/*
+ * cpu topology table
+ */
+struct cpu_topology cpu_topology[NR_CPUS];
+EXPORT_SYMBOL_GPL(cpu_topology);
+
+const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+       return &cpu_topology[cpu].core_sibling;
+}
+
+static void update_siblings_masks(unsigned int cpuid)
+{
+       struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
+       int cpu;
+
+       if (cpuid_topo->cluster_id == -1) {
+               /*
+                * DT does not contain topology information for this cpu
+                * reset it to default behaviour
+                */
+               pr_debug("CPU%u: No topology information configured\n", cpuid);
+               cpuid_topo->core_id = 0;
+               cpumask_set_cpu(cpuid, &cpuid_topo->core_sibling);
+               cpumask_set_cpu(cpuid, &cpuid_topo->thread_sibling);
+               return;
+       }
+
+       /* update core and thread sibling masks */
+       for_each_possible_cpu(cpu) {
+               cpu_topo = &cpu_topology[cpu];
+
+               if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
+                       continue;
+
+               cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+               if (cpu != cpuid)
+                       cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
+
+               if (cpuid_topo->core_id != cpu_topo->core_id)
+                       continue;
+
+               cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
+               if (cpu != cpuid)
+                       cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
+       }
+}
+
+void store_cpu_topology(unsigned int cpuid)
+{
+       update_siblings_masks(cpuid);
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void __init init_cpu_topology(void)
+{
+       unsigned int cpu;
+
+       /* init core mask and power*/
+       for_each_possible_cpu(cpu) {
+               struct cpu_topology *cpu_topo = &cpu_topology[cpu];
+
+               cpu_topo->thread_id = -1;
+               cpu_topo->core_id =  -1;
+               cpu_topo->cluster_id = -1;
+               cpumask_clear(&cpu_topo->core_sibling);
+               cpumask_clear(&cpu_topo->thread_sibling);
+       }
+}
index a7149cae16153bbacec32c420e1661b38b8aabd6..50384fec56c469b296dc5737bdf2733d2febb321 100644 (file)
@@ -106,49 +106,31 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
 
 static int __init vdso_init(void)
 {
-       struct page *pg;
-       char *vbase;
-       int i, ret = 0;
+       int i;
+
+       if (memcmp(&vdso_start, "\177ELF", 4)) {
+               pr_err("vDSO is not a valid ELF object!\n");
+               return -EINVAL;
+       }
 
        vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
        pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
                vdso_pages + 1, vdso_pages, 1L, &vdso_start);
 
        /* Allocate the vDSO pagelist, plus a page for the data. */
-       vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1),
+       vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
                                GFP_KERNEL);
-       if (vdso_pagelist == NULL) {
-               pr_err("Failed to allocate vDSO pagelist!\n");
+       if (vdso_pagelist == NULL)
                return -ENOMEM;
-       }
 
        /* Grab the vDSO code pages. */
-       for (i = 0; i < vdso_pages; i++) {
-               pg = virt_to_page(&vdso_start + i*PAGE_SIZE);
-               ClearPageReserved(pg);
-               get_page(pg);
-               vdso_pagelist[i] = pg;
-       }
-
-       /* Sanity check the shared object header. */
-       vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL);
-       if (vbase == NULL) {
-               pr_err("Failed to map vDSO pagelist!\n");
-               return -ENOMEM;
-       } else if (memcmp(vbase, "\177ELF", 4)) {
-               pr_err("vDSO is not a valid ELF object!\n");
-               ret = -EINVAL;
-               goto unmap;
-       }
+       for (i = 0; i < vdso_pages; i++)
+               vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE);
 
        /* Grab the vDSO data page. */
-       pg = virt_to_page(vdso_data);
-       get_page(pg);
-       vdso_pagelist[i] = pg;
+       vdso_pagelist[i] = virt_to_page(vdso_data);
 
-unmap:
-       vunmap(vbase);
-       return ret;
+       return 0;
 }
 arch_initcall(vdso_init);
 
index 2b0244d65c16f5c68dde0770f555bbadf4a5b073..d968796f4b2d7a88dda3605f0f16b9777879052b 100644 (file)
@@ -68,6 +68,12 @@ __do_hyp_init:
        msr     tcr_el2, x4
 
        ldr     x4, =VTCR_EL2_FLAGS
+       /*
+        * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
+        * VTCR_EL2.
+        */
+       mrs     x5, ID_AA64MMFR0_EL1
+       bfi     x4, x5, #16, #3
        msr     vtcr_el2, x4
 
        mrs     x4, mair_el1
index 1ea9f26d1b703585537d82cf30aa44ddbe879917..c46f48b33c1409d8ea6dfe3c48327a00b6376a06 100644 (file)
@@ -30,7 +30,7 @@
  *
  *     Corrupted registers: x0-x7, x9-x11
  */
-ENTRY(__flush_dcache_all)
+__flush_dcache_all:
        dsb     sy                              // ensure ordering with previous memory accesses
        mrs     x0, clidr_el1                   // read clidr
        and     x3, x0, #0x7000000              // extract loc from clidr
@@ -166,3 +166,81 @@ ENTRY(__flush_dcache_area)
        dsb     sy
        ret
 ENDPROC(__flush_dcache_area)
+
+/*
+ *     __dma_inv_range(start, end)
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+__dma_inv_range:
+       dcache_line_size x2, x3
+       sub     x3, x2, #1
+       bic     x0, x0, x3
+       bic     x1, x1, x3
+1:     dc      ivac, x0                        // invalidate D / U line
+       add     x0, x0, x2
+       cmp     x0, x1
+       b.lo    1b
+       dsb     sy
+       ret
+ENDPROC(__dma_inv_range)
+
+/*
+ *     __dma_clean_range(start, end)
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+__dma_clean_range:
+       dcache_line_size x2, x3
+       sub     x3, x2, #1
+       bic     x0, x0, x3
+1:     dc      cvac, x0                        // clean D / U line
+       add     x0, x0, x2
+       cmp     x0, x1
+       b.lo    1b
+       dsb     sy
+       ret
+ENDPROC(__dma_clean_range)
+
+/*
+ *     __dma_flush_range(start, end)
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+ENTRY(__dma_flush_range)
+       dcache_line_size x2, x3
+       sub     x3, x2, #1
+       bic     x0, x0, x3
+1:     dc      civac, x0                       // clean & invalidate D / U line
+       add     x0, x0, x2
+       cmp     x0, x1
+       b.lo    1b
+       dsb     sy
+       ret
+ENDPROC(__dma_flush_range)
+
+/*
+ *     __dma_map_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(__dma_map_area)
+       add     x1, x1, x0
+       cmp     w2, #DMA_FROM_DEVICE
+       b.eq    __dma_inv_range
+       b       __dma_clean_range
+ENDPROC(__dma_map_area)
+
+/*
+ *     __dma_unmap_area(start, size, dir)
+ *     - start - kernel virtual start address
+ *     - size  - size of region
+ *     - dir   - DMA direction
+ */
+ENTRY(__dma_unmap_area)
+       add     x1, x1, x0
+       cmp     w2, #DMA_TO_DEVICE
+       b.ne    __dma_inv_range
+       ret
+ENDPROC(__dma_unmap_area)
index fbd76785c5db640bf511a9647380ebb1ae29b3ef..0ba347e59f06a7dbfe3fe7dcc884f9435c791d6e 100644 (file)
 struct dma_map_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
-static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
-                                         dma_addr_t *dma_handle, gfp_t flags,
-                                         struct dma_attrs *attrs)
+static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
+                                bool coherent)
+{
+       if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+               return pgprot_writecombine(prot);
+       return prot;
+}
+
+static void *__dma_alloc_coherent(struct device *dev, size_t size,
+                                 dma_addr_t *dma_handle, gfp_t flags,
+                                 struct dma_attrs *attrs)
 {
        if (dev == NULL) {
                WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
                return NULL;
        }
 
-       if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+       if (IS_ENABLED(CONFIG_ZONE_DMA) &&
            dev->coherent_dma_mask <= DMA_BIT_MASK(32))
-               flags |= GFP_DMA32;
+               flags |= GFP_DMA;
        if (IS_ENABLED(CONFIG_DMA_CMA)) {
                struct page *page;
 
@@ -58,9 +66,9 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
        }
 }
 
-static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
-                                       void *vaddr, dma_addr_t dma_handle,
-                                       struct dma_attrs *attrs)
+static void __dma_free_coherent(struct device *dev, size_t size,
+                               void *vaddr, dma_addr_t dma_handle,
+                               struct dma_attrs *attrs)
 {
        if (dev == NULL) {
                WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
@@ -78,9 +86,212 @@ static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
        }
 }
 
-static struct dma_map_ops arm64_swiotlb_dma_ops = {
-       .alloc = arm64_swiotlb_alloc_coherent,
-       .free = arm64_swiotlb_free_coherent,
+static void *__dma_alloc_noncoherent(struct device *dev, size_t size,
+                                    dma_addr_t *dma_handle, gfp_t flags,
+                                    struct dma_attrs *attrs)
+{
+       struct page *page, **map;
+       void *ptr, *coherent_ptr;
+       int order, i;
+
+       size = PAGE_ALIGN(size);
+       order = get_order(size);
+
+       ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs);
+       if (!ptr)
+               goto no_mem;
+       map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA);
+       if (!map)
+               goto no_map;
+
+       /* remove any dirty cache lines on the kernel alias */
+       __dma_flush_range(ptr, ptr + size);
+
+       /* create a coherent mapping */
+       page = virt_to_page(ptr);
+       for (i = 0; i < (size >> PAGE_SHIFT); i++)
+               map[i] = page + i;
+       coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP,
+                           __get_dma_pgprot(attrs, pgprot_default, false));
+       kfree(map);
+       if (!coherent_ptr)
+               goto no_map;
+
+       return coherent_ptr;
+
+no_map:
+       __dma_free_coherent(dev, size, ptr, *dma_handle, attrs);
+no_mem:
+       *dma_handle = ~0;
+       return NULL;
+}
+
+static void __dma_free_noncoherent(struct device *dev, size_t size,
+                                  void *vaddr, dma_addr_t dma_handle,
+                                  struct dma_attrs *attrs)
+{
+       void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
+
+       vunmap(vaddr);
+       __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs);
+}
+
+static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
+                                    unsigned long offset, size_t size,
+                                    enum dma_data_direction dir,
+                                    struct dma_attrs *attrs)
+{
+       dma_addr_t dev_addr;
+
+       dev_addr = swiotlb_map_page(dev, page, offset, size, dir, attrs);
+       __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+
+       return dev_addr;
+}
+
+
+static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr,
+                                size_t size, enum dma_data_direction dir,
+                                struct dma_attrs *attrs)
+{
+       __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+       swiotlb_unmap_page(dev, dev_addr, size, dir, attrs);
+}
+
+static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+                                 int nelems, enum dma_data_direction dir,
+                                 struct dma_attrs *attrs)
+{
+       struct scatterlist *sg;
+       int i, ret;
+
+       ret = swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
+       for_each_sg(sgl, sg, ret, i)
+               __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+                              sg->length, dir);
+
+       return ret;
+}
+
+static void __swiotlb_unmap_sg_attrs(struct device *dev,
+                                    struct scatterlist *sgl, int nelems,
+                                    enum dma_data_direction dir,
+                                    struct dma_attrs *attrs)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nelems, i)
+               __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+                                sg->length, dir);
+       swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
+}
+
+static void __swiotlb_sync_single_for_cpu(struct device *dev,
+                                         dma_addr_t dev_addr, size_t size,
+                                         enum dma_data_direction dir)
+{
+       __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+       swiotlb_sync_single_for_cpu(dev, dev_addr, size, dir);
+}
+
+static void __swiotlb_sync_single_for_device(struct device *dev,
+                                            dma_addr_t dev_addr, size_t size,
+                                            enum dma_data_direction dir)
+{
+       swiotlb_sync_single_for_device(dev, dev_addr, size, dir);
+       __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+}
+
+static void __swiotlb_sync_sg_for_cpu(struct device *dev,
+                                     struct scatterlist *sgl, int nelems,
+                                     enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nelems, i)
+               __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+                                sg->length, dir);
+       swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
+}
+
+static void __swiotlb_sync_sg_for_device(struct device *dev,
+                                        struct scatterlist *sgl, int nelems,
+                                        enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
+       for_each_sg(sgl, sg, nelems, i)
+               __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+                              sg->length, dir);
+}
+
+/* vma->vm_page_prot must be set appropriately before calling this function */
+static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                            void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+       int ret = -ENXIO;
+       unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
+                                       PAGE_SHIFT;
+       unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT;
+       unsigned long off = vma->vm_pgoff;
+
+       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+               return ret;
+
+       if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
+               ret = remap_pfn_range(vma, vma->vm_start,
+                                     pfn + off,
+                                     vma->vm_end - vma->vm_start,
+                                     vma->vm_page_prot);
+       }
+
+       return ret;
+}
+
+static int __swiotlb_mmap_noncoherent(struct device *dev,
+               struct vm_area_struct *vma,
+               void *cpu_addr, dma_addr_t dma_addr, size_t size,
+               struct dma_attrs *attrs)
+{
+       vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, false);
+       return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+static int __swiotlb_mmap_coherent(struct device *dev,
+               struct vm_area_struct *vma,
+               void *cpu_addr, dma_addr_t dma_addr, size_t size,
+               struct dma_attrs *attrs)
+{
+       /* Just use whatever page_prot attributes were specified */
+       return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+struct dma_map_ops noncoherent_swiotlb_dma_ops = {
+       .alloc = __dma_alloc_noncoherent,
+       .free = __dma_free_noncoherent,
+       .mmap = __swiotlb_mmap_noncoherent,
+       .map_page = __swiotlb_map_page,
+       .unmap_page = __swiotlb_unmap_page,
+       .map_sg = __swiotlb_map_sg_attrs,
+       .unmap_sg = __swiotlb_unmap_sg_attrs,
+       .sync_single_for_cpu = __swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = __swiotlb_sync_single_for_device,
+       .sync_sg_for_cpu = __swiotlb_sync_sg_for_cpu,
+       .sync_sg_for_device = __swiotlb_sync_sg_for_device,
+       .dma_supported = swiotlb_dma_supported,
+       .mapping_error = swiotlb_dma_mapping_error,
+};
+EXPORT_SYMBOL(noncoherent_swiotlb_dma_ops);
+
+struct dma_map_ops coherent_swiotlb_dma_ops = {
+       .alloc = __dma_alloc_coherent,
+       .free = __dma_free_coherent,
+       .mmap = __swiotlb_mmap_coherent,
        .map_page = swiotlb_map_page,
        .unmap_page = swiotlb_unmap_page,
        .map_sg = swiotlb_map_sg_attrs,
@@ -92,12 +303,19 @@ static struct dma_map_ops arm64_swiotlb_dma_ops = {
        .dma_supported = swiotlb_dma_supported,
        .mapping_error = swiotlb_dma_mapping_error,
 };
+EXPORT_SYMBOL(coherent_swiotlb_dma_ops);
+
+extern int swiotlb_late_init_with_default_size(size_t default_size);
 
-void __init arm64_swiotlb_init(void)
+static int __init swiotlb_late_init(void)
 {
-       dma_ops = &arm64_swiotlb_dma_ops;
-       swiotlb_init(1);
+       size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+
+       dma_ops = &coherent_swiotlb_dma_ops;
+
+       return swiotlb_late_init_with_default_size(swiotlb_size);
 }
+subsys_initcall(swiotlb_late_init);
 
 #define PREALLOC_DMA_DEBUG_ENTRIES     4096
 
index d0b4c2efda90aa1ba8eaf2eabe8a977cb0fe2c9c..88627c450a6cbd3f5cdd0eb7056eeecaac76b6f2 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/memblock.h>
 #include <linux/sort.h>
 #include <linux/of_fdt.h>
+#include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
 
 #include <asm/sections.h>
@@ -59,22 +60,22 @@ static int __init early_initrd(char *p)
 early_param("initrd", early_initrd);
 #endif
 
-#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
-
 static void __init zone_sizes_init(unsigned long min, unsigned long max)
 {
        struct memblock_region *reg;
        unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
-       unsigned long max_dma32 = min;
+       unsigned long max_dma = min;
 
        memset(zone_size, 0, sizeof(zone_size));
 
-#ifdef CONFIG_ZONE_DMA32
        /* 4GB maximum for 32-bit only capable devices */
-       max_dma32 = max(min, min(max, MAX_DMA32_PFN));
-       zone_size[ZONE_DMA32] = max_dma32 - min;
-#endif
-       zone_size[ZONE_NORMAL] = max - max_dma32;
+       if (IS_ENABLED(CONFIG_ZONE_DMA)) {
+               unsigned long max_dma_phys =
+                       (unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1);
+               max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT));
+               zone_size[ZONE_DMA] = max_dma - min;
+       }
+       zone_size[ZONE_NORMAL] = max - max_dma;
 
        memcpy(zhole_size, zone_size, sizeof(zhole_size));
 
@@ -84,15 +85,15 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
                if (start >= max)
                        continue;
-#ifdef CONFIG_ZONE_DMA32
-               if (start < max_dma32) {
-                       unsigned long dma_end = min(end, max_dma32);
-                       zhole_size[ZONE_DMA32] -= dma_end - start;
+
+               if (IS_ENABLED(CONFIG_ZONE_DMA) && start < max_dma) {
+                       unsigned long dma_end = min(end, max_dma);
+                       zhole_size[ZONE_DMA] -= dma_end - start;
                }
-#endif
-               if (end > max_dma32) {
+
+               if (end > max_dma) {
                        unsigned long normal_end = min(end, max);
-                       unsigned long normal_start = max(start, max_dma32);
+                       unsigned long normal_start = max(start, max_dma);
                        zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
                }
        }
@@ -261,8 +262,6 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
-       arm64_swiotlb_init();
-
        max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
index 1333e6f9a8e50bd7e8996a67a392feaa4aaf95e0..e085ee6ef4e23c146627798b9c7b98411a719f36 100644 (file)
@@ -173,12 +173,6 @@ ENDPROC(cpu_do_switch_mm)
  *     value of the SCTLR_EL1 register.
  */
 ENTRY(__cpu_setup)
-       /*
-        * Preserve the link register across the function call.
-        */
-       mov     x28, lr
-       bl      __flush_dcache_all
-       mov     lr, x28
        ic      iallu                           // I+BTB cache invalidate
        tlbi    vmalle1is                       // invalidate I + D TLBs
        dsb     sy
@@ -215,8 +209,14 @@ ENTRY(__cpu_setup)
         * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
         * both user and kernel.
         */
-       ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \
+       ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | \
                      TCR_ASID16 | TCR_TBI0 | (1 << 31)
+       /*
+        * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in
+        * TCR_EL1.
+        */
+       mrs     x9, ID_AA64MMFR0_EL1
+       bfi     x10, x9, #32, #3
 #ifdef CONFIG_ARM64_64K_PAGES
        orr     x10, x10, TCR_TG0_64K
        orr     x10, x10, TCR_TG1_64K
index 79c076e168a8d155bb2cbf697fd9f7cece23e0a4..c740aa116755592c9ef8e1e93756a5125003f55a 100644 (file)
@@ -1 +1 @@
-obj-y                          += setup.o flash.o fram.o
+obj-y                          += setup.o flash.o
diff --git a/arch/avr32/boards/mimc200/fram.c b/arch/avr32/boards/mimc200/fram.c
deleted file mode 100644 (file)
index c1466a8..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * FRAM driver for MIMC200 board
- *
- * Copyright 2008 Mark Jackson <mpfj@mimc.co.uk>
- *
- * This module adds *very* simply support for the system's FRAM device.
- * At the moment, this is hard-coded to the MIMC200 platform, and only
- * supports mmap().
- */
-
-#define FRAM_VERSION   "1.0"
-
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-
-#define FRAM_BASE      0xac000000
-#define FRAM_SIZE      0x20000
-
-/*
- * The are the file operation function for user access to /dev/fram
- */
-
-static int fram_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-       int ret;
-
-       ret = remap_pfn_range(vma,
-               vma->vm_start,
-               virt_to_phys((void *)((unsigned long)FRAM_BASE)) >> PAGE_SHIFT,
-               vma->vm_end-vma->vm_start,
-               PAGE_SHARED);
-
-       if (ret != 0)
-               return -EAGAIN;
-
-       return 0;
-}
-
-static const struct file_operations fram_fops = {
-       .owner                  = THIS_MODULE,
-       .mmap                   = fram_mmap,
-       .llseek                 = noop_llseek,
-};
-
-#define FRAM_MINOR     0
-
-static struct miscdevice fram_dev = {
-       FRAM_MINOR,
-       "fram",
-       &fram_fops
-};
-
-static int __init
-fram_init(void)
-{
-       int ret;
-
-       ret = misc_register(&fram_dev);
-       if (ret) {
-               printk(KERN_ERR "fram: can't misc_register on minor=%d\n",
-                   FRAM_MINOR);
-               return ret;
-       }
-       printk(KERN_INFO "FRAM memory driver v" FRAM_VERSION "\n");
-       return 0;
-}
-
-static void __exit
-fram_cleanup_module(void)
-{
-       misc_deregister(&fram_dev);
-}
-
-module_init(fram_init);
-module_exit(fram_cleanup_module);
-
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_MISCDEV(FRAM_MINOR);
index c7c64a63c29f470ebbec5071422d148ba9bc074a..00a0f3ccd6eb994a67071d8e544762475f1ca792 100644 (file)
@@ -1,22 +1,23 @@
 
-generic-y      += clkdev.h
-generic-y       += cputime.h
-generic-y       += delay.h
-generic-y       += device.h
-generic-y       += div64.h
-generic-y       += emergency-restart.h
-generic-y      += exec.h
-generic-y       += futex.h
-generic-y      += preempt.h
-generic-y       += irq_regs.h
-generic-y      += param.h
-generic-y       += local.h
-generic-y       += local64.h
-generic-y       += percpu.h
-generic-y       += scatterlist.h
-generic-y       += sections.h
-generic-y       += topology.h
-generic-y      += trace_clock.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += exec.h
+generic-y += futex.h
+generic-y += hash.h
+generic-y += irq_regs.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += preempt.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += topology.h
+generic-y += trace_clock.h
 generic-y += vga.h
-generic-y       += xor.h
-generic-y      += hash.h
+generic-y += xor.h
index 7635e770622ee32dafb27f6368a588542791d51f..278661bbd1b0aefb081be0bdb7d15423cd27f3f3 100644 (file)
@@ -9,7 +9,7 @@
 
 static void __init check_bugs(void)
 {
-       cpu_data->loops_per_jiffy = loops_per_jiffy;
+       boot_cpu_data.loops_per_jiffy = loops_per_jiffy;
 }
 
 #endif /* __ASM_AVR32_BUGS_H */
index 48d71c5c898a18d083f8a55da807c103d7515458..972adcc1e8f40179d06a4062d2adf63416f36452 100644 (file)
@@ -83,13 +83,8 @@ static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
 
 extern struct avr32_cpuinfo boot_cpu_data;
 
-#ifdef CONFIG_SMP
-extern struct avr32_cpuinfo cpu_data[];
-#define current_cpu_data cpu_data[smp_processor_id()]
-#else
-#define cpu_data (&boot_cpu_data)
+/* No SMP support so far */
 #define current_cpu_data boot_cpu_data
-#endif
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's
index 2233be71e2e8cf7e8b62789eb6a5a7ba864d001e..0341ae27c9ec57fd06eaf88776db6ae83444c96e 100644 (file)
@@ -39,10 +39,12 @@ static ssize_t store_pc0event(struct device *dev,
                              size_t count)
 {
        unsigned long val;
-       char *endp;
+       int ret;
 
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf || val > 0x3f)
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
+       if (val > 0x3f)
                return -EINVAL;
        val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff);
        sysreg_write(PCCR, val);
@@ -61,11 +63,11 @@ static ssize_t store_pc0count(struct device *dev,
                                const char *buf, size_t count)
 {
        unsigned long val;
-       char *endp;
+       int ret;
 
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               return -EINVAL;
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
        sysreg_write(PCNT0, val);
 
        return count;
@@ -84,10 +86,12 @@ static ssize_t store_pc1event(struct device *dev,
                              size_t count)
 {
        unsigned long val;
-       char *endp;
+       int ret;
 
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf || val > 0x3f)
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
+       if (val > 0x3f)
                return -EINVAL;
        val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff);
        sysreg_write(PCCR, val);
@@ -106,11 +110,11 @@ static ssize_t store_pc1count(struct device *dev,
                              size_t count)
 {
        unsigned long val;
-       char *endp;
+       int ret;
 
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               return -EINVAL;
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
        sysreg_write(PCNT1, val);
 
        return count;
@@ -129,11 +133,11 @@ static ssize_t store_pccycles(struct device *dev,
                              size_t count)
 {
        unsigned long val;
-       char *endp;
+       int ret;
 
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               return -EINVAL;
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
        sysreg_write(PCCNT, val);
 
        return count;
@@ -152,11 +156,11 @@ static ssize_t store_pcenable(struct device *dev,
                              size_t count)
 {
        unsigned long pccr, val;
-       char *endp;
+       int ret;
 
-       val = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               return -EINVAL;
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
        if (val)
                val = 1;
 
index 6a46ecd56cfd538c7fe070b641fad3e68ffc3d1f..85d635cd7b28f84045e5bf29e62e4aab53196f85 100644 (file)
@@ -111,6 +111,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
        __flush_icache_range(start & ~(linesz - 1),
                             (end + linesz - 1) & ~(linesz - 1));
 }
+EXPORT_SYMBOL(flush_icache_range);
 
 /*
  * This one is called from __do_fault() and do_swap_page().
index 359d36fdc2471f987ff561104e9dcb2723fdcf99..0d93b9a79ca9561399a152d25a3545a09496b858 100644 (file)
@@ -10,6 +10,7 @@ generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += fb.h
 generic-y += futex.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
@@ -17,14 +18,16 @@ generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
-generic-y += local64.h
 generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += msgbuf.h
 generic-y += mutex.h
 generic-y += param.h
 generic-y += percpu.h
 generic-y += pgalloc.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sembuf.h
@@ -44,5 +47,3 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 2fd04f10cc266b86d6a88c786278c18fd2a604fb..89de539ed0100624ead2e5ea6d7f9790eed11cf2 100644 (file)
 /* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
 #include <mach/irq.h>
 
-/*
- * pm save bfin pint registers
- */
-struct adi_pm_pint_save {
-       u32 assign;
-       u32 edge_set;
-       u32 invert_set;
-};
-
 #if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE)
 # define NOP_PAD_ANOMALY_05000244 "nop; nop;"
 #else
index d73bb85ccdd3e9f7dbc49c5a3c67944f250c82a6..8dbdce8421b08c0e58322db87002ef314778cd1b 100644 (file)
@@ -15,6 +15,7 @@ generic-y += exec.h
 generic-y += fb.h
 generic-y += fcntl.h
 generic-y += futex.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += io.h
 generic-y += ioctl.h
@@ -24,6 +25,7 @@ generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += local.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += mmu.h
 generic-y += mmu_context.h
@@ -34,6 +36,7 @@ generic-y += percpu.h
 generic-y += pgalloc.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += segment.h
@@ -56,5 +59,3 @@ generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 09c5a0f5f4d1778156a5ee83715e6a2aec7f0441..86648c083bb4b1297275dc2bc4ceb3ecd949aa5b 100644 (file)
@@ -12,6 +12,7 @@
 #define _ASM_C6X_CACHE_H
 
 #include <linux/irqflags.h>
+#include <linux/init.h>
 
 /*
  * Cache line size
index f3fd8768f095cc55c606d22bf5281042a31234c2..afff5105909d953af7ca3667c773350fb4bc434d 100644 (file)
@@ -5,12 +5,14 @@ header-y += arch-v32/
 
 generic-y += barrier.h
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
 generic-y += kvm_para.h
 generic-y += linkage.h
+generic-y += mcs_spinlock.h
 generic-y += module.h
+generic-y += preempt.h
 generic-y += trace_clock.h
 generic-y += vga.h
 generic-y += xor.h
-generic-y += preempt.h
index 184066ceb1f6146c9254a778c8e9c7f6b9656668..053c17b3655926ed97427a927a83081ec289d224 100644 (file)
@@ -144,7 +144,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
  * definition, which doesn't have the same semantics.  We don't want to
  * use -fno-builtin, so just hide the name ffs.
  */
-#define ffs kernel_ffs
+#define ffs(x) kernel_ffs(x)
 
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/__fls.h>
diff --git a/arch/cris/include/asm/cputime.h b/arch/cris/include/asm/cputime.h
deleted file mode 100644 (file)
index 4446a65..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __CRIS_CPUTIME_H
-#define __CRIS_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __CRIS_CPUTIME_H */
index bc42f14c9c2e706081c66b3805a9369d65e4bce9..87b95eb8aee53e3f5280f3b985da8b0c6cc75192 100644 (file)
@@ -1,6 +1,8 @@
 
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
 generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/frv/include/asm/cputime.h b/arch/frv/include/asm/cputime.h
deleted file mode 100644 (file)
index f6c373a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_CPUTIME_H
-#define _ASM_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* _ASM_CPUTIME_H */
index c281217654487cb059e1e790c951c3a7dabdef22..67b1d16857593ddc083bf45cc8fd9e19d5430994 100644 (file)
@@ -88,7 +88,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
 
        /* Depth-First Search on bus tree */
        for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
-               bus = pci_bus_b(ln);
+               bus = list_entry(ln, struct pci_bus, node);
                if ((dev = bus->self)) {
                        for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
                                r = &dev->resource[idx];
index 38ca45d3df1e4d88230d1ab8f991510efb983450..eadcc118f9506d8fbfddfd5b0dc7e65c6f3f9673 100644 (file)
@@ -25,14 +25,16 @@ generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
-generic-y += local64.h
 generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += msgbuf.h
 generic-y += pci.h
 generic-y += percpu.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += rwsem.h
 generic-y += scatterlist.h
@@ -45,8 +47,8 @@ generic-y += siginfo.h
 generic-y += sizes.h
 generic-y += socket.h
 generic-y += sockios.h
-generic-y += statfs.h
 generic-y += stat.h
+generic-y += statfs.h
 generic-y += termbits.h
 generic-y += termios.h
 generic-y += topology.h
@@ -55,4 +57,3 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += xor.h
-generic-y += preempt.h
index efbd2929aeb75c563b5ccbf4b267be596ce921e2..b4efaf2bc13e9c104e075072dec02399542c53ec 100644 (file)
@@ -25,14 +25,13 @@ CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_MISC=m
-CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_DOCK=y
 CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_CONTAINER=m
+CONFIG_ACPI_CONTAINER=y
 CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
index 0f4e9e41f130623baae948b022dbd01468869331..0fed9ae5a42a7a0630673efe62662b6973bf64fa 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_IA64_PALINFO=y
 CONFIG_KEXEC=y
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_MISC=m
-CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
index fc7aba07c2b4f7064efa3e0e9704382e5495fdf6..54bc72eda30d4f5efefa3c3f9949fcba3155adc0 100644 (file)
@@ -16,7 +16,6 @@ CONFIG_IA64_PALINFO=y
 CONFIG_CRASH_DUMP=y
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_MISC=y
-CONFIG_ACPI_PROCFS=y
 CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PACKET=y
index 8e858b593e4f13cf79fb34fda2903531e02fd1dc..1a871b78e5709232f1f5f3e9aa8021cb4d02dd59 100644 (file)
@@ -1140,11 +1140,13 @@ sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 
 #ifdef CONFIG_NUMA
        {
+               int node = ioc->node;
                struct page *page;
-               page = alloc_pages_exact_node(ioc->node == MAX_NUMNODES ?
-                                       numa_node_id() : ioc->node, flags,
-                                       get_order(size));
 
+               if (node == NUMA_NO_NODE)
+                       node = numa_node_id();
+
+               page = alloc_pages_exact_node(node, flags, get_order(size));
                if (unlikely(!page))
                        return NULL;
 
@@ -1596,7 +1598,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
 *
 ***************************************************************/
 
-static void __init
+static void
 ioc_iova_init(struct ioc *ioc)
 {
        int tcnfg;
@@ -1807,7 +1809,7 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = {
        { SX2000_IOC_ID, "sx2000", NULL },
 };
 
-static struct ioc * __init
+static struct ioc *
 ioc_init(unsigned long hpa, void *handle)
 {
        struct ioc *ioc;
@@ -1914,7 +1916,7 @@ ioc_show(struct seq_file *s, void *v)
        seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n",
                ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));
 #ifdef CONFIG_NUMA
-       if (ioc->node != MAX_NUMNODES)
+       if (ioc->node != NUMA_NO_NODE)
                seq_printf(s, "NUMA node       : %d\n", ioc->node);
 #endif
        seq_printf(s, "IOVA size       : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024));
@@ -2015,33 +2017,21 @@ sba_connect_bus(struct pci_bus *bus)
        printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", pci_domain_nr(bus), bus->number);
 }
 
-#ifdef CONFIG_NUMA
 static void __init
 sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
 {
+#ifdef CONFIG_NUMA
        unsigned int node;
-       int pxm;
-
-       ioc->node = MAX_NUMNODES;
-
-       pxm = acpi_get_pxm(handle);
-
-       if (pxm < 0)
-               return;
-
-       node = pxm_to_node(pxm);
 
-       if (node >= MAX_NUMNODES || !node_online(node))
-               return;
+       node = acpi_get_node(handle);
+       if (node != NUMA_NO_NODE && !node_online(node))
+               node = NUMA_NO_NODE;
 
        ioc->node = node;
-       return;
-}
-#else
-#define sba_map_ioc_to_node(ioc, handle)
 #endif
+}
 
-static int __init
+static int
 acpi_sba_ioc_add(struct acpi_device *device,
                 const struct acpi_device_id *not_used)
 {
index 283a83154b5eaaab7f8dc5474f0ec722e970a1de..0da4aa2602ae01d9badaca0f960e8d6b4c16ae2b 100644 (file)
@@ -1,8 +1,9 @@
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += kvm_para.h
-generic-y += trace_clock.h
+generic-y += mcs_spinlock.h
 generic-y += preempt.h
+generic-y += trace_clock.h
 generic-y += vtime.h
-generic-y += hash.h
index 71fbaaa495ccc18af5f33cdaef92c0ab228dad8e..7d41cc0898224ec2211a6e0304e71ac4bb269a5d 100644 (file)
@@ -98,7 +98,7 @@ struct pci_controller {
        struct acpi_device *companion;
        void *iommu;
        int segment;
-       int node;               /* nearest node with memory or -1 for global allocation */
+       int node;               /* nearest node with memory or NUMA_NO_NODE for global allocation */
 
        void *platform_data;
 };
index a2496e449b75452038ab7e7b14e4bd2c796fd458..5cb55a1e606b0b5cbed352f1e7187c41d31371de 100644 (file)
@@ -77,7 +77,6 @@ void build_cpu_to_node_map(void);
 #define topology_core_id(cpu)                  (cpu_data(cpu)->core_id)
 #define topology_core_cpumask(cpu)             (&cpu_core_map[cpu])
 #define topology_thread_cpumask(cpu)           (&per_cpu(cpu_sibling_map, cpu))
-#define smt_capable()                          (smp_num_siblings > 1)
 #endif
 
 extern void arch_fix_phys_package_id(int num, u32 slot);
index 07d209c9507f292d80c45edc7b7433d78a78602b..0d407b300762d5fd5e7224bdfc8dc910485603b2 100644 (file)
 #include <asm/sal.h>
 #include <asm/cyclone.h>
 
-#define BAD_MADT_ENTRY(entry, end) (                                        \
-               (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
-               ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
 #define PREFIX                 "ACPI: "
 
 unsigned int acpi_cpei_override;
@@ -803,14 +799,9 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
  *  ACPI based hotplug CPU support
  */
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
-static
-int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
+static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
 {
 #ifdef CONFIG_ACPI_NUMA
-       int pxm_id;
-       int nid;
-
-       pxm_id = acpi_get_pxm(handle);
        /*
         * We don't have cpu-only-node hotadd. But if the system equips
         * SRAT table, pxm is already found and node is ready.
@@ -818,11 +809,10 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
         * This code here is for the system which doesn't have full SRAT
         * table for possible cpus.
         */
-       nid = acpi_map_pxm_to_node(pxm_id);
        node_cpuid[cpu].phys_id = physid;
-       node_cpuid[cpu].nid = nid;
+       node_cpuid[cpu].nid = acpi_get_node(handle);
 #endif
-       return (0);
+       return 0;
 }
 
 int additional_cpus __initdata = -1;
@@ -929,7 +919,7 @@ static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
        union acpi_object *obj;
        struct acpi_madt_io_sapic *iosapic;
        unsigned int gsi_base;
-       int pxm, node;
+       int node;
 
        /* Only care about objects w/ a method that returns the MADT */
        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
@@ -956,17 +946,9 @@ static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
 
        kfree(buffer.pointer);
 
-       /*
-        * OK, it's an IOSAPIC MADT entry, look for a _PXM value to tell
-        * us which node to associate this with.
-        */
-       pxm = acpi_get_pxm(handle);
-       if (pxm < 0)
-               return AE_OK;
-
-       node = pxm_to_node(pxm);
-
-       if (node >= MAX_NUMNODES || !node_online(node) ||
+       /* OK, it's an IOSAPIC MADT entry; associate it with a node */
+       node = acpi_get_node(handle);
+       if (node == NUMA_NO_NODE || !node_online(node) ||
            cpumask_empty(cpumask_of_node(node)))
                return AE_OK;
 
index da5b462e6de6c9e91c18d42756ff482bb9f70505..741b99c1a0b1483b153be8823ae681a141d71bf5 100644 (file)
@@ -477,6 +477,9 @@ efi_init (void)
        char *cp, vendor[100] = "unknown";
        int i;
 
+       set_bit(EFI_BOOT, &efi.flags);
+       set_bit(EFI_64BIT, &efi.flags);
+
        /*
         * It's too early to be able to use the standard kernel command line
         * support...
@@ -529,6 +532,8 @@ efi_init (void)
               efi.systab->hdr.revision >> 16,
               efi.systab->hdr.revision & 0xffff, vendor);
 
+       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
        palo_phys      = EFI_INVALID_TABLE_ADDR;
 
        if (efi_config_init(arch_tables) != 0)
@@ -657,6 +662,8 @@ efi_enter_virtual_mode (void)
                return;
        }
 
+       set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
        /*
         * Now that EFI is in virtual mode, we call the EFI functions more
         * efficiently:
index 1034884b77da428c59190f9841229fc3e3cb8f41..0884f5ecbcc3e97b86a5e4c248614359dbd7674c 100644 (file)
@@ -364,7 +364,6 @@ static irqreturn_t smp_irq_move_cleanup_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq_move_irqaction = {
        .handler =      smp_irq_move_cleanup_interrupt,
-       .flags =        IRQF_DISABLED,
        .name =         "irq_move"
 };
 
@@ -489,14 +488,13 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
        ia64_srlz_d();
        while (vector != IA64_SPURIOUS_INT_VECTOR) {
                int irq = local_vector_to_irq(vector);
-               struct irq_desc *desc = irq_to_desc(irq);
 
                if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
                        smp_local_flush_tlb();
-                       kstat_incr_irqs_this_cpu(irq, desc);
+                       kstat_incr_irq_this_cpu(irq);
                } else if (unlikely(IS_RESCHEDULE(vector))) {
                        scheduler_ipi();
-                       kstat_incr_irqs_this_cpu(irq, desc);
+                       kstat_incr_irq_this_cpu(irq);
                } else {
                        ia64_setreg(_IA64_REG_CR_TPR, vector);
                        ia64_srlz_d();
@@ -549,13 +547,12 @@ void ia64_process_pending_intr(void)
          */
        while (vector != IA64_SPURIOUS_INT_VECTOR) {
                int irq = local_vector_to_irq(vector);
-               struct irq_desc *desc = irq_to_desc(irq);
 
                if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
                        smp_local_flush_tlb();
-                       kstat_incr_irqs_this_cpu(irq, desc);
+                       kstat_incr_irq_this_cpu(irq);
                } else if (unlikely(IS_RESCHEDULE(vector))) {
-                       kstat_incr_irqs_this_cpu(irq, desc);
+                       kstat_incr_irq_this_cpu(irq);
                } else {
                        struct pt_regs *old_regs = set_irq_regs(NULL);
 
@@ -602,7 +599,6 @@ static irqreturn_t dummy_handler (int irq, void *dev_id)
 
 static struct irqaction ipi_irqaction = {
        .handler =      handle_IPI,
-       .flags =        IRQF_DISABLED,
        .name =         "IPI"
 };
 
@@ -611,13 +607,11 @@ static struct irqaction ipi_irqaction = {
  */
 static struct irqaction resched_irqaction = {
        .handler =      dummy_handler,
-       .flags =        IRQF_DISABLED,
        .name =         "resched"
 };
 
 static struct irqaction tlb_irqaction = {
        .handler =      dummy_handler,
-       .flags =        IRQF_DISABLED,
        .name =         "tlb_flush"
 };
 
index b8edfa75a83f9cd8bce4469d1d1c97b93b02d371..db7b36bb068b8d306042028560dbbaafcbf7664f 100644 (file)
@@ -217,7 +217,7 @@ void ia64_mca_printk(const char *fmt, ...)
        /* Copy the output into mlogbuf */
        if (oops_in_progress) {
                /* mlogbuf was abandoned, use printk directly instead. */
-               printk(temp_buf);
+               printk("%s", temp_buf);
        } else {
                spin_lock(&mlogbuf_wlock);
                for (p = temp_buf; *p; p++) {
@@ -268,7 +268,7 @@ void ia64_mlogbuf_dump(void)
                }
                *p = '\0';
                if (temp_buf[0])
-                       printk(temp_buf);
+                       printk("%s", temp_buf);
                mlogbuf_start = index;
 
                mlogbuf_timestamp = 0;
@@ -1772,38 +1772,32 @@ __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
 
 static struct irqaction cmci_irqaction = {
        .handler =      ia64_mca_cmc_int_handler,
-       .flags =        IRQF_DISABLED,
        .name =         "cmc_hndlr"
 };
 
 static struct irqaction cmcp_irqaction = {
        .handler =      ia64_mca_cmc_int_caller,
-       .flags =        IRQF_DISABLED,
        .name =         "cmc_poll"
 };
 
 static struct irqaction mca_rdzv_irqaction = {
        .handler =      ia64_mca_rendez_int_handler,
-       .flags =        IRQF_DISABLED,
        .name =         "mca_rdzv"
 };
 
 static struct irqaction mca_wkup_irqaction = {
        .handler =      ia64_mca_wakeup_int_handler,
-       .flags =        IRQF_DISABLED,
        .name =         "mca_wkup"
 };
 
 #ifdef CONFIG_ACPI
 static struct irqaction mca_cpe_irqaction = {
        .handler =      ia64_mca_cpe_int_handler,
-       .flags =        IRQF_DISABLED,
        .name =         "cpe_hndlr"
 };
 
 static struct irqaction mca_cpep_irqaction = {
        .handler =      ia64_mca_cpe_int_caller,
-       .flags =        IRQF_DISABLED,
        .name =         "cpe_poll"
 };
 #endif /* CONFIG_ACPI */
index fb2f1e622877e202f8bdb6be4d6922fa6431986f..c430f9198d1bfec6b50b9d6f21d2929ef55dcf45 100644 (file)
@@ -17,12 +17,9 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
 {
        struct msi_msg msg;
        u32 addr, data;
-       int cpu = first_cpu(*cpu_mask);
+       int cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
        unsigned int irq = idata->irq;
 
-       if (!cpu_online(cpu))
-               return -1;
-
        if (irq_prepare_move(irq, cpu))
                return -1;
 
@@ -139,10 +136,7 @@ static int dmar_msi_set_affinity(struct irq_data *data,
        unsigned int irq = data->irq;
        struct irq_cfg *cfg = irq_cfg + irq;
        struct msi_msg msg;
-       int cpu = cpumask_first(mask);
-
-       if (!cpu_online(cpu))
-               return -1;
+       int cpu = cpumask_first_and(mask, cpu_online_mask);
 
        if (irq_prepare_move(irq, cpu))
                return -1;
index cb592773c78b1ef1f86faa4a4190c507c4e9fdbf..d841c4bd6864907212cde6554957e65d27eaa02d 100644 (file)
@@ -6387,7 +6387,6 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
 
 static struct irqaction perfmon_irqaction = {
        .handler = pfm_interrupt_handler,
-       .flags   = IRQF_DISABLED,
        .name    = "perfmon"
 };
 
index fbaac1afb8441926d3f2fdc9eec4ed85c6122da1..71c52bc7c28d824ff3428675ac11410db654639d 100644 (file)
@@ -380,7 +380,7 @@ static cycle_t itc_get_cycles(struct clocksource *cs)
 
 static struct irqaction timer_irqaction = {
        .handler =      timer_interrupt,
-       .flags =        IRQF_DISABLED | IRQF_IRQPOLL,
+       .flags =        IRQF_IRQPOLL,
        .name =         "timer"
 };
 
index a96bcf83a735dae2f812f81e0fc54635bb3de072..20e8a9b21d7519ebf7d506e4825d83c05629ba37 100644 (file)
@@ -98,7 +98,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
        /* attempt to allocate a granule's worth of cached memory pages */
 
        page = alloc_pages_exact_node(nid,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                IA64_GRANULE_SHIFT-PAGE_SHIFT);
        if (!page) {
                mutex_unlock(&uc_pool->add_chunk_mutex);
index 5dc969dd4ac06fec04f308894bcfe27dfc324e68..eee069a0b539747da4d4d4b4d3065de1c5373be8 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/vgaarb.h>
 
 #include <asm/machvec.h>
 
  * IORESOURCE_ROM_SHADOW is used to associate the boot video
  * card with this copy. On laptops this copy has to be used since
  * the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
+ * See pci_map_rom() for use of this flag. Before marking the device
+ * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set
+ * by either arch cde or vga-arbitration, if so only apply the fixup to this
+ * already determined primary video card.
  */
 
 static void pci_fixup_video(struct pci_dev *pdev)
@@ -35,9 +37,6 @@ static void pci_fixup_video(struct pci_dev *pdev)
                return;
        /* Maybe, this machine supports legacy memory map. */
 
-       if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-               return;
-
        /* Is VGA routed to us? */
        bus = pdev->bus;
        while (bus) {
@@ -60,10 +59,14 @@ static void pci_fixup_video(struct pci_dev *pdev)
                }
                bus = bus->parent;
        }
-       pci_read_config_word(pdev, PCI_COMMAND, &config);
-       if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
-               pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
-               dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+       if (!vga_default_device() || pdev == vga_default_device()) {
+               pci_read_config_word(pdev, PCI_COMMAND, &config);
+               if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+                       pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+                       dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+                       vga_set_default_device(pdev);
+               }
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
index 9e4938d8ca4d297e331131a79d8458d97a27d256..291a582777cf3dd0320f4757ea1f9c1fc39dd17c 100644 (file)
@@ -126,7 +126,6 @@ static struct pci_controller *alloc_pci_controller(int seg)
                return NULL;
 
        controller->segment = seg;
-       controller->node = -1;
        return controller;
 }
 
@@ -430,19 +429,14 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
        struct pci_root_info *info = NULL;
        int busnum = root->secondary.start;
        struct pci_bus *pbus;
-       int pxm, ret;
+       int ret;
 
        controller = alloc_pci_controller(domain);
        if (!controller)
                return NULL;
 
        controller->companion = device;
-
-       pxm = acpi_get_pxm(device->handle);
-#ifdef CONFIG_NUMA
-       if (pxm >= 0)
-               controller->node = pxm_to_node(pxm);
-#endif
+       controller->node = acpi_get_node(device->handle);
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
index 62cf4dde6a0426dafa12ce5a3b0b56f1ccb00b41..85d095154902453fb5896734597e849af07ea74e 100644 (file)
@@ -209,8 +209,8 @@ static int sn_set_affinity_irq(struct irq_data *data,
        nasid_t nasid;
        int slice;
 
-       nasid = cpuid_to_nasid(cpumask_first(mask));
-       slice = cpuid_to_slice(cpumask_first(mask));
+       nasid = cpuid_to_nasid(cpumask_first_and(mask, cpu_online_mask));
+       slice = cpuid_to_slice(cpumask_first_and(mask, cpu_online_mask));
 
        list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
                                 sn_irq_lh[irq], list)
index 2b98b9e088def963ac47033c4717fa5ea4f24075..afc58d2799adb7a8b7ccf5d454d90a26fff0a3dc 100644 (file)
@@ -166,7 +166,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
        struct sn_pcibus_provider *provider;
        unsigned int cpu, irq = data->irq;
 
-       cpu = cpumask_first(cpu_mask);
+       cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
        sn_irq_info = sn_msi_info[irq].sn_irq_info;
        if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
                return -1;
index 932435ac4e5ce4ff721b2c455de567c5c7603861..67779a74b62dbbe2e5841253acf145867b67c9ae 100644 (file)
@@ -1,7 +1,9 @@
 
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += exec.h
+generic-y += hash.h
+generic-y += mcs_spinlock.h
 generic-y += module.h
-generic-y += trace_clock.h
 generic-y += preempt.h
-generic-y += hash.h
+generic-y += trace_clock.h
diff --git a/arch/m32r/include/asm/cputime.h b/arch/m32r/include/asm/cputime.h
deleted file mode 100644 (file)
index 0a47550..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __M32R_CPUTIME_H
-#define __M32R_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __M32R_CPUTIME_H */
index dbdd2231c75ddc9fab61fd1b2dca7c1cc60a3e3e..b2e322939256f528bfeb042bc420cd0de2efc1a3 100644 (file)
@@ -17,6 +17,7 @@ config M68K
        select FPU if MMU
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
+       select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_REL
        select MODULES_USE_ELF_RELA
index 18c0e29976e37475cf822b5b11d9bf32437791eb..2081b8cd5591c6d77385de8594e737c9d421f7be 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/irq.h>
 #include <asm/amigahw.h>
index 3e73a63c066f8a480ae543035c26cd5265f797ae..3d2b63bedf0589c67cdf0471007157bb913f18ac 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 
 #include <asm/traps.h>
 
index 559ff3af8ff7b1e8dd4a738eebe6321f1dc3ddd9..96da4963d14b21ef0b5daa023b4d16425eaebeaf 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
 CONFIG_M68030=y
 CONFIG_M68040=y
@@ -85,6 +87,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -94,6 +97,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -126,6 +131,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -163,8 +169,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -190,7 +194,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -512,7 +515,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index cb1f55df69b6c87b03dc2c1598b43fdbfd3fcfa0..1b8739f50cbf77631d0eb5fb25d22941c7233aad 100644 (file)
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
 CONFIG_M68030=y
 CONFIG_M68040=y
@@ -83,6 +85,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -92,6 +95,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -124,6 +129,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -161,8 +167,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -188,7 +192,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -470,7 +473,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index e880cfbb62d9e419bcbf4a4d006ffd420939b4f1..6ea4e91f0caabed1a806afbaab092744f23c0c98 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
 CONFIG_M68030=y
 CONFIG_M68040=y
@@ -82,6 +84,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -91,6 +94,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -123,6 +128,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -160,8 +166,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -187,7 +191,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -487,7 +490,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 4aa4f45e52a8708853925fb678a19d4889f632f3..e5a12739ff2d3535e8d9ed0dc22df8720eb4689e 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68040=y
 CONFIG_M68060=y
 CONFIG_VME=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -463,7 +466,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 7cd9d9f456fb61ab3619641b81ee8dbfbd975acf..8936d7fb0f0f15a983dcd6d0262301a7447e10b9 100644 (file)
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
 CONFIG_M68030=y
 CONFIG_M68040=y
@@ -83,6 +85,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -92,6 +95,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -124,6 +129,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -161,8 +167,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -188,7 +192,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -472,7 +475,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 31f5bd061d1466f5367fa0b0dafc1ecaa8f4d521..be5342cca25b36180991f88a49d2bfe80f49ff2f 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
 CONFIG_M68030=y
 CONFIG_M68040=y
@@ -82,6 +84,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -91,6 +94,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -123,6 +128,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -160,8 +166,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -187,7 +191,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -495,7 +498,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 4e5adff326eec88bccff93bf83933f518b94328b..f27194ade167d96fb949b1e2a42e7e74a75f6e79 100644 (file)
@@ -20,6 +20,8 @@ CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_UNIXWARE_DISKLABEL=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68020=y
 CONFIG_M68040=y
 CONFIG_M68060=y
@@ -91,6 +93,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -100,6 +103,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -132,6 +137,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -169,8 +175,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -196,7 +200,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -571,7 +574,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 02cdbac5565e5153f0970409e8247535bf818fd7..c3887603c1db4a49196af9a52c2dc85efdc641be 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68030=y
 CONFIG_VME=y
 CONFIG_MVME147=y
@@ -80,6 +82,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -89,6 +92,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -121,6 +126,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -158,8 +164,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -185,7 +189,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -463,7 +466,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 05a990a9dbd46994c60488c6eefeb807aa19f287..f7ff784d05aca2498040a3b47ea477c5793ac22d 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68040=y
 CONFIG_M68060=y
 CONFIG_VME=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 568e2a98f976ee3c91900734df88e5d675c83811..f0c72ab037be1b268abcc720be5dda97fb128323 100644 (file)
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_M68040=y
 CONFIG_M68060=y
 CONFIG_Q40=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -485,7 +488,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 60b0aeac5742e80f28c8345a856070638252897b..7bca0f464521707451d41686040fac2dfc4b2070 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_SUN3=y
 # CONFIG_COMPACTION is not set
 CONFIG_CLEANCACHE=y
@@ -78,6 +80,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -87,6 +90,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -119,6 +124,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -156,8 +162,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -183,7 +187,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 21bda331eebb04cfae90c5b94d869b18c9097d95..317f3e1fec954285880d0268bce5af93cc23be1e 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SYSV68_PARTITION=y
 CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
 CONFIG_SUN3X=y
 # CONFIG_COMPACTION is not set
 CONFIG_CLEANCACHE=y
@@ -78,6 +80,7 @@ CONFIG_NF_CONNTRACK_SANE=m
 CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
 CONFIG_NFT_CT=m
@@ -87,6 +90,8 @@ CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -119,6 +124,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
 CONFIG_NETFILTER_XT_MATCH_ESP=m
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
 CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
 CONFIG_NETFILTER_XT_MATCH_LENGTH=m
 CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -156,8 +162,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
 CONFIG_NFT_CHAIN_ROUTE_IPV4=m
 CONFIG_NFT_CHAIN_NAT_IPV4=m
 CONFIG_NF_TABLES_ARP=m
@@ -183,7 +187,6 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
 CONFIG_NFT_CHAIN_ROUTE_IPV6=m
 CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 # CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
 CONFIG_XZ_DEC_X86=y
 CONFIG_XZ_DEC_POWERPC=y
 CONFIG_XZ_DEC_IA64=y
index 6fb9e813a91074cb8ae41205bb8f899bcc35cf38..c67c94a2d67229a461239a4335def5d90d597abe 100644 (file)
@@ -14,8 +14,9 @@ generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
-generic-y += local64.h
 generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += mutex.h
 generic-y += percpu.h
index 4c99bab7e6647c0709ebacbff38b42f01ab24449..3ab329b8852173694bac06c2559841fed73d95ac 100644 (file)
 
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
 #define CONSOLE
-#define CONSOLE_PENGUIN
 #endif
 
 #ifdef CONFIG_EARLY_PRINTK
@@ -658,27 +657,6 @@ ENTRY(__start)
        movel   %a0@,%a1@
 #endif
 
-#if 0
-       /*
-        * Clear the screen
-        */
-       lea     %pc@(L(mac_videobase)),%a0
-       movel   %a0@,%a1
-       lea     %pc@(L(mac_dimensions)),%a0
-       movel   %a0@,%d1
-       swap    %d1             /* #rows is high bytes */
-       andl    #0xFFFF,%d1     /* rows */
-       subl    #10,%d1
-       lea     %pc@(L(mac_rowbytes)),%a0
-loopy2:
-       movel   %a0@,%d0
-       subql   #1,%d0
-loopx2:
-       moveb   #0x55, %a1@+
-       dbra    %d0,loopx2
-       dbra    %d1,loopy2
-#endif
-
 L(test_notmac):
 #endif /* CONFIG_MAC */
 
@@ -907,15 +885,15 @@ L(nothp):
  */
 #ifdef CONFIG_MAC
        is_not_mac(L(nocon))
-#ifdef CONSOLE
+#  ifdef CONSOLE
        console_init
-#ifdef CONSOLE_PENGUIN
+#    ifdef CONFIG_LOGO
        console_put_penguin
-#endif /* CONSOLE_PENGUIN */
+#    endif /* CONFIG_LOGO */
        console_put_stats
-#endif /* CONSOLE */
+#  endif /* CONSOLE */
 L(nocon):
-#endif /* CONFIG_MAC */
+#endif /* CONFIG_MAC */
 
 
        putc    '\n'
@@ -3324,14 +3302,13 @@ func_return     set_leds
 #define Lconsole_struct_num_columns    8
 #define Lconsole_struct_num_rows       12
 #define Lconsole_struct_left_edge      16
-#define Lconsole_struct_penguin_putc   20
 
 func_start     console_init,%a0-%a4/%d0-%d7
        /*
         *      Some of the register usage that follows
         *              a0 = pointer to boot_info
         *              a1 = pointer to screen
-        *              a2 = pointer to Lconsole_globals
+        *              a2 = pointer to console_globals
         *              d3 = pixel width of screen
         *              d4 = pixel height of screen
         *              (d3,d4) ~= (x,y) of a point just below
@@ -3456,7 +3433,7 @@ func_start        console_put_stats,%a0/%d7
 
 func_return    console_put_stats
 
-#ifdef CONSOLE_PENGUIN
+#ifdef CONFIG_LOGO
 func_start     console_put_penguin,%a0-%a1/%d0-%d7
        /*
         *      Get 'that_penguin' onto the screen in the upper right corner
@@ -3799,38 +3776,6 @@ L(console_plot_pixel_exit):
 func_return    console_plot_pixel
 #endif /* CONSOLE */
 
-#if 0
-/*
- * This is some old code lying around.  I don't believe
- * it's used or important anymore.  My guess is it contributed
- * to getting to this point, but it's done for now.
- * It was still in the 2.1.77 head.S, so it's still here.
- * (And still not used!)
- */
-L(showtest):
-       moveml  %a0/%d7,%sp@-
-       puts    "A="
-       putn    %a1
-
-       .long   0xf0119f15              | ptestr        #5,%a1@,#7,%a0
-
-       puts    "DA="
-       putn    %a0
-
-       puts    "D="
-       putn    %a0@
-
-       puts    "S="
-       lea     %pc@(L(mmu)),%a0
-       .long   0xf0106200              | pmove         %psr,%a0@
-       clrl    %d7
-       movew   %a0@,%d7
-       putn    %d7
-
-       putc    '\n'
-       moveml  %sp@+,%a0/%d7
-       rts
-#endif /* 0 */
 
 __INITDATA
        .align  4
@@ -3849,7 +3794,6 @@ L(console_globals):
        .long   0               /* max num columns */
        .long   0               /* max num rows */
        .long   0               /* left edge */
-       .long   0               /* mac putc */
 L(console_font):
        .long   0               /* pointer to console font (struct font_desc) */
 L(console_font_data):
index 077d3a70fed1995611f89e0f5795c40da07378df..5b8d66fbf3832a2c70d95d7841f4c5e38e9171cf 100644 (file)
@@ -10,9 +10,9 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
index b716d807c2ece0b222da935b6796f789b2486c97..c29ead89a31778da9d5f217b6cc984c1176a6772 100644 (file)
@@ -13,6 +13,7 @@ generic-y += fb.h
 generic-y += fcntl.h
 generic-y += futex.h
 generic-y += hardirq.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -23,6 +24,7 @@ generic-y += kmap_types.h
 generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += msgbuf.h
 generic-y += mutex.h
 generic-y += param.h
@@ -30,6 +32,7 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += sembuf.h
@@ -52,5 +55,3 @@ generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 2b98bc73642afb4cd07c7c412c416c9a87cb69de..c98ed95c054185913aa3fb63dbf641d6984ba2d8 100644 (file)
@@ -1,8 +1,10 @@
 
 generic-y += barrier.h
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
-generic-y += trace_clock.h
-generic-y += syscalls.h
+generic-y += mcs_spinlock.h
 generic-y += preempt.h
+generic-y += syscalls.h
+generic-y += trace_clock.h
diff --git a/arch/microblaze/include/asm/cputime.h b/arch/microblaze/include/asm/cputime.h
deleted file mode 100644 (file)
index 6d68ad7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
index 66804adcacf02f3430c31f5d1ba275e5d04da382..70996cc66aa228c688d298ade87fd31c5cedaaac 100644 (file)
@@ -1294,11 +1294,6 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       return pci_enable_resources(dev, mask);
-}
-
 static void pcibios_setup_phb_resources(struct pci_controller *hose,
                                        struct list_head *resources)
 {
index dcae3a7035db55a278b1a8cac80faa5ac2199003..95fa1f1d5c8b4a70d3ee991e7a5bb32b5db22740 100644 (file)
@@ -1776,12 +1776,12 @@ endchoice
 
 config FORCE_MAX_ZONEORDER
        int "Maximum zone order"
-       range 14 64 if HUGETLB_PAGE && PAGE_SIZE_64KB
-       default "14" if HUGETLB_PAGE && PAGE_SIZE_64KB
-       range 13 64 if HUGETLB_PAGE && PAGE_SIZE_32KB
-       default "13" if HUGETLB_PAGE && PAGE_SIZE_32KB
-       range 12 64 if HUGETLB_PAGE && PAGE_SIZE_16KB
-       default "12" if HUGETLB_PAGE && PAGE_SIZE_16KB
+       range 14 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+       default "14" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+       range 13 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+       default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+       range 12 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
+       default "12" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
        range 11 64
        default "11"
        help
@@ -2353,9 +2353,8 @@ config SECCOMP
          If unsure, say Y. Only embedded should say N here.
 
 config MIPS_O32_FP64_SUPPORT
-       bool "Support for O32 binaries using 64-bit FP"
+       bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)"
        depends on 32BIT || MIPS32_O32
-       default y
        help
          When this is enabled, the kernel will support use of 64-bit floating
          point registers with binaries using the O32 ABI along with the
@@ -2367,7 +2366,14 @@ config MIPS_O32_FP64_SUPPORT
          of your kernel & potentially improve FP emulation performance by
          saying N here.
 
-         If unsure, say Y.
+         Although binutils currently supports use of this flag the details
+         concerning its effect upon the O32 ABI in userland are still being
+         worked on. In order to avoid userland becoming dependant upon current
+         behaviour before the details have been finalised, this option should
+         be considered experimental and only enabled by those working upon
+         said details.
+
+         If unsure, say N.
 
 config USE_OF
        bool
index 9edc35ff8cf1420e9576f195f92658e71517c073..acf9a2a37f5a055a0c794d7aa62a46e75527f6a4 100644 (file)
@@ -53,10 +53,8 @@ void __init prom_init(void)
        prom_init_cmdline();
 
        memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
+       if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
                memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
        add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
index 9969dbab19e36e3f2bd1210c93840bc85bfd7f16..25a59a23547e392b593a140d4f9bac3f2e882831 100644 (file)
@@ -52,10 +52,8 @@ void __init prom_init(void)
        prom_init_cmdline();
 
        memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
+       if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
                memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
        add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
index 6d612e2b949b20f3875f7993b29de8e77435194c..cdd8246f92b33f8494712247a16348a8b41f27f1 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/errno.h>
 #include <linux/export.h>
 #include <linux/string.h>
 #include <bcm47xx_board.h>
index 6decb27cf48b4343e9358283775f82df82ed0aa5..2bed73a684aea021b4a296076880fed6a2ec489b 100644 (file)
@@ -196,7 +196,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
        char nvram_var[10];
        char buf[30];
 
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < 32; i++) {
                err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
                if (err <= 0)
                        continue;
index 25fbfae06c1f8585359c65d975bfc3240e00faa8..c2bb4f896ce788cbba4b6c48cd18ef875e5bdfd6 100644 (file)
@@ -975,10 +975,6 @@ static int octeon_irq_ciu_xlat(struct irq_domain *d,
        if (ciu > 1 || bit > 63)
                return -EINVAL;
 
-       /* These are the GPIO lines */
-       if (ciu == 0 && bit >= 16 && bit < 32)
-               return -EINVAL;
-
        *out_hwirq = (ciu << 6) | bit;
        *out_type = 0;
 
@@ -1007,6 +1003,10 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
        if (!octeon_irq_virq_in_range(virq))
                return -EINVAL;
 
+       /* Don't map irq if it is reserved for GPIO. */
+       if (line == 0 && bit >= 16 && bit <32)
+               return 0;
+
        if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
                return -EINVAL;
 
@@ -1525,10 +1525,6 @@ static int octeon_irq_ciu2_xlat(struct irq_domain *d,
        ciu = intspec[0];
        bit = intspec[1];
 
-       /* Line 7  are the GPIO lines */
-       if (ciu > 6 || bit > 63)
-               return -EINVAL;
-
        *out_hwirq = (ciu << 6) | bit;
        *out_type = 0;
 
@@ -1570,8 +1566,14 @@ static int octeon_irq_ciu2_map(struct irq_domain *d,
        if (!octeon_irq_virq_in_range(virq))
                return -EINVAL;
 
-       /* Line 7  are the GPIO lines */
-       if (line > 6 || octeon_irq_ciu_to_irq[line][bit] != 0)
+       /*
+        * Don't map irq if it is reserved for GPIO.
+        * (Line 7 are the GPIO lines.)
+        */
+       if (line == 7)
+               return 0;
+
+       if (line > 7 || octeon_irq_ciu_to_irq[line][bit] != 0)
                return -EINVAL;
 
        if (octeon_irq_ciu2_is_edge(line, bit))
index 2d7f65052c1f3ffe9c9f191539a196dff97339f0..05439187891dfa02e582dc1caa2b6abbbfb8395b 100644 (file)
@@ -2,16 +2,17 @@
 generic-y += cputime.h
 generic-y += current.h
 generic-y += emergency-restart.h
+generic-y += hash.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += mutex.h
 generic-y += parport.h
 generic-y += percpu.h
+generic-y += preempt.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += segment.h
 generic-y += serial.h
 generic-y += trace_clock.h
-generic-y += preempt.h
 generic-y += ucontext.h
 generic-y += xor.h
-generic-y += hash.h
index 3220c93ea981da828e94820bb6ec7c9a570db70f..4225e99bd7bfdbe75b0e47cd8b974c2dd92e1ddc 100644 (file)
@@ -9,6 +9,7 @@
 #define _ASM_ASMMACRO_H
 
 #include <asm/hazards.h>
+#include <asm/asm-offsets.h>
 
 #ifdef CONFIG_32BIT
 #include <asm/asmmacro-32.h>
        .endm
 
        .macro  local_irq_disable reg=t0
+#ifdef CONFIG_PREEMPT
+       lw      \reg, TI_PRE_COUNT($28)
+       addi    \reg, \reg, 1
+       sw      \reg, TI_PRE_COUNT($28)
+#endif
        mfc0    \reg, CP0_STATUS
        ori     \reg, \reg, 1
        xori    \reg, \reg, 1
        mtc0    \reg, CP0_STATUS
        irq_disable_hazard
+#ifdef CONFIG_PREEMPT
+       lw      \reg, TI_PRE_COUNT($28)
+       addi    \reg, \reg, -1
+       sw      \reg, TI_PRE_COUNT($28)
+#endif
        .endm
 #endif /* CONFIG_MIPS_MT_SMTC */
 
        .endm
 
        .macro  fpu_save_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        sll     \tmp, \status, 5
        bgez    \tmp, 10f
        fpu_save_16odd \thread
        .endm
 
        .macro  fpu_restore_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        sll     \tmp, \status, 5
        bgez    \tmp, 10f                               # 16 register mode?
 
index 6b9749540edffedf8903b0384cb8a505d1054edd..58e50cbdb1a6d577ef6ffbac115efcd593b6dedc 100644 (file)
@@ -57,7 +57,7 @@ static inline int __enable_fpu(enum fpu_mode mode)
                return 0;
 
        case FPU_64BIT:
-#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
+#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT))
                /* we only have a 32-bit FPU */
                return SIGFPE;
 #endif
index ce35c9af0c28b2dd8d179e1f5ad75d9fc610ba4c..992aaba603b5ca24da6242c5aebef4ea80aeb0e2 100644 (file)
@@ -22,12 +22,12 @@ extern void _mcount(void);
 #define safe_load(load, src, dst, error)               \
 do {                                                   \
        asm volatile (                                  \
-               "1: " load " %[" STR(dst) "], 0(%[" STR(src) "])\n"\
-               "   li %[" STR(error) "], 0\n"          \
+               "1: " load " %[tmp_dst], 0(%[tmp_src])\n"       \
+               "   li %[tmp_err], 0\n"                 \
                "2:\n"                                  \
                                                        \
                ".section .fixup, \"ax\"\n"             \
-               "3: li %[" STR(error) "], 1\n"          \
+               "3: li %[tmp_err], 1\n"                 \
                "   j 2b\n"                             \
                ".previous\n"                           \
                                                        \
@@ -35,8 +35,8 @@ do {                                                  \
                STR(PTR) "\t1b, 3b\n\t"                 \
                ".previous\n"                           \
                                                        \
-               : [dst] "=&r" (dst), [error] "=r" (error)\
-               : [src] "r" (src)                       \
+               : [tmp_dst] "=&r" (dst), [tmp_err] "=r" (error)\
+               : [tmp_src] "r" (src)                   \
                : "memory"                              \
        );                                              \
 } while (0)
@@ -44,12 +44,12 @@ do {                                                        \
 #define safe_store(store, src, dst, error)     \
 do {                                           \
        asm volatile (                          \
-               "1: " store " %[" STR(src) "], 0(%[" STR(dst) "])\n"\
-               "   li %[" STR(error) "], 0\n"  \
+               "1: " store " %[tmp_src], 0(%[tmp_dst])\n"\
+               "   li %[tmp_err], 0\n"         \
                "2:\n"                          \
                                                \
                ".section .fixup, \"ax\"\n"     \
-               "3: li %[" STR(error) "], 1\n"  \
+               "3: li %[tmp_err], 1\n"         \
                "   j 2b\n"                     \
                ".previous\n"                   \
                                                \
@@ -57,8 +57,8 @@ do {                                          \
                STR(PTR) "\t1b, 3b\n\t"         \
                ".previous\n"                   \
                                                \
-               : [error] "=r" (error)          \
-               : [dst] "r" (dst), [src] "r" (src)\
+               : [tmp_err] "=r" (error)        \
+               : [tmp_dst] "r" (dst), [tmp_src] "r" (src)\
                : "memory"                      \
        );                                      \
 } while (0)
index 33e8dbfc1b631626b3f52dd9c60d27957ae0f364..f35b131977e62a3ef0d81c47da6827f47d527b71 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __ASM_MIPS_SYSCALL_H
 #define __ASM_MIPS_SYSCALL_H
 
+#include <linux/compiler.h>
 #include <linux/audit.h>
 #include <linux/elf-em.h>
 #include <linux/kernel.h>
@@ -39,14 +40,14 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
 
 #ifdef CONFIG_32BIT
        case 4: case 5: case 6: case 7:
-               return get_user(*arg, (int *)usp + 4 * n);
+               return get_user(*arg, (int *)usp + n);
 #endif
 
 #ifdef CONFIG_64BIT
        case 4: case 5: case 6: case 7:
 #ifdef CONFIG_MIPS32_O32
                if (test_thread_flag(TIF_32BIT_REGS))
-                       return get_user(*arg, (int *)usp + 4 * n);
+                       return get_user(*arg, (int *)usp + n);
                else
 #endif
                        *arg = regs->regs[4 + n];
@@ -57,6 +58,8 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
        default:
                BUG();
        }
+
+       unreachable();
 }
 
 static inline long syscall_get_return_value(struct task_struct *task,
@@ -83,11 +86,10 @@ static inline void syscall_get_arguments(struct task_struct *task,
                                         unsigned int i, unsigned int n,
                                         unsigned long *args)
 {
-       unsigned long arg;
        int ret;
 
        while (n--)
-               ret |= mips_get_syscall_arg(&arg, task, regs, i++);
+               ret |= mips_get_syscall_arg(args++, task, regs, i++);
 
        /*
         * No way to communicate an error because this is a void function.
index 12609a17dc8b5893faacf8df47b954b10a140664..20ea4859c82259534425ceb3833aa098f7400cf2 100644 (file)
@@ -10,8 +10,4 @@
 
 #include <topology.h>
 
-#ifdef CONFIG_SMP
-#define smt_capable()  (smp_num_siblings > 1)
-#endif
-
 #endif /* __ASM_TOPOLOGY_H */
index 4d3b92886665799d2ca2b746d8efc310cc0c1168..413d6c612bec059e0e5579d3167d67e6bb8e7ad0 100644 (file)
@@ -24,7 +24,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
index b39ba25b41ccd2db0ae723ba01c4fab3a82621a6..f25181b19941db0544dc8e98187827343df99238 100644 (file)
@@ -163,8 +163,8 @@ enum cop1_sdw_func {
  */
 enum cop1x_func {
        lwxc1_op     =  0x00, ldxc1_op     =  0x01,
-       pfetch_op    =  0x07, swxc1_op     =  0x08,
-       sdxc1_op     =  0x09, madd_s_op    =  0x20,
+       swxc1_op     =  0x08, sdxc1_op     =  0x09,
+       pfetch_op    =  0x0f, madd_s_op    =  0x20,
        madd_d_op    =  0x21, madd_e_op    =  0x22,
        msub_s_op    =  0x28, msub_d_op    =  0x29,
        msub_e_op    =  0x2a, nmadd_s_op   =  0x30,
index 185ba258361b979ee9531bd18d38b0242e1de979..374ed74cd516d91e27638ce12e4c3c731a191ef4 100644 (file)
@@ -111,11 +111,10 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
        safe_store_code(new_code1, ip, faulted);
        if (unlikely(faulted))
                return -EFAULT;
-       ip += 4;
-       safe_store_code(new_code2, ip, faulted);
+       safe_store_code(new_code2, ip + 4, faulted);
        if (unlikely(faulted))
                return -EFAULT;
-       flush_icache_range(ip, ip + 8); /* original ip + 12 */
+       flush_icache_range(ip, ip + 8);
        return 0;
 }
 #endif
index 253b2fb520267fb3536584df6d395a6b860392f1..73b0ddf910d41b08dd1bacd97f862e97f94f4c95 100644 (file)
@@ -35,9 +35,9 @@
 LEAF(_save_fp_context)
        cfc1    t1, fcr31
 
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        .set    push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
        .set    mips64r2
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5
@@ -146,11 +146,11 @@ LEAF(_save_fp_context32)
  *  - cp1 status/control register
  */
 LEAF(_restore_fp_context)
-       EX      lw t0, SC_FPC_CSR(a0)
+       EX      lw t1, SC_FPC_CSR(a0)
 
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        .set    push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
        .set    mips64r2
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5
@@ -191,7 +191,7 @@ LEAF(_restore_fp_context)
        EX      ldc1 $f26, SC_FPREGS+208(a0)
        EX      ldc1 $f28, SC_FPREGS+224(a0)
        EX      ldc1 $f30, SC_FPREGS+240(a0)
-       ctc1    t0, fcr31
+       ctc1    t1, fcr31
        jr      ra
         li     v0, 0                                   # success
        END(_restore_fp_context)
@@ -199,7 +199,7 @@ LEAF(_restore_fp_context)
 #ifdef CONFIG_MIPS32_COMPAT
 LEAF(_restore_fp_context32)
        /* Restore an o32 sigcontext.  */
-       EX      lw t0, SC32_FPC_CSR(a0)
+       EX      lw t1, SC32_FPC_CSR(a0)
 
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5
@@ -239,7 +239,7 @@ LEAF(_restore_fp_context32)
        EX      ldc1 $f26, SC32_FPREGS+208(a0)
        EX      ldc1 $f28, SC32_FPREGS+224(a0)
        EX      ldc1 $f30, SC32_FPREGS+240(a0)
-       ctc1    t0, fcr31
+       ctc1    t1, fcr31
        jr      ra
         li     v0, 0                                   # success
        END(_restore_fp_context32)
index 56dc6963515314962ad22ee0a5676edf87937122..758fb3cd2326c34dd119d86d1c3ee5c5d148ee29 100644 (file)
@@ -112,5 +112,8 @@ void __exit rtlx_module_exit(void)
 
        for (i = 0; i < RTLX_CHANNELS; i++)
                device_destroy(mt_class, MKDEV(major, i));
+
        unregister_chrdev(major, RTLX_MODULE_NAME);
+
+       aprp_hook = NULL;
 }
index 91d61ba422b4677fdc956b0a5707ddb58740212a..9c1aca00fd5442e8b44a259ad99e2c328718b600 100644 (file)
@@ -144,5 +144,8 @@ void __exit rtlx_module_exit(void)
 
        for (i = 0; i < RTLX_CHANNELS; i++)
                device_destroy(mt_class, MKDEV(major, i));
+
        unregister_chrdev(major, RTLX_MODULE_NAME);
+
+       aprp_hook = NULL;
 }
index dfc1b911be04b7480cb30809ba59583cc76598b6..c1681d65dd5c8e580cc26dbf896caa90ad857df9 100644 (file)
@@ -1007,7 +1007,7 @@ static void __irq_entry smtc_clock_tick_interrupt(void)
        int irq = MIPS_CPU_IRQ_BASE + 1;
 
        irq_enter();
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
        cd = &per_cpu(mips_clockevent_device, cpu);
        cd->event_handler(cd);
        irq_exit();
index 506925b2c3f366a12aecfb8ecc3cf6d69274654d..0b4e2e38294bf174132fcb4036cc958a370cfbec 100644 (file)
@@ -1538,10 +1538,10 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                break;
        }
 
-       case 0x7:               /* 7 */
-               if (MIPSInst_FUNC(ir) != pfetch_op) {
+       case 0x3:
+               if (MIPSInst_FUNC(ir) != pfetch_op)
                        return SIGILL;
-               }
+
                /* ignore prefx operation */
                break;
 
index 592ac0427426acd4b83d1272f4e8c43c7716bca1..84ac523b0ce08675ecd102a2beeda2b66ce92f11 100644 (file)
@@ -72,7 +72,7 @@ int amon_cpu_start(int cpu,
        return 0;
 }
 
-#ifdef CONFIG_MIPS_VPE_LOADER
+#ifdef CONFIG_MIPS_VPE_LOADER_CMP
 int vpe_run(struct vpe *v)
 {
        struct vpe_notifications *n;
index ca3e3a46a42f90dedc359c1729d7b3c55365fc92..2242181a62841e2c86cd87ab3859bee35ca91099 100644 (file)
@@ -119,7 +119,7 @@ static void malta_hw0_irqdispatch(void)
 
        do_IRQ(MALTA_INT_BASE + irq);
 
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_MT
        if (aprp_hook)
                aprp_hook();
 #endif
@@ -310,7 +310,7 @@ static void ipi_call_dispatch(void)
 
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 {
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_CMP
        if (aprp_hook)
                aprp_hook();
 #endif
index d37be36dc659b4df1f3b22787f84c6908bc5eb45..2b91b0e6156670a723c4cd46749065a0f798d347 100644 (file)
@@ -150,6 +150,7 @@ msi_irq_allocated:
                msg.address_lo =
                        ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
                msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
+               break;
        case OCTEON_DMA_BAR_TYPE_BIG:
                /* When using big bar, Bar 0 is based at 0 */
                msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
index 3db64d51798ddb4afd1fd3893a270c954db0a921..58b40ae5933535bc869f76f4bfacc52fb5f705d4 100644 (file)
@@ -148,7 +148,7 @@ static void __irq_entry indy_buserror_irq(void)
        int irq = SGI_BUSERR_IRQ;
 
        irq_enter();
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
        ip22_be_interrupt(irq);
        irq_exit();
 }
index 6071924493353c96c3c69560f90ab2488d49c617..045aa89f28d8c79fc8ffed9217f9e1a62e56e229 100644 (file)
@@ -123,7 +123,7 @@ void __irq_entry indy_8254timer_irq(void)
        char c;
 
        irq_enter();
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
        printk(KERN_ALERT "Oops, got 8254 interrupt.\n");
        ArcRead(0, &c, 1, &cnt);
        ArcEnterInteractiveMode();
index 09d6e16a70f14f0b294f99a4b193862cfde8dcca..59cfe2659771e058bf08823c8b6b83fa22a44fa7 100644 (file)
@@ -95,7 +95,7 @@ static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
        u64 cur_ints;
        unsigned long flags;
 
-       i = cpumask_first(mask);
+       i = cpumask_first_and(mask, cpu_online_mask);
 
        /* Convert logical CPU to physical CPU */
        cpu = cpu_logical_map(i);
index 54e2c4de15c1638706879b6356c85c13c10165a0..70d9182b26f155703bbf7eb74a781a61681f2dc3 100644 (file)
@@ -182,7 +182,7 @@ void bcm1480_mailbox_interrupt(void)
        int irq = K_BCM1480_INT_MBOX_0_0;
        unsigned int action;
 
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
        /* Load the mailbox register to figure out what we're supposed to do */
        action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
 
index fca0cdb99509a3484e11c022a9e4ec00bfda8dd8..6d8dba5cf3480af010e2f1807238a19a468884de 100644 (file)
@@ -88,7 +88,7 @@ static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask,
        u64 cur_ints;
        unsigned long flags;
 
-       i = cpumask_first(mask);
+       i = cpumask_first_and(mask, cpu_online_mask);
 
        /* Convert logical CPU to physical CPU */
        cpu = cpu_logical_map(i);
index d7b942db0ea519e0c5f6f8b39c69fa21589a5eaa..db976117dd4d77948547b2f34a7a1b7ddde2a15b 100644 (file)
@@ -170,7 +170,7 @@ void sb1250_mailbox_interrupt(void)
        int irq = K_INT_MBOX_0;
        unsigned int action;
 
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
        /* Load the mailbox register to figure out what we're supposed to do */
        action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff;
 
index 992e989ab7853d3f3e1be4bbb432cf4c2de8c7a2..654d5ba6e31077354f130f22a198c7b6adb45743 100644 (file)
@@ -1,7 +1,9 @@
 
 generic-y += barrier.h
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
-generic-y += trace_clock.h
+generic-y += mcs_spinlock.h
 generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/mn10300/include/asm/cputime.h b/arch/mn10300/include/asm/cputime.h
deleted file mode 100644 (file)
index 6d68ad7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
index ccce35e3e179150c87f5f94af2a2463333236a68..60f64ca1752aff964ee6274ed066ccf9744d5034 100644 (file)
@@ -113,7 +113,7 @@ int __init init_clockevents(void)
        cd->set_next_event      = next_event;
 
        iact = &per_cpu(timer_irq, cpu);
-       iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;
+       iact->flags = IRQF_SHARED | IRQF_TIMER;
        iact->handler = timer_interrupt;
 
        clockevents_register_device(cd);
index bf6e949a2f87a63f701f3a23a468574da4561cfe..7ecf69879e2d6ff077296a79605d8f367b70fdd4 100644 (file)
@@ -985,17 +985,17 @@ static int mn10300_serial_startup(struct uart_port *_port)
        irq_set_chip(port->tm_irq, &mn10300_serial_pic);
 
        if (request_irq(port->rx_irq, mn10300_serial_interrupt,
-                       IRQF_DISABLED | IRQF_NOBALANCING,
+                       IRQF_NOBALANCING,
                        port->rx_name, port) < 0)
                goto error;
 
        if (request_irq(port->tx_irq, mn10300_serial_interrupt,
-                       IRQF_DISABLED | IRQF_NOBALANCING,
+                       IRQF_NOBALANCING,
                        port->tx_name, port) < 0)
                goto error2;
 
        if (request_irq(port->tm_irq, mn10300_serial_interrupt,
-                       IRQF_DISABLED | IRQF_NOBALANCING,
+                       IRQF_NOBALANCING,
                        port->tm_name, port) < 0)
                goto error3;
        mn10300_serial_mask_ack(port->tm_irq);
index db64a7166c095850c6bf18fcadcdaa3a444859fe..a2d8e6938d6716bca53162a00775291bca58d227 100644 (file)
@@ -142,7 +142,7 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
        NMICR = NMICR_WDIF;
 
        nmi_count(smp_processor_id())++;
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
 
        for_each_online_cpu(cpu) {
 
index a17f9c9c14c9f3b7115d41f4ad765ee70de3ba2a..f984193718b1003f03861e79cd137b4a8c23badd 100644 (file)
@@ -143,7 +143,7 @@ static struct irqaction call_function_ipi = {
 static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
 static struct irqaction local_timer_ipi = {
        .handler        = smp_ipi_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_NOBALANCING,
+       .flags          = IRQF_NOBALANCING,
        .name           = "smp local timer IPI"
 };
 #endif
index e16c216f31dcdd3ce0c4279f6e921ce13db1f41e..073e2ccc4a441b419bc58c2207eba4f5e7eae81c 100644 (file)
@@ -76,7 +76,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask)
 static struct irqaction fpga_irq[]  = {
        [0] = {
                .handler        = fpga_interrupt,
-               .flags          = IRQF_DISABLED | IRQF_SHARED,
+               .flags          = IRQF_SHARED,
                .name           = "fpga",
        },
 };
index 2e40f1ca86677ecff7f232beb909128aa509e9d3..480af0d9c2f5dbe20fb39dc6331648dacb043a97 100644 (file)
@@ -10,8 +10,8 @@ generic-y += bugs.h
 generic-y += cacheflush.h
 generic-y += checksum.h
 generic-y += clkdev.h
-generic-y += cmpxchg.h
 generic-y += cmpxchg-local.h
+generic-y += cmpxchg.h
 generic-y += cputime.h
 generic-y += current.h
 generic-y += device.h
@@ -25,6 +25,7 @@ generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += futex.h
 generic-y += hardirq.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -34,6 +35,7 @@ generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
 generic-y += local.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += module.h
 generic-y += msgbuf.h
@@ -41,6 +43,7 @@ generic-y += pci.h
 generic-y += percpu.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sections.h
@@ -53,11 +56,11 @@ generic-y += siginfo.h
 generic-y += signal.h
 generic-y += socket.h
 generic-y += sockios.h
-generic-y += statfs.h
 generic-y += stat.h
+generic-y += statfs.h
 generic-y += string.h
-generic-y += switch_to.h
 generic-y += swab.h
+generic-y += switch_to.h
 generic-y += termbits.h
 generic-y += termios.h
 generic-y += topology.h
@@ -68,5 +71,3 @@ generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 752c981bc3c7fc36dbd0fb01705f4c691e7ee6bd..ecf25e6678ad5a2f0e2bd63761699e85c9d2d759 100644 (file)
@@ -1,9 +1,29 @@
 
+generic-y += auxvec.h
 generic-y += barrier.h
-generic-y += word-at-a-time.h auxvec.h user.h cputime.h emergency-restart.h \
-         segment.h topology.h vga.h device.h percpu.h hw_irq.h mutex.h \
-         div64.h irq_regs.h kdebug.h kvm_para.h local64.h local.h param.h \
-         poll.h xor.h clkdev.h exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += exec.h
 generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kvm_para.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += preempt.h
+generic-y += segment.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += user.h
+generic-y += vga.h
+generic-y += word-at-a-time.h
+generic-y += xor.h
index 637fe031aa8476d743a8141ca9b549019985a0c6..60d5d174dfe413e14cb5117a04536ce7948d937d 100644 (file)
@@ -32,17 +32,6 @@ void copy_page_asm(void *to, void *from);
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
                        struct page *pg);
 
-/* #define CONFIG_PARISC_TMPALIAS */
-
-#ifdef CONFIG_PARISC_TMPALIAS
-void clear_user_highpage(struct page *page, unsigned long vaddr);
-#define clear_user_highpage clear_user_highpage
-struct vm_area_struct;
-void copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr, struct vm_area_struct *vma);
-#define __HAVE_ARCH_COPY_USER_HIGHPAGE
-#endif
-
 /*
  * These are used to make use of C type-checking..
  */
index 3516e0b27044d5e5cf987cf53acf735059a5b016..64f2992e439fcd81811e7a44d322bdc5aafd9ff1 100644 (file)
@@ -191,8 +191,4 @@ static __inline__ int arch_write_can_lock(arch_rwlock_t *rw)
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
 
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SPINLOCK_H */
index 42706794a36f34d12fa598df238ade3db602e9c6..265ae5190b0a70e4dc2539d9a661e1e3d2deda05 100644 (file)
 #define __NR_finit_module      (__NR_Linux + 333)
 #define __NR_sched_setattr     (__NR_Linux + 334)
 #define __NR_sched_getattr     (__NR_Linux + 335)
+#define __NR_utimes            (__NR_Linux + 336)
 
-#define __NR_Linux_syscalls    (__NR_sched_getattr + 1)
+#define __NR_Linux_syscalls    (__NR_utimes + 1)
 
 
 #define __IGNORE_select                /* newselect */
 #define __IGNORE_fadvise64     /* fadvise64_64 */
-#define __IGNORE_utimes                /* utime */
 
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
index ac87a40502e6f6a0e11d21eaf6789259859ad092..a6ffc775a9f8105381b3da46214290a421a79c6c 100644 (file)
@@ -581,67 +581,3 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
                __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
        }
 }
-
-#ifdef CONFIG_PARISC_TMPALIAS
-
-void clear_user_highpage(struct page *page, unsigned long vaddr)
-{
-       void *vto;
-       unsigned long flags;
-
-       /* Clear using TMPALIAS region.  The page doesn't need to
-          be flushed but the kernel mapping needs to be purged.  */
-
-       vto = kmap_atomic(page);
-
-       /* The PA-RISC 2.0 Architecture book states on page F-6:
-          "Before a write-capable translation is enabled, *all*
-          non-equivalently-aliased translations must be removed
-          from the page table and purged from the TLB.  (Note
-          that the caches are not required to be flushed at this
-          time.)  Before any non-equivalent aliased translation
-          is re-enabled, the virtual address range for the writeable
-          page (the entire page) must be flushed from the cache,
-          and the write-capable translation removed from the page
-          table and purged from the TLB."  */
-
-       purge_kernel_dcache_page_asm((unsigned long)vto);
-       purge_tlb_start(flags);
-       pdtlb_kernel(vto);
-       purge_tlb_end(flags);
-       preempt_disable();
-       clear_user_page_asm(vto, vaddr);
-       preempt_enable();
-
-       pagefault_enable();             /* kunmap_atomic(addr, KM_USER0); */
-}
-
-void copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr, struct vm_area_struct *vma)
-{
-       void *vfrom, *vto;
-       unsigned long flags;
-
-       /* Copy using TMPALIAS region.  This has the advantage
-          that the `from' page doesn't need to be flushed.  However,
-          the `to' page must be flushed in copy_user_page_asm since
-          it can be used to bring in executable code.  */
-
-       vfrom = kmap_atomic(from);
-       vto = kmap_atomic(to);
-
-       purge_kernel_dcache_page_asm((unsigned long)vto);
-       purge_tlb_start(flags);
-       pdtlb_kernel(vto);
-       pdtlb_kernel(vfrom);
-       purge_tlb_end(flags);
-       preempt_disable();
-       copy_user_page_asm(vto, vfrom, vaddr);
-       flush_dcache_page_asm(__pa(vto), vaddr);
-       preempt_enable();
-
-       pagefault_enable();             /* kunmap_atomic(addr, KM_USER1); */
-       pagefault_enable();             /* kunmap_atomic(addr, KM_USER0); */
-}
-
-#endif /* CONFIG_PARISC_TMPALIAS */
index 8ceac4785609279079e321384ec8e6b59a2b4cc7..cfe056fe7f5c636f45f642950a01e0ce4cb7e536 100644 (file)
@@ -117,7 +117,7 @@ int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest)
                return -EINVAL;
 
        /* whatever mask they set, we just allow one CPU */
-       cpu_dest = first_cpu(*dest);
+       cpu_dest = cpumask_first_and(dest, cpu_online_mask);
 
        return cpu_dest;
 }
index 8fa3fbb3e4d3806f15ab0d98543a35d8b18155ce..80e5dd248934e26ca94916c1e1f7c2cd6cffbefd 100644 (file)
        ENTRY_SAME(finit_module)
        ENTRY_SAME(sched_setattr)
        ENTRY_SAME(sched_getattr)       /* 335 */
+       ENTRY_COMP(utimes)
 
        /* Nothing yet */
 
index 957bf344c0f533e4ebf0c6248b3ba02caf3d8595..b9fcecc706ab3eb072349eb07c4ad0439a8a5eac 100644 (file)
@@ -736,10 +736,6 @@ config FSL_LBC
          controller.  Also contains some common code used by
          drivers for specific local bus peripherals.
 
-config FSL_IFC
-       bool
-        depends on FSL_SOC
-
 config FSL_GTM
        bool
        depends on PPC_83xx || QUICC_ENGINE || CPM2
index 6c0a955a1b06277d05b7bf159da202279b2038e9..3fb1bc432f4f6106f1a892ce02113ec68970af6a 100644 (file)
@@ -1,7 +1,8 @@
 
 generic-y += clkdev.h
+generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
 generic-y += rwsem.h
 generic-y += trace_clock.h
-generic-y += preempt.h
 generic-y += vtime.h
-generic-y += hash.h
diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h
deleted file mode 100644 (file)
index f49ddb1..0000000
+++ /dev/null
@@ -1,838 +0,0 @@
-/* Freescale Integrated Flash Controller
- *
- * Copyright 2011 Freescale Semiconductor, Inc
- *
- * Author: Dipen Dudhat <dipen.dudhat@freescale.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
- */
-
-#ifndef __ASM_FSL_IFC_H
-#define __ASM_FSL_IFC_H
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/io.h>
-
-#include <linux/of_platform.h>
-#include <linux/interrupt.h>
-
-#define FSL_IFC_BANK_COUNT 4
-
-/*
- * CSPR - Chip Select Property Register
- */
-#define CSPR_BA                                0xFFFF0000
-#define CSPR_BA_SHIFT                  16
-#define CSPR_PORT_SIZE                 0x00000180
-#define CSPR_PORT_SIZE_SHIFT           7
-/* Port Size 8 bit */
-#define CSPR_PORT_SIZE_8               0x00000080
-/* Port Size 16 bit */
-#define CSPR_PORT_SIZE_16              0x00000100
-/* Port Size 32 bit */
-#define CSPR_PORT_SIZE_32              0x00000180
-/* Write Protect */
-#define CSPR_WP                                0x00000040
-#define CSPR_WP_SHIFT                  6
-/* Machine Select */
-#define CSPR_MSEL                      0x00000006
-#define CSPR_MSEL_SHIFT                        1
-/* NOR */
-#define CSPR_MSEL_NOR                  0x00000000
-/* NAND */
-#define CSPR_MSEL_NAND                 0x00000002
-/* GPCM */
-#define CSPR_MSEL_GPCM                 0x00000004
-/* Bank Valid */
-#define CSPR_V                         0x00000001
-#define CSPR_V_SHIFT                   0
-
-/*
- * Address Mask Register
- */
-#define IFC_AMASK_MASK                 0xFFFF0000
-#define IFC_AMASK_SHIFT                        16
-#define IFC_AMASK(n)                   (IFC_AMASK_MASK << \
-                                       (__ilog2(n) - IFC_AMASK_SHIFT))
-
-/*
- * Chip Select Option Register IFC_NAND Machine
- */
-/* Enable ECC Encoder */
-#define CSOR_NAND_ECC_ENC_EN           0x80000000
-#define CSOR_NAND_ECC_MODE_MASK                0x30000000
-/* 4 bit correction per 520 Byte sector */
-#define CSOR_NAND_ECC_MODE_4           0x00000000
-/* 8 bit correction per 528 Byte sector */
-#define CSOR_NAND_ECC_MODE_8           0x10000000
-/* Enable ECC Decoder */
-#define CSOR_NAND_ECC_DEC_EN           0x04000000
-/* Row Address Length */
-#define CSOR_NAND_RAL_MASK             0x01800000
-#define CSOR_NAND_RAL_SHIFT            20
-#define CSOR_NAND_RAL_1                        0x00000000
-#define CSOR_NAND_RAL_2                        0x00800000
-#define CSOR_NAND_RAL_3                        0x01000000
-#define CSOR_NAND_RAL_4                        0x01800000
-/* Page Size 512b, 2k, 4k */
-#define CSOR_NAND_PGS_MASK             0x00180000
-#define CSOR_NAND_PGS_SHIFT            16
-#define CSOR_NAND_PGS_512              0x00000000
-#define CSOR_NAND_PGS_2K               0x00080000
-#define CSOR_NAND_PGS_4K               0x00100000
-#define CSOR_NAND_PGS_8K               0x00180000
-/* Spare region Size */
-#define CSOR_NAND_SPRZ_MASK            0x0000E000
-#define CSOR_NAND_SPRZ_SHIFT           13
-#define CSOR_NAND_SPRZ_16              0x00000000
-#define CSOR_NAND_SPRZ_64              0x00002000
-#define CSOR_NAND_SPRZ_128             0x00004000
-#define CSOR_NAND_SPRZ_210             0x00006000
-#define CSOR_NAND_SPRZ_218             0x00008000
-#define CSOR_NAND_SPRZ_224             0x0000A000
-#define CSOR_NAND_SPRZ_CSOR_EXT                0x0000C000
-/* Pages Per Block */
-#define CSOR_NAND_PB_MASK              0x00000700
-#define CSOR_NAND_PB_SHIFT             8
-#define CSOR_NAND_PB(n)                ((__ilog2(n) - 5) << CSOR_NAND_PB_SHIFT)
-/* Time for Read Enable High to Output High Impedance */
-#define CSOR_NAND_TRHZ_MASK            0x0000001C
-#define CSOR_NAND_TRHZ_SHIFT           2
-#define CSOR_NAND_TRHZ_20              0x00000000
-#define CSOR_NAND_TRHZ_40              0x00000004
-#define CSOR_NAND_TRHZ_60              0x00000008
-#define CSOR_NAND_TRHZ_80              0x0000000C
-#define CSOR_NAND_TRHZ_100             0x00000010
-/* Buffer control disable */
-#define CSOR_NAND_BCTLD                        0x00000001
-
-/*
- * Chip Select Option Register - NOR Flash Mode
- */
-/* Enable Address shift Mode */
-#define CSOR_NOR_ADM_SHFT_MODE_EN      0x80000000
-/* Page Read Enable from NOR device */
-#define CSOR_NOR_PGRD_EN               0x10000000
-/* AVD Toggle Enable during Burst Program */
-#define CSOR_NOR_AVD_TGL_PGM_EN                0x01000000
-/* Address Data Multiplexing Shift */
-#define CSOR_NOR_ADM_MASK              0x0003E000
-#define CSOR_NOR_ADM_SHIFT_SHIFT       13
-#define CSOR_NOR_ADM_SHIFT(n)  ((n) << CSOR_NOR_ADM_SHIFT_SHIFT)
-/* Type of the NOR device hooked */
-#define CSOR_NOR_NOR_MODE_AYSNC_NOR    0x00000000
-#define CSOR_NOR_NOR_MODE_AVD_NOR      0x00000020
-/* Time for Read Enable High to Output High Impedance */
-#define CSOR_NOR_TRHZ_MASK             0x0000001C
-#define CSOR_NOR_TRHZ_SHIFT            2
-#define CSOR_NOR_TRHZ_20               0x00000000
-#define CSOR_NOR_TRHZ_40               0x00000004
-#define CSOR_NOR_TRHZ_60               0x00000008
-#define CSOR_NOR_TRHZ_80               0x0000000C
-#define CSOR_NOR_TRHZ_100              0x00000010
-/* Buffer control disable */
-#define CSOR_NOR_BCTLD                 0x00000001
-
-/*
- * Chip Select Option Register - GPCM Mode
- */
-/* GPCM Mode - Normal */
-#define CSOR_GPCM_GPMODE_NORMAL                0x00000000
-/* GPCM Mode - GenericASIC */
-#define CSOR_GPCM_GPMODE_ASIC          0x80000000
-/* Parity Mode odd/even */
-#define CSOR_GPCM_PARITY_EVEN          0x40000000
-/* Parity Checking enable/disable */
-#define CSOR_GPCM_PAR_EN               0x20000000
-/* GPCM Timeout Count */
-#define CSOR_GPCM_GPTO_MASK            0x0F000000
-#define CSOR_GPCM_GPTO_SHIFT           24
-#define CSOR_GPCM_GPTO(n)      ((__ilog2(n) - 8) << CSOR_GPCM_GPTO_SHIFT)
-/* GPCM External Access Termination mode for read access */
-#define CSOR_GPCM_RGETA_EXT            0x00080000
-/* GPCM External Access Termination mode for write access */
-#define CSOR_GPCM_WGETA_EXT            0x00040000
-/* Address Data Multiplexing Shift */
-#define CSOR_GPCM_ADM_MASK             0x0003E000
-#define CSOR_GPCM_ADM_SHIFT_SHIFT      13
-#define CSOR_GPCM_ADM_SHIFT(n) ((n) << CSOR_GPCM_ADM_SHIFT_SHIFT)
-/* Generic ASIC Parity error indication delay */
-#define CSOR_GPCM_GAPERRD_MASK         0x00000180
-#define CSOR_GPCM_GAPERRD_SHIFT                7
-#define CSOR_GPCM_GAPERRD(n)   (((n) - 1) << CSOR_GPCM_GAPERRD_SHIFT)
-/* Time for Read Enable High to Output High Impedance */
-#define CSOR_GPCM_TRHZ_MASK            0x0000001C
-#define CSOR_GPCM_TRHZ_20              0x00000000
-#define CSOR_GPCM_TRHZ_40              0x00000004
-#define CSOR_GPCM_TRHZ_60              0x00000008
-#define CSOR_GPCM_TRHZ_80              0x0000000C
-#define CSOR_GPCM_TRHZ_100             0x00000010
-/* Buffer control disable */
-#define CSOR_GPCM_BCTLD                        0x00000001
-
-/*
- * Ready Busy Status Register (RB_STAT)
- */
-/* CSn is READY */
-#define IFC_RB_STAT_READY_CS0          0x80000000
-#define IFC_RB_STAT_READY_CS1          0x40000000
-#define IFC_RB_STAT_READY_CS2          0x20000000
-#define IFC_RB_STAT_READY_CS3          0x10000000
-
-/*
- * General Control Register (GCR)
- */
-#define IFC_GCR_MASK                   0x8000F800
-/* reset all IFC hardware */
-#define IFC_GCR_SOFT_RST_ALL           0x80000000
-/* Turnaroud Time of external buffer */
-#define IFC_GCR_TBCTL_TRN_TIME         0x0000F800
-#define IFC_GCR_TBCTL_TRN_TIME_SHIFT   11
-
-/*
- * Common Event and Error Status Register (CM_EVTER_STAT)
- */
-/* Chip select error */
-#define IFC_CM_EVTER_STAT_CSER         0x80000000
-
-/*
- * Common Event and Error Enable Register (CM_EVTER_EN)
- */
-/* Chip select error checking enable */
-#define IFC_CM_EVTER_EN_CSEREN         0x80000000
-
-/*
- * Common Event and Error Interrupt Enable Register (CM_EVTER_INTR_EN)
- */
-/* Chip select error interrupt enable */
-#define IFC_CM_EVTER_INTR_EN_CSERIREN  0x80000000
-
-/*
- * Common Transfer Error Attribute Register-0 (CM_ERATTR0)
- */
-/* transaction type of error Read/Write */
-#define IFC_CM_ERATTR0_ERTYP_READ      0x80000000
-#define IFC_CM_ERATTR0_ERAID           0x0FF00000
-#define IFC_CM_ERATTR0_ERAID_SHIFT     20
-#define IFC_CM_ERATTR0_ESRCID          0x0000FF00
-#define IFC_CM_ERATTR0_ESRCID_SHIFT    8
-
-/*
- * Clock Control Register (CCR)
- */
-#define IFC_CCR_MASK                   0x0F0F8800
-/* Clock division ratio */
-#define IFC_CCR_CLK_DIV_MASK           0x0F000000
-#define IFC_CCR_CLK_DIV_SHIFT          24
-#define IFC_CCR_CLK_DIV(n)             ((n-1) << IFC_CCR_CLK_DIV_SHIFT)
-/* IFC Clock Delay */
-#define IFC_CCR_CLK_DLY_MASK           0x000F0000
-#define IFC_CCR_CLK_DLY_SHIFT          16
-#define IFC_CCR_CLK_DLY(n)             ((n) << IFC_CCR_CLK_DLY_SHIFT)
-/* Invert IFC clock before sending out */
-#define IFC_CCR_INV_CLK_EN             0x00008000
-/* Fedback IFC Clock */
-#define IFC_CCR_FB_IFC_CLK_SEL         0x00000800
-
-/*
- * Clock Status Register (CSR)
- */
-/* Clk is stable */
-#define IFC_CSR_CLK_STAT_STABLE                0x80000000
-
-/*
- * IFC_NAND Machine Specific Registers
- */
-/*
- * NAND Configuration Register (NCFGR)
- */
-/* Auto Boot Mode */
-#define IFC_NAND_NCFGR_BOOT            0x80000000
-/* Addressing Mode-ROW0+n/COL0 */
-#define IFC_NAND_NCFGR_ADDR_MODE_RC0   0x00000000
-/* Addressing Mode-ROW0+n/COL0+n */
-#define IFC_NAND_NCFGR_ADDR_MODE_RC1   0x00400000
-/* Number of loop iterations of FIR sequences for multi page operations */
-#define IFC_NAND_NCFGR_NUM_LOOP_MASK   0x0000F000
-#define IFC_NAND_NCFGR_NUM_LOOP_SHIFT  12
-#define IFC_NAND_NCFGR_NUM_LOOP(n)     ((n) << IFC_NAND_NCFGR_NUM_LOOP_SHIFT)
-/* Number of wait cycles */
-#define IFC_NAND_NCFGR_NUM_WAIT_MASK   0x000000FF
-#define IFC_NAND_NCFGR_NUM_WAIT_SHIFT  0
-
-/*
- * NAND Flash Command Registers (NAND_FCR0/NAND_FCR1)
- */
-/* General purpose FCM flash command bytes CMD0-CMD7 */
-#define IFC_NAND_FCR0_CMD0             0xFF000000
-#define IFC_NAND_FCR0_CMD0_SHIFT       24
-#define IFC_NAND_FCR0_CMD1             0x00FF0000
-#define IFC_NAND_FCR0_CMD1_SHIFT       16
-#define IFC_NAND_FCR0_CMD2             0x0000FF00
-#define IFC_NAND_FCR0_CMD2_SHIFT       8
-#define IFC_NAND_FCR0_CMD3             0x000000FF
-#define IFC_NAND_FCR0_CMD3_SHIFT       0
-#define IFC_NAND_FCR1_CMD4             0xFF000000
-#define IFC_NAND_FCR1_CMD4_SHIFT       24
-#define IFC_NAND_FCR1_CMD5             0x00FF0000
-#define IFC_NAND_FCR1_CMD5_SHIFT       16
-#define IFC_NAND_FCR1_CMD6             0x0000FF00
-#define IFC_NAND_FCR1_CMD6_SHIFT       8
-#define IFC_NAND_FCR1_CMD7             0x000000FF
-#define IFC_NAND_FCR1_CMD7_SHIFT       0
-
-/*
- * Flash ROW and COL Address Register (ROWn, COLn)
- */
-/* Main/spare region locator */
-#define IFC_NAND_COL_MS                        0x80000000
-/* Column Address */
-#define IFC_NAND_COL_CA_MASK           0x00000FFF
-
-/*
- * NAND Flash Byte Count Register (NAND_BC)
- */
-/* Byte Count for read/Write */
-#define IFC_NAND_BC                    0x000001FF
-
-/*
- * NAND Flash Instruction Registers (NAND_FIR0/NAND_FIR1/NAND_FIR2)
- */
-/* NAND Machine specific opcodes OP0-OP14*/
-#define IFC_NAND_FIR0_OP0              0xFC000000
-#define IFC_NAND_FIR0_OP0_SHIFT                26
-#define IFC_NAND_FIR0_OP1              0x03F00000
-#define IFC_NAND_FIR0_OP1_SHIFT                20
-#define IFC_NAND_FIR0_OP2              0x000FC000
-#define IFC_NAND_FIR0_OP2_SHIFT                14
-#define IFC_NAND_FIR0_OP3              0x00003F00
-#define IFC_NAND_FIR0_OP3_SHIFT                8
-#define IFC_NAND_FIR0_OP4              0x000000FC
-#define IFC_NAND_FIR0_OP4_SHIFT                2
-#define IFC_NAND_FIR1_OP5              0xFC000000
-#define IFC_NAND_FIR1_OP5_SHIFT                26
-#define IFC_NAND_FIR1_OP6              0x03F00000
-#define IFC_NAND_FIR1_OP6_SHIFT                20
-#define IFC_NAND_FIR1_OP7              0x000FC000
-#define IFC_NAND_FIR1_OP7_SHIFT                14
-#define IFC_NAND_FIR1_OP8              0x00003F00
-#define IFC_NAND_FIR1_OP8_SHIFT                8
-#define IFC_NAND_FIR1_OP9              0x000000FC
-#define IFC_NAND_FIR1_OP9_SHIFT                2
-#define IFC_NAND_FIR2_OP10             0xFC000000
-#define IFC_NAND_FIR2_OP10_SHIFT       26
-#define IFC_NAND_FIR2_OP11             0x03F00000
-#define IFC_NAND_FIR2_OP11_SHIFT       20
-#define IFC_NAND_FIR2_OP12             0x000FC000
-#define IFC_NAND_FIR2_OP12_SHIFT       14
-#define IFC_NAND_FIR2_OP13             0x00003F00
-#define IFC_NAND_FIR2_OP13_SHIFT       8
-#define IFC_NAND_FIR2_OP14             0x000000FC
-#define IFC_NAND_FIR2_OP14_SHIFT       2
-
-/*
- * Instruction opcodes to be programmed
- * in FIR registers- 6bits
- */
-enum ifc_nand_fir_opcodes {
-       IFC_FIR_OP_NOP,
-       IFC_FIR_OP_CA0,
-       IFC_FIR_OP_CA1,
-       IFC_FIR_OP_CA2,
-       IFC_FIR_OP_CA3,
-       IFC_FIR_OP_RA0,
-       IFC_FIR_OP_RA1,
-       IFC_FIR_OP_RA2,
-       IFC_FIR_OP_RA3,
-       IFC_FIR_OP_CMD0,
-       IFC_FIR_OP_CMD1,
-       IFC_FIR_OP_CMD2,
-       IFC_FIR_OP_CMD3,
-       IFC_FIR_OP_CMD4,
-       IFC_FIR_OP_CMD5,
-       IFC_FIR_OP_CMD6,
-       IFC_FIR_OP_CMD7,
-       IFC_FIR_OP_CW0,
-       IFC_FIR_OP_CW1,
-       IFC_FIR_OP_CW2,
-       IFC_FIR_OP_CW3,
-       IFC_FIR_OP_CW4,
-       IFC_FIR_OP_CW5,
-       IFC_FIR_OP_CW6,
-       IFC_FIR_OP_CW7,
-       IFC_FIR_OP_WBCD,
-       IFC_FIR_OP_RBCD,
-       IFC_FIR_OP_BTRD,
-       IFC_FIR_OP_RDSTAT,
-       IFC_FIR_OP_NWAIT,
-       IFC_FIR_OP_WFR,
-       IFC_FIR_OP_SBRD,
-       IFC_FIR_OP_UA,
-       IFC_FIR_OP_RB,
-};
-
-/*
- * NAND Chip Select Register (NAND_CSEL)
- */
-#define IFC_NAND_CSEL                  0x0C000000
-#define IFC_NAND_CSEL_SHIFT            26
-#define IFC_NAND_CSEL_CS0              0x00000000
-#define IFC_NAND_CSEL_CS1              0x04000000
-#define IFC_NAND_CSEL_CS2              0x08000000
-#define IFC_NAND_CSEL_CS3              0x0C000000
-
-/*
- * NAND Operation Sequence Start (NANDSEQ_STRT)
- */
-/* NAND Flash Operation Start */
-#define IFC_NAND_SEQ_STRT_FIR_STRT     0x80000000
-/* Automatic Erase */
-#define IFC_NAND_SEQ_STRT_AUTO_ERS     0x00800000
-/* Automatic Program */
-#define IFC_NAND_SEQ_STRT_AUTO_PGM     0x00100000
-/* Automatic Copyback */
-#define IFC_NAND_SEQ_STRT_AUTO_CPB     0x00020000
-/* Automatic Read Operation */
-#define IFC_NAND_SEQ_STRT_AUTO_RD      0x00004000
-/* Automatic Status Read */
-#define IFC_NAND_SEQ_STRT_AUTO_STAT_RD 0x00000800
-
-/*
- * NAND Event and Error Status Register (NAND_EVTER_STAT)
- */
-/* Operation Complete */
-#define IFC_NAND_EVTER_STAT_OPC                0x80000000
-/* Flash Timeout Error */
-#define IFC_NAND_EVTER_STAT_FTOER      0x08000000
-/* Write Protect Error */
-#define IFC_NAND_EVTER_STAT_WPER       0x04000000
-/* ECC Error */
-#define IFC_NAND_EVTER_STAT_ECCER      0x02000000
-/* RCW Load Done */
-#define IFC_NAND_EVTER_STAT_RCW_DN     0x00008000
-/* Boot Loadr Done */
-#define IFC_NAND_EVTER_STAT_BOOT_DN    0x00004000
-/* Bad Block Indicator search select */
-#define IFC_NAND_EVTER_STAT_BBI_SRCH_SE        0x00000800
-
-/*
- * NAND Flash Page Read Completion Event Status Register
- * (PGRDCMPL_EVT_STAT)
- */
-#define PGRDCMPL_EVT_STAT_MASK         0xFFFF0000
-/* Small Page 0-15 Done */
-#define PGRDCMPL_EVT_STAT_SECTION_SP(n)        (1 << (31 - (n)))
-/* Large Page(2K) 0-3 Done */
-#define PGRDCMPL_EVT_STAT_LP_2K(n)     (0xF << (28 - (n)*4))
-/* Large Page(4K) 0-1 Done */
-#define PGRDCMPL_EVT_STAT_LP_4K(n)     (0xFF << (24 - (n)*8))
-
-/*
- * NAND Event and Error Enable Register (NAND_EVTER_EN)
- */
-/* Operation complete event enable */
-#define IFC_NAND_EVTER_EN_OPC_EN       0x80000000
-/* Page read complete event enable */
-#define IFC_NAND_EVTER_EN_PGRDCMPL_EN  0x20000000
-/* Flash Timeout error enable */
-#define IFC_NAND_EVTER_EN_FTOER_EN     0x08000000
-/* Write Protect error enable */
-#define IFC_NAND_EVTER_EN_WPER_EN      0x04000000
-/* ECC error logging enable */
-#define IFC_NAND_EVTER_EN_ECCER_EN     0x02000000
-
-/*
- * NAND Event and Error Interrupt Enable Register (NAND_EVTER_INTR_EN)
- */
-/* Enable interrupt for operation complete */
-#define IFC_NAND_EVTER_INTR_OPCIR_EN           0x80000000
-/* Enable interrupt for Page read complete */
-#define IFC_NAND_EVTER_INTR_PGRDCMPLIR_EN      0x20000000
-/* Enable interrupt for Flash timeout error */
-#define IFC_NAND_EVTER_INTR_FTOERIR_EN         0x08000000
-/* Enable interrupt for Write protect error */
-#define IFC_NAND_EVTER_INTR_WPERIR_EN          0x04000000
-/* Enable interrupt for ECC error*/
-#define IFC_NAND_EVTER_INTR_ECCERIR_EN         0x02000000
-
-/*
- * NAND Transfer Error Attribute Register-0 (NAND_ERATTR0)
- */
-#define IFC_NAND_ERATTR0_MASK          0x0C080000
-/* Error on CS0-3 for NAND */
-#define IFC_NAND_ERATTR0_ERCS_CS0      0x00000000
-#define IFC_NAND_ERATTR0_ERCS_CS1      0x04000000
-#define IFC_NAND_ERATTR0_ERCS_CS2      0x08000000
-#define IFC_NAND_ERATTR0_ERCS_CS3      0x0C000000
-/* Transaction type of error Read/Write */
-#define IFC_NAND_ERATTR0_ERTTYPE_READ  0x00080000
-
-/*
- * NAND Flash Status Register (NAND_FSR)
- */
-/* First byte of data read from read status op */
-#define IFC_NAND_NFSR_RS0              0xFF000000
-/* Second byte of data read from read status op */
-#define IFC_NAND_NFSR_RS1              0x00FF0000
-
-/*
- * ECC Error Status Registers (ECCSTAT0-ECCSTAT3)
- */
-/* Number of ECC errors on sector n (n = 0-15) */
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_MASK  0x0F000000
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_SHIFT 24
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_MASK  0x000F0000
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_SHIFT 16
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_MASK  0x00000F00
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_SHIFT 8
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_MASK  0x0000000F
-#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_SHIFT 0
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_MASK  0x0F000000
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_SHIFT 24
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_MASK  0x000F0000
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_SHIFT 16
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_MASK  0x00000F00
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_SHIFT 8
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_MASK  0x0000000F
-#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_SHIFT 0
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_MASK  0x0F000000
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_SHIFT 24
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_MASK  0x000F0000
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_SHIFT 16
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_MASK 0x00000F00
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_SHIFT        8
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_MASK 0x0000000F
-#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_SHIFT        0
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_MASK 0x0F000000
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_SHIFT        24
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_MASK 0x000F0000
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_SHIFT        16
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_MASK 0x00000F00
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_SHIFT        8
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_MASK 0x0000000F
-#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_SHIFT        0
-
-/*
- * NAND Control Register (NANDCR)
- */
-#define IFC_NAND_NCR_FTOCNT_MASK       0x1E000000
-#define IFC_NAND_NCR_FTOCNT_SHIFT      25
-#define IFC_NAND_NCR_FTOCNT(n) ((_ilog2(n) - 8)  << IFC_NAND_NCR_FTOCNT_SHIFT)
-
-/*
- * NAND_AUTOBOOT_TRGR
- */
-/* Trigger RCW load */
-#define IFC_NAND_AUTOBOOT_TRGR_RCW_LD  0x80000000
-/* Trigget Auto Boot */
-#define IFC_NAND_AUTOBOOT_TRGR_BOOT_LD 0x20000000
-
-/*
- * NAND_MDR
- */
-/* 1st read data byte when opcode SBRD */
-#define IFC_NAND_MDR_RDATA0            0xFF000000
-/* 2nd read data byte when opcode SBRD */
-#define IFC_NAND_MDR_RDATA1            0x00FF0000
-
-/*
- * NOR Machine Specific Registers
- */
-/*
- * NOR Event and Error Status Register (NOR_EVTER_STAT)
- */
-/* NOR Command Sequence Operation Complete */
-#define IFC_NOR_EVTER_STAT_OPC_NOR     0x80000000
-/* Write Protect Error */
-#define IFC_NOR_EVTER_STAT_WPER                0x04000000
-/* Command Sequence Timeout Error */
-#define IFC_NOR_EVTER_STAT_STOER       0x01000000
-
-/*
- * NOR Event and Error Enable Register (NOR_EVTER_EN)
- */
-/* NOR Command Seq complete event enable */
-#define IFC_NOR_EVTER_EN_OPCEN_NOR     0x80000000
-/* Write Protect Error Checking Enable */
-#define IFC_NOR_EVTER_EN_WPEREN                0x04000000
-/* Timeout Error Enable */
-#define IFC_NOR_EVTER_EN_STOEREN       0x01000000
-
-/*
- * NOR Event and Error Interrupt Enable Register (NOR_EVTER_INTR_EN)
- */
-/* Enable interrupt for OPC complete */
-#define IFC_NOR_EVTER_INTR_OPCEN_NOR   0x80000000
-/* Enable interrupt for write protect error */
-#define IFC_NOR_EVTER_INTR_WPEREN      0x04000000
-/* Enable interrupt for timeout error */
-#define IFC_NOR_EVTER_INTR_STOEREN     0x01000000
-
-/*
- * NOR Transfer Error Attribute Register-0 (NOR_ERATTR0)
- */
-/* Source ID for error transaction */
-#define IFC_NOR_ERATTR0_ERSRCID                0xFF000000
-/* AXI ID for error transation */
-#define IFC_NOR_ERATTR0_ERAID          0x000FF000
-/* Chip select corresponds to NOR error */
-#define IFC_NOR_ERATTR0_ERCS_CS0       0x00000000
-#define IFC_NOR_ERATTR0_ERCS_CS1       0x00000010
-#define IFC_NOR_ERATTR0_ERCS_CS2       0x00000020
-#define IFC_NOR_ERATTR0_ERCS_CS3       0x00000030
-/* Type of transaction read/write */
-#define IFC_NOR_ERATTR0_ERTYPE_READ    0x00000001
-
-/*
- * NOR Transfer Error Attribute Register-2 (NOR_ERATTR2)
- */
-#define IFC_NOR_ERATTR2_ER_NUM_PHASE_EXP       0x000F0000
-#define IFC_NOR_ERATTR2_ER_NUM_PHASE_PER       0x00000F00
-
-/*
- * NOR Control Register (NORCR)
- */
-#define IFC_NORCR_MASK                 0x0F0F0000
-/* No. of Address/Data Phase */
-#define IFC_NORCR_NUM_PHASE_MASK       0x0F000000
-#define IFC_NORCR_NUM_PHASE_SHIFT      24
-#define IFC_NORCR_NUM_PHASE(n) ((n-1) << IFC_NORCR_NUM_PHASE_SHIFT)
-/* Sequence Timeout Count */
-#define IFC_NORCR_STOCNT_MASK          0x000F0000
-#define IFC_NORCR_STOCNT_SHIFT         16
-#define IFC_NORCR_STOCNT(n)    ((__ilog2(n) - 8) << IFC_NORCR_STOCNT_SHIFT)
-
-/*
- * GPCM Machine specific registers
- */
-/*
- * GPCM Event and Error Status Register (GPCM_EVTER_STAT)
- */
-/* Timeout error */
-#define IFC_GPCM_EVTER_STAT_TOER       0x04000000
-/* Parity error */
-#define IFC_GPCM_EVTER_STAT_PER                0x01000000
-
-/*
- * GPCM Event and Error Enable Register (GPCM_EVTER_EN)
- */
-/* Timeout error enable */
-#define IFC_GPCM_EVTER_EN_TOER_EN      0x04000000
-/* Parity error enable */
-#define IFC_GPCM_EVTER_EN_PER_EN       0x01000000
-
-/*
- * GPCM Event and Error Interrupt Enable Register (GPCM_EVTER_INTR_EN)
- */
-/* Enable Interrupt for timeout error */
-#define IFC_GPCM_EEIER_TOERIR_EN       0x04000000
-/* Enable Interrupt for Parity error */
-#define IFC_GPCM_EEIER_PERIR_EN                0x01000000
-
-/*
- * GPCM Transfer Error Attribute Register-0 (GPCM_ERATTR0)
- */
-/* Source ID for error transaction */
-#define IFC_GPCM_ERATTR0_ERSRCID       0xFF000000
-/* AXI ID for error transaction */
-#define IFC_GPCM_ERATTR0_ERAID         0x000FF000
-/* Chip select corresponds to GPCM error */
-#define IFC_GPCM_ERATTR0_ERCS_CS0      0x00000000
-#define IFC_GPCM_ERATTR0_ERCS_CS1      0x00000040
-#define IFC_GPCM_ERATTR0_ERCS_CS2      0x00000080
-#define IFC_GPCM_ERATTR0_ERCS_CS3      0x000000C0
-/* Type of transaction read/Write */
-#define IFC_GPCM_ERATTR0_ERTYPE_READ   0x00000001
-
-/*
- * GPCM Transfer Error Attribute Register-2 (GPCM_ERATTR2)
- */
-/* On which beat of address/data parity error is observed */
-#define IFC_GPCM_ERATTR2_PERR_BEAT             0x00000C00
-/* Parity Error on byte */
-#define IFC_GPCM_ERATTR2_PERR_BYTE             0x000000F0
-/* Parity Error reported in addr or data phase */
-#define IFC_GPCM_ERATTR2_PERR_DATA_PHASE       0x00000001
-
-/*
- * GPCM Status Register (GPCM_STAT)
- */
-#define IFC_GPCM_STAT_BSY              0x80000000  /* GPCM is busy */
-
-/*
- * IFC Controller NAND Machine registers
- */
-struct fsl_ifc_nand {
-       __be32 ncfgr;
-       u32 res1[0x4];
-       __be32 nand_fcr0;
-       __be32 nand_fcr1;
-       u32 res2[0x8];
-       __be32 row0;
-       u32 res3;
-       __be32 col0;
-       u32 res4;
-       __be32 row1;
-       u32 res5;
-       __be32 col1;
-       u32 res6;
-       __be32 row2;
-       u32 res7;
-       __be32 col2;
-       u32 res8;
-       __be32 row3;
-       u32 res9;
-       __be32 col3;
-       u32 res10[0x24];
-       __be32 nand_fbcr;
-       u32 res11;
-       __be32 nand_fir0;
-       __be32 nand_fir1;
-       __be32 nand_fir2;
-       u32 res12[0x10];
-       __be32 nand_csel;
-       u32 res13;
-       __be32 nandseq_strt;
-       u32 res14;
-       __be32 nand_evter_stat;
-       u32 res15;
-       __be32 pgrdcmpl_evt_stat;
-       u32 res16[0x2];
-       __be32 nand_evter_en;
-       u32 res17[0x2];
-       __be32 nand_evter_intr_en;
-       u32 res18[0x2];
-       __be32 nand_erattr0;
-       __be32 nand_erattr1;
-       u32 res19[0x10];
-       __be32 nand_fsr;
-       u32 res20;
-       __be32 nand_eccstat[4];
-       u32 res21[0x20];
-       __be32 nanndcr;
-       u32 res22[0x2];
-       __be32 nand_autoboot_trgr;
-       u32 res23;
-       __be32 nand_mdr;
-       u32 res24[0x5C];
-};
-
-/*
- * IFC controller NOR Machine registers
- */
-struct fsl_ifc_nor {
-       __be32 nor_evter_stat;
-       u32 res1[0x2];
-       __be32 nor_evter_en;
-       u32 res2[0x2];
-       __be32 nor_evter_intr_en;
-       u32 res3[0x2];
-       __be32 nor_erattr0;
-       __be32 nor_erattr1;
-       __be32 nor_erattr2;
-       u32 res4[0x4];
-       __be32 norcr;
-       u32 res5[0xEF];
-};
-
-/*
- * IFC controller GPCM Machine registers
- */
-struct fsl_ifc_gpcm {
-       __be32 gpcm_evter_stat;
-       u32 res1[0x2];
-       __be32 gpcm_evter_en;
-       u32 res2[0x2];
-       __be32 gpcm_evter_intr_en;
-       u32 res3[0x2];
-       __be32 gpcm_erattr0;
-       __be32 gpcm_erattr1;
-       __be32 gpcm_erattr2;
-       __be32 gpcm_stat;
-       u32 res4[0x1F3];
-};
-
-/*
- * IFC Controller Registers
- */
-struct fsl_ifc_regs {
-       __be32 ifc_rev;
-       u32 res1[0x2];
-       struct {
-               __be32 cspr_ext;
-               __be32 cspr;
-               u32 res2;
-       } cspr_cs[FSL_IFC_BANK_COUNT];
-       u32 res3[0x19];
-       struct {
-               __be32 amask;
-               u32 res4[0x2];
-       } amask_cs[FSL_IFC_BANK_COUNT];
-       u32 res5[0x17];
-       struct {
-               __be32 csor_ext;
-               __be32 csor;
-               u32 res6;
-       } csor_cs[FSL_IFC_BANK_COUNT];
-       u32 res7[0x19];
-       struct {
-               __be32 ftim[4];
-               u32 res8[0x8];
-       } ftim_cs[FSL_IFC_BANK_COUNT];
-       u32 res9[0x60];
-       __be32 rb_stat;
-       u32 res10[0x2];
-       __be32 ifc_gcr;
-       u32 res11[0x2];
-       __be32 cm_evter_stat;
-       u32 res12[0x2];
-       __be32 cm_evter_en;
-       u32 res13[0x2];
-       __be32 cm_evter_intr_en;
-       u32 res14[0x2];
-       __be32 cm_erattr0;
-       __be32 cm_erattr1;
-       u32 res15[0x2];
-       __be32 ifc_ccr;
-       __be32 ifc_csr;
-       u32 res16[0x2EB];
-       struct fsl_ifc_nand ifc_nand;
-       struct fsl_ifc_nor ifc_nor;
-       struct fsl_ifc_gpcm ifc_gpcm;
-};
-
-extern unsigned int convert_ifc_address(phys_addr_t addr_base);
-extern int fsl_ifc_find(phys_addr_t addr_base);
-
-/* overview of the fsl ifc controller */
-
-struct fsl_ifc_ctrl {
-       /* device info */
-       struct device                   *dev;
-       struct fsl_ifc_regs __iomem     *regs;
-       int                             irq;
-       int                             nand_irq;
-       spinlock_t                      lock;
-       void                            *nand;
-
-       u32 nand_stat;
-       wait_queue_head_t nand_wait;
-};
-
-extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
-
-
-#endif /* __ASM_FSL_IFC_H */
index d0b5fca6b0776fc8ef220483b91b1557c73a0835..c9202151079f2b1d6e99af4569b82ce68c785573 100644 (file)
@@ -99,7 +99,6 @@ static inline int prrn_is_enabled(void)
 
 #ifdef CONFIG_SMP
 #include <asm/cputable.h>
-#define smt_capable()          (cpu_has_feature(CPU_FTR_SMT))
 
 #ifdef CONFIG_PPC64
 #include <asm/smp.h>
index fdc679d309ec4c030d6f407d35675fb1b2527473..bb61ca58ca6d8272955d7023852f97cbe180c676 100644 (file)
@@ -143,13 +143,30 @@ static void eeh_disable_irq(struct pci_dev *dev)
 static void eeh_enable_irq(struct pci_dev *dev)
 {
        struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
-       struct irq_desc *desc;
 
        if ((edev->mode) & EEH_DEV_IRQ_DISABLED) {
                edev->mode &= ~EEH_DEV_IRQ_DISABLED;
-
-               desc = irq_to_desc(dev->irq);
-               if (desc && desc->depth > 0)
+               /*
+                * FIXME !!!!!
+                *
+                * This is just ass backwards. This maze has
+                * unbalanced irq_enable/disable calls. So instead of
+                * finding the root cause it works around the warning
+                * in the irq_enable code by conditionally calling
+                * into it.
+                *
+                * That's just wrong.The warning in the core code is
+                * there to tell people to fix their assymetries in
+                * their own code, not by abusing the core information
+                * to avoid it.
+                *
+                * I so wish that the assymetry would be the other way
+                * round and a few more irq_disable calls render that
+                * shit unusable forever.
+                *
+                *      tglx
+                */
+               if (irqd_irq_disabled(irq_get_irq_data(dev->irq)))
                        enable_irq(dev->irq);
        }
 }
index 1d0848bba049bf2c97bd09d9d86864857af128a7..ca1cd7459c4a3e60c73de7f4169484b03804cdbc 100644 (file)
@@ -465,7 +465,6 @@ static inline void check_stack_overflow(void)
 
 void __do_irq(struct pt_regs *regs)
 {
-       struct irq_desc *desc;
        unsigned int irq;
 
        irq_enter();
@@ -487,11 +486,8 @@ void __do_irq(struct pt_regs *regs)
        /* And finally process it */
        if (unlikely(irq == NO_IRQ))
                __get_cpu_var(irq_stat).spurious_irqs++;
-       else {
-               desc = irq_to_desc(irq);
-               if (likely(desc))
-                       desc->handle_irq(irq, desc);
-       }
+       else
+               generic_handle_irq(irq);
 
        trace_irq_exit(regs);
 
index a9e311f7a9dd58026e1fbd108ae1239415aa6153..2a4779091a5809a42b64d187224dc46da59fa07c 100644 (file)
@@ -208,7 +208,6 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
                          unsigned long in_devfn)
 {
        struct pci_controller* hose;
-       struct list_head *ln;
        struct pci_bus *bus = NULL;
        struct device_node *hose_node;
 
@@ -230,8 +229,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
         * used on pre-domains setup. We return the first match
         */
 
-       for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
-               bus = pci_bus_b(ln);
+       list_for_each_entry(bus, &pci_root_buses, node) {
                if (in_bus >= bus->number && in_bus <= bus->busn_res.end)
                        break;
                bus = NULL;
index 8d4c247f17389f283d02bc48dba044ff077e3ffe..af064d28b36524c5ce9c8fc982a58eec65ebbfc7 100644 (file)
@@ -1048,6 +1048,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
        flush_altivec_to_thread(src);
        flush_vsx_to_thread(src);
        flush_spe_to_thread(src);
+       /*
+        * Flush TM state out so we can copy it.  __switch_to_tm() does this
+        * flush but it removes the checkpointed state from the current CPU and
+        * transitions the CPU out of TM mode.  Hence we need to call
+        * tm_recheckpoint_new_task() (on the same task) to restore the
+        * checkpointed state back and the TM mode.
+        */
+       __switch_to_tm(src);
+       tm_recheckpoint_new_task(src);
 
        *dst = *src;
 
index 1482327cfeba9c1a846be00ae54e2606a1ac07b9..d88736fbece67c6627e6f33a9c4fd3e31ee2b533 100644 (file)
@@ -81,6 +81,7 @@ _GLOBAL(relocate)
 
 6:     blr
 
+.balign 8
 p_dyn: .llong  __dynamic_start - 0b
 p_rela:        .llong  __rela_dyn_start - 0b
 p_st:  .llong  _stext - 0b
index e66d4ec04d953a78a314b43a3a07f47ca27f5ae7..818dce344e82a0fa0a94fe7f21eefdb2483fbc68 100644 (file)
@@ -1504,73 +1504,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 1:     addi    r8,r8,16
        .endr
 
-       /* Save DEC */
-       mfspr   r5,SPRN_DEC
-       mftb    r6
-       extsw   r5,r5
-       add     r5,r5,r6
-       std     r5,VCPU_DEC_EXPIRES(r9)
-
-BEGIN_FTR_SECTION
-       b       8f
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
-       /* Save POWER8-specific registers */
-       mfspr   r5, SPRN_IAMR
-       mfspr   r6, SPRN_PSPB
-       mfspr   r7, SPRN_FSCR
-       std     r5, VCPU_IAMR(r9)
-       stw     r6, VCPU_PSPB(r9)
-       std     r7, VCPU_FSCR(r9)
-       mfspr   r5, SPRN_IC
-       mfspr   r6, SPRN_VTB
-       mfspr   r7, SPRN_TAR
-       std     r5, VCPU_IC(r9)
-       std     r6, VCPU_VTB(r9)
-       std     r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       mfspr   r5, SPRN_TFHAR
-       mfspr   r6, SPRN_TFIAR
-       mfspr   r7, SPRN_TEXASR
-       std     r5, VCPU_TFHAR(r9)
-       std     r6, VCPU_TFIAR(r9)
-       std     r7, VCPU_TEXASR(r9)
-#endif
-       mfspr   r8, SPRN_EBBHR
-       std     r8, VCPU_EBBHR(r9)
-       mfspr   r5, SPRN_EBBRR
-       mfspr   r6, SPRN_BESCR
-       mfspr   r7, SPRN_CSIGR
-       mfspr   r8, SPRN_TACR
-       std     r5, VCPU_EBBRR(r9)
-       std     r6, VCPU_BESCR(r9)
-       std     r7, VCPU_CSIGR(r9)
-       std     r8, VCPU_TACR(r9)
-       mfspr   r5, SPRN_TCSCR
-       mfspr   r6, SPRN_ACOP
-       mfspr   r7, SPRN_PID
-       mfspr   r8, SPRN_WORT
-       std     r5, VCPU_TCSCR(r9)
-       std     r6, VCPU_ACOP(r9)
-       stw     r7, VCPU_GUEST_PID(r9)
-       std     r8, VCPU_WORT(r9)
-8:
-
-       /* Save and reset AMR and UAMOR before turning on the MMU */
-BEGIN_FTR_SECTION
-       mfspr   r5,SPRN_AMR
-       mfspr   r6,SPRN_UAMOR
-       std     r5,VCPU_AMR(r9)
-       std     r6,VCPU_UAMOR(r9)
-       li      r6,0
-       mtspr   SPRN_AMR,r6
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
        /* Unset guest mode */
        li      r0, KVM_GUEST_MODE_NONE
        stb     r0, HSTATE_IN_GUEST(r13)
@@ -2203,7 +2136,7 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        mfspr   r6,SPRN_VRSAVE
-       stw     r6,VCPU_VRSAVE(r3)
+       stw     r6,VCPU_VRSAVE(r31)
        mtlr    r30
        mtmsrd  r5
        isync
@@ -2240,7 +2173,7 @@ BEGIN_FTR_SECTION
        bl      .load_vr_state
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
-       lwz     r7,VCPU_VRSAVE(r4)
+       lwz     r7,VCPU_VRSAVE(r31)
        mtspr   SPRN_VRSAVE,r7
        mtlr    r30
        mr      r4,r31
index 1f0ebdeea5f77cdd63a844680912242d8b0a7574..863d89386f607dd86a3edb08d594448b3b5fe260 100644 (file)
@@ -1121,8 +1121,7 @@ oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
        int ret = 0;
        struct cpufreq_freqs *frq = data;
        if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
-           (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
-           (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+           (val == CPUFREQ_POSTCHANGE && frq->old > frq->new))
                set_spu_profiling_frequency(frq->new, spu_cycle_reset);
        return ret;
 }
index 5ec1e47a0d771eba56e8b8c42111a19aed7df25a..e865d748179b2ac1b0b7550c1d3bebbcae71e049 100644 (file)
@@ -123,7 +123,8 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order)
 
        area->nid = nid;
        area->order = order;
-       area->pages = alloc_pages_exact_node(area->nid, GFP_KERNEL|GFP_THISNODE,
+       area->pages = alloc_pages_exact_node(area->nid,
+                                               GFP_KERNEL|__GFP_THISNODE,
                                                area->order);
 
        if (!area->pages) {
index 49318385d4fac71e6122588da95c895a18d9198d..4a0a64fe25df274a16051b668a3497b4632e8bf1 100644 (file)
@@ -83,7 +83,6 @@ static struct timer_list spuloadavg_timer;
 #define MIN_SPU_TIMESLICE      max(5 * HZ / (1000 * SPUSCHED_TICK), 1)
 #define DEF_SPU_TIMESLICE      (100 * HZ / (1000 * SPUSCHED_TICK))
 
-#define MAX_USER_PRIO          (MAX_PRIO - MAX_RT_PRIO)
 #define SCALE_PRIO(x, prio) \
        max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE)
 
index 110f4fbd319f628373522e99672a95dcffda6688..81a7a0a79be75e0c8035baa992a6a674546c94eb 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/of_fdt.h>
 #include <linux/interrupt.h>
 #include <linux/bug.h>
-#include <linux/cpuidle.h>
 #include <linux/pci.h>
 
 #include <asm/machdep.h>
@@ -225,16 +224,6 @@ static int __init pnv_probe(void)
        return 1;
 }
 
-void powernv_idle(void)
-{
-       /* Hook to cpuidle framework if available, else
-        * call on default platform idle code
-        */
-       if (cpuidle_idle_call()) {
-               power7_idle();
-       }
-}
-
 define_machine(powernv) {
        .name                   = "PowerNV",
        .probe                  = pnv_probe,
@@ -244,7 +233,7 @@ define_machine(powernv) {
        .show_cpuinfo           = pnv_show_cpuinfo,
        .progress               = pnv_progress,
        .machine_shutdown       = pnv_shutdown,
-       .power_save             = powernv_idle,
+       .power_save             = power7_idle,
        .calibrate_decr         = generic_calibrate_decr,
        .dma_set_mask           = pnv_dma_set_mask,
 #ifdef CONFIG_KEXEC
index efe61374f6eae3eda2447a351787958a2f562cf8..203cbf0dc101a7b4bb93aec27f8a89cf4f015ecb 100644 (file)
@@ -37,15 +37,15 @@ find_bus_among_children(struct pci_bus *bus,
                         struct device_node *dn)
 {
        struct pci_bus *child = NULL;
-       struct list_head *tmp;
+       struct pci_bus *tmp;
        struct device_node *busdn;
 
        busdn = pci_bus_to_OF_node(bus);
        if (busdn == dn)
                return bus;
 
-       list_for_each(tmp, &bus->children) {
-               child = find_bus_among_children(pci_bus_b(tmp), dn);
+       list_for_each_entry(tmp, &bus->children, node) {
+               child = find_bus_among_children(tmp, dn);
                if (child)
                        break;
        };
index 972df0ffd4dcc4dff154fe84ada40705b173b9f7..2db8cc691bf49dcd5b72b150c48bde8ec440f841 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/irq.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
-#include <linux/cpuidle.h>
 #include <linux/of.h>
 #include <linux/kexec.h>
 
@@ -356,29 +355,24 @@ early_initcall(alloc_dispatch_log_kmem_cache);
 
 static void pseries_lpar_idle(void)
 {
-       /* This would call on the cpuidle framework, and the back-end pseries
-        * driver to  go to idle states
+       /*
+        * Default handler to go into low thread priority and possibly
+        * low power mode by cedeing processor to hypervisor
         */
-       if (cpuidle_idle_call()) {
-               /* On error, execute default handler
-                * to go into low thread priority and possibly
-                * low power mode by cedeing processor to hypervisor
-                */
 
-               /* Indicate to hypervisor that we are idle. */
-               get_lppaca()->idle = 1;
+       /* Indicate to hypervisor that we are idle. */
+       get_lppaca()->idle = 1;
 
-               /*
-                * Yield the processor to the hypervisor.  We return if
-                * an external interrupt occurs (which are driven prior
-                * to returning here) or if a prod occurs from another
-                * processor. When returning here, external interrupts
-                * are enabled.
-                */
-               cede_processor();
+       /*
+        * Yield the processor to the hypervisor.  We return if
+        * an external interrupt occurs (which are driven prior
+        * to returning here) or if a prod occurs from another
+        * processor. When returning here, external interrupts
+        * are enabled.
+        */
+       cede_processor();
 
-               get_lppaca()->idle = 0;
-       }
+       get_lppaca()->idle = 0;
 }
 
 /*
index f67ac900d870039985c1a3ae4e633e46f3ecca7c..afbcc37aa094559200aff7c477bcefeabdae2c49 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_FSL_SOC)         += fsl_soc.o fsl_mpic_err.o
 obj-$(CONFIG_FSL_PCI)          += fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)          += fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)          += fsl_lbc.o
-obj-$(CONFIG_FSL_IFC)          += fsl_ifc.o
 obj-$(CONFIG_FSL_GTM)          += fsl_gtm.o
 obj-$(CONFIG_FSL_85XX_CACHE_SRAM)      += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)      += simple_gpio.o
index b74085cea1af2565f3aea17f127943eb03ba7fec..2d20f10a42030394581c001e9f19793ebe4667bd 100644 (file)
@@ -28,8 +28,6 @@
 #include <asm/ehv_pic.h>
 #include <asm/fsl_hcalls.h>
 
-#include "../../../kernel/irq/settings.h"
-
 static struct ehv_pic *global_ehv_pic;
 static DEFINE_SPINLOCK(ehv_pic_lock);
 
@@ -113,17 +111,13 @@ static unsigned int ehv_pic_type_to_vecpri(unsigned int type)
 int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
 {
        unsigned int src = virq_to_hw(d->irq);
-       struct irq_desc *desc = irq_to_desc(d->irq);
        unsigned int vecpri, vold, vnew, prio, cpu_dest;
        unsigned long flags;
 
        if (flow_type == IRQ_TYPE_NONE)
                flow_type = IRQ_TYPE_LEVEL_LOW;
 
-       irq_settings_clr_level(desc);
-       irq_settings_set_trigger_mask(desc, flow_type);
-       if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
-               irq_settings_set_level(desc);
+       irqd_set_trigger_type(d, flow_type);
 
        vecpri = ehv_pic_type_to_vecpri(flow_type);
 
@@ -144,7 +138,7 @@ int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
        ev_int_set_config(src, vecpri, prio, cpu_dest);
 
        spin_unlock_irqrestore(&ehv_pic_lock, flags);
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
 static struct irq_chip ehv_pic_irq_chip = {
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c
deleted file mode 100644 (file)
index fbc885b..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc
- *
- * Freescale Integrated Flash Controller
- *
- * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <asm/prom.h>
-#include <asm/fsl_ifc.h>
-
-struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
-EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
-
-/*
- * convert_ifc_address - convert the base address
- * @addr_base: base address of the memory bank
- */
-unsigned int convert_ifc_address(phys_addr_t addr_base)
-{
-       return addr_base & CSPR_BA;
-}
-EXPORT_SYMBOL(convert_ifc_address);
-
-/*
- * fsl_ifc_find - find IFC bank
- * @addr_base: base address of the memory bank
- *
- * This function walks IFC banks comparing "Base address" field of the CSPR
- * registers with the supplied addr_base argument. When bases match this
- * function returns bank number (starting with 0), otherwise it returns
- * appropriate errno value.
- */
-int fsl_ifc_find(phys_addr_t addr_base)
-{
-       int i = 0;
-
-       if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
-               return -ENODEV;
-
-       for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) {
-               u32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
-               if (cspr & CSPR_V && (cspr & CSPR_BA) ==
-                               convert_ifc_address(addr_base))
-                       return i;
-       }
-
-       return -ENOENT;
-}
-EXPORT_SYMBOL(fsl_ifc_find);
-
-static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
-{
-       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
-
-       /*
-        * Clear all the common status and event registers
-        */
-       if (in_be32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
-               out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
-
-       /* enable all error and events */
-       out_be32(&ifc->cm_evter_en, IFC_CM_EVTER_EN_CSEREN);
-
-       /* enable all error and event interrupts */
-       out_be32(&ifc->cm_evter_intr_en, IFC_CM_EVTER_INTR_EN_CSERIREN);
-       out_be32(&ifc->cm_erattr0, 0x0);
-       out_be32(&ifc->cm_erattr1, 0x0);
-
-       return 0;
-}
-
-static int fsl_ifc_ctrl_remove(struct platform_device *dev)
-{
-       struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
-
-       free_irq(ctrl->nand_irq, ctrl);
-       free_irq(ctrl->irq, ctrl);
-
-       irq_dispose_mapping(ctrl->nand_irq);
-       irq_dispose_mapping(ctrl->irq);
-
-       iounmap(ctrl->regs);
-
-       dev_set_drvdata(&dev->dev, NULL);
-       kfree(ctrl);
-
-       return 0;
-}
-
-/*
- * NAND events are split between an operational interrupt which only
- * receives OPC, and an error interrupt that receives everything else,
- * including non-NAND errors.  Whichever interrupt gets to it first
- * records the status and wakes the wait queue.
- */
-static DEFINE_SPINLOCK(nand_irq_lock);
-
-static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
-{
-       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
-       unsigned long flags;
-       u32 stat;
-
-       spin_lock_irqsave(&nand_irq_lock, flags);
-
-       stat = in_be32(&ifc->ifc_nand.nand_evter_stat);
-       if (stat) {
-               out_be32(&ifc->ifc_nand.nand_evter_stat, stat);
-               ctrl->nand_stat = stat;
-               wake_up(&ctrl->nand_wait);
-       }
-
-       spin_unlock_irqrestore(&nand_irq_lock, flags);
-
-       return stat;
-}
-
-static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
-{
-       struct fsl_ifc_ctrl *ctrl = data;
-
-       if (check_nand_stat(ctrl))
-               return IRQ_HANDLED;
-
-       return IRQ_NONE;
-}
-
-/*
- * NOTE: This interrupt is used to report ifc events of various kinds,
- * such as transaction errors on the chipselects.
- */
-static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
-{
-       struct fsl_ifc_ctrl *ctrl = data;
-       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
-       u32 err_axiid, err_srcid, status, cs_err, err_addr;
-       irqreturn_t ret = IRQ_NONE;
-
-       /* read for chip select error */
-       cs_err = in_be32(&ifc->cm_evter_stat);
-       if (cs_err) {
-               dev_err(ctrl->dev, "transaction sent to IFC is not mapped to"
-                               "any memory bank 0x%08X\n", cs_err);
-               /* clear the chip select error */
-               out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
-
-               /* read error attribute registers print the error information */
-               status = in_be32(&ifc->cm_erattr0);
-               err_addr = in_be32(&ifc->cm_erattr1);
-
-               if (status & IFC_CM_ERATTR0_ERTYP_READ)
-                       dev_err(ctrl->dev, "Read transaction error"
-                               "CM_ERATTR0 0x%08X\n", status);
-               else
-                       dev_err(ctrl->dev, "Write transaction error"
-                               "CM_ERATTR0 0x%08X\n", status);
-
-               err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
-                                       IFC_CM_ERATTR0_ERAID_SHIFT;
-               dev_err(ctrl->dev, "AXI ID of the error"
-                                       "transaction 0x%08X\n", err_axiid);
-
-               err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
-                                       IFC_CM_ERATTR0_ESRCID_SHIFT;
-               dev_err(ctrl->dev, "SRC ID of the error"
-                                       "transaction 0x%08X\n", err_srcid);
-
-               dev_err(ctrl->dev, "Transaction Address corresponding to error"
-                                       "ERADDR 0x%08X\n", err_addr);
-
-               ret = IRQ_HANDLED;
-       }
-
-       if (check_nand_stat(ctrl))
-               ret = IRQ_HANDLED;
-
-       return ret;
-}
-
-/*
- * fsl_ifc_ctrl_probe
- *
- * called by device layer when it finds a device matching
- * one our driver can handled. This code allocates all of
- * the resources needed for the controller only.  The
- * resources for the NAND banks themselves are allocated
- * in the chip probe function.
-*/
-static int fsl_ifc_ctrl_probe(struct platform_device *dev)
-{
-       int ret = 0;
-
-
-       dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
-
-       fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
-       if (!fsl_ifc_ctrl_dev)
-               return -ENOMEM;
-
-       dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
-
-       /* IOMAP the entire IFC region */
-       fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
-       if (!fsl_ifc_ctrl_dev->regs) {
-               dev_err(&dev->dev, "failed to get memory region\n");
-               ret = -ENODEV;
-               goto err;
-       }
-
-       /* get the Controller level irq */
-       fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
-       if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
-               dev_err(&dev->dev, "failed to get irq resource "
-                                                       "for IFC\n");
-               ret = -ENODEV;
-               goto err;
-       }
-
-       /* get the nand machine irq */
-       fsl_ifc_ctrl_dev->nand_irq =
-                       irq_of_parse_and_map(dev->dev.of_node, 1);
-
-       fsl_ifc_ctrl_dev->dev = &dev->dev;
-
-       ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
-       if (ret < 0)
-               goto err;
-
-       init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
-
-       ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
-                         "fsl-ifc", fsl_ifc_ctrl_dev);
-       if (ret != 0) {
-               dev_err(&dev->dev, "failed to install irq (%d)\n",
-                       fsl_ifc_ctrl_dev->irq);
-               goto err_irq;
-       }
-
-       if (fsl_ifc_ctrl_dev->nand_irq) {
-               ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,
-                               0, "fsl-ifc-nand", fsl_ifc_ctrl_dev);
-               if (ret != 0) {
-                       dev_err(&dev->dev, "failed to install irq (%d)\n",
-                               fsl_ifc_ctrl_dev->nand_irq);
-                       goto err_nandirq;
-               }
-       }
-
-       return 0;
-
-err_nandirq:
-       free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
-       irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
-err_irq:
-       free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
-       irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
-err:
-       return ret;
-}
-
-static const struct of_device_id fsl_ifc_match[] = {
-       {
-               .compatible = "fsl,ifc",
-       },
-       {},
-};
-
-static struct platform_driver fsl_ifc_ctrl_driver = {
-       .driver = {
-               .name   = "fsl-ifc",
-               .of_match_table = fsl_ifc_match,
-       },
-       .probe       = fsl_ifc_ctrl_probe,
-       .remove      = fsl_ifc_ctrl_remove,
-};
-
-module_platform_driver(fsl_ifc_ctrl_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Freescale Semiconductor");
-MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");
index 65a07750f4f946f038bb2e2a4e13f9f6d05dce83..953f17c8d17cde75f73ef78ebc59aa0235e9fde0 100644 (file)
@@ -117,6 +117,7 @@ config S390
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZ4
@@ -140,6 +141,7 @@ config S390
        select OLD_SIGACTION
        select OLD_SIGSUSPEND3
        select SYSCTL_EXCEPTION_TRACE
+       select TTY
        select VIRT_CPU_ACCOUNTING
        select VIRT_TO_BUS
 
@@ -415,6 +417,10 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
 config ARCH_ENABLE_MEMORY_HOTREMOVE
        def_bool y
 
+config ARCH_ENABLE_SPLIT_PMD_PTLOCK
+       def_bool y
+       depends on 64BIT
+
 config FORCE_MAX_ZONEORDER
        int
        default "9"
index de8e2b3b0180e0650dd5a100f9e57a9b89e99359..69b23b25ac34a4f3f6c6faeb305648ef5a7e5b63 100644 (file)
@@ -171,7 +171,7 @@ static int __init appldata_os_init(void)
        int rc, max_size;
 
        max_size = sizeof(struct appldata_os_data) +
-                  (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+                  (num_possible_cpus() * sizeof(struct appldata_os_per_cpu));
        if (max_size > APPLDATA_MAX_REC_SIZE) {
                pr_err("Maximum OS record size %i exceeds the maximum "
                       "record size %i\n", max_size, APPLDATA_MAX_REC_SIZE);
index e0af2ee587511d023abf72a35b3353668da921ca..ddaae2f5c9137d0155ef5d5e943b40d097471881 100644 (file)
@@ -46,6 +46,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_CFQ_GROUP_IOSCHED=y
 CONFIG_DEFAULT_DEADLINE=y
 CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
 CONFIG_PREEMPT=y
 CONFIG_HZ_100=y
 CONFIG_MEMORY_HOTPLUG=y
@@ -58,7 +59,6 @@ CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_CHSC_SCH=y
 CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
@@ -101,7 +101,6 @@ CONFIG_TCP_CONG_VENO=m
 CONFIG_TCP_CONG_YEAH=m
 CONFIG_TCP_CONG_ILLINOIS=m
 CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
@@ -111,6 +110,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
 CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
 CONFIG_IPV6_SIT=m
 CONFIG_IPV6_GRE=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -135,7 +135,17 @@ CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
 CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_AUDIT=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -204,7 +214,9 @@ CONFIG_IP_SET_HASH_IP=m
 CONFIG_IP_SET_HASH_IPPORT=m
 CONFIG_IP_SET_HASH_IPPORTIP=m
 CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
 CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
 CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
@@ -227,6 +239,11 @@ CONFIG_IP_VS_FTP=m
 CONFIG_IP_VS_PE_SIP=m
 CONFIG_NF_CONNTRACK_IPV4=m
 # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -249,6 +266,9 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -268,6 +288,7 @@ CONFIG_IP6_NF_SECURITY=m
 CONFIG_NF_NAT_IPV6=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
 CONFIG_NET_SCTPPROBE=m
 CONFIG_RDS=m
 CONFIG_RDS_RDMA=m
@@ -314,6 +335,7 @@ CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
 CONFIG_NET_CLS_FLOW=m
 CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=m
 CONFIG_NET_ACT_GACT=m
@@ -381,8 +403,8 @@ CONFIG_BLK_DEV_DM=m
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
 CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 CONFIG_DM_MULTIPATH_QL=m
@@ -434,7 +456,6 @@ CONFIG_TN3270_FS=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_INFINIBAND=m
@@ -534,13 +555,23 @@ CONFIG_UNUSED_SYMBOLS=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_SELFTEST=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_SLUB_DEBUG_ON=y
 CONFIG_SLUB_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_RB=y
 CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
 CONFIG_DEBUG_PER_CPU_MAPS=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_RT_MUTEX_TESTER=y
@@ -573,9 +604,11 @@ CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
 CONFIG_BLK_DEV_IO_TRACE=y
 # CONFIG_KPROBE_EVENT is not set
 CONFIG_LKDTM=m
+CONFIG_TEST_LIST_SORT=y
 CONFIG_KPROBES_SANITY_TEST=y
-CONFIG_RBTREE_TEST=m
+CONFIG_RBTREE_TEST=y
 CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_DMA_API_DEBUG=y
 # CONFIG_STRICT_DEVMEM is not set
@@ -638,7 +671,6 @@ CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_ASYMMETRIC_KEY_TYPE=m
 CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
 CONFIG_X509_CERTIFICATE_PARSER=m
 CONFIG_CRC7=m
 CONFIG_CRC8=m
index b9f6b4cab927e79618600f806351441083e89428..c81a74e3e25a698340a3fae730ec3a5c27324508 100644 (file)
@@ -46,6 +46,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_CFQ_GROUP_IOSCHED=y
 CONFIG_DEFAULT_DEADLINE=y
 CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
 CONFIG_HZ_100=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
@@ -56,7 +57,6 @@ CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_CHSC_SCH=y
 CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
@@ -99,7 +99,6 @@ CONFIG_TCP_CONG_VENO=m
 CONFIG_TCP_CONG_YEAH=m
 CONFIG_TCP_CONG_ILLINOIS=m
 CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
@@ -109,6 +108,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
 CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
 CONFIG_IPV6_SIT=m
 CONFIG_IPV6_GRE=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -133,7 +133,17 @@ CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
 CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_AUDIT=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -202,7 +212,9 @@ CONFIG_IP_SET_HASH_IP=m
 CONFIG_IP_SET_HASH_IPPORT=m
 CONFIG_IP_SET_HASH_IPPORTIP=m
 CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
 CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
 CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
@@ -225,6 +237,11 @@ CONFIG_IP_VS_FTP=m
 CONFIG_IP_VS_PE_SIP=m
 CONFIG_NF_CONNTRACK_IPV4=m
 # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -247,6 +264,9 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -266,6 +286,7 @@ CONFIG_IP6_NF_SECURITY=m
 CONFIG_NF_NAT_IPV6=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
 CONFIG_NET_SCTPPROBE=m
 CONFIG_RDS=m
 CONFIG_RDS_RDMA=m
@@ -311,6 +332,7 @@ CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
 CONFIG_NET_CLS_FLOW=m
 CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=m
 CONFIG_NET_ACT_GACT=m
@@ -378,8 +400,8 @@ CONFIG_BLK_DEV_DM=m
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
 CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 CONFIG_DM_MULTIPATH_QL=m
@@ -431,7 +453,6 @@ CONFIG_TN3270_FS=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_INFINIBAND=m
@@ -540,6 +561,7 @@ CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_LKDTM=m
 CONFIG_RBTREE_TEST=m
 CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
 # CONFIG_STRICT_DEVMEM is not set
 CONFIG_S390_PTDUMP=y
@@ -601,7 +623,6 @@ CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_ASYMMETRIC_KEY_TYPE=m
 CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
 CONFIG_X509_CERTIFICATE_PARSER=m
 CONFIG_CRC7=m
 CONFIG_CRC8=m
index 91087b43e8fa3d1016f5cd27fb5e10caa03483e2..b5ba8fe1cc6487c7cb67a6948b3d23895888950d 100644 (file)
@@ -44,6 +44,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
 CONFIG_CFQ_GROUP_IOSCHED=y
 CONFIG_DEFAULT_DEADLINE=y
 CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
 CONFIG_HZ_100=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
@@ -54,7 +55,6 @@ CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_CHSC_SCH=y
 CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
@@ -97,7 +97,6 @@ CONFIG_TCP_CONG_VENO=m
 CONFIG_TCP_CONG_YEAH=m
 CONFIG_TCP_CONG_ILLINOIS=m
 CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
@@ -107,6 +106,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
 CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
 CONFIG_IPV6_SIT=m
 CONFIG_IPV6_GRE=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -131,7 +131,17 @@ CONFIG_NF_CONNTRACK_SIP=m
 CONFIG_NF_CONNTRACK_TFTP=m
 CONFIG_NF_CT_NETLINK=m
 CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_AUDIT=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -200,7 +210,9 @@ CONFIG_IP_SET_HASH_IP=m
 CONFIG_IP_SET_HASH_IPPORT=m
 CONFIG_IP_SET_HASH_IPPORTIP=m
 CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
 CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
 CONFIG_IP_SET_HASH_NETPORT=m
 CONFIG_IP_SET_HASH_NETIFACE=m
 CONFIG_IP_SET_LIST_SET=m
@@ -223,6 +235,11 @@ CONFIG_IP_VS_FTP=m
 CONFIG_IP_VS_PE_SIP=m
 CONFIG_NF_CONNTRACK_IPV4=m
 # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -245,6 +262,9 @@ CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
 CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
@@ -264,6 +284,7 @@ CONFIG_IP6_NF_SECURITY=m
 CONFIG_NF_NAT_IPV6=m
 CONFIG_IP6_NF_TARGET_MASQUERADE=m
 CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
 CONFIG_NET_SCTPPROBE=m
 CONFIG_RDS=m
 CONFIG_RDS_RDMA=m
@@ -309,6 +330,7 @@ CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
 CONFIG_NET_CLS_FLOW=m
 CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=m
 CONFIG_NET_ACT_GACT=m
@@ -376,8 +398,8 @@ CONFIG_BLK_DEV_DM=m
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
 CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 CONFIG_DM_MULTIPATH_QL=m
@@ -429,7 +451,6 @@ CONFIG_TN3270_FS=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_INFINIBAND=m
@@ -532,6 +553,7 @@ CONFIG_LATENCYTOP=y
 CONFIG_BLK_DEV_IO_TRACE=y
 # CONFIG_KPROBE_EVENT is not set
 CONFIG_LKDTM=m
+CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
 # CONFIG_STRICT_DEVMEM is not set
 CONFIG_S390_PTDUMP=y
@@ -593,7 +615,6 @@ CONFIG_CRYPTO_AES_S390=m
 CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_ASYMMETRIC_KEY_TYPE=m
 CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
 CONFIG_X509_CERTIFICATE_PARSER=m
 CONFIG_CRC7=m
 CONFIG_CRC8=m
index d725c4d956e4551aecfdba78d0c02e857e7ad7b4..cef073ca1f07f2aca39ece9e52f4ce16468ee0b4 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_HZ_100=y
 # CONFIG_CHSC_SCH is not set
 # CONFIG_SCM_BUS is not set
 CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_SECCOMP is not set
 # CONFIG_IUCV is not set
index 33f57514f4245a3835438801c99e11c749ac33a3..4557cb7ffddf80bda691e9254a831f275220473c 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_PARTITION_ADVANCED=y
 CONFIG_IBM_PARTITION=y
 CONFIG_DEFAULT_DEADLINE=y
 CONFIG_MARCH_Z196=y
+CONFIG_NR_CPUS=256
 CONFIG_HZ_100=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
@@ -122,22 +123,31 @@ CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DETECT_HUNG_TASK=y
 CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_LOCK_STAT=y
 CONFIG_DEBUG_LOCKDEP=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_WRITECOUNT=y
 CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_NOTIFIERS=y
 CONFIG_PROVE_RCU=y
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
 CONFIG_RCU_TRACE=y
 CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_KPROBES_SANITY_TEST=y
 # CONFIG_STRICT_DEVMEM is not set
+CONFIG_S390_PTDUMP=y
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_TEST=m
index 24908ce149f15c89f1fbf5f4c8cc0b09b8a9ec13..32040ace00ea2431a18428dca5c34c0c4ebde10c 100644 (file)
@@ -32,7 +32,7 @@ struct diag2fc_data {
        __u32 pcpus;
        __u32 lcpus;
        __u32 vcpus;
-       __u32 cpu_min;
+       __u32 ocpus;
        __u32 cpu_max;
        __u32 cpu_shares;
        __u32 cpu_use_samp;
@@ -142,7 +142,12 @@ static int hpyfs_vm_create_guest(struct dentry *systems_dir,
        ATTRIBUTE(cpus_dir, "capped", capped_value);
        ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
        ATTRIBUTE(cpus_dir, "count", data->vcpus);
-       ATTRIBUTE(cpus_dir, "weight_min", data->cpu_min);
+       /*
+        * Note: The "weight_min" attribute got the wrong name.
+        * The value represents the number of non-stopped (operating)
+        * CPUS.
+        */
+       ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
        ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
        ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
 
index 8386a4a1f19a35ba4cf1e93259b3bca911928408..57892a8a905584d79fd112a7c2e67a319a3f9e45 100644 (file)
@@ -1,6 +1,7 @@
 
 
 generic-y += clkdev.h
-generic-y += trace_clock.h
-generic-y += preempt.h
 generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
index 4bbb5957ed1b6db504cec7328100af49d70607e3..bd93ff6661b809643e4dcd3e94747c4464a763a2 100644 (file)
@@ -44,11 +44,21 @@ struct airq_iv {
 
 struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
 void airq_iv_release(struct airq_iv *iv);
-unsigned long airq_iv_alloc_bit(struct airq_iv *iv);
-void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit);
+unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num);
+void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num);
 unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
                           unsigned long end);
 
+static inline unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+{
+       return airq_iv_alloc(iv, 1);
+}
+
+static inline void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+{
+       airq_iv_free(iv, bit, 1);
+}
+
 static inline unsigned long airq_iv_end(struct airq_iv *iv)
 {
        return iv->end;
index 6e6ad06808293b7e88949351f647e516af8f16b2..ec5ef891db6bb8f159bc25a8c98679ea27fb4cb8 100644 (file)
@@ -13,9 +13,9 @@
  *
  * The bitop functions are defined to work on unsigned longs, so for an
  * s390x system the bits end up numbered:
- *   |63..............0|127............64|191...........128|255...........196|
+ *   |63..............0|127............64|191...........128|255...........192|
  * and on s390:
- *   |31.....0|63....31|95....64|127...96|159..128|191..160|223..192|255..224|
+ *   |31.....0|63....32|95....64|127...96|159..128|191..160|223..192|255..224|
  *
  * There are a few little-endian macros used mostly for filesystem
  * bitmaps, these work on similar bit arrays layouts, but
@@ -30,7 +30,7 @@
  * on an s390x system the bits are numbered:
  *   |0..............63|64............127|128...........191|192...........255|
  * and on s390:
- *   |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ *   |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
  *
  * The main difference is that bit 0-63 (64b) or 0-31 (32b) in the bit
  * number field needs to be reversed compared to the LSB0 encoded bit
@@ -304,7 +304,7 @@ static inline int test_bit(unsigned long nr, const volatile unsigned long *ptr)
  * On an s390x system the bits are numbered:
  *   |0..............63|64............127|128...........191|192...........255|
  * and on s390:
- *   |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ *   |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
  */
 unsigned long find_first_bit_inv(const unsigned long *addr, unsigned long size);
 unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
index f201af8be580ddc876de2f5de96952aaaf493cb5..a9c2c06861772f63b52988cc98afa80058fc0f22 100644 (file)
@@ -219,7 +219,9 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
 #define to_ccwdev(n) container_of(n, struct ccw_device, dev)
 #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
 
-extern struct ccw_device *ccw_device_probe_console(void);
+extern struct ccw_device *ccw_device_create_console(struct ccw_driver *);
+extern void ccw_device_destroy_console(struct ccw_device *);
+extern int ccw_device_enable_console(struct ccw_device *);
 extern void ccw_device_wait_idle(struct ccw_device *);
 extern int ccw_device_force_console(struct ccw_device *);
 
index 4f57a4f3909a1682822a61976cbc4e01f417dda5..7403648563554604e19b6cfbd0873bee868c7644 100644 (file)
@@ -44,22 +44,15 @@ csum_partial(const void *buff, int len, __wsum sum)
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  *
- * Copy from userspace and compute checksum.  If we catch an exception
- * then zero the rest of the buffer.
+ * Copy from userspace and compute checksum.
  */
 static inline __wsum
 csum_partial_copy_from_user(const void __user *src, void *dst,
                                           int len, __wsum sum,
                                           int *err_ptr)
 {
-       int missing;
-
-       missing = copy_from_user(dst, src, len);
-       if (missing) {
-               memset(dst + len - missing, 0, missing);
+       if (unlikely(copy_from_user(dst, src, len)))
                *err_ptr = -EFAULT;
-       }
-               
        return csum_partial(dst, len, sum);
 }
 
index 5d7e8cf83bd6c7d53b5f2a34fc2120add4cfa2d8..d350ed9d0fbb2e2955cade45aea5d7632716bfb9 100644 (file)
@@ -8,7 +8,11 @@
 #include <linux/thread_info.h>
 
 #define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p(typeof(0?(t)0:0ULL), u64))
-#define __SC_DELOUSE(t,v) (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v))
+
+#define __SC_DELOUSE(t,v) ({ \
+       BUILD_BUG_ON(sizeof(t) > 4 && !__TYPE_IS_PTR(t)); \
+       (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v)); \
+})
 
 #define PSW32_MASK_PER         0x40000000UL
 #define PSW32_MASK_DAT         0x04000000UL
index 51bcaa0fdeefaa33b289a521b6cd95be411ada27..fda46bd38c99a7b529ce71925e862efdc3c88a5d 100644 (file)
@@ -5,7 +5,10 @@
 #include <linux/uaccess.h>
 #include <asm/errno.h>
 
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval);
+int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old);
+
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -17,7 +20,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
                oparg = 1 << oparg;
 
        pagefault_disable();
-       ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval);
+       ret = __futex_atomic_op_inuser(op, uaddr, oparg, &oldval);
        pagefault_enable();
 
        if (!ret) {
@@ -34,10 +37,4 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
        return ret;
 }
 
-static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
-                                               u32 oldval, u32 newval)
-{
-       return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
-}
-
 #endif /* _ASM_S390_FUTEX_H */
index eef3dd3fd9a9f76d105b2c92d266dc5079c7833f..9bf95bb30f1a6cf27d0494396168f87e23cf8a65 100644 (file)
@@ -106,7 +106,9 @@ struct kvm_s390_sie_block {
        __u64   gbea;                   /* 0x0180 */
        __u8    reserved188[24];        /* 0x0188 */
        __u32   fac;                    /* 0x01a0 */
-       __u8    reserved1a4[68];        /* 0x01a4 */
+       __u8    reserved1a4[20];        /* 0x01a4 */
+       __u64   cbrlo;                  /* 0x01b8 */
+       __u8    reserved1c0[40];        /* 0x01c0 */
        __u64   itdba;                  /* 0x01e8 */
        __u8    reserved1f0[16];        /* 0x01f0 */
 } __attribute__((packed));
@@ -155,6 +157,7 @@ struct kvm_vcpu_stat {
        u32 instruction_stsi;
        u32 instruction_stfl;
        u32 instruction_tprot;
+       u32 instruction_essa;
        u32 instruction_sigp_sense;
        u32 instruction_sigp_sense_running;
        u32 instruction_sigp_external_call;
index 5d1f950704dc6272ec368279b2a01f82274fe220..38149b63dc44a360ab3b0db2dfca4f23e64cc63a 100644 (file)
@@ -48,13 +48,42 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
 {
-       cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
-       update_mm(next, tsk);
+       int cpu = smp_processor_id();
+
+       if (prev == next)
+               return;
+       if (atomic_inc_return(&next->context.attach_count) >> 16) {
+               /* Delay update_mm until all TLB flushes are done. */
+               set_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+       } else {
+               cpumask_set_cpu(cpu, mm_cpumask(next));
+               update_mm(next, tsk);
+               if (next->context.flush_mm)
+                       /* Flush pending TLBs */
+                       __tlb_flush_mm(next);
+       }
        atomic_dec(&prev->context.attach_count);
        WARN_ON(atomic_read(&prev->context.attach_count) < 0);
-       atomic_inc(&next->context.attach_count);
-       /* Check for TLBs not flushed yet */
-       __tlb_flush_mm_lazy(next);
+}
+
+#define finish_arch_post_lock_switch finish_arch_post_lock_switch
+static inline void finish_arch_post_lock_switch(void)
+{
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->mm;
+
+       if (!test_tsk_thread_flag(tsk, TIF_TLB_WAIT))
+               return;
+       preempt_disable();
+       clear_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+       while (atomic_read(&mm->context.attach_count) >> 16)
+               cpu_relax();
+
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+       update_mm(mm, tsk);
+       if (mm->context.flush_mm)
+               __tlb_flush_mm(mm);
+       preempt_enable();
 }
 
 #define enter_lazy_tlb(mm,tsk) do { } while (0)
index e1408ddb94f8d6d5107561374bb759a37c5d8eb1..884017cbfa9fade412372f7f781e503b3f39513b 100644 (file)
@@ -22,6 +22,7 @@ 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 *);
 
+void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long);
 int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
                          unsigned long key, bool nq);
 
@@ -91,11 +92,22 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
        unsigned long *table = crst_table_alloc(mm);
-       if (table)
-               crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
+
+       if (!table)
+               return NULL;
+       crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
+       if (!pgtable_pmd_page_ctor(virt_to_page(table))) {
+               crst_table_free(mm, table);
+               return NULL;
+       }
        return (pmd_t *) table;
 }
-#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+       pgtable_pmd_page_dtor(virt_to_page(pmd));
+       crst_table_free(mm, (unsigned long *) pmd);
+}
 
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
 {
index 2204400d0bd58d4a1e45c82394ff5cbd100aa2cc..1ab75eaacbd417079d3e6de25e8401c87e24a1d7 100644 (file)
@@ -229,6 +229,7 @@ extern unsigned long MODULES_END;
 #define _PAGE_READ     0x010           /* SW pte read bit */
 #define _PAGE_WRITE    0x020           /* SW pte write bit */
 #define _PAGE_SPECIAL  0x040           /* SW associated with special page */
+#define _PAGE_UNUSED   0x080           /* SW bit for pgste usage state */
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /* Set of bits not changed in pte_modify */
@@ -394,6 +395,12 @@ extern unsigned long MODULES_END;
 
 #endif /* CONFIG_64BIT */
 
+/* Guest Page State used for virtualization */
+#define _PGSTE_GPS_ZERO                0x0000000080000000UL
+#define _PGSTE_GPS_USAGE_MASK  0x0000000003000000UL
+#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL
+#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL
+
 /*
  * A user page table pointer has the space-switch-event bit, the
  * private-space-control bit and the storage-alteration-event-control
@@ -617,6 +624,14 @@ static inline int pte_none(pte_t pte)
        return pte_val(pte) == _PAGE_INVALID;
 }
 
+static inline int pte_swap(pte_t pte)
+{
+       /* Bit pattern: (pte & 0x603) == 0x402 */
+       return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT |
+                               _PAGE_TYPE | _PAGE_PRESENT))
+               == (_PAGE_INVALID | _PAGE_TYPE);
+}
+
 static inline int pte_file(pte_t pte)
 {
        /* Bit pattern: (pte & 0x601) == 0x600 */
@@ -821,20 +836,20 @@ unsigned long gmap_translate(unsigned long address, struct gmap *);
 unsigned long __gmap_fault(unsigned long address, struct gmap *);
 unsigned long gmap_fault(unsigned long address, struct gmap *);
 void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
+void __gmap_zap(unsigned long address, struct gmap *);
 
 void gmap_register_ipte_notifier(struct gmap_notifier *);
 void gmap_unregister_ipte_notifier(struct gmap_notifier *);
 int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
-void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *);
+void gmap_do_ipte_notify(struct mm_struct *, pte_t *);
 
 static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
-                                       unsigned long addr,
                                        pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
        if (pgste_val(pgste) & PGSTE_IN_BIT) {
                pgste_val(pgste) &= ~PGSTE_IN_BIT;
-               gmap_do_ipte_notify(mm, addr, ptep);
+               gmap_do_ipte_notify(mm, ptep);
        }
 #endif
        return pgste;
@@ -852,6 +867,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
+               pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
                pgste_set_key(ptep, pgste, entry);
                pgste_set_pte(ptep, entry);
                pgste_set_unlock(ptep, pgste);
@@ -881,6 +897,12 @@ static inline int pte_young(pte_t pte)
        return (pte_val(pte) & _PAGE_YOUNG) != 0;
 }
 
+#define __HAVE_ARCH_PTE_UNUSED
+static inline int pte_unused(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_UNUSED;
+}
+
 /*
  * pgd/pmd/pte modification functions
  */
@@ -1034,30 +1056,41 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
 
 static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
 {
-       if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+       unsigned long pto = (unsigned long) ptep;
+
 #ifndef CONFIG_64BIT
-               /* pto must point to the start of the segment table */
-               pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00);
-#else
-               /* ipte in zarch mode can do the math */
-               pte_t *pto = ptep;
+       /* pto in ESA mode must point to the start of the segment table */
+       pto &= 0x7ffffc00;
 #endif
-               asm volatile(
-                       "       ipte    %2,%3"
-                       : "=m" (*ptep) : "m" (*ptep),
-                         "a" (pto), "a" (address));
-       }
+       /* Invalidation + global TLB flush for the pte */
+       asm volatile(
+               "       ipte    %2,%3"
+               : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
+}
+
+static inline void ptep_flush_direct(struct mm_struct *mm,
+                                    unsigned long address, pte_t *ptep)
+{
+       if (pte_val(*ptep) & _PAGE_INVALID)
+               return;
+       __ptep_ipte(address, ptep);
 }
 
 static inline void ptep_flush_lazy(struct mm_struct *mm,
                                   unsigned long address, pte_t *ptep)
 {
-       int active = (mm == current->active_mm) ? 1 : 0;
+       int active, count;
 
-       if (atomic_read(&mm->context.attach_count) > active)
-               __ptep_ipte(address, ptep);
-       else
+       if (pte_val(*ptep) & _PAGE_INVALID)
+               return;
+       active = (mm == current->active_mm) ? 1 : 0;
+       count = atomic_add_return(0x10000, &mm->context.attach_count);
+       if ((count & 0xffff) <= active) {
+               pte_val(*ptep) |= _PAGE_INVALID;
                mm->context.flush_mm = 1;
+       } else
+               __ptep_ipte(address, ptep);
+       atomic_sub(0x10000, &mm->context.attach_count);
 }
 
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -1070,11 +1103,11 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 
        if (mm_has_pgste(vma->vm_mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste = pgste_ipte_notify(vma->vm_mm, addr, ptep, pgste);
+               pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
        }
 
        pte = *ptep;
-       __ptep_ipte(addr, ptep);
+       ptep_flush_direct(vma->vm_mm, addr, ptep);
        young = pte_young(pte);
        pte = pte_mkold(pte);
 
@@ -1116,7 +1149,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+               pgste = pgste_ipte_notify(mm, ptep, pgste);
        }
 
        pte = *ptep;
@@ -1140,12 +1173,11 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste_ipte_notify(mm, address, ptep, pgste);
+               pgste_ipte_notify(mm, ptep, pgste);
        }
 
        pte = *ptep;
        ptep_flush_lazy(mm, address, ptep);
-       pte_val(*ptep) |= _PAGE_INVALID;
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_update_all(&pte, pgste);
@@ -1178,14 +1210,17 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
 
        if (mm_has_pgste(vma->vm_mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
+               pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
        }
 
        pte = *ptep;
-       __ptep_ipte(address, ptep);
+       ptep_flush_direct(vma->vm_mm, address, ptep);
        pte_val(*ptep) = _PAGE_INVALID;
 
        if (mm_has_pgste(vma->vm_mm)) {
+               if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) ==
+                   _PGSTE_GPS_USAGE_UNUSED)
+                       pte_val(pte) |= _PAGE_UNUSED;
                pgste = pgste_update_all(&pte, pgste);
                pgste_set_unlock(ptep, pgste);
        }
@@ -1209,7 +1244,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
 
        if (!full && mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+               pgste = pgste_ipte_notify(mm, ptep, pgste);
        }
 
        pte = *ptep;
@@ -1234,7 +1269,7 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
        if (pte_write(pte)) {
                if (mm_has_pgste(mm)) {
                        pgste = pgste_get_lock(ptep);
-                       pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+                       pgste = pgste_ipte_notify(mm, ptep, pgste);
                }
 
                ptep_flush_lazy(mm, address, ptep);
@@ -1260,10 +1295,10 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
                return 0;
        if (mm_has_pgste(vma->vm_mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
+               pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
        }
 
-       __ptep_ipte(address, ptep);
+       ptep_flush_direct(vma->vm_mm, address, ptep);
 
        if (mm_has_pgste(vma->vm_mm)) {
                pgste_set_pte(ptep, entry);
@@ -1447,12 +1482,16 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
 static inline void pmdp_flush_lazy(struct mm_struct *mm,
                                   unsigned long address, pmd_t *pmdp)
 {
-       int active = (mm == current->active_mm) ? 1 : 0;
+       int active, count;
 
-       if ((atomic_read(&mm->context.attach_count) & 0xffff) > active)
-               __pmd_idte(address, pmdp);
-       else
+       active = (mm == current->active_mm) ? 1 : 0;
+       count = atomic_add_return(0x10000, &mm->context.attach_count);
+       if ((count & 0xffff) <= active) {
+               pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
                mm->context.flush_mm = 1;
+       } else
+               __pmd_idte(address, pmdp);
+       atomic_sub(0x10000, &mm->context.attach_count);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
index 9c82cebddabd78938b1d66baef004c74f3bd97ec..f4783c0b7b43cfd4e58c2c4bfed19013f465fb1b 100644 (file)
@@ -83,6 +83,7 @@ struct per_struct_kernel {
  * These are defined as per linux/ptrace.h, which see.
  */
 #define arch_has_single_step() (1)
+#define arch_has_block_step()  (1)
 
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
index abaca2275c7a5acb3f0f730539e4d8d5fd6cd19f..2f5e9932b4defddda4587c6593492712f2fb85c1 100644 (file)
@@ -46,6 +46,7 @@ int sclp_cpu_configure(u8 cpu);
 int sclp_cpu_deconfigure(u8 cpu);
 unsigned long long sclp_get_rnmax(void);
 unsigned long long sclp_get_rzm(void);
+unsigned int sclp_get_max_cpu(void);
 int sclp_sdias_blk_count(void);
 int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
 int sclp_chp_configure(struct chp_id chpid);
index 94cfbe442f124cc720f2436c7e3c34d485cf0139..406f3a1e63efcce54ccbe6c409d6246bbdb7a887 100644 (file)
@@ -59,7 +59,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
 #define MACHINE_FLAG_DIAG44    (1UL << 4)
 #define MACHINE_FLAG_IDTE      (1UL << 5)
 #define MACHINE_FLAG_DIAG9C    (1UL << 6)
-#define MACHINE_FLAG_MVCOS     (1UL << 7)
 #define MACHINE_FLAG_KVM       (1UL << 8)
 #define MACHINE_FLAG_ESOP      (1UL << 9)
 #define MACHINE_FLAG_EDAT1     (1UL << 10)
@@ -85,7 +84,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
 #define MACHINE_HAS_IDTE       (0)
 #define MACHINE_HAS_DIAG44     (1)
 #define MACHINE_HAS_MVPG       (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG)
-#define MACHINE_HAS_MVCOS      (0)
 #define MACHINE_HAS_EDAT1      (0)
 #define MACHINE_HAS_EDAT2      (0)
 #define MACHINE_HAS_LPP                (0)
@@ -98,7 +96,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
 #define MACHINE_HAS_IDTE       (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE)
 #define MACHINE_HAS_DIAG44     (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44)
 #define MACHINE_HAS_MVPG       (1)
-#define MACHINE_HAS_MVCOS      (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
 #define MACHINE_HAS_EDAT1      (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
 #define MACHINE_HAS_EDAT2      (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
 #define MACHINE_HAS_LPP                (S390_lowcore.machine_flags & MACHINE_FLAG_LPP)
index 10e0fcd3633d178f25b299a709b9c80706f05818..3ccd71b903454a667ec116a21fa0678a6f80dafe 100644 (file)
@@ -81,6 +81,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NOTIFY_RESUME      1       /* callback before returning to user */
 #define TIF_SIGPENDING         2       /* signal pending */
 #define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_TLB_WAIT           4       /* wait for TLB flush completion */
 #define TIF_PER_TRAP           6       /* deliver sigtrap on return to user */
 #define TIF_MCCK_PENDING       7       /* machine check handling is pending */
 #define TIF_SYSCALL_TRACE      8       /* syscall trace active */
@@ -91,11 +92,13 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    19      /* restore signal mask in do_signal() */
 #define TIF_SINGLE_STEP                20      /* This task is single stepped */
+#define TIF_BLOCK_STEP         21      /* This task is block stepped */
 
 #define _TIF_SYSCALL           (1<<TIF_SYSCALL)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
+#define _TIF_TLB_WAIT          (1<<TIF_TLB_WAIT)
 #define _TIF_PER_TRAP          (1<<TIF_PER_TRAP)
 #define _TIF_MCCK_PENDING      (1<<TIF_MCCK_PENDING)
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
index 79330af9a5f85442745110001defbaa2a1964bb8..4133b3f72fb09a04c9f640cd214ef4a21a69c9db 100644 (file)
@@ -92,33 +92,58 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
 #define ARCH_HAS_SORT_EXTABLE
 #define ARCH_HAS_SEARCH_EXTABLE
 
-struct uaccess_ops {
-       size_t (*copy_from_user)(size_t, const void __user *, void *);
-       size_t (*copy_to_user)(size_t, void __user *, const void *);
-       size_t (*copy_in_user)(size_t, void __user *, const void __user *);
-       size_t (*clear_user)(size_t, void __user *);
-       size_t (*strnlen_user)(size_t, const char __user *);
-       size_t (*strncpy_from_user)(size_t, const char __user *, char *);
-       int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
-       int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
-};
+int __handle_fault(unsigned long, unsigned long, int);
 
-extern struct uaccess_ops uaccess;
-extern struct uaccess_ops uaccess_mvcos;
-extern struct uaccess_ops uaccess_pt;
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:   Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+unsigned long __must_check __copy_from_user(void *to, const void __user *from,
+                                           unsigned long n);
+
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:   Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long __must_check __copy_to_user(void __user *to, const void *from,
+                                         unsigned long n);
 
-extern int __handle_fault(unsigned long, unsigned long, int);
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
 
-static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
+static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
 {
-       size = uaccess.copy_to_user(size, ptr, x);
-       return size ? -EFAULT : size;
+       size = __copy_to_user(ptr, x, size);
+       return size ? -EFAULT : 0;
 }
 
-static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
+static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
 {
-       size = uaccess.copy_from_user(size, ptr, x);
-       return size ? -EFAULT : size;
+       size = __copy_from_user(x, ptr, size);
+       return size ? -EFAULT : 0;
 }
 
 /*
@@ -135,8 +160,8 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
        case 2:                                                 \
        case 4:                                                 \
        case 8:                                                 \
-               __pu_err = __put_user_fn(sizeof (*(ptr)),       \
-                                        ptr, &__x);            \
+               __pu_err = __put_user_fn(&__x, ptr,             \
+                                        sizeof(*(ptr)));       \
                break;                                          \
        default:                                                \
                __put_user_bad();                               \
@@ -152,7 +177,7 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
 })
 
 
-extern int __put_user_bad(void) __attribute__((noreturn));
+int __put_user_bad(void) __attribute__((noreturn));
 
 #define __get_user(x, ptr)                                     \
 ({                                                             \
@@ -161,29 +186,29 @@ extern int __put_user_bad(void) __attribute__((noreturn));
        switch (sizeof(*(ptr))) {                               \
        case 1: {                                               \
                unsigned char __x;                              \
-               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
-                                        ptr, &__x);            \
+               __gu_err = __get_user_fn(&__x, ptr,             \
+                                        sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
        case 2: {                                               \
                unsigned short __x;                             \
-               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
-                                        ptr, &__x);            \
+               __gu_err = __get_user_fn(&__x, ptr,             \
+                                        sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
        case 4: {                                               \
                unsigned int __x;                               \
-               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
-                                        ptr, &__x);            \
+               __gu_err = __get_user_fn(&__x, ptr,             \
+                                        sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
        case 8: {                                               \
                unsigned long long __x;                         \
-               __gu_err = __get_user_fn(sizeof (*(ptr)),       \
-                                        ptr, &__x);            \
+               __gu_err = __get_user_fn(&__x, ptr,             \
+                                        sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
@@ -200,34 +225,11 @@ extern int __put_user_bad(void) __attribute__((noreturn));
        __get_user(x, ptr);                                     \
 })
 
-extern int __get_user_bad(void) __attribute__((noreturn));
+int __get_user_bad(void) __attribute__((noreturn));
 
 #define __put_user_unaligned __put_user
 #define __get_user_unaligned __get_user
 
-/**
- * __copy_to_user: - Copy a block of data into user space, with less checking.
- * @to:   Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from kernel space to user space.  Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-static inline unsigned long __must_check
-__copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       return uaccess.copy_to_user(n, to, from);
-}
-
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
-
 /**
  * copy_to_user: - Copy a block of data into user space.
  * @to:   Destination address, in user space.
@@ -248,30 +250,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
        return __copy_to_user(to, from, n);
 }
 
-/**
- * __copy_from_user: - Copy a block of data from user space, with less checking.
- * @to:   Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n:    Number of bytes to copy.
- *
- * Context: User context only.  This function may sleep.
- *
- * Copy data from user space to kernel space.  Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-static inline unsigned long __must_check
-__copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       return uaccess.copy_from_user(n, from, to);
-}
-
-extern void copy_from_user_overflow(void)
+void copy_from_user_overflow(void)
 #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
 __compiletime_warning("copy_from_user() buffer size is not provably correct")
 #endif
@@ -306,11 +285,8 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
        return __copy_from_user(to, from, n);
 }
 
-static inline unsigned long __must_check
-__copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
-       return uaccess.copy_in_user(n, to, from);
-}
+unsigned long __must_check
+__copy_in_user(void __user *to, const void __user *from, unsigned long n);
 
 static inline unsigned long __must_check
 copy_in_user(void __user *to, const void __user *from, unsigned long n)
@@ -322,18 +298,22 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n)
 /*
  * Copy a null terminated string from userspace.
  */
+
+long __strncpy_from_user(char *dst, const char __user *src, long count);
+
 static inline long __must_check
 strncpy_from_user(char *dst, const char __user *src, long count)
 {
        might_fault();
-       return uaccess.strncpy_from_user(count, src, dst);
+       return __strncpy_from_user(dst, src, count);
 }
 
-static inline unsigned long
-strnlen_user(const char __user * src, unsigned long n)
+unsigned long __must_check __strnlen_user(const char __user *src, unsigned long count);
+
+static inline unsigned long strnlen_user(const char __user *src, unsigned long n)
 {
        might_fault();
-       return uaccess.strnlen_user(n, src);
+       return __strnlen_user(src, n);
 }
 
 /**
@@ -355,21 +335,14 @@ strnlen_user(const char __user * src, unsigned long n)
 /*
  * Zero Userspace
  */
+unsigned long __must_check __clear_user(void __user *to, unsigned long size);
 
-static inline unsigned long __must_check
-__clear_user(void __user *to, unsigned long n)
-{
-       return uaccess.clear_user(n, to);
-}
-
-static inline unsigned long __must_check
-clear_user(void __user *to, unsigned long n)
+static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
 {
        might_fault();
-       return uaccess.clear_user(n, to);
+       return __clear_user(to, n);
 }
 
-extern int copy_to_user_real(void __user *dest, void *src, size_t count);
-extern int copy_from_user_real(void *dest, void __user *src, size_t count);
+int copy_to_user_real(void __user *dest, void *src, unsigned long count);
 
 #endif /* __S390_UACCESS_H */
index 7e0b498a2c2ba95c8ca56537e673b18c4a0065d3..a150f4fabe437a5f39ddcafb88c598895c909518 100644 (file)
@@ -402,6 +402,12 @@ typedef struct
 #define PTRACE_DISABLE_TE            0x5010
 #define PTRACE_TE_ABORT_RAND         0x5011
 
+/*
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
+ * not overlap with any of the number assigned in <linux/ptrace.h>.
+ */
+#define PTRACE_SINGLEBLOCK     12      /* resume execution until next branch */
+
 /*
  * PT_PROT definition is loosely based on hppa bsd definition in
  * gdb/hppab-nat.c
index 1b3ac09c11b6df2981ca3dbde3cc6df3fba5d2e9..a95c4ca99617e43360fb3b867ac3aefb92b374d6 100644 (file)
@@ -47,9 +47,8 @@ obj-$(CONFIG_SCHED_BOOK)      += topology.o
 obj-$(CONFIG_HIBERNATION)      += suspend.o swsusp_asm64.o
 obj-$(CONFIG_AUDIT)            += audit.o
 compat-obj-$(CONFIG_AUDIT)     += compat_audit.o
-obj-$(CONFIG_COMPAT)           += compat_linux.o compat_signal.o \
-                                       compat_wrapper.o compat_exec_domain.o \
-                                       $(compat-obj-y)
+obj-$(CONFIG_COMPAT)           += compat_linux.o compat_signal.o
+obj-$(CONFIG_COMPAT)           += compat_wrapper.o $(compat-obj-y)
 
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c
deleted file mode 100644 (file)
index 765fabd..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Support for 32-bit Linux for S390 personality.
- *
- * Copyright IBM Corp. 2000
- * Author(s): Gerhard Tonn (ton@de.ibm.com)
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/personality.h>
-#include <linux/sched.h>
-
-static struct exec_domain s390_exec_domain;
-
-static int __init s390_init (void)
-{
-       s390_exec_domain.name = "Linux/s390";
-       s390_exec_domain.handler = NULL;
-       s390_exec_domain.pers_low = PER_LINUX32;
-       s390_exec_domain.pers_high = PER_LINUX32;
-       s390_exec_domain.signal_map = default_exec_domain.signal_map;
-       s390_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
-       register_exec_domain(&s390_exec_domain);
-       return 0;
-}
-
-__initcall(s390_init);
index db02052bd137254c1c6d46314005ed4fce1a6204..ca38139423ae7f22e3a4d5e33d4990d9f4bc5daa 100644 (file)
 #define SET_STAT_UID(stat, uid)                (stat).st_uid = high2lowuid(uid)
 #define SET_STAT_GID(stat, gid)                (stat).st_gid = high2lowgid(gid)
 
-asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_chown16, const char __user *, filename,
+                      u16, user, u16, group)
 {
        return sys_chown(filename, low2highuid(user), low2highgid(group));
 }
 
-asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_lchown16, const char __user *,
+                      filename, u16, user, u16, group)
 {
        return sys_lchown(filename, low2highuid(user), low2highgid(group));
 }
 
-asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_fchown16, unsigned int, fd, u16, user, u16, group)
 {
        return sys_fchown(fd, low2highuid(user), low2highgid(group));
 }
 
-asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
+COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid)
 {
        return sys_setregid(low2highgid(rgid), low2highgid(egid));
 }
 
-asmlinkage long sys32_setgid16(u16 gid)
+COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
 {
        return sys_setgid((gid_t)gid);
 }
 
-asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
+COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
 {
        return sys_setreuid(low2highuid(ruid), low2highuid(euid));
 }
 
-asmlinkage long sys32_setuid16(u16 uid)
+COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
 {
        return sys_setuid((uid_t)uid);
 }
 
-asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
+COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
 {
        return sys_setresuid(low2highuid(ruid), low2highuid(euid),
-               low2highuid(suid));
+                            low2highuid(suid));
 }
 
-asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __user *suidp)
+COMPAT_SYSCALL_DEFINE3(s390_getresuid16, u16 __user *, ruidp,
+                      u16 __user *, euidp, u16 __user *, suidp)
 {
        const struct cred *cred = current_cred();
        int retval;
@@ -144,13 +147,14 @@ asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __us
        return retval;
 }
 
-asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
+COMPAT_SYSCALL_DEFINE3(s390_setresgid16, u16, rgid, u16, egid, u16, sgid)
 {
        return sys_setresgid(low2highgid(rgid), low2highgid(egid),
-               low2highgid(sgid));
+                            low2highgid(sgid));
 }
 
-asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __user *sgidp)
+COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp,
+                      u16 __user *, egidp, u16 __user *, sgidp)
 {
        const struct cred *cred = current_cred();
        int retval;
@@ -167,12 +171,12 @@ asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __us
        return retval;
 }
 
-asmlinkage long sys32_setfsuid16(u16 uid)
+COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
 {
        return sys_setfsuid((uid_t)uid);
 }
 
-asmlinkage long sys32_setfsgid16(u16 gid)
+COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
 {
        return sys_setfsgid((gid_t)gid);
 }
@@ -215,7 +219,7 @@ static int groups16_from_user(struct group_info *group_info, u16 __user *groupli
        return 0;
 }
 
-asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
+COMPAT_SYSCALL_DEFINE2(s390_getgroups16, int, gidsetsize, u16 __user *, grouplist)
 {
        const struct cred *cred = current_cred();
        int i;
@@ -240,7 +244,7 @@ out:
        return i;
 }
 
-asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
+COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplist)
 {
        struct group_info *group_info;
        int retval;
@@ -265,22 +269,22 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
        return retval;
 }
 
-asmlinkage long sys32_getuid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getuid16)
 {
        return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
 }
 
-asmlinkage long sys32_geteuid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_geteuid16)
 {
        return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
 }
 
-asmlinkage long sys32_getgid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getgid16)
 {
        return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
 }
 
-asmlinkage long sys32_getegid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getegid16)
 {
        return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
 }
@@ -295,41 +299,35 @@ COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second,
 }
 #endif
 
-asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
+COMPAT_SYSCALL_DEFINE3(s390_truncate64, const char __user *, path, u32, high, u32, low)
 {
-       if ((int)high < 0)
-               return -EINVAL;
-       else
-               return sys_truncate(path, (high << 32) | low);
+       return sys_truncate(path, (unsigned long)high << 32 | low);
 }
 
-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+COMPAT_SYSCALL_DEFINE3(s390_ftruncate64, unsigned int, fd, u32, high, u32, low)
 {
-       if ((int)high < 0)
-               return -EINVAL;
-       else
-               return sys_ftruncate(fd, (high << 32) | low);
+       return sys_ftruncate(fd, (unsigned long)high << 32 | low);
 }
 
-asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
-                               size_t count, u32 poshi, u32 poslo)
+COMPAT_SYSCALL_DEFINE5(s390_pread64, unsigned int, fd, char __user *, ubuf,
+                      compat_size_t, count, u32, high, u32, low)
 {
        if ((compat_ssize_t) count < 0)
                return -EINVAL;
-       return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+       return sys_pread64(fd, ubuf, count, (unsigned long)high << 32 | low);
 }
 
-asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
-                               size_t count, u32 poshi, u32 poslo)
+COMPAT_SYSCALL_DEFINE5(s390_pwrite64, unsigned int, fd, const char __user *, ubuf,
+                      compat_size_t, count, u32, high, u32, low)
 {
        if ((compat_ssize_t) count < 0)
                return -EINVAL;
-       return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+       return sys_pwrite64(fd, ubuf, count, (unsigned long)high << 32 | low);
 }
 
-asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+COMPAT_SYSCALL_DEFINE4(s390_readahead, int, fd, u32, high, u32, low, s32, count)
 {
-       return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+       return sys_readahead(fd, (unsigned long)high << 32 | low, count);
 }
 
 struct stat64_emu31 {
@@ -381,7 +379,7 @@ static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
        return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 
 }
 
-asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_stat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
 {
        struct kstat stat;
        int ret = vfs_stat(filename, &stat);
@@ -390,7 +388,7 @@ asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 _
        return ret;
 }
 
-asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_lstat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
 {
        struct kstat stat;
        int ret = vfs_lstat(filename, &stat);
@@ -399,7 +397,7 @@ asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31
        return ret;
 }
 
-asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_fstat64, unsigned int, fd, struct stat64_emu31 __user *, statbuf)
 {
        struct kstat stat;
        int ret = vfs_fstat(fd, &stat);
@@ -408,8 +406,8 @@ asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * sta
        return ret;
 }
 
-asmlinkage long sys32_fstatat64(unsigned int dfd, const char __user *filename,
-                               struct stat64_emu31 __user* statbuf, int flag)
+COMPAT_SYSCALL_DEFINE4(s390_fstatat64, unsigned int, dfd, const char __user *, filename,
+                      struct stat64_emu31 __user *, statbuf, int, flag)
 {
        struct kstat stat;
        int error;
@@ -435,7 +433,7 @@ struct mmap_arg_struct_emu31 {
        compat_ulong_t offset;
 };
 
-asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
+COMPAT_SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct_emu31 __user *, arg)
 {
        struct mmap_arg_struct_emu31 a;
 
@@ -447,7 +445,7 @@ asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
                              a.offset >> PAGE_SHIFT);
 }
 
-asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
+COMPAT_SYSCALL_DEFINE1(s390_mmap2, struct mmap_arg_struct_emu31 __user *, arg)
 {
        struct mmap_arg_struct_emu31 a;
 
@@ -456,7 +454,7 @@ asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 }
 
-asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
+COMPAT_SYSCALL_DEFINE3(s390_read, unsigned int, fd, char __user *, buf, compat_size_t, count)
 {
        if ((compat_ssize_t) count < 0)
                return -EINVAL; 
@@ -464,7 +462,7 @@ asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
        return sys_read(fd, buf, count);
 }
 
-asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t count)
+COMPAT_SYSCALL_DEFINE3(s390_write, unsigned int, fd, const char __user *, buf, compat_size_t, count)
 {
        if ((compat_ssize_t) count < 0)
                return -EINVAL; 
@@ -478,14 +476,13 @@ asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t cou
  * because the 31 bit values differ from the 64 bit values.
  */
 
-asmlinkage long
-sys32_fadvise64(int fd, loff_t offset, size_t len, int advise)
+COMPAT_SYSCALL_DEFINE5(s390_fadvise64, int, fd, u32, high, u32, low, compat_size_t, len, int, advise)
 {
        if (advise == 4)
                advise = POSIX_FADV_DONTNEED;
        else if (advise == 5)
                advise = POSIX_FADV_NOREUSE;
-       return sys_fadvise64(fd, offset, len, advise);
+       return sys_fadvise64(fd, (unsigned long)high << 32 | low, len, advise);
 }
 
 struct fadvise64_64_args {
@@ -495,8 +492,7 @@ struct fadvise64_64_args {
        int advice;
 };
 
-asmlinkage long
-sys32_fadvise64_64(struct fadvise64_64_args __user *args)
+COMPAT_SYSCALL_DEFINE1(s390_fadvise64_64, struct fadvise64_64_args __user *, args)
 {
        struct fadvise64_64_args a;
 
@@ -508,3 +504,17 @@ sys32_fadvise64_64(struct fadvise64_64_args __user *args)
                a.advice = POSIX_FADV_NOREUSE;
        return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
 }
+
+COMPAT_SYSCALL_DEFINE6(s390_sync_file_range, int, fd, u32, offhigh, u32, offlow,
+                      u32, nhigh, u32, nlow, unsigned int, flags)
+{
+       return sys_sync_file_range(fd, ((loff_t)offhigh << 32) + offlow,
+                                  ((u64)nhigh << 32) + nlow, flags);
+}
+
+COMPAT_SYSCALL_DEFINE6(s390_fallocate, int, fd, int, mode, u32, offhigh, u32, offlow,
+                      u32, lenhigh, u32, lenlow)
+{
+       return sys_fallocate(fd, mode, ((loff_t)offhigh << 32) + offlow,
+                            ((u64)lenhigh << 32) + lenlow);
+}
index 1bfda3eca37909988c26564b11398b6b75302c50..39ddfdb40ae86228c89f126b02e6f488ca1ae57e 100644 (file)
@@ -76,46 +76,43 @@ struct stat64_emu31;
 struct mmap_arg_struct_emu31;
 struct fadvise64_64_args;
 
-long sys32_chown16(const char __user * filename, u16 user, u16 group);
-long sys32_lchown16(const char __user * filename, u16 user, u16 group);
-long sys32_fchown16(unsigned int fd, u16 user, u16 group);
-long sys32_setregid16(u16 rgid, u16 egid);
-long sys32_setgid16(u16 gid);
-long sys32_setreuid16(u16 ruid, u16 euid);
-long sys32_setuid16(u16 uid);
-long sys32_setresuid16(u16 ruid, u16 euid, u16 suid);
-long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid);
-long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid);
-long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid);
-long sys32_setfsuid16(u16 uid);
-long sys32_setfsgid16(u16 gid);
-long sys32_getgroups16(int gidsetsize, u16 __user *grouplist);
-long sys32_setgroups16(int gidsetsize, u16 __user *grouplist);
-long sys32_getuid16(void);
-long sys32_geteuid16(void);
-long sys32_getgid16(void);
-long sys32_getegid16(void);
-long sys32_truncate64(const char __user * path, unsigned long high,
-                     unsigned long low);
-long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low);
-long sys32_init_module(void __user *umod, unsigned long len,
-                      const char __user *uargs);
-long sys32_delete_module(const char __user *name_user, unsigned int flags);
-long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
-                  u32 poshi, u32 poslo);
-long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
-                   size_t count, u32 poshi, u32 poslo);
-compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count);
-long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf);
-long sys32_lstat64(const char __user * filename,
-                  struct stat64_emu31 __user * statbuf);
-long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf);
-long sys32_fstatat64(unsigned int dfd, const char __user *filename,
-                    struct stat64_emu31 __user* statbuf, int flag);
-unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg);
-long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg);
-long sys32_read(unsigned int fd, char __user * buf, size_t count);
-long sys32_write(unsigned int fd, const char __user * buf, size_t count);
-long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise);
-long sys32_fadvise64_64(struct fadvise64_64_args __user *args);
+long compat_sys_s390_chown16(const char __user *filename, u16 user, u16 group);
+long compat_sys_s390_lchown16(const char __user *filename, u16 user, u16 group);
+long compat_sys_s390_fchown16(unsigned int fd, u16 user, u16 group);
+long compat_sys_s390_setregid16(u16 rgid, u16 egid);
+long compat_sys_s390_setgid16(u16 gid);
+long compat_sys_s390_setreuid16(u16 ruid, u16 euid);
+long compat_sys_s390_setuid16(u16 uid);
+long compat_sys_s390_setresuid16(u16 ruid, u16 euid, u16 suid);
+long compat_sys_s390_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid);
+long compat_sys_s390_setresgid16(u16 rgid, u16 egid, u16 sgid);
+long compat_sys_s390_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid);
+long compat_sys_s390_setfsuid16(u16 uid);
+long compat_sys_s390_setfsgid16(u16 gid);
+long compat_sys_s390_getgroups16(int gidsetsize, u16 __user *grouplist);
+long compat_sys_s390_setgroups16(int gidsetsize, u16 __user *grouplist);
+long compat_sys_s390_getuid16(void);
+long compat_sys_s390_geteuid16(void);
+long compat_sys_s390_getgid16(void);
+long compat_sys_s390_getegid16(void);
+long compat_sys_s390_truncate64(const char __user *path, u32 high, u32 low);
+long compat_sys_s390_ftruncate64(unsigned int fd, u32 high, u32 low);
+long compat_sys_s390_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, u32 high, u32 low);
+long compat_sys_s390_pwrite64(unsigned int fd, const char __user *ubuf, compat_size_t count, u32 high, u32 low);
+long compat_sys_s390_readahead(int fd, u32 high, u32 low, s32 count);
+long compat_sys_s390_stat64(const char __user *filename, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_lstat64(const char __user *filename, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_fstat64(unsigned int fd, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_fstatat64(unsigned int dfd, const char __user *filename, struct stat64_emu31 __user *statbuf, int flag);
+long compat_sys_s390_old_mmap(struct mmap_arg_struct_emu31 __user *arg);
+long compat_sys_s390_mmap2(struct mmap_arg_struct_emu31 __user *arg);
+long compat_sys_s390_read(unsigned int fd, char __user * buf, compat_size_t count);
+long compat_sys_s390_write(unsigned int fd, const char __user * buf, compat_size_t count);
+long compat_sys_s390_fadvise64(int fd, u32 high, u32 low, compat_size_t len, int advise);
+long compat_sys_s390_fadvise64_64(struct fadvise64_64_args __user *args);
+long compat_sys_s390_sync_file_range(int fd, u32 offhigh, u32 offlow, u32 nhigh, u32 nlow, unsigned int flags);
+long compat_sys_s390_fallocate(int fd, int mode, u32 offhigh, u32 offlow, u32 lenhigh, u32 lenlow);
+long compat_sys_sigreturn(void);
+long compat_sys_rt_sigreturn(void);
+
 #endif /* _ASM_S390X_S390_H */
index 8b84bc373e945bbb2edaba876addbbf5a850fcdd..7df5ed9f44d7c2d471e99bd3f21195d958638c3d 100644 (file)
@@ -241,7 +241,7 @@ static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
        return 0;
 }
 
-asmlinkage long sys32_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(sigreturn)
 {
        struct pt_regs *regs = task_pt_regs(current);
        sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
@@ -260,7 +260,7 @@ badframe:
        return 0;
 }
 
-asmlinkage long sys32_rt_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
 {
        struct pt_regs *regs = task_pt_regs(current);
        rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
deleted file mode 100644 (file)
index 0248949..0000000
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
-*    wrapper for 31 bit compatible system calls.
-*
-*    Copyright IBM Corp. 2000, 2006
-*    Author(s): Gerhard Tonn (ton@de.ibm.com),
-*              Thomas Spatzier (tspat@de.ibm.com)
-*/
-
-#include <linux/linkage.h>
-
-ENTRY(sys32_exit_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_exit                # branch to sys_exit
-
-ENTRY(sys32_read_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # char *
-       llgfr   %r4,%r4                 # size_t
-       jg      sys32_read              # branch to sys_read
-
-ENTRY(sys32_write_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # size_t
-       jg      sys32_write             # branch to system call
-
-ENTRY(sys32_close_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_close               # branch to system call
-
-ENTRY(sys32_creat_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_creat               # branch to system call
-
-ENTRY(sys32_link_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # const char *
-       jg      sys_link                # branch to system call
-
-ENTRY(sys32_unlink_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       jg      sys_unlink              # branch to system call
-
-ENTRY(sys32_chdir_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       jg      sys_chdir               # branch to system call
-
-ENTRY(sys32_time_wrapper)
-       llgtr   %r2,%r2                 # int *
-       jg      compat_sys_time         # branch to system call
-
-ENTRY(sys32_mknod_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       llgfr   %r4,%r4                 # dev
-       jg      sys_mknod               # branch to system call
-
-ENTRY(sys32_chmod_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # mode_t
-       jg      sys_chmod               # branch to system call
-
-ENTRY(sys32_lchown16_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # __kernel_old_uid_emu31_t
-       llgfr   %r4,%r4                 # __kernel_old_uid_emu31_t
-       jg      sys32_lchown16          # branch to system call
-
-#sys32_getpid_wrapper                          # void
-
-ENTRY(sys32_mount_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # char *
-       llgfr   %r5,%r5                 # unsigned long
-       llgtr   %r6,%r6                 # void *
-       jg      compat_sys_mount        # branch to system call
-
-ENTRY(sys32_oldumount_wrapper)
-       llgtr   %r2,%r2                 # char *
-       jg      sys_oldumount           # branch to system call
-
-ENTRY(sys32_setuid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_uid_emu31_t
-       jg      sys32_setuid16          # branch to system call
-
-#sys32_getuid16_wrapper                        # void
-
-ENTRY(sys32_ptrace_wrapper)
-       lgfr    %r2,%r2                 # long
-       lgfr    %r3,%r3                 # long
-       llgtr   %r4,%r4                 # long
-       llgfr   %r5,%r5                 # long
-       jg      compat_sys_ptrace       # branch to system call
-
-ENTRY(sys32_alarm_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_alarm               # branch to system call
-
-ENTRY(compat_sys_utime_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct compat_utimbuf *
-       jg      compat_sys_utime        # branch to system call
-
-ENTRY(sys32_access_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_access              # branch to system call
-
-ENTRY(sys32_nice_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_nice                # branch to system call
-
-#sys32_sync_wrapper                    # void
-
-ENTRY(sys32_kill_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       jg      sys_kill                # branch to system call
-
-ENTRY(sys32_rename_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # const char *
-       jg      sys_rename              # branch to system call
-
-ENTRY(sys32_mkdir_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_mkdir               # branch to system call
-
-ENTRY(sys32_rmdir_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       jg      sys_rmdir               # branch to system call
-
-ENTRY(sys32_dup_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_dup                 # branch to system call
-
-ENTRY(sys32_pipe_wrapper)
-       llgtr   %r2,%r2                 # u32 *
-       jg      sys_pipe                # branch to system call
-
-ENTRY(compat_sys_times_wrapper)
-       llgtr   %r2,%r2                 # struct compat_tms *
-       jg      compat_sys_times        # branch to system call
-
-ENTRY(sys32_brk_wrapper)
-       llgtr   %r2,%r2                 # unsigned long
-       jg      sys_brk                 # branch to system call
-
-ENTRY(sys32_setgid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_gid_emu31_t
-       jg      sys32_setgid16          # branch to system call
-
-#sys32_getgid16_wrapper                        # void
-
-ENTRY(sys32_signal_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # __sighandler_t
-       jg      sys_signal
-
-#sys32_geteuid16_wrapper               # void
-
-#sys32_getegid16_wrapper               # void
-
-ENTRY(sys32_acct_wrapper)
-       llgtr   %r2,%r2                 # char *
-       jg      sys_acct                # branch to system call
-
-ENTRY(sys32_umount_wrapper)
-       llgtr   %r2,%r2                 # char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_umount              # branch to system call
-
-ENTRY(compat_sys_ioctl_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       llgfr   %r4,%r4                 # unsigned int
-       jg      compat_sys_ioctl        # branch to system call
-
-ENTRY(compat_sys_fcntl_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       llgfr   %r4,%r4                 # unsigned long
-       jg      compat_sys_fcntl        # branch to system call
-
-ENTRY(sys32_setpgid_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       lgfr    %r3,%r3                 # pid_t
-       jg      sys_setpgid             # branch to system call
-
-ENTRY(sys32_umask_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_umask               # branch to system call
-
-ENTRY(sys32_chroot_wrapper)
-       llgtr   %r2,%r2                 # char *
-       jg      sys_chroot              # branch to system call
-
-ENTRY(sys32_ustat_wrapper)
-       llgfr   %r2,%r2                 # dev_t
-       llgtr   %r3,%r3                 # struct ustat *
-       jg      compat_sys_ustat
-
-ENTRY(sys32_dup2_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       jg      sys_dup2                # branch to system call
-
-#sys32_getppid_wrapper                 # void
-
-#sys32_getpgrp_wrapper                 # void
-
-#sys32_setsid_wrapper                  # void
-
-ENTRY(sys32_setreuid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_uid_emu31_t
-       llgfr   %r3,%r3                 # __kernel_old_uid_emu31_t
-       jg      sys32_setreuid16        # branch to system call
-
-ENTRY(sys32_setregid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_gid_emu31_t
-       llgfr   %r3,%r3                 # __kernel_old_gid_emu31_t
-       jg      sys32_setregid16        # branch to system call
-
-ENTRY(sys_sigsuspend_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       llgfr   %r4,%r4                 # old_sigset_t
-       jg      sys_sigsuspend
-
-ENTRY(compat_sys_sigpending_wrapper)
-       llgtr   %r2,%r2                 # compat_old_sigset_t *
-       jg      compat_sys_sigpending   # branch to system call
-
-ENTRY(sys32_sethostname_wrapper)
-       llgtr   %r2,%r2                 # char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_sethostname         # branch to system call
-
-ENTRY(compat_sys_setrlimit_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # struct rlimit_emu31 *
-       jg      compat_sys_setrlimit    # branch to system call
-
-ENTRY(compat_sys_old_getrlimit_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # struct rlimit_emu31 *
-       jg      compat_sys_old_getrlimit # branch to system call
-
-ENTRY(compat_sys_getrlimit_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # struct rlimit_emu31 *
-       jg      compat_sys_getrlimit    # branch to system call
-
-ENTRY(sys32_mmap2_wrapper)
-       llgtr   %r2,%r2                 # struct mmap_arg_struct_emu31 *
-       jg      sys32_mmap2                     # branch to system call
-
-ENTRY(compat_sys_gettimeofday_wrapper)
-       llgtr   %r2,%r2                 # struct timeval_emu31 *
-       llgtr   %r3,%r3                 # struct timezone *
-       jg      compat_sys_gettimeofday # branch to system call
-
-ENTRY(compat_sys_settimeofday_wrapper)
-       llgtr   %r2,%r2                 # struct timeval_emu31 *
-       llgtr   %r3,%r3                 # struct timezone *
-       jg      compat_sys_settimeofday # branch to system call
-
-ENTRY(sys32_getgroups16_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # __kernel_old_gid_emu31_t *
-       jg      sys32_getgroups16       # branch to system call
-
-ENTRY(sys32_setgroups16_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # __kernel_old_gid_emu31_t *
-       jg      sys32_setgroups16       # branch to system call
-
-ENTRY(sys32_symlink_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # const char *
-       jg      sys_symlink             # branch to system call
-
-ENTRY(sys32_readlink_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # char *
-       lgfr    %r4,%r4                 # int
-       jg      sys_readlink            # branch to system call
-
-ENTRY(sys32_uselib_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       jg      sys_uselib              # branch to system call
-
-ENTRY(sys32_swapon_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_swapon              # branch to system call
-
-ENTRY(sys32_reboot_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       llgfr   %r4,%r4                 # unsigned int
-       llgtr   %r5,%r5                 # void *
-       jg      sys_reboot              # branch to system call
-
-ENTRY(old32_readdir_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # void *
-       llgfr   %r4,%r4                 # unsigned int
-       jg      compat_sys_old_readdir  # branch to system call
-
-ENTRY(old32_mmap_wrapper)
-       llgtr   %r2,%r2                 # struct mmap_arg_struct_emu31 *
-       jg      old32_mmap              # branch to system call
-
-ENTRY(sys32_munmap_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # size_t
-       jg      sys_munmap              # branch to system call
-
-ENTRY(sys32_fchmod_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # mode_t
-       jg      sys_fchmod              # branch to system call
-
-ENTRY(sys32_fchown16_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # compat_uid_t
-       llgfr   %r4,%r4                 # compat_uid_t
-       jg      sys32_fchown16          # branch to system call
-
-ENTRY(sys32_getpriority_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       jg      sys_getpriority         # branch to system call
-
-ENTRY(sys32_setpriority_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       lgfr    %r4,%r4                 # int
-       jg      sys_setpriority         # branch to system call
-
-ENTRY(compat_sys_statfs_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct compat_statfs *
-       jg      compat_sys_statfs       # branch to system call
-
-ENTRY(compat_sys_fstatfs_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # struct compat_statfs *
-       jg      compat_sys_fstatfs      # branch to system call
-
-ENTRY(compat_sys_socketcall_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # u32 *
-       jg      compat_sys_socketcall   # branch to system call
-
-ENTRY(sys32_syslog_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # char *
-       lgfr    %r4,%r4                 # int
-       jg      sys_syslog              # branch to system call
-
-ENTRY(compat_sys_newstat_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct stat_emu31 *
-       jg      compat_sys_newstat      # branch to system call
-
-ENTRY(compat_sys_newlstat_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct stat_emu31 *
-       jg      compat_sys_newlstat     # branch to system call
-
-ENTRY(compat_sys_newfstat_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # struct stat_emu31 *
-       jg      compat_sys_newfstat     # branch to system call
-
-#sys32_vhangup_wrapper                 # void
-
-ENTRY(sys32_swapoff_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       jg      sys_swapoff             # branch to system call
-
-ENTRY(compat_sys_sysinfo_wrapper)
-       llgtr   %r2,%r2                 # struct sysinfo_emu31 *
-       jg      compat_sys_sysinfo      # branch to system call
-
-ENTRY(sys32_fsync_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_fsync               # branch to system call
-
-#sys32_sigreturn_wrapper               # done in sigreturn_glue
-
-#sys32_clone_wrapper                   # done in clone_glue
-
-ENTRY(sys32_setdomainname_wrapper)
-       llgtr   %r2,%r2                 # char *
-       lgfr    %r3,%r3                 # int
-       jg      sys_setdomainname       # branch to system call
-
-ENTRY(sys32_newuname_wrapper)
-       llgtr   %r2,%r2                 # struct new_utsname *
-       jg      sys_newuname            # branch to system call
-
-ENTRY(compat_sys_adjtimex_wrapper)
-       llgtr   %r2,%r2                 # struct compat_timex *
-       jg      compat_sys_adjtimex     # branch to system call
-
-ENTRY(sys32_mprotect_wrapper)
-       llgtr   %r2,%r2                 # unsigned long (actually pointer
-       llgfr   %r3,%r3                 # size_t
-       llgfr   %r4,%r4                 # unsigned long
-       jg      sys_mprotect            # branch to system call
-
-ENTRY(sys_init_module_wrapper)
-       llgtr   %r2,%r2                 # void *
-       llgfr   %r3,%r3                 # unsigned long
-       llgtr   %r4,%r4                 # char *
-       jg      sys_init_module         # branch to system call
-
-ENTRY(sys_delete_module_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # unsigned int
-       jg      sys_delete_module       # branch to system call
-
-ENTRY(sys32_quotactl_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # qid_t
-       llgtr   %r5,%r5                 # caddr_t
-       jg      sys_quotactl            # branch to system call
-
-ENTRY(sys32_getpgid_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       jg      sys_getpgid             # branch to system call
-
-ENTRY(sys32_fchdir_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_fchdir              # branch to system call
-
-ENTRY(sys32_bdflush_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # long
-       jg      sys_bdflush             # branch to system call
-
-ENTRY(sys32_sysfs_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       jg      sys_sysfs               # branch to system call
-
-ENTRY(sys32_personality_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_s390_personality    # branch to system call
-
-ENTRY(sys32_setfsuid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_uid_emu31_t
-       jg      sys32_setfsuid16        # branch to system call
-
-ENTRY(sys32_setfsgid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_gid_emu31_t
-       jg      sys32_setfsgid16        # branch to system call
-
-ENTRY(sys32_llseek_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       llgtr   %r5,%r5                 # loff_t *
-       llgfr   %r6,%r6                 # unsigned int
-       jg      sys_llseek              # branch to system call
-
-ENTRY(sys32_getdents_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # void *
-       llgfr   %r4,%r4                 # unsigned int
-       jg      compat_sys_getdents     # branch to system call
-
-ENTRY(compat_sys_select_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # compat_fd_set *
-       llgtr   %r4,%r4                 # compat_fd_set *
-       llgtr   %r5,%r5                 # compat_fd_set *
-       llgtr   %r6,%r6                 # struct compat_timeval *
-       jg      compat_sys_select       # branch to system call
-
-ENTRY(sys32_flock_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       jg      sys_flock               # branch to system call
-
-ENTRY(sys32_msync_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # size_t
-       lgfr    %r4,%r4                 # int
-       jg      sys_msync               # branch to system call
-
-ENTRY(compat_sys_readv_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const struct compat_iovec *
-       llgfr   %r4,%r4                 # unsigned long
-       jg      compat_sys_readv        # branch to system call
-
-ENTRY(compat_sys_writev_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const struct compat_iovec *
-       llgfr   %r4,%r4                 # unsigned long
-       jg      compat_sys_writev       # branch to system call
-
-ENTRY(sys32_getsid_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       jg      sys_getsid              # branch to system call
-
-ENTRY(sys32_fdatasync_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_fdatasync           # branch to system call
-
-ENTRY(sys32_mlock_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # size_t
-       jg      sys_mlock               # branch to system call
-
-ENTRY(sys32_munlock_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # size_t
-       jg      sys_munlock             # branch to system call
-
-ENTRY(sys32_mlockall_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_mlockall            # branch to system call
-
-#sys32_munlockall_wrapper              # void
-
-ENTRY(sys32_sched_setparam_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       llgtr   %r3,%r3                 # struct sched_param *
-       jg      sys_sched_setparam      # branch to system call
-
-ENTRY(sys32_sched_getparam_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       llgtr   %r3,%r3                 # struct sched_param *
-       jg      sys_sched_getparam      # branch to system call
-
-ENTRY(sys32_sched_setscheduler_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       lgfr    %r3,%r3                 # int
-       llgtr   %r4,%r4                 # struct sched_param *
-       jg      sys_sched_setscheduler  # branch to system call
-
-ENTRY(sys32_sched_getscheduler_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       jg      sys_sched_getscheduler  # branch to system call
-
-#sys32_sched_yield_wrapper             # void
-
-ENTRY(sys32_sched_get_priority_max_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_sched_get_priority_max      # branch to system call
-
-ENTRY(sys32_sched_get_priority_min_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_sched_get_priority_min      # branch to system call
-
-ENTRY(compat_sys_nanosleep_wrapper)
-       llgtr   %r2,%r2                 # struct compat_timespec *
-       llgtr   %r3,%r3                 # struct compat_timespec *
-       jg      compat_sys_nanosleep            # branch to system call
-
-ENTRY(sys32_mremap_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       llgfr   %r5,%r5                 # unsigned long
-       llgfr   %r6,%r6                 # unsigned long
-       jg      sys_mremap              # branch to system call
-
-ENTRY(sys32_setresuid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_uid_emu31_t
-       llgfr   %r3,%r3                 # __kernel_old_uid_emu31_t
-       llgfr   %r4,%r4                 # __kernel_old_uid_emu31_t
-       jg      sys32_setresuid16       # branch to system call
-
-ENTRY(sys32_getresuid16_wrapper)
-       llgtr   %r2,%r2                 # __kernel_old_uid_emu31_t *
-       llgtr   %r3,%r3                 # __kernel_old_uid_emu31_t *
-       llgtr   %r4,%r4                 # __kernel_old_uid_emu31_t *
-       jg      sys32_getresuid16       # branch to system call
-
-ENTRY(sys32_poll_wrapper)
-       llgtr   %r2,%r2                 # struct pollfd *
-       llgfr   %r3,%r3                 # unsigned int
-       lgfr    %r4,%r4                 # int
-       jg      sys_poll                # branch to system call
-
-ENTRY(sys32_setresgid16_wrapper)
-       llgfr   %r2,%r2                 # __kernel_old_gid_emu31_t
-       llgfr   %r3,%r3                 # __kernel_old_gid_emu31_t
-       llgfr   %r4,%r4                 # __kernel_old_gid_emu31_t
-       jg      sys32_setresgid16       # branch to system call
-
-ENTRY(sys32_getresgid16_wrapper)
-       llgtr   %r2,%r2                 # __kernel_old_gid_emu31_t *
-       llgtr   %r3,%r3                 # __kernel_old_gid_emu31_t *
-       llgtr   %r4,%r4                 # __kernel_old_gid_emu31_t *
-       jg      sys32_getresgid16       # branch to system call
-
-ENTRY(sys32_prctl_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       llgfr   %r5,%r5                 # unsigned long
-       llgfr   %r6,%r6                 # unsigned long
-       jg      sys_prctl               # branch to system call
-
-#sys32_rt_sigreturn_wrapper            # done in rt_sigreturn_glue
-
-ENTRY(sys32_pread64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # char *
-       llgfr   %r4,%r4                 # size_t
-       llgfr   %r5,%r5                 # u32
-       llgfr   %r6,%r6                 # u32
-       jg      sys32_pread64           # branch to system call
-
-ENTRY(sys32_pwrite64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # size_t
-       llgfr   %r5,%r5                 # u32
-       llgfr   %r6,%r6                 # u32
-       jg      sys32_pwrite64          # branch to system call
-
-ENTRY(sys32_chown16_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # __kernel_old_uid_emu31_t
-       llgfr   %r4,%r4                 # __kernel_old_gid_emu31_t
-       jg      sys32_chown16           # branch to system call
-
-ENTRY(sys32_getcwd_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgfr   %r3,%r3                 # unsigned long
-       jg      sys_getcwd              # branch to system call
-
-ENTRY(sys32_capget_wrapper)
-       llgtr   %r2,%r2                 # cap_user_header_t
-       llgtr   %r3,%r3                 # cap_user_data_t
-       jg      sys_capget              # branch to system call
-
-ENTRY(sys32_capset_wrapper)
-       llgtr   %r2,%r2                 # cap_user_header_t
-       llgtr   %r3,%r3                 # const cap_user_data_t
-       jg      sys_capset              # branch to system call
-
-#sys32_vfork_wrapper                   # done in vfork_glue
-
-ENTRY(sys32_truncate64_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       jg      sys32_truncate64        # branch to system call
-
-ENTRY(sys32_ftruncate64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       jg      sys32_ftruncate64       # branch to system call
-
-ENTRY(sys32_lchown_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # uid_t
-       llgfr   %r4,%r4                 # gid_t
-       jg      sys_lchown              # branch to system call
-
-#sys32_getuid_wrapper                  # void
-#sys32_getgid_wrapper                  # void
-#sys32_geteuid_wrapper                 # void
-#sys32_getegid_wrapper                 # void
-
-ENTRY(sys32_setreuid_wrapper)
-       llgfr   %r2,%r2                 # uid_t
-       llgfr   %r3,%r3                 # uid_t
-       jg      sys_setreuid            # branch to system call
-
-ENTRY(sys32_setregid_wrapper)
-       llgfr   %r2,%r2                 # gid_t
-       llgfr   %r3,%r3                 # gid_t
-       jg      sys_setregid            # branch to system call
-
-ENTRY(sys32_getgroups_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # gid_t *
-       jg      sys_getgroups           # branch to system call
-
-ENTRY(sys32_setgroups_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # gid_t *
-       jg      sys_setgroups           # branch to system call
-
-ENTRY(sys32_fchown_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # uid_t
-       llgfr   %r4,%r4                 # gid_t
-       jg      sys_fchown              # branch to system call
-
-ENTRY(sys32_setresuid_wrapper)
-       llgfr   %r2,%r2                 # uid_t
-       llgfr   %r3,%r3                 # uid_t
-       llgfr   %r4,%r4                 # uid_t
-       jg      sys_setresuid           # branch to system call
-
-ENTRY(sys32_getresuid_wrapper)
-       llgtr   %r2,%r2                 # uid_t *
-       llgtr   %r3,%r3                 # uid_t *
-       llgtr   %r4,%r4                 # uid_t *
-       jg      sys_getresuid           # branch to system call
-
-ENTRY(sys32_setresgid_wrapper)
-       llgfr   %r2,%r2                 # gid_t
-       llgfr   %r3,%r3                 # gid_t
-       llgfr   %r4,%r4                 # gid_t
-       jg      sys_setresgid           # branch to system call
-
-ENTRY(sys32_getresgid_wrapper)
-       llgtr   %r2,%r2                 # gid_t *
-       llgtr   %r3,%r3                 # gid_t *
-       llgtr   %r4,%r4                 # gid_t *
-       jg      sys_getresgid           # branch to system call
-
-ENTRY(sys32_chown_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # uid_t
-       llgfr   %r4,%r4                 # gid_t
-       jg      sys_chown               # branch to system call
-
-ENTRY(sys32_setuid_wrapper)
-       llgfr   %r2,%r2                 # uid_t
-       jg      sys_setuid              # branch to system call
-
-ENTRY(sys32_setgid_wrapper)
-       llgfr   %r2,%r2                 # gid_t
-       jg      sys_setgid              # branch to system call
-
-ENTRY(sys32_setfsuid_wrapper)
-       llgfr   %r2,%r2                 # uid_t
-       jg      sys_setfsuid            # branch to system call
-
-ENTRY(sys32_setfsgid_wrapper)
-       llgfr   %r2,%r2                 # gid_t
-       jg      sys_setfsgid            # branch to system call
-
-ENTRY(sys32_pivot_root_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # const char *
-       jg      sys_pivot_root          # branch to system call
-
-ENTRY(sys32_mincore_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # size_t
-       llgtr   %r4,%r4                 # unsigned char *
-       jg      sys_mincore             # branch to system call
-
-ENTRY(sys32_madvise_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # size_t
-       lgfr    %r4,%r4                 # int
-       jg      sys_madvise             # branch to system call
-
-ENTRY(sys32_getdents64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # void *
-       llgfr   %r4,%r4                 # unsigned int
-       jg      sys_getdents64          # branch to system call
-
-ENTRY(compat_sys_fcntl64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       llgfr   %r4,%r4                 # unsigned long
-       jg      compat_sys_fcntl64      # branch to system call
-
-ENTRY(sys32_stat64_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct stat64 *
-       jg      sys32_stat64            # branch to system call
-
-ENTRY(sys32_lstat64_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct stat64 *
-       jg      sys32_lstat64           # branch to system call
-
-ENTRY(sys32_stime_wrapper)
-       llgtr   %r2,%r2                 # long *
-       jg      compat_sys_stime        # branch to system call
-
-ENTRY(sys32_fstat64_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgtr   %r3,%r3                 # struct stat64 *
-       jg      sys32_fstat64           # branch to system call
-
-ENTRY(sys32_setxattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # void *
-       llgfr   %r5,%r5                 # size_t
-       lgfr    %r6,%r6                 # int
-       jg      sys_setxattr
-
-ENTRY(sys32_lsetxattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # void *
-       llgfr   %r5,%r5                 # size_t
-       lgfr    %r6,%r6                 # int
-       jg      sys_lsetxattr
-
-ENTRY(sys32_fsetxattr_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # void *
-       llgfr   %r5,%r5                 # size_t
-       lgfr    %r6,%r6                 # int
-       jg      sys_fsetxattr
-
-ENTRY(sys32_getxattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # void *
-       llgfr   %r5,%r5                 # size_t
-       jg      sys_getxattr
-
-ENTRY(sys32_lgetxattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # void *
-       llgfr   %r5,%r5                 # size_t
-       jg      sys_lgetxattr
-
-ENTRY(sys32_fgetxattr_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # void *
-       llgfr   %r5,%r5                 # size_t
-       jg      sys_fgetxattr
-
-ENTRY(sys32_listxattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgfr   %r4,%r4                 # size_t
-       jg      sys_listxattr
-
-ENTRY(sys32_llistxattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       llgfr   %r4,%r4                 # size_t
-       jg      sys_llistxattr
-
-ENTRY(sys32_flistxattr_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # char *
-       llgfr   %r4,%r4                 # size_t
-       jg      sys_flistxattr
-
-ENTRY(sys32_removexattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       jg      sys_removexattr
-
-ENTRY(sys32_lremovexattr_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # char *
-       jg      sys_lremovexattr
-
-ENTRY(sys32_fremovexattr_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # char *
-       jg      sys_fremovexattr
-
-ENTRY(sys32_sched_setaffinity_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgfr   %r3,%r3                 # unsigned int
-       llgtr   %r4,%r4                 # unsigned long *
-       jg      compat_sys_sched_setaffinity
-
-ENTRY(sys32_sched_getaffinity_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgfr   %r3,%r3                 # unsigned int
-       llgtr   %r4,%r4                 # unsigned long *
-       jg      compat_sys_sched_getaffinity
-
-ENTRY(sys32_exit_group_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_exit_group          # branch to system call
-
-ENTRY(sys32_set_tid_address_wrapper)
-       llgtr   %r2,%r2                 # int *
-       jg      sys_set_tid_address     # branch to system call
-
-ENTRY(sys_epoll_create_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_epoll_create        # branch to system call
-
-ENTRY(sys_epoll_ctl_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       lgfr    %r4,%r4                 # int
-       llgtr   %r5,%r5                 # struct epoll_event *
-       jg      sys_epoll_ctl           # branch to system call
-
-ENTRY(sys_epoll_wait_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # struct epoll_event *
-       lgfr    %r4,%r4                 # int
-       lgfr    %r5,%r5                 # int
-       jg      sys_epoll_wait          # branch to system call
-
-ENTRY(sys32_fadvise64_wrapper)
-       lgfr    %r2,%r2                 # int
-       sllg    %r3,%r3,32              # get high word of 64bit loff_t
-       or      %r3,%r4                 # get low word of 64bit loff_t
-       llgfr   %r4,%r5                 # size_t (unsigned long)
-       lgfr    %r5,%r6                 # int
-       jg      sys32_fadvise64
-
-ENTRY(sys32_fadvise64_64_wrapper)
-       llgtr   %r2,%r2                 # struct fadvise64_64_args *
-       jg      sys32_fadvise64_64
-
-ENTRY(sys32_clock_settime_wrapper)
-       lgfr    %r2,%r2                 # clockid_t (int)
-       llgtr   %r3,%r3                 # struct compat_timespec *
-       jg      compat_sys_clock_settime
-
-ENTRY(sys32_clock_gettime_wrapper)
-       lgfr    %r2,%r2                 # clockid_t (int)
-       llgtr   %r3,%r3                 # struct compat_timespec *
-       jg      compat_sys_clock_gettime
-
-ENTRY(sys32_clock_getres_wrapper)
-       lgfr    %r2,%r2                 # clockid_t (int)
-       llgtr   %r3,%r3                 # struct compat_timespec *
-       jg      compat_sys_clock_getres
-
-ENTRY(sys32_clock_nanosleep_wrapper)
-       lgfr    %r2,%r2                 # clockid_t (int)
-       lgfr    %r3,%r3                 # int
-       llgtr   %r4,%r4                 # struct compat_timespec *
-       llgtr   %r5,%r5                 # struct compat_timespec *
-       jg      compat_sys_clock_nanosleep
-
-ENTRY(sys32_timer_create_wrapper)
-       lgfr    %r2,%r2                 # timer_t (int)
-       llgtr   %r3,%r3                 # struct compat_sigevent *
-       llgtr   %r4,%r4                 # timer_t *
-       jg      compat_sys_timer_create
-
-ENTRY(sys32_timer_settime_wrapper)
-       lgfr    %r2,%r2                 # timer_t (int)
-       lgfr    %r3,%r3                 # int
-       llgtr   %r4,%r4                 # struct compat_itimerspec *
-       llgtr   %r5,%r5                 # struct compat_itimerspec *
-       jg      compat_sys_timer_settime
-
-ENTRY(sys32_timer_gettime_wrapper)
-       lgfr    %r2,%r2                 # timer_t (int)
-       llgtr   %r3,%r3                 # struct compat_itimerspec *
-       jg      compat_sys_timer_gettime
-
-ENTRY(sys32_timer_getoverrun_wrapper)
-       lgfr    %r2,%r2                 # timer_t (int)
-       jg      sys_timer_getoverrun
-
-ENTRY(sys32_timer_delete_wrapper)
-       lgfr    %r2,%r2                 # timer_t (int)
-       jg      sys_timer_delete
-
-ENTRY(sys32_io_setup_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # u32 *
-       jg      compat_sys_io_setup
-
-ENTRY(sys32_io_destroy_wrapper)
-       llgfr   %r2,%r2                 # (aio_context_t) u32
-       jg      sys_io_destroy
-
-ENTRY(sys32_io_getevents_wrapper)
-       llgfr   %r2,%r2                 # (aio_context_t) u32
-       lgfr    %r3,%r3                 # long
-       lgfr    %r4,%r4                 # long
-       llgtr   %r5,%r5                 # struct io_event *
-       llgtr   %r6,%r6                 # struct compat_timespec *
-       jg      compat_sys_io_getevents
-
-ENTRY(sys32_io_submit_wrapper)
-       llgfr   %r2,%r2                 # (aio_context_t) u32
-       lgfr    %r3,%r3                 # long
-       llgtr   %r4,%r4                 # struct iocb **
-       jg      compat_sys_io_submit
-
-ENTRY(sys32_io_cancel_wrapper)
-       llgfr   %r2,%r2                 # (aio_context_t) u32
-       llgtr   %r3,%r3                 # struct iocb *
-       llgtr   %r4,%r4                 # struct io_event *
-       jg      sys_io_cancel
-
-ENTRY(compat_sys_statfs64_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgfr   %r3,%r3                 # compat_size_t
-       llgtr   %r4,%r4                 # struct compat_statfs64 *
-       jg      compat_sys_statfs64
-
-ENTRY(compat_sys_fstatfs64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int fd
-       llgfr   %r3,%r3                 # compat_size_t
-       llgtr   %r4,%r4                 # struct compat_statfs64 *
-       jg      compat_sys_fstatfs64
-
-ENTRY(compat_sys_mq_open_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       llgfr   %r4,%r4                 # mode_t
-       llgtr   %r5,%r5                 # struct compat_mq_attr *
-       jg      compat_sys_mq_open
-
-ENTRY(sys32_mq_unlink_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       jg      sys_mq_unlink
-
-ENTRY(compat_sys_mq_timedsend_wrapper)
-       lgfr    %r2,%r2                 # mqd_t
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # size_t
-       llgfr   %r5,%r5                 # unsigned int
-       llgtr   %r6,%r6                 # const struct compat_timespec *
-       jg      compat_sys_mq_timedsend
-
-ENTRY(compat_sys_mq_timedreceive_wrapper)
-       lgfr    %r2,%r2                 # mqd_t
-       llgtr   %r3,%r3                 # char *
-       llgfr   %r4,%r4                 # size_t
-       llgtr   %r5,%r5                 # unsigned int *
-       llgtr   %r6,%r6                 # const struct compat_timespec *
-       jg      compat_sys_mq_timedreceive
-
-ENTRY(compat_sys_mq_notify_wrapper)
-       lgfr    %r2,%r2                 # mqd_t
-       llgtr   %r3,%r3                 # struct compat_sigevent *
-       jg      compat_sys_mq_notify
-
-ENTRY(compat_sys_mq_getsetattr_wrapper)
-       lgfr    %r2,%r2                 # mqd_t
-       llgtr   %r3,%r3                 # struct compat_mq_attr *
-       llgtr   %r4,%r4                 # struct compat_mq_attr *
-       jg      compat_sys_mq_getsetattr
-
-ENTRY(compat_sys_add_key_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # const char *
-       llgtr   %r4,%r4                 # const void *
-       llgfr   %r5,%r5                 # size_t
-       llgfr   %r6,%r6                 # (key_serial_t) u32
-       jg      sys_add_key
-
-ENTRY(compat_sys_request_key_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       llgtr   %r3,%r3                 # const char *
-       llgtr   %r4,%r4                 # const void *
-       llgfr   %r5,%r5                 # (key_serial_t) u32
-       jg      sys_request_key
-
-ENTRY(sys32_remap_file_pages_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # unsigned long
-       llgfr   %r4,%r4                 # unsigned long
-       llgfr   %r5,%r5                 # unsigned long
-       llgfr   %r6,%r6                 # unsigned long
-       jg      sys_remap_file_pages
-
-ENTRY(compat_sys_kexec_load_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # unsigned long
-       llgtr   %r4,%r4                 # struct kexec_segment *
-       llgfr   %r5,%r5                 # unsigned long
-       jg      compat_sys_kexec_load
-
-ENTRY(sys_ioprio_set_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       lgfr    %r4,%r4                 # int
-       jg      sys_ioprio_set
-
-ENTRY(sys_ioprio_get_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       jg      sys_ioprio_get
-
-ENTRY(sys_inotify_add_watch_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # u32
-       jg      sys_inotify_add_watch
-
-ENTRY(sys_inotify_rm_watch_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgfr   %r3,%r3                 # u32
-       jg      sys_inotify_rm_watch
-
-ENTRY(sys_mkdirat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       lgfr    %r4,%r4                 # int
-       jg      sys_mkdirat
-
-ENTRY(sys_mknodat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       lgfr    %r4,%r4                 # int
-       llgfr   %r5,%r5                 # unsigned int
-       jg      sys_mknodat
-
-ENTRY(sys_fchownat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # uid_t
-       llgfr   %r5,%r5                 # gid_t
-       lgfr    %r6,%r6                 # int
-       jg      sys_fchownat
-
-ENTRY(compat_sys_futimesat_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # struct timeval *
-       jg      compat_sys_futimesat
-
-ENTRY(sys32_fstatat64_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # struct stat64 *
-       lgfr    %r5,%r5                 # int
-       jg      sys32_fstatat64
-
-ENTRY(sys_unlinkat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       lgfr    %r4,%r4                 # int
-       jg      sys_unlinkat
-
-ENTRY(sys_renameat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       lgfr    %r4,%r4                 # int
-       llgtr   %r5,%r5                 # const char *
-       jg      sys_renameat
-
-ENTRY(sys_linkat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       lgfr    %r4,%r4                 # int
-       llgtr   %r5,%r5                 # const char *
-       lgfr    %r6,%r6                 # int
-       jg      sys_linkat
-
-ENTRY(sys_symlinkat_wrapper)
-       llgtr   %r2,%r2                 # const char *
-       lgfr    %r3,%r3                 # int
-       llgtr   %r4,%r4                 # const char *
-       jg      sys_symlinkat
-
-ENTRY(sys_readlinkat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       llgtr   %r4,%r4                 # char *
-       lgfr    %r5,%r5                 # int
-       jg      sys_readlinkat
-
-ENTRY(sys_fchmodat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       llgfr   %r4,%r4                 # mode_t
-       jg      sys_fchmodat
-
-ENTRY(sys_faccessat_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char *
-       lgfr    %r4,%r4                 # int
-       jg      sys_faccessat
-
-ENTRY(compat_sys_pselect6_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # fd_set *
-       llgtr   %r4,%r4                 # fd_set *
-       llgtr   %r5,%r5                 # fd_set *
-       llgtr   %r6,%r6                 # struct timespec *
-       llgt    %r0,164(%r15)           # void *
-       stg     %r0,160(%r15)
-       jg      compat_sys_pselect6
-
-ENTRY(compat_sys_ppoll_wrapper)
-       llgtr   %r2,%r2                 # struct pollfd *
-       llgfr   %r3,%r3                 # unsigned int
-       llgtr   %r4,%r4                 # struct timespec *
-       llgtr   %r5,%r5                 # const sigset_t *
-       llgfr   %r6,%r6                 # size_t
-       jg      compat_sys_ppoll
-
-ENTRY(sys_unshare_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       jg      sys_unshare
-
-ENTRY(sys_splice_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # loff_t *
-       lgfr    %r4,%r4                 # int
-       llgtr   %r5,%r5                 # loff_t *
-       llgfr   %r6,%r6                 # size_t
-       llgf    %r0,164(%r15)           # unsigned int
-       stg     %r0,160(%r15)
-       jg      sys_splice
-
-ENTRY(sys_sync_file_range_wrapper)
-       lgfr    %r2,%r2                 # int
-       sllg    %r3,%r3,32              # get high word of 64bit loff_t
-       or      %r3,%r4                 # get low word of 64bit loff_t
-       sllg    %r4,%r5,32              # get high word of 64bit loff_t
-       or      %r4,%r6                 # get low word of 64bit loff_t
-       llgf    %r5,164(%r15)           # unsigned int
-       jg      sys_sync_file_range
-
-ENTRY(sys_tee_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       llgfr   %r4,%r4                 # size_t
-       llgfr   %r5,%r5                 # unsigned int
-       jg      sys_tee
-
-ENTRY(sys_getcpu_wrapper)
-       llgtr   %r2,%r2                 # unsigned *
-       llgtr   %r3,%r3                 # unsigned *
-       llgtr   %r4,%r4                 # struct getcpu_cache *
-       jg      sys_getcpu
-
-ENTRY(compat_sys_utimes_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # struct compat_timeval *
-       jg      compat_sys_utimes
-
-ENTRY(compat_sys_utimensat_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgtr   %r3,%r3                 # char *
-       llgtr   %r4,%r4                 # struct compat_timespec *
-       lgfr    %r5,%r5                 # int
-       jg      compat_sys_utimensat
-
-ENTRY(sys_eventfd_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       jg      sys_eventfd
-
-ENTRY(sys_fallocate_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       sllg    %r4,%r4,32              # get high word of 64bit loff_t
-       lr      %r4,%r5                 # get low word of 64bit loff_t
-       sllg    %r5,%r6,32              # get high word of 64bit loff_t
-       l       %r5,164(%r15)           # get low word of 64bit loff_t
-       jg      sys_fallocate
-
-ENTRY(sys_timerfd_create_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       jg      sys_timerfd_create
-
-ENTRY(sys_eventfd2_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       lgfr    %r3,%r3                 # int
-       jg      sys_eventfd2
-
-ENTRY(sys_inotify_init1_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_inotify_init1
-
-ENTRY(sys_pipe2_wrapper)
-       llgtr   %r2,%r2                 # u32 *
-       lgfr    %r3,%r3                 # int
-       jg      sys_pipe2               # branch to system call
-
-ENTRY(sys_dup3_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       lgfr    %r4,%r4                 # int
-       jg      sys_dup3                # branch to system call
-
-ENTRY(sys_epoll_create1_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_epoll_create1       # branch to system call
-
-ENTRY(sys32_readahead_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgfr   %r3,%r3                 # u32
-       llgfr   %r4,%r4                 # u32
-       lgfr    %r5,%r5                 # s32
-       jg      sys32_readahead         # branch to system call
-
-ENTRY(sys_tkill_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       lgfr    %r3,%r3                 # int
-       jg      sys_tkill               # branch to system call
-
-ENTRY(sys_tgkill_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       lgfr    %r3,%r3                 # pid_t
-       lgfr    %r4,%r4                 # int
-       jg      sys_tgkill              # branch to system call
-
-ENTRY(compat_sys_keyctl_wrapper)
-       llgfr   %r2,%r2                 # u32
-       llgfr   %r3,%r3                 # u32
-       llgfr   %r4,%r4                 # u32
-       llgfr   %r5,%r5                 # u32
-       llgfr   %r6,%r6                 # u32
-       jg      compat_sys_keyctl       # branch to system call
-
-ENTRY(sys_perf_event_open_wrapper)
-       llgtr   %r2,%r2                 # const struct perf_event_attr *
-       lgfr    %r3,%r3                 # pid_t
-       lgfr    %r4,%r4                 # int
-       lgfr    %r5,%r5                 # int
-       llgfr   %r6,%r6                 # unsigned long
-       jg      sys_perf_event_open     # branch to system call
-
-ENTRY(sys_clone_wrapper)
-       llgfr   %r2,%r2                 # unsigned long
-       llgfr   %r3,%r3                 # unsigned long
-       llgtr   %r4,%r4                 # int *
-       llgtr   %r5,%r5                 # int *
-       jg      sys_clone               # branch to system call
-
-ENTRY(sys32_execve_wrapper)
-       llgtr   %r2,%r2                 # char *
-       llgtr   %r3,%r3                 # compat_uptr_t *
-       llgtr   %r4,%r4                 # compat_uptr_t *
-       jg      compat_sys_execve       # branch to system call
-
-ENTRY(sys_fanotify_init_wrapper)
-       llgfr   %r2,%r2                 # unsigned int
-       llgfr   %r3,%r3                 # unsigned int
-       jg      sys_fanotify_init       # branch to system call
-
-ENTRY(sys_prlimit64_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       llgfr   %r3,%r3                 # unsigned int
-       llgtr   %r4,%r4                 # const struct rlimit64 __user *
-       llgtr   %r5,%r5                 # struct rlimit64 __user *
-       jg      sys_prlimit64           # branch to system call
-
-ENTRY(sys_name_to_handle_at_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char __user *
-       llgtr   %r4,%r4                 # struct file_handle __user *
-       llgtr   %r5,%r5                 # int __user *
-       lgfr    %r6,%r6                 # int
-       jg      sys_name_to_handle_at
-
-ENTRY(compat_sys_clock_adjtime_wrapper)
-       lgfr    %r2,%r2                 # clockid_t (int)
-       llgtr   %r3,%r3                 # struct compat_timex __user *
-       jg      compat_sys_clock_adjtime
-
-ENTRY(sys_syncfs_wrapper)
-       lgfr    %r2,%r2                 # int
-       jg      sys_syncfs
-
-ENTRY(sys_setns_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       jg      sys_setns
-
-ENTRY(compat_sys_process_vm_readv_wrapper)
-       lgfr    %r2,%r2                 # compat_pid_t
-       llgtr   %r3,%r3                 # struct compat_iovec __user *
-       llgfr   %r4,%r4                 # unsigned long
-       llgtr   %r5,%r5                 # struct compat_iovec __user *
-       llgfr   %r6,%r6                 # unsigned long
-       llgf    %r0,164(%r15)           # unsigned long
-       stg     %r0,160(%r15)
-       jg      compat_sys_process_vm_readv
-
-ENTRY(compat_sys_process_vm_writev_wrapper)
-       lgfr    %r2,%r2                 # compat_pid_t
-       llgtr   %r3,%r3                 # struct compat_iovec __user *
-       llgfr   %r4,%r4                 # unsigned long
-       llgtr   %r5,%r5                 # struct compat_iovec __user *
-       llgfr   %r6,%r6                 # unsigned long
-       llgf    %r0,164(%r15)           # unsigned long
-       stg     %r0,160(%r15)
-       jg      compat_sys_process_vm_writev
-
-ENTRY(sys_s390_runtime_instr_wrapper)
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       jg      sys_s390_runtime_instr
-
-ENTRY(sys_kcmp_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       lgfr    %r3,%r3                 # pid_t
-       lgfr    %r4,%r4                 # int
-       llgfr   %r5,%r5                 # unsigned long
-       llgfr   %r6,%r6                 # unsigned long
-       jg      sys_kcmp
-
-ENTRY(sys_finit_module_wrapper)
-       lgfr    %r2,%r2                 # int
-       llgtr   %r3,%r3                 # const char __user *
-       lgfr    %r4,%r4                 # int
-       jg      sys_finit_module
-
-ENTRY(sys_sched_setattr_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       llgtr   %r3,%r3                 # struct sched_attr __user *
-       jg      sys_sched_setattr
-
-ENTRY(sys_sched_getattr_wrapper)
-       lgfr    %r2,%r2                 # pid_t
-       llgtr   %r3,%r3                 # const char __user *
-       llgfr   %r4,%r4                 # unsigned int
-       jg      sys_sched_getattr
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
new file mode 100644 (file)
index 0000000..824c39d
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *  Compat sytem call wrappers.
+ *
+ *    Copyright IBM Corp. 2014
+ */
+
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+#include "entry.h"
+
+#define COMPAT_SYSCALL_WRAP1(name, ...) \
+       COMPAT_SYSCALL_WRAPx(1, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP2(name, ...) \
+       COMPAT_SYSCALL_WRAPx(2, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP3(name, ...) \
+       COMPAT_SYSCALL_WRAPx(3, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP4(name, ...) \
+       COMPAT_SYSCALL_WRAPx(4, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP5(name, ...) \
+       COMPAT_SYSCALL_WRAPx(5, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP6(name, ...) \
+       COMPAT_SYSCALL_WRAPx(6, _##name, __VA_ARGS__)
+
+#define __SC_COMPAT_TYPE(t, a) \
+       __typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a
+
+#define __SC_COMPAT_CAST(t, a)                                         \
+({                                                                     \
+       long __ReS = a;                                                 \
+                                                                       \
+       BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) &&              \
+                    !__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t));            \
+       if (__TYPE_IS_L(t))                                             \
+               __ReS = (s32)a;                                         \
+       if (__TYPE_IS_UL(t))                                            \
+               __ReS = (u32)a;                                         \
+       if (__TYPE_IS_PTR(t))                                           \
+               __ReS = a & 0x7fffffff;                                 \
+       (t)__ReS;                                                       \
+})
+
+/*
+ * The COMPAT_SYSCALL_WRAP macro generates system call wrappers to be used by
+ * compat tasks. These wrappers will only be used for system calls where only
+ * the system call arguments need sign or zero extension or zeroing of the upper
+ * 33 bits of pointers.
+ * Note: since the wrapper function will afterwards call a system call which
+ * again performs zero and sign extension for all system call arguments with
+ * a size of less than eight bytes, these compat wrappers only touch those
+ * system call arguments with a size of eight bytes ((unsigned) long and
+ * pointers). Zero and sign extension for e.g. int parameters will be done by
+ * the regular system call wrappers.
+ */
+#define COMPAT_SYSCALL_WRAPx(x, name, ...)                                     \
+       asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));              \
+       asmlinkage long compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__));\
+       asmlinkage long compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__)) \
+       {                                                                       \
+               return sys##name(__MAP(x,__SC_COMPAT_CAST,__VA_ARGS__));        \
+       }
+
+COMPAT_SYSCALL_WRAP1(exit, int, error_code);
+COMPAT_SYSCALL_WRAP1(close, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(creat, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP2(link, const char __user *, oldname, const char __user *, newname);
+COMPAT_SYSCALL_WRAP1(unlink, const char __user *, pathname);
+COMPAT_SYSCALL_WRAP1(chdir, const char __user *, filename);
+COMPAT_SYSCALL_WRAP3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev);
+COMPAT_SYSCALL_WRAP2(chmod, const char __user *, filename, umode_t, mode);
+COMPAT_SYSCALL_WRAP1(oldumount, char __user *, name);
+COMPAT_SYSCALL_WRAP1(alarm, unsigned int, seconds);
+COMPAT_SYSCALL_WRAP2(access, const char __user *, filename, int, mode);
+COMPAT_SYSCALL_WRAP1(nice, int, increment);
+COMPAT_SYSCALL_WRAP2(kill, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP2(rename, const char __user *, oldname, const char __user *, newname);
+COMPAT_SYSCALL_WRAP2(mkdir, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP1(rmdir, const char __user *, pathname);
+COMPAT_SYSCALL_WRAP1(dup, unsigned int, fildes);
+COMPAT_SYSCALL_WRAP1(pipe, int __user *, fildes);
+COMPAT_SYSCALL_WRAP1(brk, unsigned long, brk);
+COMPAT_SYSCALL_WRAP2(signal, int, sig, __sighandler_t, handler);
+COMPAT_SYSCALL_WRAP1(acct, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(umount, char __user *, name, int, flags);
+COMPAT_SYSCALL_WRAP2(setpgid, pid_t, pid, pid_t, pgid);
+COMPAT_SYSCALL_WRAP1(umask, int, mask);
+COMPAT_SYSCALL_WRAP1(chroot, const char __user *, filename);
+COMPAT_SYSCALL_WRAP2(dup2, unsigned int, oldfd, unsigned int, newfd);
+COMPAT_SYSCALL_WRAP3(sigsuspend, int, unused1, int, unused2, old_sigset_t, mask);
+COMPAT_SYSCALL_WRAP2(sethostname, char __user *, name, int, len);
+COMPAT_SYSCALL_WRAP2(symlink, const char __user *, old, const char __user *, new);
+COMPAT_SYSCALL_WRAP3(readlink, const char __user *, path, char __user *, buf, int, bufsiz);
+COMPAT_SYSCALL_WRAP1(uselib, const char __user *, library);
+COMPAT_SYSCALL_WRAP2(swapon, const char __user *, specialfile, int, swap_flags);
+COMPAT_SYSCALL_WRAP4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg);
+COMPAT_SYSCALL_WRAP2(munmap, unsigned long, addr, size_t, len);
+COMPAT_SYSCALL_WRAP2(fchmod, unsigned int, fd, umode_t, mode);
+COMPAT_SYSCALL_WRAP2(getpriority, int, which, int, who);
+COMPAT_SYSCALL_WRAP3(setpriority, int, which, int, who, int, niceval);
+COMPAT_SYSCALL_WRAP3(syslog, int, type, char __user *, buf, int, len);
+COMPAT_SYSCALL_WRAP1(swapoff, const char __user *, specialfile);
+COMPAT_SYSCALL_WRAP1(fsync, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(setdomainname, char __user *, name, int, len);
+COMPAT_SYSCALL_WRAP1(newuname, struct new_utsname __user *, name);
+COMPAT_SYSCALL_WRAP3(mprotect, unsigned long, start, size_t, len, unsigned long, prot);
+COMPAT_SYSCALL_WRAP3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs);
+COMPAT_SYSCALL_WRAP2(delete_module, const char __user *, name_user, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(quotactl, unsigned int, cmd, const char __user *, special, qid_t, id, void __user *, addr);
+COMPAT_SYSCALL_WRAP1(getpgid, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(fchdir, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(bdflush, int, func, long, data);
+COMPAT_SYSCALL_WRAP3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2);
+COMPAT_SYSCALL_WRAP1(s390_personality, unsigned int, personality);
+COMPAT_SYSCALL_WRAP5(llseek, unsigned int, fd, unsigned long, high, unsigned long, low, loff_t __user *, result, unsigned int, whence);
+COMPAT_SYSCALL_WRAP2(flock, unsigned int, fd, unsigned int, cmd);
+COMPAT_SYSCALL_WRAP3(msync, unsigned long, start, size_t, len, int, flags);
+COMPAT_SYSCALL_WRAP1(getsid, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(fdatasync, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(mlock, unsigned long, start, size_t, len);
+COMPAT_SYSCALL_WRAP2(munlock, unsigned long, start, size_t, len);
+COMPAT_SYSCALL_WRAP1(mlockall, int, flags);
+COMPAT_SYSCALL_WRAP2(sched_setparam, pid_t, pid, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP2(sched_getparam, pid_t, pid, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP1(sched_getscheduler, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(sched_get_priority_max, int, policy);
+COMPAT_SYSCALL_WRAP1(sched_get_priority_min, int, policy);
+COMPAT_SYSCALL_WRAP5(mremap, unsigned long, addr, unsigned long, old_len, unsigned long, new_len, unsigned long, flags, unsigned long, new_addr);
+COMPAT_SYSCALL_WRAP3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout);
+COMPAT_SYSCALL_WRAP5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5);
+COMPAT_SYSCALL_WRAP2(getcwd, char __user *, buf, unsigned long, size);
+COMPAT_SYSCALL_WRAP2(capget, cap_user_header_t, header, cap_user_data_t, dataptr);
+COMPAT_SYSCALL_WRAP2(capset, cap_user_header_t, header, const cap_user_data_t, data);
+COMPAT_SYSCALL_WRAP3(lchown, const char __user *, filename, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP2(setreuid, uid_t, ruid, uid_t, euid);
+COMPAT_SYSCALL_WRAP2(setregid, gid_t, rgid, gid_t, egid);
+COMPAT_SYSCALL_WRAP2(getgroups, int, gidsetsize, gid_t __user *, grouplist);
+COMPAT_SYSCALL_WRAP2(setgroups, int, gidsetsize, gid_t __user *, grouplist);
+COMPAT_SYSCALL_WRAP3(fchown, unsigned int, fd, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid);
+COMPAT_SYSCALL_WRAP3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid);
+COMPAT_SYSCALL_WRAP3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid);
+COMPAT_SYSCALL_WRAP3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid);
+COMPAT_SYSCALL_WRAP3(chown, const char __user *, filename, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP1(setuid, uid_t, uid);
+COMPAT_SYSCALL_WRAP1(setgid, gid_t, gid);
+COMPAT_SYSCALL_WRAP1(setfsuid, uid_t, uid);
+COMPAT_SYSCALL_WRAP1(setfsgid, gid_t, gid);
+COMPAT_SYSCALL_WRAP2(pivot_root, const char __user *, new_root, const char __user *, put_old);
+COMPAT_SYSCALL_WRAP3(mincore, unsigned long, start, size_t, len, unsigned char __user *, vec);
+COMPAT_SYSCALL_WRAP3(madvise, unsigned long, start, size_t, len, int, behavior);
+COMPAT_SYSCALL_WRAP5(setxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP5(lsetxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP5(fsetxattr, int, fd, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP3(getdents64, unsigned int, fd, struct linux_dirent64 __user *, dirent, unsigned int, count);
+COMPAT_SYSCALL_WRAP4(getxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP4(lgetxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP4(fgetxattr, int, fd, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP3(listxattr, const char __user *, path, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP3(llistxattr, const char __user *, path, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP3(flistxattr, int, fd, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP2(removexattr, const char __user *, path, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(lremovexattr, const char __user *, path, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(fremovexattr, int, fd, const char __user *, name);
+COMPAT_SYSCALL_WRAP1(exit_group, int, error_code);
+COMPAT_SYSCALL_WRAP1(set_tid_address, int __user *, tidptr);
+COMPAT_SYSCALL_WRAP1(epoll_create, int, size);
+COMPAT_SYSCALL_WRAP4(epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event __user *, event);
+COMPAT_SYSCALL_WRAP4(epoll_wait, int, epfd, struct epoll_event __user *, events, int, maxevents, int, timeout);
+COMPAT_SYSCALL_WRAP1(timer_getoverrun, timer_t, timer_id);
+COMPAT_SYSCALL_WRAP1(timer_delete, compat_timer_t, compat_timer_id);
+COMPAT_SYSCALL_WRAP1(io_destroy, aio_context_t, ctx);
+COMPAT_SYSCALL_WRAP3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, struct io_event __user *, result);
+COMPAT_SYSCALL_WRAP1(mq_unlink, const char __user *, name);
+COMPAT_SYSCALL_WRAP5(add_key, const char __user *, tp, const char __user *, dsc, const void __user *, pld, size_t, len, key_serial_t, id);
+COMPAT_SYSCALL_WRAP4(request_key, const char __user *, tp, const char __user *, dsc, const char __user *, info, key_serial_t, id);
+COMPAT_SYSCALL_WRAP5(remap_file_pages, unsigned long, start, unsigned long, size, unsigned long, prot, unsigned long, pgoff, unsigned long, flags);
+COMPAT_SYSCALL_WRAP3(ioprio_set, int, which, int, who, int, ioprio);
+COMPAT_SYSCALL_WRAP2(ioprio_get, int, which, int, who);
+COMPAT_SYSCALL_WRAP3(inotify_add_watch, int, fd, const char __user *, path, u32, mask);
+COMPAT_SYSCALL_WRAP2(inotify_rm_watch, int, fd, __s32, wd);
+COMPAT_SYSCALL_WRAP3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev);
+COMPAT_SYSCALL_WRAP5(fchownat, int, dfd, const char __user *, filename, uid_t, user, gid_t, group, int, flag);
+COMPAT_SYSCALL_WRAP3(unlinkat, int, dfd, const char __user *, pathname, int, flag);
+COMPAT_SYSCALL_WRAP4(renameat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname);
+COMPAT_SYSCALL_WRAP5(linkat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, int, flags);
+COMPAT_SYSCALL_WRAP3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname);
+COMPAT_SYSCALL_WRAP4(readlinkat, int, dfd, const char __user *, path, char __user *, buf, int, bufsiz);
+COMPAT_SYSCALL_WRAP3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode);
+COMPAT_SYSCALL_WRAP3(faccessat, int, dfd, const char __user *, filename, int, mode);
+COMPAT_SYSCALL_WRAP1(unshare, unsigned long, unshare_flags);
+COMPAT_SYSCALL_WRAP6(splice, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags);
+COMPAT_SYSCALL_WRAP3(getcpu, unsigned __user *, cpu, unsigned __user *, node, struct getcpu_cache __user *, cache);
+COMPAT_SYSCALL_WRAP1(eventfd, unsigned int, count);
+COMPAT_SYSCALL_WRAP2(timerfd_create, int, clockid, int, flags);
+COMPAT_SYSCALL_WRAP2(eventfd2, unsigned int, count, int, flags);
+COMPAT_SYSCALL_WRAP1(inotify_init1, int, flags);
+COMPAT_SYSCALL_WRAP2(pipe2, int __user *, fildes, int, flags);
+COMPAT_SYSCALL_WRAP3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags);
+COMPAT_SYSCALL_WRAP1(epoll_create1, int, flags);
+COMPAT_SYSCALL_WRAP2(tkill, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP3(tgkill, int, tgid, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags);
+COMPAT_SYSCALL_WRAP5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, int, tls_val);
+COMPAT_SYSCALL_WRAP2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags);
+COMPAT_SYSCALL_WRAP4(prlimit64, pid_t, pid, unsigned int, resource, const struct rlimit64 __user *, new_rlim, struct rlimit64 __user *, old_rlim);
+COMPAT_SYSCALL_WRAP5(name_to_handle_at, int, dfd, const char __user *, name, struct file_handle __user *, handle, int __user *, mnt_id, int, flag);
+COMPAT_SYSCALL_WRAP1(syncfs, int, fd);
+COMPAT_SYSCALL_WRAP2(setns, int, fd, int, nstype);
+COMPAT_SYSCALL_WRAP2(s390_runtime_instr, int, command, int, signum);
+COMPAT_SYSCALL_WRAP5(kcmp, pid_t, pid1, pid_t, pid2, int, type, unsigned long, idx1, unsigned long, idx2);
+COMPAT_SYSCALL_WRAP3(finit_module, int, fd, const char __user *, uargs, int, flags);
+COMPAT_SYSCALL_WRAP3(sched_setattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(sched_getattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, size, unsigned int, flags);
index fca20b5fe79e085e4795861edf7f4bb5736c67cb..6b594439cca5a68fa3fd8ece0484cc0f8b9d11bd 100644 (file)
@@ -380,8 +380,6 @@ static __init void detect_machine_facilities(void)
                S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2;
        if (test_facility(3))
                S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
-       if (test_facility(27))
-               S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
        if (test_facility(40))
                S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
        if (test_facility(50) && test_facility(73))
index 0dc2b6d0a1ec8557f7450d5fbd255d2758bf8512..526d3735ed29050d317ef1327039397a4594d71f 100644 (file)
@@ -43,6 +43,7 @@ _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_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
@@ -159,10 +160,12 @@ ENTRY(__switch_to)
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        mvc     __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
        l       %r15,__THREAD_ksp(%r3)          # load kernel stack of next
-       tm      __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+       lhi     %r6,_TIF_TRANSFER               # transfer TIF bits
+       n       %r6,__TI_flags(%r4)             # isolate TIF bits
        jz      0f
-       ni      __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
-       oi      __TI_flags+3(%r5),_TIF_MCCK_PENDING     # set it in next
+       o       %r6,__TI_flags(%r5)             # set TIF bits of next
+       st      %r6,__TI_flags(%r5)
+       ni      __TI_flags+3(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
 0:     lm      %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        br      %r14
 
index cb533f78c09ed5795ee365eec00374c5db662a9c..6ac78192455f386aa72a15bdd2b73c55f844a5b5 100644 (file)
@@ -67,9 +67,7 @@ struct s390_mmap_arg_struct;
 struct fadvise64_64_args;
 struct old_sigaction;
 
-long sys_sigreturn(void);
-long sys_rt_sigreturn(void);
-long sys32_sigreturn(void);
-long sys32_rt_sigreturn(void);
+long sys_s390_personality(unsigned int personality);
+long sys_s390_runtime_instr(int command, int signum);
 
 #endif /* _ENTRY_H */
index 384e609b47110dc59c7a96cfa419e864cca86b2a..e09dbe5f29015a9fc794cddb2f7ff57053594cdc 100644 (file)
@@ -48,6 +48,7 @@ _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_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
 
 #define BASED(name) name-system_call(%r13)
 
@@ -189,10 +190,12 @@ ENTRY(__switch_to)
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        mvc     __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
        lg      %r15,__THREAD_ksp(%r3)          # load kernel stack of next
-       tm      __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+       llill   %r6,_TIF_TRANSFER               # transfer TIF bits
+       ng      %r6,__TI_flags(%r4)             # isolate TIF bits
        jz      0f
-       ni      __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
-       oi      __TI_flags+7(%r5),_TIF_MCCK_PENDING     # set it in next
+       og      %r6,__TI_flags(%r5)             # set TIF bits of next
+       stg     %r6,__TI_flags(%r5)
+       ni      __TI_flags+7(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
 0:     lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        br      %r14
 
index bb27a262c44aa8076dfe7eb9cb5a243d8c315079..a770be97db4da7c513e7952d0360c85a5d5154bb 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
+#include <linux/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/cputime.h>
 #include <asm/lowcore.h>
index 5d2dfa31c4efad44028d41b60b6d43631ecaedc6..61595c1f0a0fe7d502bb6c213519929effe48b02 100644 (file)
@@ -121,7 +121,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
                               : PERF_RECORD_MISC_KERNEL;
 }
 
-void print_debug_cf(void)
+static void print_debug_cf(void)
 {
        struct cpumf_ctr_info cf_info;
        int cpu = smp_processor_id();
index f6be6087a0e98edb3d2917228cb65b4657b61d11..4ac8fafec95fa87d0b680c6222ac3c9e9f06700a 100644 (file)
@@ -85,7 +85,10 @@ void update_cr_regs(struct task_struct *task)
 
        /* merge TIF_SINGLE_STEP into user specified PER registers. */
        if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
-               new.control |= PER_EVENT_IFETCH;
+               if (test_tsk_thread_flag(task, TIF_BLOCK_STEP))
+                       new.control |= PER_EVENT_BRANCH;
+               else
+                       new.control |= PER_EVENT_IFETCH;
 #ifdef CONFIG_64BIT
                new.control |= PER_CONTROL_SUSPENSION;
                new.control |= PER_EVENT_TRANSACTION_END;
@@ -107,14 +110,22 @@ void update_cr_regs(struct task_struct *task)
 
 void user_enable_single_step(struct task_struct *task)
 {
+       clear_tsk_thread_flag(task, TIF_BLOCK_STEP);
        set_tsk_thread_flag(task, TIF_SINGLE_STEP);
 }
 
 void user_disable_single_step(struct task_struct *task)
 {
+       clear_tsk_thread_flag(task, TIF_BLOCK_STEP);
        clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
 }
 
+void user_enable_block_step(struct task_struct *task)
+{
+       set_tsk_thread_flag(task, TIF_SINGLE_STEP);
+       set_tsk_thread_flag(task, TIF_BLOCK_STEP);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
index 09e2f468f48bc874e61c3d12b9d751b04c5f0126..f70f2489fa5fe241fd107596d2879d0fe331f7bc 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/compat.h>
 
 #include <asm/ipl.h>
-#include <asm/uaccess.h>
 #include <asm/facility.h>
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
 #include <asm/sclp.h>
 #include "entry.h"
 
-/*
- * User copy operations.
- */
-struct uaccess_ops uaccess;
-EXPORT_SYMBOL(uaccess);
-
 /*
  * Machine setup..
  */
@@ -294,14 +287,6 @@ static int __init parse_vmalloc(char *arg)
 }
 early_param("vmalloc", parse_vmalloc);
 
-static int __init early_parse_user_mode(char *p)
-{
-       if (!p || strcmp(p, "primary") == 0)
-               return 0;
-       return 1;
-}
-early_param("user_mode", early_parse_user_mode);
-
 void *restart_stack __attribute__((__section__(".data")));
 
 static void __init setup_lowcore(void)
@@ -1009,8 +994,6 @@ void __init setup_arch(char **cmdline_p)
        init_mm.end_data = (unsigned long) &_edata;
        init_mm.brk = (unsigned long) &_end;
 
-       uaccess = MACHINE_HAS_MVCOS ? uaccess_mvcos : uaccess_pt;
-
        parse_early_param();
        detect_memory_layout(memory_chunk, memory_end);
        os_info_init();
index a7125b62a9a6c1f77289a0d834358fea1971cb87..8827883310ddbc05c765f17b2125e804dc2cd85e 100644 (file)
@@ -773,11 +773,11 @@ void __noreturn cpu_die(void)
 
 void __init smp_fill_possible_mask(void)
 {
-       unsigned int possible, cpu;
+       unsigned int possible, sclp, cpu;
 
-       possible = setup_possible_cpus;
-       if (!possible)
-               possible = MACHINE_IS_VM ? 64 : nr_cpu_ids;
+       sclp = sclp_get_max_cpu() ?: nr_cpu_ids;
+       possible = setup_possible_cpus ?: nr_cpu_ids;
+       possible = min(possible, sclp);
        for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
                set_cpu_possible(cpu, true);
 }
index 143992152ec95d7c2b96c1978d1bae78da480efb..542ef488bac176fb0b3a1efed9e34e2e2af0c730 100644 (file)
 #define NI_SYSCALL SYSCALL(sys_ni_syscall,sys_ni_syscall,sys_ni_syscall)
 
 NI_SYSCALL                                                     /* 0 */
-SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
+SYSCALL(sys_exit,sys_exit,compat_sys_exit)
 SYSCALL(sys_fork,sys_fork,sys_fork)
-SYSCALL(sys_read,sys_read,sys32_read_wrapper)
-SYSCALL(sys_write,sys_write,sys32_write_wrapper)
+SYSCALL(sys_read,sys_read,compat_sys_s390_read)
+SYSCALL(sys_write,sys_write,compat_sys_s390_write)
 SYSCALL(sys_open,sys_open,compat_sys_open)                     /* 5 */
-SYSCALL(sys_close,sys_close,sys32_close_wrapper)
+SYSCALL(sys_close,sys_close,compat_sys_close)
 SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall)
-SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
-SYSCALL(sys_link,sys_link,sys32_link_wrapper)
-SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper)            /* 10 */
-SYSCALL(sys_execve,sys_execve,sys32_execve_wrapper)
-SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper)
-SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper)            /* old time syscall */
-SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
-SYSCALL(sys_chmod,sys_chmod,sys32_chmod_wrapper)               /* 15 */
-SYSCALL(sys_lchown16,sys_ni_syscall,sys32_lchown16_wrapper)    /* old lchown16 syscall*/
+SYSCALL(sys_creat,sys_creat,compat_sys_creat)
+SYSCALL(sys_link,sys_link,compat_sys_link)
+SYSCALL(sys_unlink,sys_unlink,compat_sys_unlink)               /* 10 */
+SYSCALL(sys_execve,sys_execve,compat_sys_execve)
+SYSCALL(sys_chdir,sys_chdir,compat_sys_chdir)
+SYSCALL(sys_time,sys_ni_syscall,compat_sys_time)               /* old time syscall */
+SYSCALL(sys_mknod,sys_mknod,compat_sys_mknod)
+SYSCALL(sys_chmod,sys_chmod,compat_sys_chmod)                  /* 15 */
+SYSCALL(sys_lchown16,sys_ni_syscall,compat_sys_s390_lchown16)  /* old lchown16 syscall*/
 NI_SYSCALL                                                     /* old break syscall holder */
 NI_SYSCALL                                                     /* old stat syscall holder */
 SYSCALL(sys_lseek,sys_lseek,compat_sys_lseek)
 SYSCALL(sys_getpid,sys_getpid,sys_getpid)                      /* 20 */
-SYSCALL(sys_mount,sys_mount,sys32_mount_wrapper)
-SYSCALL(sys_oldumount,sys_oldumount,sys32_oldumount_wrapper)
-SYSCALL(sys_setuid16,sys_ni_syscall,sys32_setuid16_wrapper)    /* old setuid16 syscall*/
-SYSCALL(sys_getuid16,sys_ni_syscall,sys32_getuid16)            /* old getuid16 syscall*/
-SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper)          /* 25 old stime syscall */
-SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
-SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
+SYSCALL(sys_mount,sys_mount,compat_sys_mount)
+SYSCALL(sys_oldumount,sys_oldumount,compat_sys_oldumount)
+SYSCALL(sys_setuid16,sys_ni_syscall,compat_sys_s390_setuid16)  /* old setuid16 syscall*/
+SYSCALL(sys_getuid16,sys_ni_syscall,compat_sys_s390_getuid16)  /* old getuid16 syscall*/
+SYSCALL(sys_stime,sys_ni_syscall,compat_sys_stime)             /* 25 old stime syscall */
+SYSCALL(sys_ptrace,sys_ptrace,compat_sys_ptrace)
+SYSCALL(sys_alarm,sys_alarm,compat_sys_alarm)
 NI_SYSCALL                                                     /* old fstat syscall */
 SYSCALL(sys_pause,sys_pause,sys_pause)
-SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper)          /* 30 */
+SYSCALL(sys_utime,sys_utime,compat_sys_utime)          /* 30 */
 NI_SYSCALL                                                     /* old stty syscall */
 NI_SYSCALL                                                     /* old gtty syscall */
-SYSCALL(sys_access,sys_access,sys32_access_wrapper)
-SYSCALL(sys_nice,sys_nice,sys32_nice_wrapper)
+SYSCALL(sys_access,sys_access,compat_sys_access)
+SYSCALL(sys_nice,sys_nice,compat_sys_nice)
 NI_SYSCALL                                                     /* 35 old ftime syscall */
 SYSCALL(sys_sync,sys_sync,sys_sync)
-SYSCALL(sys_kill,sys_kill,sys32_kill_wrapper)
-SYSCALL(sys_rename,sys_rename,sys32_rename_wrapper)
-SYSCALL(sys_mkdir,sys_mkdir,sys32_mkdir_wrapper)
-SYSCALL(sys_rmdir,sys_rmdir,sys32_rmdir_wrapper)               /* 40 */
-SYSCALL(sys_dup,sys_dup,sys32_dup_wrapper)
-SYSCALL(sys_pipe,sys_pipe,sys32_pipe_wrapper)
-SYSCALL(sys_times,sys_times,compat_sys_times_wrapper)
+SYSCALL(sys_kill,sys_kill,compat_sys_kill)
+SYSCALL(sys_rename,sys_rename,compat_sys_rename)
+SYSCALL(sys_mkdir,sys_mkdir,compat_sys_mkdir)
+SYSCALL(sys_rmdir,sys_rmdir,compat_sys_rmdir)          /* 40 */
+SYSCALL(sys_dup,sys_dup,compat_sys_dup)
+SYSCALL(sys_pipe,sys_pipe,compat_sys_pipe)
+SYSCALL(sys_times,sys_times,compat_sys_times)
 NI_SYSCALL                                                     /* old prof syscall */
-SYSCALL(sys_brk,sys_brk,sys32_brk_wrapper)                     /* 45 */
-SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16_wrapper)    /* old setgid16 syscall*/
-SYSCALL(sys_getgid16,sys_ni_syscall,sys32_getgid16)            /* old getgid16 syscall*/
-SYSCALL(sys_signal,sys_signal,sys32_signal_wrapper)
-SYSCALL(sys_geteuid16,sys_ni_syscall,sys32_geteuid16)          /* old geteuid16 syscall */
-SYSCALL(sys_getegid16,sys_ni_syscall,sys32_getegid16)          /* 50 old getegid16 syscall */
-SYSCALL(sys_acct,sys_acct,sys32_acct_wrapper)
-SYSCALL(sys_umount,sys_umount,sys32_umount_wrapper)
+SYSCALL(sys_brk,sys_brk,compat_sys_brk)                                /* 45 */
+SYSCALL(sys_setgid16,sys_ni_syscall,compat_sys_s390_setgid16)  /* old setgid16 syscall*/
+SYSCALL(sys_getgid16,sys_ni_syscall,compat_sys_s390_getgid16)  /* old getgid16 syscall*/
+SYSCALL(sys_signal,sys_signal,compat_sys_signal)
+SYSCALL(sys_geteuid16,sys_ni_syscall,compat_sys_s390_geteuid16)        /* old geteuid16 syscall */
+SYSCALL(sys_getegid16,sys_ni_syscall,compat_sys_s390_getegid16)        /* 50 old getegid16 syscall */
+SYSCALL(sys_acct,sys_acct,compat_sys_acct)
+SYSCALL(sys_umount,sys_umount,compat_sys_umount)
 NI_SYSCALL                                                     /* old lock syscall */
-SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl_wrapper)
-SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl_wrapper)          /* 55 */
+SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl)
+SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl)          /* 55 */
 NI_SYSCALL                                                     /* intel mpx syscall */
-SYSCALL(sys_setpgid,sys_setpgid,sys32_setpgid_wrapper)
+SYSCALL(sys_setpgid,sys_setpgid,compat_sys_setpgid)
 NI_SYSCALL                                                     /* old ulimit syscall */
 NI_SYSCALL                                                     /* old uname syscall */
-SYSCALL(sys_umask,sys_umask,sys32_umask_wrapper)               /* 60 */
-SYSCALL(sys_chroot,sys_chroot,sys32_chroot_wrapper)
-SYSCALL(sys_ustat,sys_ustat,sys32_ustat_wrapper)
-SYSCALL(sys_dup2,sys_dup2,sys32_dup2_wrapper)
+SYSCALL(sys_umask,sys_umask,compat_sys_umask)                  /* 60 */
+SYSCALL(sys_chroot,sys_chroot,compat_sys_chroot)
+SYSCALL(sys_ustat,sys_ustat,compat_sys_ustat)
+SYSCALL(sys_dup2,sys_dup2,compat_sys_dup2)
 SYSCALL(sys_getppid,sys_getppid,sys_getppid)
 SYSCALL(sys_getpgrp,sys_getpgrp,sys_getpgrp)                   /* 65 */
 SYSCALL(sys_setsid,sys_setsid,sys_setsid)
 SYSCALL(sys_sigaction,sys_sigaction,compat_sys_sigaction)
 NI_SYSCALL                                                     /* old sgetmask syscall*/
 NI_SYSCALL                                                     /* old ssetmask syscall*/
-SYSCALL(sys_setreuid16,sys_ni_syscall,sys32_setreuid16_wrapper)        /* old setreuid16 syscall */
-SYSCALL(sys_setregid16,sys_ni_syscall,sys32_setregid16_wrapper)        /* old setregid16 syscall */
-SYSCALL(sys_sigsuspend,sys_sigsuspend,sys_sigsuspend_wrapper)
-SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending_wrapper)
-SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
-SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper)      /* 75 */
-SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
+SYSCALL(sys_setreuid16,sys_ni_syscall,compat_sys_s390_setreuid16) /* old setreuid16 syscall */
+SYSCALL(sys_setregid16,sys_ni_syscall,compat_sys_s390_setregid16) /* old setregid16 syscall */
+SYSCALL(sys_sigsuspend,sys_sigsuspend,compat_sys_sigsuspend)
+SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending)
+SYSCALL(sys_sethostname,sys_sethostname,compat_sys_sethostname)
+SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit)      /* 75 */
+SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit)
 SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage)
-SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday_wrapper)
-SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday_wrapper)
-SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper)      /* 80 old getgroups16 syscall */
-SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper)      /* old setgroups16 syscall */
+SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday)
+SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday)
+SYSCALL(sys_getgroups16,sys_ni_syscall,compat_sys_s390_getgroups16)    /* 80 old getgroups16 syscall */
+SYSCALL(sys_setgroups16,sys_ni_syscall,compat_sys_s390_setgroups16)    /* old setgroups16 syscall */
 NI_SYSCALL                                                     /* old select syscall */
-SYSCALL(sys_symlink,sys_symlink,sys32_symlink_wrapper)
+SYSCALL(sys_symlink,sys_symlink,compat_sys_symlink)
 NI_SYSCALL                                                     /* old lstat syscall */
-SYSCALL(sys_readlink,sys_readlink,sys32_readlink_wrapper)      /* 85 */
-SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper)
-SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper)
-SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper)
-SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper)   /* old readdir syscall */
-SYSCALL(sys_old_mmap,sys_old_mmap,old32_mmap_wrapper)          /* 90 */
-SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper)
+SYSCALL(sys_readlink,sys_readlink,compat_sys_readlink)         /* 85 */
+SYSCALL(sys_uselib,sys_uselib,compat_sys_uselib)
+SYSCALL(sys_swapon,sys_swapon,compat_sys_swapon)
+SYSCALL(sys_reboot,sys_reboot,compat_sys_reboot)
+SYSCALL(sys_ni_syscall,sys_ni_syscall,compat_sys_old_readdir)  /* old readdir syscall */
+SYSCALL(sys_old_mmap,sys_old_mmap,compat_sys_s390_old_mmap)    /* 90 */
+SYSCALL(sys_munmap,sys_munmap,compat_sys_munmap)
 SYSCALL(sys_truncate,sys_truncate,compat_sys_truncate)
 SYSCALL(sys_ftruncate,sys_ftruncate,compat_sys_ftruncate)
-SYSCALL(sys_fchmod,sys_fchmod,sys32_fchmod_wrapper)
-SYSCALL(sys_fchown16,sys_ni_syscall,sys32_fchown16_wrapper)    /* 95 old fchown16 syscall*/
-SYSCALL(sys_getpriority,sys_getpriority,sys32_getpriority_wrapper)
-SYSCALL(sys_setpriority,sys_setpriority,sys32_setpriority_wrapper)
+SYSCALL(sys_fchmod,sys_fchmod,compat_sys_fchmod)
+SYSCALL(sys_fchown16,sys_ni_syscall,compat_sys_s390_fchown16)  /* 95 old fchown16 syscall*/
+SYSCALL(sys_getpriority,sys_getpriority,compat_sys_getpriority)
+SYSCALL(sys_setpriority,sys_setpriority,compat_sys_setpriority)
 NI_SYSCALL                                                     /* old profil syscall */
-SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper)
-SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper)    /* 100 */
+SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs)
+SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs)    /* 100 */
 NI_SYSCALL                                                     /* ioperm for i386 */
-SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
-SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
+SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall)
+SYSCALL(sys_syslog,sys_syslog,compat_sys_syslog)
 SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer)
 SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer)      /* 105 */
-SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
-SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
-SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
+SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat)
+SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat)
+SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat)
 NI_SYSCALL                                                     /* old uname syscall */
 SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,compat_sys_lookup_dcookie)       /* 110 */
 SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
 NI_SYSCALL                                                     /* old "idle" system call */
 NI_SYSCALL                                                     /* vm86old for i386 */
 SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4)
-SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper)         /* 115 */
-SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
+SYSCALL(sys_swapoff,sys_swapoff,compat_sys_swapoff)            /* 115 */
+SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo)
 SYSCALL(sys_s390_ipc,sys_s390_ipc,compat_sys_s390_ipc)
-SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
-SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
-SYSCALL(sys_clone,sys_clone,sys_clone_wrapper)                 /* 120 */
-SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
-SYSCALL(sys_newuname,sys_newuname,sys32_newuname_wrapper)
+SYSCALL(sys_fsync,sys_fsync,compat_sys_fsync)
+SYSCALL(sys_sigreturn,sys_sigreturn,compat_sys_sigreturn)
+SYSCALL(sys_clone,sys_clone,compat_sys_clone)                  /* 120 */
+SYSCALL(sys_setdomainname,sys_setdomainname,compat_sys_setdomainname)
+SYSCALL(sys_newuname,sys_newuname,compat_sys_newuname)
 NI_SYSCALL                                                     /* modify_ldt for i386 */
-SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
-SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper)      /* 125 */
+SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex)
+SYSCALL(sys_mprotect,sys_mprotect,compat_sys_mprotect)         /* 125 */
 SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask)
 NI_SYSCALL                                                     /* old "create module" */
-SYSCALL(sys_init_module,sys_init_module,sys_init_module_wrapper)
-SYSCALL(sys_delete_module,sys_delete_module,sys_delete_module_wrapper)
+SYSCALL(sys_init_module,sys_init_module,compat_sys_init_module)
+SYSCALL(sys_delete_module,sys_delete_module,compat_sys_delete_module)
 NI_SYSCALL                                                     /* 130: old get_kernel_syms */
-SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper)
-SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper)
-SYSCALL(sys_fchdir,sys_fchdir,sys32_fchdir_wrapper)
-SYSCALL(sys_bdflush,sys_bdflush,sys32_bdflush_wrapper)
-SYSCALL(sys_sysfs,sys_sysfs,sys32_sysfs_wrapper)               /* 135 */
-SYSCALL(sys_personality,sys_s390_personality,sys32_personality_wrapper)
+SYSCALL(sys_quotactl,sys_quotactl,compat_sys_quotactl)
+SYSCALL(sys_getpgid,sys_getpgid,compat_sys_getpgid)
+SYSCALL(sys_fchdir,sys_fchdir,compat_sys_fchdir)
+SYSCALL(sys_bdflush,sys_bdflush,compat_sys_bdflush)
+SYSCALL(sys_sysfs,sys_sysfs,compat_sys_sysfs)          /* 135 */
+SYSCALL(sys_personality,sys_s390_personality,compat_sys_s390_personality)
 NI_SYSCALL                                                     /* for afs_syscall */
-SYSCALL(sys_setfsuid16,sys_ni_syscall,sys32_setfsuid16_wrapper)        /* old setfsuid16 syscall */
-SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper)        /* old setfsgid16 syscall */
-SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper)            /* 140 */
-SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
-SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
-SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
-SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
-SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper)          /* 145 */
-SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
-SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
-SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
+SYSCALL(sys_setfsuid16,sys_ni_syscall,compat_sys_s390_setfsuid16)      /* old setfsuid16 syscall */
+SYSCALL(sys_setfsgid16,sys_ni_syscall,compat_sys_s390_setfsgid16)      /* old setfsgid16 syscall */
+SYSCALL(sys_llseek,sys_llseek,compat_sys_llseek)               /* 140 */
+SYSCALL(sys_getdents,sys_getdents,compat_sys_getdents)
+SYSCALL(sys_select,sys_select,compat_sys_select)
+SYSCALL(sys_flock,sys_flock,compat_sys_flock)
+SYSCALL(sys_msync,sys_msync,compat_sys_msync)
+SYSCALL(sys_readv,sys_readv,compat_sys_readv)          /* 145 */
+SYSCALL(sys_writev,sys_writev,compat_sys_writev)
+SYSCALL(sys_getsid,sys_getsid,compat_sys_getsid)
+SYSCALL(sys_fdatasync,sys_fdatasync,compat_sys_fdatasync)
 SYSCALL(sys_sysctl,sys_sysctl,compat_sys_sysctl)
-SYSCALL(sys_mlock,sys_mlock,sys32_mlock_wrapper)               /* 150 */
-SYSCALL(sys_munlock,sys_munlock,sys32_munlock_wrapper)
-SYSCALL(sys_mlockall,sys_mlockall,sys32_mlockall_wrapper)
+SYSCALL(sys_mlock,sys_mlock,compat_sys_mlock)                  /* 150 */
+SYSCALL(sys_munlock,sys_munlock,compat_sys_munlock)
+SYSCALL(sys_mlockall,sys_mlockall,compat_sys_mlockall)
 SYSCALL(sys_munlockall,sys_munlockall,sys_munlockall)
-SYSCALL(sys_sched_setparam,sys_sched_setparam,sys32_sched_setparam_wrapper)
-SYSCALL(sys_sched_getparam,sys_sched_getparam,sys32_sched_getparam_wrapper)    /* 155 */
-SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,sys32_sched_setscheduler_wrapper)
-SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,sys32_sched_getscheduler_wrapper)
+SYSCALL(sys_sched_setparam,sys_sched_setparam,compat_sys_sched_setparam)
+SYSCALL(sys_sched_getparam,sys_sched_getparam,compat_sys_sched_getparam)       /* 155 */
+SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,compat_sys_sched_setscheduler)
+SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,compat_sys_sched_getscheduler)
 SYSCALL(sys_sched_yield,sys_sched_yield,sys_sched_yield)
-SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
-SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper)    /* 160 */
+SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,compat_sys_sched_get_priority_max)
+SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,compat_sys_sched_get_priority_min)       /* 160 */
 SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,compat_sys_sched_rr_get_interval)
-SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep_wrapper)
-SYSCALL(sys_mremap,sys_mremap,sys32_mremap_wrapper)
-SYSCALL(sys_setresuid16,sys_ni_syscall,sys32_setresuid16_wrapper)      /* old setresuid16 syscall */
-SYSCALL(sys_getresuid16,sys_ni_syscall,sys32_getresuid16_wrapper)      /* 165 old getresuid16 syscall */
+SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep)
+SYSCALL(sys_mremap,sys_mremap,compat_sys_mremap)
+SYSCALL(sys_setresuid16,sys_ni_syscall,compat_sys_s390_setresuid16)    /* old setresuid16 syscall */
+SYSCALL(sys_getresuid16,sys_ni_syscall,compat_sys_s390_getresuid16)    /* 165 old getresuid16 syscall */
 NI_SYSCALL                                                     /* for vm86 */
 NI_SYSCALL                                                     /* old sys_query_module */
-SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
+SYSCALL(sys_poll,sys_poll,compat_sys_poll)
 NI_SYSCALL                                                     /* old nfsservctl */
-SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper)      /* 170 old setresgid16 syscall */
-SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper)      /* old getresgid16 syscall */
-SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
-SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn)
+SYSCALL(sys_setresgid16,sys_ni_syscall,compat_sys_s390_setresgid16)    /* 170 old setresgid16 syscall */
+SYSCALL(sys_getresgid16,sys_ni_syscall,compat_sys_s390_getresgid16)    /* old getresgid16 syscall */
+SYSCALL(sys_prctl,sys_prctl,compat_sys_prctl)
+SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,compat_sys_rt_sigreturn)
 SYSCALL(sys_rt_sigaction,sys_rt_sigaction,compat_sys_rt_sigaction)
 SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,compat_sys_rt_sigprocmask) /* 175 */
 SYSCALL(sys_rt_sigpending,sys_rt_sigpending,compat_sys_rt_sigpending)
 SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait)
 SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,compat_sys_rt_sigqueueinfo)
 SYSCALL(sys_rt_sigsuspend,sys_rt_sigsuspend,compat_sys_rt_sigsuspend)
-SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper)         /* 180 */
-SYSCALL(sys_pwrite64,sys_pwrite64,sys32_pwrite64_wrapper)
-SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper)      /* old chown16 syscall */
-SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
-SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
-SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper)            /* 185 */
+SYSCALL(sys_pread64,sys_pread64,compat_sys_s390_pread64)               /* 180 */
+SYSCALL(sys_pwrite64,sys_pwrite64,compat_sys_s390_pwrite64)
+SYSCALL(sys_chown16,sys_ni_syscall,compat_sys_s390_chown16)    /* old chown16 syscall */
+SYSCALL(sys_getcwd,sys_getcwd,compat_sys_getcwd)
+SYSCALL(sys_capget,sys_capget,compat_sys_capget)
+SYSCALL(sys_capset,sys_capset,compat_sys_capset)               /* 185 */
 SYSCALL(sys_sigaltstack,sys_sigaltstack,compat_sys_sigaltstack)
 SYSCALL(sys_sendfile,sys_sendfile64,compat_sys_sendfile)
 NI_SYSCALL                                                     /* streams1 */
 NI_SYSCALL                                                     /* streams2 */
 SYSCALL(sys_vfork,sys_vfork,sys_vfork)                         /* 190 */
-SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper)
-SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper)
-SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
-SYSCALL(sys_ftruncate64,sys_ni_syscall,sys32_ftruncate64_wrapper)
-SYSCALL(sys_stat64,sys_ni_syscall,sys32_stat64_wrapper)                /* 195 */
-SYSCALL(sys_lstat64,sys_ni_syscall,sys32_lstat64_wrapper)
-SYSCALL(sys_fstat64,sys_ni_syscall,sys32_fstat64_wrapper)
-SYSCALL(sys_lchown,sys_lchown,sys32_lchown_wrapper)
+SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit)
+SYSCALL(sys_mmap2,sys_mmap2,compat_sys_s390_mmap2)
+SYSCALL(sys_truncate64,sys_ni_syscall,compat_sys_s390_truncate64)
+SYSCALL(sys_ftruncate64,sys_ni_syscall,compat_sys_s390_ftruncate64)
+SYSCALL(sys_stat64,sys_ni_syscall,compat_sys_s390_stat64)              /* 195 */
+SYSCALL(sys_lstat64,sys_ni_syscall,compat_sys_s390_lstat64)
+SYSCALL(sys_fstat64,sys_ni_syscall,compat_sys_s390_fstat64)
+SYSCALL(sys_lchown,sys_lchown,compat_sys_lchown)
 SYSCALL(sys_getuid,sys_getuid,sys_getuid)
 SYSCALL(sys_getgid,sys_getgid,sys_getgid)                      /* 200 */
 SYSCALL(sys_geteuid,sys_geteuid,sys_geteuid)
 SYSCALL(sys_getegid,sys_getegid,sys_getegid)
-SYSCALL(sys_setreuid,sys_setreuid,sys32_setreuid_wrapper)
-SYSCALL(sys_setregid,sys_setregid,sys32_setregid_wrapper)
-SYSCALL(sys_getgroups,sys_getgroups,sys32_getgroups_wrapper)   /* 205 */
-SYSCALL(sys_setgroups,sys_setgroups,sys32_setgroups_wrapper)
-SYSCALL(sys_fchown,sys_fchown,sys32_fchown_wrapper)
-SYSCALL(sys_setresuid,sys_setresuid,sys32_setresuid_wrapper)
-SYSCALL(sys_getresuid,sys_getresuid,sys32_getresuid_wrapper)
-SYSCALL(sys_setresgid,sys_setresgid,sys32_setresgid_wrapper)   /* 210 */
-SYSCALL(sys_getresgid,sys_getresgid,sys32_getresgid_wrapper)
-SYSCALL(sys_chown,sys_chown,sys32_chown_wrapper)
-SYSCALL(sys_setuid,sys_setuid,sys32_setuid_wrapper)
-SYSCALL(sys_setgid,sys_setgid,sys32_setgid_wrapper)
-SYSCALL(sys_setfsuid,sys_setfsuid,sys32_setfsuid_wrapper)      /* 215 */
-SYSCALL(sys_setfsgid,sys_setfsgid,sys32_setfsgid_wrapper)
-SYSCALL(sys_pivot_root,sys_pivot_root,sys32_pivot_root_wrapper)
-SYSCALL(sys_mincore,sys_mincore,sys32_mincore_wrapper)
-SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper)
-SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper)        /* 220 */
-SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper)
-SYSCALL(sys_readahead,sys_readahead,sys32_readahead_wrapper)
+SYSCALL(sys_setreuid,sys_setreuid,compat_sys_setreuid)
+SYSCALL(sys_setregid,sys_setregid,compat_sys_setregid)
+SYSCALL(sys_getgroups,sys_getgroups,compat_sys_getgroups)      /* 205 */
+SYSCALL(sys_setgroups,sys_setgroups,compat_sys_setgroups)
+SYSCALL(sys_fchown,sys_fchown,compat_sys_fchown)
+SYSCALL(sys_setresuid,sys_setresuid,compat_sys_setresuid)
+SYSCALL(sys_getresuid,sys_getresuid,compat_sys_getresuid)
+SYSCALL(sys_setresgid,sys_setresgid,compat_sys_setresgid)      /* 210 */
+SYSCALL(sys_getresgid,sys_getresgid,compat_sys_getresgid)
+SYSCALL(sys_chown,sys_chown,compat_sys_chown)
+SYSCALL(sys_setuid,sys_setuid,compat_sys_setuid)
+SYSCALL(sys_setgid,sys_setgid,compat_sys_setgid)
+SYSCALL(sys_setfsuid,sys_setfsuid,compat_sys_setfsuid) /* 215 */
+SYSCALL(sys_setfsgid,sys_setfsgid,compat_sys_setfsgid)
+SYSCALL(sys_pivot_root,sys_pivot_root,compat_sys_pivot_root)
+SYSCALL(sys_mincore,sys_mincore,compat_sys_mincore)
+SYSCALL(sys_madvise,sys_madvise,compat_sys_madvise)
+SYSCALL(sys_getdents64,sys_getdents64,compat_sys_getdents64)   /* 220 */
+SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64)
+SYSCALL(sys_readahead,sys_readahead,compat_sys_s390_readahead)
 SYSCALL(sys_sendfile64,sys_ni_syscall,compat_sys_sendfile64)
-SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper)
-SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper)   /* 225 */
-SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper)
-SYSCALL(sys_getxattr,sys_getxattr,sys32_getxattr_wrapper)
-SYSCALL(sys_lgetxattr,sys_lgetxattr,sys32_lgetxattr_wrapper)
-SYSCALL(sys_fgetxattr,sys_fgetxattr,sys32_fgetxattr_wrapper)
-SYSCALL(sys_listxattr,sys_listxattr,sys32_listxattr_wrapper)   /* 230 */
-SYSCALL(sys_llistxattr,sys_llistxattr,sys32_llistxattr_wrapper)
-SYSCALL(sys_flistxattr,sys_flistxattr,sys32_flistxattr_wrapper)
-SYSCALL(sys_removexattr,sys_removexattr,sys32_removexattr_wrapper)
-SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper)
-SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper)  /* 235 */
+SYSCALL(sys_setxattr,sys_setxattr,compat_sys_setxattr)
+SYSCALL(sys_lsetxattr,sys_lsetxattr,compat_sys_lsetxattr)      /* 225 */
+SYSCALL(sys_fsetxattr,sys_fsetxattr,compat_sys_fsetxattr)
+SYSCALL(sys_getxattr,sys_getxattr,compat_sys_getxattr)
+SYSCALL(sys_lgetxattr,sys_lgetxattr,compat_sys_lgetxattr)
+SYSCALL(sys_fgetxattr,sys_fgetxattr,compat_sys_fgetxattr)
+SYSCALL(sys_listxattr,sys_listxattr,compat_sys_listxattr)      /* 230 */
+SYSCALL(sys_llistxattr,sys_llistxattr,compat_sys_llistxattr)
+SYSCALL(sys_flistxattr,sys_flistxattr,compat_sys_flistxattr)
+SYSCALL(sys_removexattr,sys_removexattr,compat_sys_removexattr)
+SYSCALL(sys_lremovexattr,sys_lremovexattr,compat_sys_lremovexattr)
+SYSCALL(sys_fremovexattr,sys_fremovexattr,compat_sys_fremovexattr)     /* 235 */
 SYSCALL(sys_gettid,sys_gettid,sys_gettid)
-SYSCALL(sys_tkill,sys_tkill,sys_tkill_wrapper)
+SYSCALL(sys_tkill,sys_tkill,compat_sys_tkill)
 SYSCALL(sys_futex,sys_futex,compat_sys_futex)
-SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
-SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper)   /* 240 */
-SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill_wrapper)
+SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,compat_sys_sched_setaffinity)
+SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,compat_sys_sched_getaffinity)      /* 240 */
+SYSCALL(sys_tgkill,sys_tgkill,compat_sys_tgkill)
 NI_SYSCALL                                                     /* reserved for TUX */
-SYSCALL(sys_io_setup,sys_io_setup,sys32_io_setup_wrapper)
-SYSCALL(sys_io_destroy,sys_io_destroy,sys32_io_destroy_wrapper)
-SYSCALL(sys_io_getevents,sys_io_getevents,sys32_io_getevents_wrapper)  /* 245 */
-SYSCALL(sys_io_submit,sys_io_submit,sys32_io_submit_wrapper)
-SYSCALL(sys_io_cancel,sys_io_cancel,sys32_io_cancel_wrapper)
-SYSCALL(sys_exit_group,sys_exit_group,sys32_exit_group_wrapper)
-SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper)
-SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper)     /* 250 */
-SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper)
-SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper)
-SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper)
-SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper)
-SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper)       /* 255 */
-SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper)
-SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys32_timer_getoverrun_wrapper)
-SYSCALL(sys_timer_delete,sys_timer_delete,sys32_timer_delete_wrapper)
-SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper)
-SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper)       /* 260 */
-SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper)
-SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
+SYSCALL(sys_io_setup,sys_io_setup,compat_sys_io_setup)
+SYSCALL(sys_io_destroy,sys_io_destroy,compat_sys_io_destroy)
+SYSCALL(sys_io_getevents,sys_io_getevents,compat_sys_io_getevents)     /* 245 */
+SYSCALL(sys_io_submit,sys_io_submit,compat_sys_io_submit)
+SYSCALL(sys_io_cancel,sys_io_cancel,compat_sys_io_cancel)
+SYSCALL(sys_exit_group,sys_exit_group,compat_sys_exit_group)
+SYSCALL(sys_epoll_create,sys_epoll_create,compat_sys_epoll_create)
+SYSCALL(sys_epoll_ctl,sys_epoll_ctl,compat_sys_epoll_ctl)      /* 250 */
+SYSCALL(sys_epoll_wait,sys_epoll_wait,compat_sys_epoll_wait)
+SYSCALL(sys_set_tid_address,sys_set_tid_address,compat_sys_set_tid_address)
+SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,compat_sys_s390_fadvise64)
+SYSCALL(sys_timer_create,sys_timer_create,compat_sys_timer_create)
+SYSCALL(sys_timer_settime,sys_timer_settime,compat_sys_timer_settime)  /* 255 */
+SYSCALL(sys_timer_gettime,sys_timer_gettime,compat_sys_timer_gettime)
+SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,compat_sys_timer_getoverrun)
+SYSCALL(sys_timer_delete,sys_timer_delete,compat_sys_timer_delete)
+SYSCALL(sys_clock_settime,sys_clock_settime,compat_sys_clock_settime)
+SYSCALL(sys_clock_gettime,sys_clock_gettime,compat_sys_clock_gettime)  /* 260 */
+SYSCALL(sys_clock_getres,sys_clock_getres,compat_sys_clock_getres)
+SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,compat_sys_clock_nanosleep)
 NI_SYSCALL                                                     /* reserved for vserver */
-SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
-SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
-SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
-SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
+SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,compat_sys_s390_fadvise64_64)
+SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64)
+SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64)
+SYSCALL(sys_remap_file_pages,sys_remap_file_pages,compat_sys_remap_file_pages)
 NI_SYSCALL                                                     /* 268 sys_mbind */
 NI_SYSCALL                                                     /* 269 sys_get_mempolicy */
 NI_SYSCALL                                                     /* 270 sys_set_mempolicy */
-SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open_wrapper)
-SYSCALL(sys_mq_unlink,sys_mq_unlink,sys32_mq_unlink_wrapper)
-SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
-SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
-SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
-SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
-SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
-SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
-SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
-SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl_wrapper)               /* 280 */
+SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open)
+SYSCALL(sys_mq_unlink,sys_mq_unlink,compat_sys_mq_unlink)
+SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend)
+SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive)
+SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify) /* 275 */
+SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr)
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load)
+SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key)
+SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key)
+SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl)               /* 280 */
 SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid)
-SYSCALL(sys_ioprio_set,sys_ioprio_set,sys_ioprio_set_wrapper)
-SYSCALL(sys_ioprio_get,sys_ioprio_get,sys_ioprio_get_wrapper)
+SYSCALL(sys_ioprio_set,sys_ioprio_set,compat_sys_ioprio_set)
+SYSCALL(sys_ioprio_get,sys_ioprio_get,compat_sys_ioprio_get)
 SYSCALL(sys_inotify_init,sys_inotify_init,sys_inotify_init)
-SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,sys_inotify_add_watch_wrapper)     /* 285 */
-SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,sys_inotify_rm_watch_wrapper)
+SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,compat_sys_inotify_add_watch)      /* 285 */
+SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,compat_sys_inotify_rm_watch)
 NI_SYSCALL                                                     /* 287 sys_migrate_pages */
 SYSCALL(sys_openat,sys_openat,compat_sys_openat)
-SYSCALL(sys_mkdirat,sys_mkdirat,sys_mkdirat_wrapper)
-SYSCALL(sys_mknodat,sys_mknodat,sys_mknodat_wrapper)   /* 290 */
-SYSCALL(sys_fchownat,sys_fchownat,sys_fchownat_wrapper)
-SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat_wrapper)
-SYSCALL(sys_fstatat64,sys_newfstatat,sys32_fstatat64_wrapper)
-SYSCALL(sys_unlinkat,sys_unlinkat,sys_unlinkat_wrapper)
-SYSCALL(sys_renameat,sys_renameat,sys_renameat_wrapper)        /* 295 */
-SYSCALL(sys_linkat,sys_linkat,sys_linkat_wrapper)
-SYSCALL(sys_symlinkat,sys_symlinkat,sys_symlinkat_wrapper)
-SYSCALL(sys_readlinkat,sys_readlinkat,sys_readlinkat_wrapper)
-SYSCALL(sys_fchmodat,sys_fchmodat,sys_fchmodat_wrapper)
-SYSCALL(sys_faccessat,sys_faccessat,sys_faccessat_wrapper)     /* 300 */
-SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6_wrapper)
-SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll_wrapper)
-SYSCALL(sys_unshare,sys_unshare,sys_unshare_wrapper)
+SYSCALL(sys_mkdirat,sys_mkdirat,compat_sys_mkdirat)
+SYSCALL(sys_mknodat,sys_mknodat,compat_sys_mknodat)    /* 290 */
+SYSCALL(sys_fchownat,sys_fchownat,compat_sys_fchownat)
+SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat)
+SYSCALL(sys_fstatat64,sys_newfstatat,compat_sys_s390_fstatat64)
+SYSCALL(sys_unlinkat,sys_unlinkat,compat_sys_unlinkat)
+SYSCALL(sys_renameat,sys_renameat,compat_sys_renameat) /* 295 */
+SYSCALL(sys_linkat,sys_linkat,compat_sys_linkat)
+SYSCALL(sys_symlinkat,sys_symlinkat,compat_sys_symlinkat)
+SYSCALL(sys_readlinkat,sys_readlinkat,compat_sys_readlinkat)
+SYSCALL(sys_fchmodat,sys_fchmodat,compat_sys_fchmodat)
+SYSCALL(sys_faccessat,sys_faccessat,compat_sys_faccessat)      /* 300 */
+SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6)
+SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll)
+SYSCALL(sys_unshare,sys_unshare,compat_sys_unshare)
 SYSCALL(sys_set_robust_list,sys_set_robust_list,compat_sys_set_robust_list)
 SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list)
-SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
-SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
-SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
+SYSCALL(sys_splice,sys_splice,compat_sys_splice)
+SYSCALL(sys_sync_file_range,sys_sync_file_range,compat_sys_s390_sync_file_range)
+SYSCALL(sys_tee,sys_tee,compat_sys_tee)
 SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice)
 NI_SYSCALL                                                     /* 310 sys_move_pages */
-SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
+SYSCALL(sys_getcpu,sys_getcpu,compat_sys_getcpu)
 SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait)
-SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
-SYSCALL(sys_s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
-SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper)      /* 315 */
+SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes)
+SYSCALL(sys_s390_fallocate,sys_fallocate,compat_sys_s390_fallocate)
+SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat)      /* 315 */
 SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd)
 NI_SYSCALL                                             /* 317 old sys_timer_fd */
-SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
-SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
+SYSCALL(sys_eventfd,sys_eventfd,compat_sys_eventfd)
+SYSCALL(sys_timerfd_create,sys_timerfd_create,compat_sys_timerfd_create)
 SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime) /* 320 */
 SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime)
 SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4)
-SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper)
-SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
-SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */
-SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
-SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
+SYSCALL(sys_eventfd2,sys_eventfd2,compat_sys_eventfd2)
+SYSCALL(sys_inotify_init1,sys_inotify_init1,compat_sys_inotify_init1)
+SYSCALL(sys_pipe2,sys_pipe2,compat_sys_pipe2) /* 325 */
+SYSCALL(sys_dup3,sys_dup3,compat_sys_dup3)
+SYSCALL(sys_epoll_create1,sys_epoll_create1,compat_sys_epoll_create1)
 SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv)
 SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev)
 SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo) /* 330 */
-SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper)
-SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper)
+SYSCALL(sys_perf_event_open,sys_perf_event_open,compat_sys_perf_event_open)
+SYSCALL(sys_fanotify_init,sys_fanotify_init,compat_sys_fanotify_init)
 SYSCALL(sys_fanotify_mark,sys_fanotify_mark,compat_sys_fanotify_mark)
-SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper)
-SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrapper) /* 335 */
+SYSCALL(sys_prlimit64,sys_prlimit64,compat_sys_prlimit64)
+SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,compat_sys_name_to_handle_at) /* 335 */
 SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at)
-SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
-SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
-SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
-SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */
-SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
-SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)
-SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper)
-SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper)
-SYSCALL(sys_sched_setattr,sys_sched_setattr,sys_sched_setattr_wrapper) /* 345 */
-SYSCALL(sys_sched_getattr,sys_sched_getattr,sys_sched_getattr_wrapper)
+SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime)
+SYSCALL(sys_syncfs,sys_syncfs,compat_sys_syncfs)
+SYSCALL(sys_setns,sys_setns,compat_sys_setns)
+SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv) /* 340 */
+SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev)
+SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,compat_sys_s390_runtime_instr)
+SYSCALL(sys_kcmp,sys_kcmp,compat_sys_kcmp)
+SYSCALL(sys_finit_module,sys_finit_module,compat_sys_finit_module)
+SYSCALL(sys_sched_setattr,sys_sched_setattr,compat_sys_sched_setattr) /* 345 */
+SYSCALL(sys_sched_getattr,sys_sched_getattr,compat_sys_sched_getattr)
index 4b2e3e317004a3cf5d725887c1136c9cbcdd4045..6298fed11cedf8bcfcb536474d33552a115f2fe2 100644 (file)
@@ -451,7 +451,6 @@ static int __init topology_init(void)
        }
        set_topology_timer();
 out:
-       update_cpu_masks();
        return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching);
 }
 device_initcall(topology_init);
index 8216c0e0b2e299494ee297540ed0d7015e006858..6f9cfa50037246d8d37bb5dd81a21d643ff3f544 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <asm/pgalloc.h>
 #include <asm/virtio-ccw.h>
 #include "kvm-s390.h"
 #include "trace.h"
@@ -86,9 +87,11 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
        switch (subcode) {
        case 3:
                vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
+               page_table_reset_pgste(current->mm, 0, TASK_SIZE);
                break;
        case 4:
                vcpu->run->s390_reset_flags = 0;
+               page_table_reset_pgste(current->mm, 0, TASK_SIZE);
                break;
        default:
                return -EOPNOTSUPP;
index e0676f390d57d22aeaf991a95c0a7d0e3458d369..10b5db3c9bc4a71d179ed02b994d7fdea6109311 100644 (file)
@@ -68,6 +68,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "instruction_storage_key", VCPU_STAT(instruction_storage_key) },
        { "instruction_stsch", VCPU_STAT(instruction_stsch) },
        { "instruction_chsc", VCPU_STAT(instruction_chsc) },
+       { "instruction_essa", VCPU_STAT(instruction_essa) },
        { "instruction_stsi", VCPU_STAT(instruction_stsi) },
        { "instruction_stfl", VCPU_STAT(instruction_stfl) },
        { "instruction_tprot", VCPU_STAT(instruction_tprot) },
@@ -283,7 +284,11 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
        if (kvm_is_ucontrol(vcpu->kvm))
                gmap_free(vcpu->arch.gmap);
 
+       if (vcpu->arch.sie_block->cbrlo)
+               __free_page(__pfn_to_page(
+                               vcpu->arch.sie_block->cbrlo >> PAGE_SHIFT));
        free_page((unsigned long)(vcpu->arch.sie_block));
+
        kvm_vcpu_uninit(vcpu);
        kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
@@ -390,6 +395,8 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
+       struct page *cbrl;
+
        atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
                                                    CPUSTAT_SM |
                                                    CPUSTAT_STOPPED |
@@ -401,6 +408,14 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->ecb2  = 8;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) vfacilities;
+       if (kvm_enabled_cmma()) {
+               cbrl = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               if (cbrl) {
+                       vcpu->arch.sie_block->ecb2 |= 0x80;
+                       vcpu->arch.sie_block->ecb2 &= ~0x08;
+                       vcpu->arch.sie_block->cbrlo = page_to_phys(cbrl);
+               }
+       }
        hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
        tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
                     (unsigned long) vcpu);
@@ -761,6 +776,16 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
        return rc;
 }
 
+bool kvm_enabled_cmma(void)
+{
+       if (!MACHINE_IS_LPAR)
+               return false;
+       /* only enable for z10 and later */
+       if (!MACHINE_HAS_EDAT1)
+               return false;
+       return true;
+}
+
 static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
        int rc, exit_reason;
index f9559b0bd620962d095851fc5c884a759b49996c..564514f410f45682272bdc5a3e5064306a9e9960 100644 (file)
@@ -156,6 +156,8 @@ 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);
+/* are we going to support cmma? */
+bool kvm_enabled_cmma(void);
 /* implemented in diag.c */
 int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
 
index 75beea632a10ee7c1bba185d344831e11ec684c5..aacb6b129914bc1c7d207d0587fc4fb2efe66ccf 100644 (file)
@@ -636,8 +636,49 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static int handle_essa(struct kvm_vcpu *vcpu)
+{
+       /* entries expected to be 1FF */
+       int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
+       unsigned long *cbrlo, cbrle;
+       struct gmap *gmap;
+       int i;
+
+       VCPU_EVENT(vcpu, 5, "cmma release %d pages", entries);
+       gmap = vcpu->arch.gmap;
+       vcpu->stat.instruction_essa++;
+       if (!kvm_enabled_cmma() || !vcpu->arch.sie_block->cbrlo)
+               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->arch.sie_block->ipb & 0xf0000000) >> 28) > 6)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       /* Rewind PSW to repeat the ESSA instruction */
+       vcpu->arch.sie_block->gpsw.addr =
+               __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
+       vcpu->arch.sie_block->cbrlo &= PAGE_MASK;       /* reset nceo */
+       cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
+       down_read(&gmap->mm->mmap_sem);
+       for (i = 0; i < entries; ++i) {
+               cbrle = cbrlo[i];
+               if (unlikely(cbrle & ~PAGE_MASK || cbrle < 2 * PAGE_SIZE))
+                       /* invalid entry */
+                       break;
+               /* try to free backing */
+               __gmap_zap(cbrle, gmap);
+       }
+       up_read(&gmap->mm->mmap_sem);
+       if (i < entries)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+       return 0;
+}
+
 static const intercept_handler_t b9_handlers[256] = {
        [0x8d] = handle_epsw,
+       [0xab] = handle_essa,
        [0xaf] = handle_pfmf,
 };
 
index b068729e50ace9711774adab984f03a8a41e9338..e3fffe1dff513a05ec2839114b1952c65801721c 100644 (file)
@@ -2,8 +2,7 @@
 # Makefile for s390-specific library files..
 #
 
-lib-y += delay.o string.o uaccess_pt.o find.o
+lib-y += delay.o string.o uaccess_pt.o uaccess_mvcos.o find.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
 obj-$(CONFIG_64BIT) += mem64.o
-lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
index 620d34d6487e5217ce485ab7a6a00e8a19a9171c..922003c1b90d388c96b26c33a19947dc1c8d95d0 100644 (file)
@@ -4,7 +4,7 @@
  * On s390x the bits are numbered:
  *   |0..............63|64............127|128...........191|192...........255|
  * and on s390:
- *   |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ *   |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
  *
  * The reason for this bit numbering is the fact that the hardware sets bits
  * in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap
index b1a22173d027b9bde6774194631d635932bc42ff..c7e0e81f4b4ebf73cf15664f048301faaffccabb 100644 (file)
@@ -6,7 +6,11 @@
 #ifndef __ARCH_S390_LIB_UACCESS_H
 #define __ARCH_S390_LIB_UACCESS_H
 
-extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
+unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n);
+unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n);
+unsigned long copy_in_user_pt(void __user *to, const void __user *from, unsigned long n);
+unsigned long clear_user_pt(void __user *to, unsigned long n);
+unsigned long strnlen_user_pt(const char __user *src, unsigned long count);
+long strncpy_from_user_pt(char *dst, const char __user *src, long count);
 
 #endif /* __ARCH_S390_LIB_UACCESS_H */
index 4b7993bf69b96bd42f503e8772f29caedf5dd4b0..ae97b8df11aa12e154e3403fc080a603395d5346 100644 (file)
@@ -6,8 +6,11 @@
  *              Gerald Schaefer (gerald.schaefer@de.ibm.com)
  */
 
+#include <linux/jump_label.h>
 #include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/mm.h>
+#include <asm/facility.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
 #include "uaccess.h"
 #define SLR    "slgr"
 #endif
 
-static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static struct static_key have_mvcos = STATIC_KEY_INIT_TRUE;
+
+static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
+                                                unsigned long size)
 {
        register unsigned long reg0 asm("0") = 0x81UL;
        unsigned long tmp1, tmp2;
@@ -65,7 +71,16 @@ static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
        return size;
 }
 
-static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       if (static_key_true(&have_mvcos))
+               return copy_from_user_mvcos(to, from, n);
+       return copy_from_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_from_user);
+
+static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
+                                              unsigned long size)
 {
        register unsigned long reg0 asm("0") = 0x810000UL;
        unsigned long tmp1, tmp2;
@@ -94,8 +109,16 @@ static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
        return size;
 }
 
-static size_t copy_in_user_mvcos(size_t size, void __user *to,
-                                const void __user *from)
+unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       if (static_key_true(&have_mvcos))
+               return copy_to_user_mvcos(to, from, n);
+       return copy_to_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_to_user);
+
+static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
+                                              unsigned long size)
 {
        register unsigned long reg0 asm("0") = 0x810081UL;
        unsigned long tmp1, tmp2;
@@ -117,7 +140,15 @@ static size_t copy_in_user_mvcos(size_t size, void __user *to,
        return size;
 }
 
-static size_t clear_user_mvcos(size_t size, void __user *to)
+unsigned long __copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+       if (static_key_true(&have_mvcos))
+               return copy_in_user_mvcos(to, from, n);
+       return copy_in_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_in_user);
+
+static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
 {
        register unsigned long reg0 asm("0") = 0x810000UL;
        unsigned long tmp1, tmp2;
@@ -145,17 +176,26 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
        return size;
 }
 
-static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+unsigned long __clear_user(void __user *to, unsigned long size)
 {
-       size_t done, len, offset, len_str;
+       if (static_key_true(&have_mvcos))
+               return clear_user_mvcos(to, size);
+       return clear_user_pt(to, size);
+}
+EXPORT_SYMBOL(__clear_user);
+
+static inline unsigned long strnlen_user_mvcos(const char __user *src,
+                                              unsigned long count)
+{
+       unsigned long done, len, offset, len_str;
        char buf[256];
 
        done = 0;
        do {
-               offset = (size_t)src & ~PAGE_MASK;
+               offset = (unsigned long)src & ~PAGE_MASK;
                len = min(256UL, PAGE_SIZE - offset);
                len = min(count - done, len);
-               if (copy_from_user_mvcos(len, src, buf))
+               if (copy_from_user_mvcos(buf, src, len))
                        return 0;
                len_str = strnlen(buf, len);
                done += len_str;
@@ -164,18 +204,26 @@ static size_t strnlen_user_mvcos(size_t count, const char __user *src)
        return done + 1;
 }
 
-static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
-                                     char *dst)
+unsigned long __strnlen_user(const char __user *src, unsigned long count)
 {
-       size_t done, len, offset, len_str;
+       if (static_key_true(&have_mvcos))
+               return strnlen_user_mvcos(src, count);
+       return strnlen_user_pt(src, count);
+}
+EXPORT_SYMBOL(__strnlen_user);
 
-       if (unlikely(!count))
+static inline long strncpy_from_user_mvcos(char *dst, const char __user *src,
+                                          long count)
+{
+       unsigned long done, len, offset, len_str;
+
+       if (unlikely(count <= 0))
                return 0;
        done = 0;
        do {
-               offset = (size_t)src & ~PAGE_MASK;
+               offset = (unsigned long)src & ~PAGE_MASK;
                len = min(count - done, PAGE_SIZE - offset);
-               if (copy_from_user_mvcos(len, src, dst))
+               if (copy_from_user_mvcos(dst, src, len))
                        return -EFAULT;
                len_str = strnlen(dst, len);
                done += len_str;
@@ -185,13 +233,31 @@ static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
        return done;
 }
 
-struct uaccess_ops uaccess_mvcos = {
-       .copy_from_user = copy_from_user_mvcos,
-       .copy_to_user = copy_to_user_mvcos,
-       .copy_in_user = copy_in_user_mvcos,
-       .clear_user = clear_user_mvcos,
-       .strnlen_user = strnlen_user_mvcos,
-       .strncpy_from_user = strncpy_from_user_mvcos,
-       .futex_atomic_op = futex_atomic_op_pt,
-       .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
-};
+long __strncpy_from_user(char *dst, const char __user *src, long count)
+{
+       if (static_key_true(&have_mvcos))
+               return strncpy_from_user_mvcos(dst, src, count);
+       return strncpy_from_user_pt(dst, src, count);
+}
+EXPORT_SYMBOL(__strncpy_from_user);
+
+/*
+ * The uaccess page tabe walk variant can be enforced with the "uaccesspt"
+ * kernel parameter. This is mainly for debugging purposes.
+ */
+static int force_uaccess_pt __initdata;
+
+static int __init parse_uaccess_pt(char *__unused)
+{
+       force_uaccess_pt = 1;
+       return 0;
+}
+early_param("uaccesspt", parse_uaccess_pt);
+
+static int __init uaccess_init(void)
+{
+       if (IS_ENABLED(CONFIG_32BIT) || force_uaccess_pt || !test_facility(27))
+               static_key_slow_dec(&have_mvcos);
+       return 0;
+}
+early_initcall(uaccess_init);
index 61ebcc9ccb3472abe320fd8ed4939b4cc5074ebe..8d39760bae68f9f4e65bbbf4d42d5db25ef4958c 100644 (file)
@@ -22,7 +22,7 @@
 #define SLR    "slgr"
 #endif
 
-static size_t strnlen_kernel(size_t count, const char __user *src)
+static unsigned long strnlen_kernel(const char __user *src, unsigned long count)
 {
        register unsigned long reg0 asm("0") = 0UL;
        unsigned long tmp1, tmp2;
@@ -42,8 +42,8 @@ static size_t strnlen_kernel(size_t count, const char __user *src)
        return count;
 }
 
-static size_t copy_in_kernel(size_t count, void __user *to,
-                            const void __user *from)
+static unsigned long copy_in_kernel(void __user *to, const void __user *from,
+                                   unsigned long count)
 {
        unsigned long tmp1;
 
@@ -146,8 +146,8 @@ static unsigned long follow_table(struct mm_struct *mm,
 
 #endif /* CONFIG_64BIT */
 
-static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
-                                            size_t n, int write_user)
+static inline unsigned long __user_copy_pt(unsigned long uaddr, void *kptr,
+                                          unsigned long n, int write_user)
 {
        struct mm_struct *mm = current->mm;
        unsigned long offset, done, size, kaddr;
@@ -189,8 +189,7 @@ fault:
  * Do DAT for user address by page table walk, return kernel address.
  * This function needs to be called with current->mm->page_table_lock held.
  */
-static __always_inline unsigned long __dat_user_addr(unsigned long uaddr,
-                                                    int write)
+static inline unsigned long __dat_user_addr(unsigned long uaddr, int write)
 {
        struct mm_struct *mm = current->mm;
        unsigned long kaddr;
@@ -211,29 +210,29 @@ fault:
        return 0;
 }
 
-static size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
+unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n)
 {
-       size_t rc;
+       unsigned long rc;
 
        if (segment_eq(get_fs(), KERNEL_DS))
-               return copy_in_kernel(n, (void __user *) to, from);
+               return copy_in_kernel((void __user *) to, from, n);
        rc = __user_copy_pt((unsigned long) from, to, n, 0);
        if (unlikely(rc))
                memset(to + n - rc, 0, rc);
        return rc;
 }
 
-static size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
+unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n)
 {
        if (segment_eq(get_fs(), KERNEL_DS))
-               return copy_in_kernel(n, to, (void __user *) from);
+               return copy_in_kernel(to, (void __user *) from, n);
        return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
 }
 
-static size_t clear_user_pt(size_t n, void __user *to)
+unsigned long clear_user_pt(void __user *to, unsigned long n)
 {
        void *zpage = (void *) empty_zero_page;
-       long done, size, ret;
+       unsigned long done, size, ret;
 
        done = 0;
        do {
@@ -242,7 +241,7 @@ static size_t clear_user_pt(size_t n, void __user *to)
                else
                        size = n - done;
                if (segment_eq(get_fs(), KERNEL_DS))
-                       ret = copy_in_kernel(n, to, (void __user *) zpage);
+                       ret = copy_in_kernel(to, (void __user *) zpage, n);
                else
                        ret = __user_copy_pt((unsigned long) to, zpage, size, 1);
                done += size;
@@ -253,17 +252,17 @@ static size_t clear_user_pt(size_t n, void __user *to)
        return 0;
 }
 
-static size_t strnlen_user_pt(size_t count, const char __user *src)
+unsigned long strnlen_user_pt(const char __user *src, unsigned long count)
 {
        unsigned long uaddr = (unsigned long) src;
        struct mm_struct *mm = current->mm;
        unsigned long offset, done, len, kaddr;
-       size_t len_str;
+       unsigned long len_str;
 
        if (unlikely(!count))
                return 0;
        if (segment_eq(get_fs(), KERNEL_DS))
-               return strnlen_kernel(count, src);
+               return strnlen_kernel(src, count);
        if (!mm)
                return 0;
        done = 0;
@@ -289,19 +288,18 @@ fault:
        goto retry;
 }
 
-static size_t strncpy_from_user_pt(size_t count, const char __user *src,
-                                  char *dst)
+long strncpy_from_user_pt(char *dst, const char __user *src, long count)
 {
-       size_t done, len, offset, len_str;
+       unsigned long done, len, offset, len_str;
 
-       if (unlikely(!count))
+       if (unlikely(count <= 0))
                return 0;
        done = 0;
        do {
-               offset = (size_t)src & ~PAGE_MASK;
+               offset = (unsigned long)src & ~PAGE_MASK;
                len = min(count - done, PAGE_SIZE - offset);
                if (segment_eq(get_fs(), KERNEL_DS)) {
-                       if (copy_in_kernel(len, (void __user *) dst, src))
+                       if (copy_in_kernel((void __user *) dst, src, len))
                                return -EFAULT;
                } else {
                        if (__user_copy_pt((unsigned long) src, dst, len, 0))
@@ -315,8 +313,8 @@ static size_t strncpy_from_user_pt(size_t count, const char __user *src,
        return done;
 }
 
-static size_t copy_in_user_pt(size_t n, void __user *to,
-                             const void __user *from)
+unsigned long copy_in_user_pt(void __user *to, const void __user *from,
+                             unsigned long n)
 {
        struct mm_struct *mm = current->mm;
        unsigned long offset_max, uaddr, done, size, error_code;
@@ -326,7 +324,7 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
        int write_user;
 
        if (segment_eq(get_fs(), KERNEL_DS))
-               return copy_in_kernel(n, to, from);
+               return copy_in_kernel(to, from, n);
        if (!mm)
                return n;
        done = 0;
@@ -411,7 +409,7 @@ static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
        return ret;
 }
 
-int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
+int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old)
 {
        int ret;
 
@@ -449,8 +447,8 @@ static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
        return ret;
 }
 
-int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
-                           u32 oldval, u32 newval)
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                                 u32 oldval, u32 newval)
 {
        int ret;
 
@@ -471,14 +469,3 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
        put_page(virt_to_page(uaddr));
        return ret;
 }
-
-struct uaccess_ops uaccess_pt = {
-       .copy_from_user         = copy_from_user_pt,
-       .copy_to_user           = copy_to_user_pt,
-       .copy_in_user           = copy_in_user_pt,
-       .clear_user             = clear_user_pt,
-       .strnlen_user           = strnlen_user_pt,
-       .strncpy_from_user      = strncpy_from_user_pt,
-       .futex_atomic_op        = futex_atomic_op_pt,
-       .futex_atomic_cmpxchg   = futex_atomic_cmpxchg_pt,
-};
index d1e0e0c7a7e22e44f7f136a0bcef51bf412f1099..2a2e35416d2fe7fc4a835795f5c64bca444f1de4 100644 (file)
@@ -128,7 +128,7 @@ void memcpy_absolute(void *dest, void *src, size_t count)
 /*
  * Copy memory from kernel (real) to user (virtual)
  */
-int copy_to_user_real(void __user *dest, void *src, size_t count)
+int copy_to_user_real(void __user *dest, void *src, unsigned long count)
 {
        int offs = 0, size, rc;
        char *buf;
@@ -151,32 +151,6 @@ out:
        return rc;
 }
 
-/*
- * Copy memory from user (virtual) to kernel (real)
- */
-int copy_from_user_real(void *dest, void __user *src, size_t count)
-{
-       int offs = 0, size, rc;
-       char *buf;
-
-       buf = (char *) __get_free_page(GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       rc = -EFAULT;
-       while (offs < count) {
-               size = min(PAGE_SIZE, count - offs);
-               if (copy_from_user(buf, src + offs, size))
-                       goto out;
-               if (memcpy_real(dest + offs, buf, size))
-                       goto out;
-               offs += size;
-       }
-       rc = 0;
-out:
-       free_page((unsigned long) buf);
-       return rc;
-}
-
 /*
  * Check if physical address is within prefix or zero page
  */
index 3584ed9b20a183de8c58cb4521c99517c2532c9a..796c9320c709f5850bb0679778a28bc488773be2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/quicklist.h>
 #include <linux/rcupdate.h>
 #include <linux/slab.h>
+#include <linux/swapops.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -594,6 +595,82 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
 }
 EXPORT_SYMBOL_GPL(gmap_fault);
 
+static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm)
+{
+       if (!non_swap_entry(entry))
+               dec_mm_counter(mm, MM_SWAPENTS);
+       else if (is_migration_entry(entry)) {
+               struct page *page = migration_entry_to_page(entry);
+
+               if (PageAnon(page))
+                       dec_mm_counter(mm, MM_ANONPAGES);
+               else
+                       dec_mm_counter(mm, MM_FILEPAGES);
+       }
+       free_swap_and_cache(entry);
+}
+
+/**
+ * The mm->mmap_sem lock must be held
+ */
+static void gmap_zap_unused(struct mm_struct *mm, unsigned long address)
+{
+       unsigned long ptev, pgstev;
+       spinlock_t *ptl;
+       pgste_t pgste;
+       pte_t *ptep, pte;
+
+       ptep = get_locked_pte(mm, address, &ptl);
+       if (unlikely(!ptep))
+               return;
+       pte = *ptep;
+       if (!pte_swap(pte))
+               goto out_pte;
+       /* Zap unused and logically-zero pages */
+       pgste = pgste_get_lock(ptep);
+       pgstev = pgste_val(pgste);
+       ptev = pte_val(pte);
+       if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) ||
+           ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID))) {
+               gmap_zap_swap_entry(pte_to_swp_entry(pte), mm);
+               pte_clear(mm, address, ptep);
+       }
+       pgste_set_unlock(ptep, pgste);
+out_pte:
+       pte_unmap_unlock(*ptep, ptl);
+}
+
+/*
+ * this function is assumed to be called with mmap_sem held
+ */
+void __gmap_zap(unsigned long address, struct gmap *gmap)
+{
+       unsigned long *table, *segment_ptr;
+       unsigned long segment, pgstev, ptev;
+       struct gmap_pgtable *mp;
+       struct page *page;
+
+       segment_ptr = gmap_table_walk(address, gmap);
+       if (IS_ERR(segment_ptr))
+               return;
+       segment = *segment_ptr;
+       if (segment & _SEGMENT_ENTRY_INVALID)
+               return;
+       page = pfn_to_page(segment >> PAGE_SHIFT);
+       mp = (struct gmap_pgtable *) page->index;
+       address = mp->vmaddr | (address & ~PMD_MASK);
+       /* Page table is present */
+       table = (unsigned long *)(segment & _SEGMENT_ENTRY_ORIGIN);
+       table = table + ((address >> 12) & 0xff);
+       pgstev = table[PTRS_PER_PTE];
+       ptev = table[0];
+       /* quick check, checked again with locks held */
+       if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) ||
+           ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID)))
+               gmap_zap_unused(gmap->mm, address);
+}
+EXPORT_SYMBOL_GPL(__gmap_zap);
+
 void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
 {
 
@@ -671,7 +748,7 @@ EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier);
 /**
  * gmap_ipte_notify - mark a range of ptes for invalidation notification
  * @gmap: pointer to guest mapping meta data structure
- * @address: virtual address in the guest address space
+ * @start: virtual address in the guest address space
  * @len: size of area
  *
  * Returns 0 if for each page in the given range a gmap mapping exists and
@@ -725,13 +802,12 @@ EXPORT_SYMBOL_GPL(gmap_ipte_notify);
 /**
  * gmap_do_ipte_notify - call all invalidation callbacks for a specific pte.
  * @mm: pointer to the process mm_struct
- * @addr: virtual address in the process address space
  * @pte: pointer to the page table entry
  *
  * This function is assumed to be called with the page table lock held
  * for the pte to notify.
  */
-void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long addr, pte_t *pte)
+void gmap_do_ipte_notify(struct mm_struct *mm, pte_t *pte)
 {
        unsigned long segment_offset;
        struct gmap_notifier *nb;
@@ -802,6 +878,78 @@ static inline void page_table_free_pgste(unsigned long *table)
        __free_page(page);
 }
 
+static inline unsigned long page_table_reset_pte(struct mm_struct *mm,
+                       pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+       pte_t *start_pte, *pte;
+       spinlock_t *ptl;
+       pgste_t pgste;
+
+       start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+       pte = start_pte;
+       do {
+               pgste = pgste_get_lock(pte);
+               pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK;
+               pgste_set_unlock(pte, pgste);
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+       pte_unmap_unlock(start_pte, ptl);
+
+       return addr;
+}
+
+static inline unsigned long page_table_reset_pmd(struct mm_struct *mm,
+                       pud_t *pud, unsigned long addr, unsigned long end)
+{
+       unsigned long next;
+       pmd_t *pmd;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+               if (pmd_none_or_clear_bad(pmd))
+                       continue;
+               next = page_table_reset_pte(mm, pmd, addr, next);
+       } while (pmd++, addr = next, addr != end);
+
+       return addr;
+}
+
+static inline unsigned long page_table_reset_pud(struct mm_struct *mm,
+                       pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       unsigned long next;
+       pud_t *pud;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       continue;
+               next = page_table_reset_pmd(mm, pud, addr, next);
+       } while (pud++, addr = next, addr != end);
+
+       return addr;
+}
+
+void page_table_reset_pgste(struct mm_struct *mm,
+                       unsigned long start, unsigned long end)
+{
+       unsigned long addr, next;
+       pgd_t *pgd;
+
+       addr = start;
+       down_read(&mm->mmap_sem);
+       pgd = pgd_offset(mm, addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       continue;
+               next = page_table_reset_pud(mm, pgd, addr, next);
+       } while (pgd++, addr = next, addr != end);
+       up_read(&mm->mmap_sem);
+}
+EXPORT_SYMBOL(page_table_reset_pgste);
+
 int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
                          unsigned long key, bool nq)
 {
@@ -1248,7 +1396,7 @@ void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
 {
        struct list_head *lh = (struct list_head *) pgtable;
 
-       assert_spin_locked(&mm->page_table_lock);
+       assert_spin_locked(pmd_lockptr(mm, pmdp));
 
        /* FIFO */
        if (!pmd_huge_pte(mm, pmdp))
@@ -1264,7 +1412,7 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
        pgtable_t pgtable;
        pte_t *ptep;
 
-       assert_spin_locked(&mm->page_table_lock);
+       assert_spin_locked(pmd_lockptr(mm, pmdp));
 
        /* FIFO */
        pgtable = pmd_huge_pte(mm, pmdp);
index 66670ff262a0b5b722aa2f20418f1dae3c2e389f..1df1d29ac81d3710caafad1f7ce0094f530d721d 100644 (file)
@@ -686,27 +686,13 @@ int pcibios_add_device(struct pci_dev *pdev)
 int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
-       struct resource *res;
-       u16 cmd;
-       int i;
 
        zdev->pdev = pdev;
        zpci_debug_init_device(zdev);
        zpci_fmb_enable_device(zdev);
        zpci_map_resources(zdev);
 
-       pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
-               res = &pdev->resource[i];
-
-               if (res->flags & IORESOURCE_IO)
-                       return -EINVAL;
-
-               if (res->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-       }
-       pci_write_config_word(pdev, PCI_COMMAND, cmd);
-       return 0;
+       return pci_enable_resources(pdev, mask);
 }
 
 void pcibios_disable_device(struct pci_dev *pdev)
index 75c69b402e05aa3ca12f3b7ee8ca78864886c1b4..c5c66840ac00a8fd8382584a6dabc5b699596b17 100644 (file)
@@ -139,7 +139,7 @@ void zpci_debug_exit_device(struct zpci_dev *zdev)
 int __init zpci_debug_init(void)
 {
        /* event trace buffer */
-       pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long));
+       pci_debug_msg_id = debug_register("pci_msg", 8, 1, 8 * sizeof(long));
        if (!pci_debug_msg_id)
                return -EINVAL;
        debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
index 146b9d5e89f83ba0b41506aa369254d5869dbe88..2f947aba4bd4d248984c1c865248e71fd3a0445c 100644 (file)
@@ -1,10 +1,12 @@
 
 header-y +=
 
+
 generic-y += barrier.h
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
 generic-y += trace_clock.h
 generic-y += xor.h
-generic-y += preempt.h
-
diff --git a/arch/score/include/asm/cputime.h b/arch/score/include/asm/cputime.h
deleted file mode 100644 (file)
index 1fced99..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SCORE_CPUTIME_H
-#define _ASM_SCORE_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* _ASM_SCORE_CPUTIME_H */
index 6357710753d548f3a2ccf8c964d4053636796bc6..364d204298fae1af77191ac5f496b6dc5cdb30d1 100644 (file)
@@ -123,15 +123,6 @@ config SYS_SUPPORTS_NUMA
 config SYS_SUPPORTS_PCI
        bool
 
-config SYS_SUPPORTS_CMT
-       bool
-
-config SYS_SUPPORTS_MTU2
-       bool
-
-config SYS_SUPPORTS_TMU
-       bool
-
 config STACKTRACE_SUPPORT
        def_bool y
 
@@ -191,14 +182,14 @@ config CPU_SH3
        bool
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
-       select SYS_SUPPORTS_TMU
+       select SYS_SUPPORTS_SH_TMU
 
 config CPU_SH4
        bool
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
        select CPU_HAS_FPU if !CPU_SH4AL_DSP
-       select SYS_SUPPORTS_TMU
+       select SYS_SUPPORTS_SH_TMU
        select SYS_SUPPORTS_HUGETLBFS if MMU
 
 config CPU_SH4A
@@ -213,7 +204,7 @@ config CPU_SH4AL_DSP
 config CPU_SH5
        bool
        select CPU_HAS_FPU
-       select SYS_SUPPORTS_TMU
+       select SYS_SUPPORTS_SH_TMU
        select SYS_SUPPORTS_HUGETLBFS if MMU
 
 config CPU_SHX2
@@ -250,7 +241,7 @@ choice
 config CPU_SUBTYPE_SH7619
        bool "Support SH7619 processor"
        select CPU_SH2
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
 
 # SH-2A Processor Support
 
@@ -258,50 +249,50 @@ config CPU_SUBTYPE_SH7201
        bool "Support SH7201 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_MTU2
  
 config CPU_SUBTYPE_SH7203
        bool "Support SH7203 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
-       select SYS_SUPPORTS_CMT
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_MTU2
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PINCTRL
 
 config CPU_SUBTYPE_SH7206
        bool "Support SH7206 processor"
        select CPU_SH2A
-       select SYS_SUPPORTS_CMT
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_MTU2
 
 config CPU_SUBTYPE_SH7263
        bool "Support SH7263 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
-       select SYS_SUPPORTS_CMT
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_MTU2
 
 config CPU_SUBTYPE_SH7264
        bool "Support SH7264 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
-       select SYS_SUPPORTS_CMT
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_MTU2
        select PINCTRL
 
 config CPU_SUBTYPE_SH7269
        bool "Support SH7269 processor"
        select CPU_SH2A
        select CPU_HAS_FPU
-       select SYS_SUPPORTS_CMT
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_CMT
+       select SYS_SUPPORTS_SH_MTU2
        select PINCTRL
 
 config CPU_SUBTYPE_MXG
        bool "Support MX-G processor"
        select CPU_SH2A
-       select SYS_SUPPORTS_MTU2
+       select SYS_SUPPORTS_SH_MTU2
        help
          Select MX-G if running on an R8A03022BG part.
 
@@ -354,7 +345,7 @@ config CPU_SUBTYPE_SH7720
        bool "Support SH7720 processor"
        select CPU_SH3
        select CPU_HAS_DSP
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select USB_ARCH_HAS_OHCI
        select USB_OHCI_SH if USB_OHCI_HCD
@@ -366,7 +357,7 @@ config CPU_SUBTYPE_SH7721
        bool "Support SH7721 processor"
        select CPU_SH3
        select CPU_HAS_DSP
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
        select USB_ARCH_HAS_OHCI
        select USB_OHCI_SH if USB_OHCI_HCD
        help
@@ -422,7 +413,7 @@ config CPU_SUBTYPE_SH7723
        select CPU_SHX2
        select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PINCTRL
        help
@@ -434,7 +425,7 @@ config CPU_SUBTYPE_SH7724
        select CPU_SHX2
        select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PINCTRL
        help
@@ -514,7 +505,7 @@ config CPU_SUBTYPE_SH7343
        bool "Support SH7343 processor"
        select CPU_SH4AL_DSP
        select ARCH_SHMOBILE
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
 
 config CPU_SUBTYPE_SH7722
        bool "Support SH7722 processor"
@@ -523,7 +514,7 @@ config CPU_SUBTYPE_SH7722
        select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PINCTRL
 
@@ -534,7 +525,7 @@ config CPU_SUBTYPE_SH7366
        select ARCH_SHMOBILE
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
-       select SYS_SUPPORTS_CMT
+       select SYS_SUPPORTS_SH_CMT
 
 endchoice
 
@@ -567,27 +558,6 @@ source "arch/sh/boards/Kconfig"
 
 menu "Timer and clock configuration"
 
-config SH_TIMER_TMU
-       bool "TMU timer driver"
-       depends on SYS_SUPPORTS_TMU
-       default y
-       help
-         This enables the build of the TMU timer driver.
-
-config SH_TIMER_CMT
-       bool "CMT timer driver"
-       depends on SYS_SUPPORTS_CMT
-       default y
-       help
-         This enables build of the CMT timer driver.
-
-config SH_TIMER_MTU2
-       bool "MTU2 timer driver"
-       depends on SYS_SUPPORTS_MTU2
-       default y
-       help
-         This enables build of the MTU2 timer driver.
-
 config SH_PCLK_FREQ
        int "Peripheral clock frequency (in Hz)"
        depends on SH_CLK_CPG_LEGACY
index 5bc3a15465c71a53906ed0f99a848298c30b2831..85d5255d259f690247494072635d35f29f9c5c8d 100644 (file)
@@ -861,14 +861,12 @@ static struct asoc_simple_card_info fsi_da7210_info = {
        .card           = "FSIB-DA7210",
        .codec          = "da7210.0-001a",
        .platform       = "sh_fsi.0",
-       .daifmt         = SND_SOC_DAIFMT_I2S,
+       .daifmt         = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
        .cpu_dai = {
                .name   = "fsib-dai",
-               .fmt    = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
        },
        .codec_dai = {
                .name   = "da7210-hifi",
-               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
        },
 };
 
index 21e4230659a57d978ac7631016ca42adf1ddc795..1162bc6945a38ebd19ac3f13def4cef2459b907a 100644 (file)
@@ -304,14 +304,12 @@ static struct asoc_simple_card_info fsi_ak4642_info = {
        .card           = "FSIA-AK4642",
        .codec          = "ak4642-codec.0-0012",
        .platform       = "sh_fsi.0",
-       .daifmt         = SND_SOC_DAIFMT_LEFT_J,
+       .daifmt         = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
        .cpu_dai = {
                .name   = "fsia-dai",
-               .fmt    = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
        },
        .codec_dai = {
                .name   = "ak4642-hifi",
-               .fmt    = SND_SOC_DAIFMT_CBM_CFM,
                .sysclk = 11289600,
        },
 };
index 60ed3e1c4b753dd92ba4c58cc59def3079ef2050..1bc09ee7948f00a678d9564331dcdd2ae9cb7c78 100644 (file)
@@ -186,11 +186,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return start;
 }
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       return pci_enable_resources(dev, mask);
-}
-
 static void __init
 pcibios_bus_report_status_early(struct pci_channel *hose,
                                int top_bus, int current_bus,
index 0cd7198a452425dbc96d7dbc72c7c61223527bb2..c19e47dacb31bceec56abeac4c96ca32ad3a2977 100644 (file)
@@ -8,18 +8,21 @@ generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
 generic-y += fcntl.h
+generic-y += hash.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += msgbuf.h
 generic-y += param.h
 generic-y += parport.h
 generic-y += percpu.h
 generic-y += poll.h
-generic-y += mman.h
-generic-y += msgbuf.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sembuf.h
@@ -34,5 +37,3 @@ generic-y += termios.h
 generic-y += trace_clock.h
 generic-y += ucontext.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 673515bc413559a24600f988baeb91e8a6b9b1d4..aa1b2b9088a77b061758f48f4a434185e760d6ca 100644 (file)
@@ -18,7 +18,7 @@
 #define SH_CACHE_ASSOC         8
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define CCR            0xffffffec
+#define SH_CCR         0xffffffec
 
 #define CCR_CACHE_CE   0x01    /* Cache enable */
 #define CCR_CACHE_WT   0x02    /* CCR[bit1=1,bit2=1] */
index defb0baa5a0682b95222bccc60440ee760bd6680..b27ce92cb600bc17c47dacda12d0e3dc9f8d06a1 100644 (file)
@@ -17,8 +17,8 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xfffc1000 /* CCR1 */
-#define CCR2           0xfffc1004
+#define SH_CCR         0xfffc1000 /* CCR1 */
+#define SH_CCR2                0xfffc1004
 
 /*
  * Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not
index bee2d81c56bfbde6392866f1d4bb05b58d1aa4b8..29700fd88c75d30be16340966c3013f1c880f076 100644 (file)
@@ -17,7 +17,7 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xffffffec      /* Address of Cache Control Register */
+#define SH_CCR         0xffffffec      /* Address of Cache Control Register */
 
 #define CCR_CACHE_CE   0x01    /* Cache Enable */
 #define CCR_CACHE_WT   0x02    /* Write-Through (for P0,U0,P3) (else writeback) */
index 7bfb9e8b069c22d789318085e866440502f0c755..92c4cd119b662f99dc4ed9d0f5d1b54dea3001a9 100644 (file)
@@ -17,7 +17,7 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xff00001c      /* Address of Cache Control Register */
+#define SH_CCR         0xff00001c      /* Address of Cache Control Register */
 #define CCR_CACHE_OCE  0x0001  /* Operand Cache Enable */
 #define CCR_CACHE_WT   0x0002  /* Write-Through (for P0,U0,P3) (else writeback)*/
 #define CCR_CACHE_CB   0x0004  /* Copy-Back (for P1) (else writethrough) */
index ecf83cd158dc38fefb91f2fa83cdb452cfa5c6bf..0d7360d549c17858c59f93b6dc0d279f4222a640 100644 (file)
@@ -112,7 +112,7 @@ static void cache_init(void)
        unsigned long ccr, flags;
 
        jump_to_uncached();
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
 
        /*
         * At this point we don't know whether the cache is enabled or not - a
@@ -189,7 +189,7 @@ static void cache_init(void)
 
        l2_cache_init();
 
-       __raw_writel(flags, CCR);
+       __raw_writel(flags, SH_CCR);
        back_to_cached();
 }
 #else
index 2ea4483fd7227c669796644bc47bd3e80b252222..be616ee0cf8799a6c7deeb058a7a92da6a8f213c 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/thread_info.h>
 #include <linux/irqflags.h>
 #include <linux/smp.h>
-#include <linux/cpuidle.h>
 #include <linux/atomic.h>
 #include <asm/pgalloc.h>
 #include <asm/smp.h>
@@ -40,8 +39,7 @@ void arch_cpu_idle_dead(void)
 
 void arch_cpu_idle(void)
 {
-       if (cpuidle_idle_call())
-               sh_idle();
+       sh_idle();
 }
 
 void __init select_idle_routine(void)
index 0833736afa3238185196bb10e408ebf9328e35ea..65a1ecd77f96005b8977df46076475266d0a37e6 100644 (file)
@@ -217,19 +217,6 @@ void __init init_IRQ(void)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_chip *chip = irq_data_get_irq_chip(data);
-
-       printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n",
-              irq, data->node, cpu);
-
-       raw_spin_lock_irq(&desc->lock);
-       chip->irq_set_affinity(data, cpumask_of(cpu), false);
-       raw_spin_unlock_irq(&desc->lock);
-}
-
 /*
  * The CPU has been marked offline.  Migrate IRQs off this CPU.  If
  * the affinity settings do not allow other CPUs, force them onto any
@@ -250,11 +237,8 @@ void migrate_irqs(void)
                                                    irq, cpu);
 
                                cpumask_setall(data->affinity);
-                               newcpu = cpumask_any_and(data->affinity,
-                                                        cpu_online_mask);
                        }
-
-                       route_irq(data, irq, newcpu);
+                       irq_set_affinity(irq, data->affinity);
                }
        }
 }
index 115725198038da862a19ef634a0ec38adf23b76f..777e50f33c00f3f96fe4b34f7723132507b13935 100644 (file)
@@ -36,7 +36,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
         */
        jump_to_uncached();
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        if ((ccr & CCR_CACHE_ENABLE) == 0) {
                back_to_cached();
 
index defcf719f2e84eb5cae2b6be57fed58227eeb6ec..a74259f2f9815e93d499634b67d9756472662e76 100644 (file)
@@ -63,9 +63,9 @@ static void sh2__flush_invalidate_region(void *start, int size)
        local_irq_save(flags);
        jump_to_uncached();
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        ccr |= CCR_CACHE_INVALIDATE;
-       __raw_writel(ccr, CCR);
+       __raw_writel(ccr, SH_CCR);
 
        back_to_cached();
        local_irq_restore(flags);
index 949e2d3138a0ca24ffe07e6228a68eeeb72321e9..ee87d081259b86950d527151618a3e52814ade5a 100644 (file)
@@ -134,7 +134,8 @@ static void sh2a__flush_invalidate_region(void *start, int size)
 
        /* If there are too many pages then just blow the cache */
        if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
-               __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
+               __raw_writel(__raw_readl(SH_CCR) | CCR_OCACHE_INVALIDATE,
+                            SH_CCR);
        } else {
                for (v = begin; v < end; v += L1_CACHE_BYTES)
                        sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
@@ -167,7 +168,8 @@ static void sh2a_flush_icache_range(void *args)
        /* I-Cache invalidate */
        /* If there are too many pages then just blow the cache */
        if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
-               __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR);
+               __raw_writel(__raw_readl(SH_CCR) | CCR_ICACHE_INVALIDATE,
+                            SH_CCR);
        } else {
                for (v = start; v < end; v += L1_CACHE_BYTES)
                        sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v);
index 0e529285b28d42c688fb0901349ba70218385d51..51d8f7f31d1d797392ab2813f4fb3d4d33480598 100644 (file)
@@ -133,9 +133,9 @@ static void flush_icache_all(void)
        jump_to_uncached();
 
        /* Flush I-cache */
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        ccr |= CCR_CACHE_ICI;
-       __raw_writel(ccr, CCR);
+       __raw_writel(ccr, SH_CCR);
 
        /*
         * back_to_cached() will take care of the barrier for us, don't add
index c0adbee97b5f29a2cdb33f6124c1d62ee821ebec..24c58b7dc02265c795000fa997ac96da59207175 100644 (file)
@@ -19,7 +19,7 @@ void __init shx3_cache_init(void)
 {
        unsigned int ccr;
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
 
        /*
         * If we've got cache aliases, resolve them in hardware.
@@ -40,5 +40,5 @@ void __init shx3_cache_init(void)
        ccr |= CCR_CACHE_IBE;
 #endif
 
-       writel_uncached(ccr, CCR);
+       writel_uncached(ccr, SH_CCR);
 }
index 616966a96cba61d6a680d4bc57cf71150a04fb3e..097c2cdd117f53c543fb919ba6740210b1471a4a 100644 (file)
@@ -285,8 +285,8 @@ void __init cpu_cache_init(void)
 {
        unsigned int cache_disabled = 0;
 
-#ifdef CCR
-       cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+#ifdef SH_CCR
+       cache_disabled = !(__raw_readl(SH_CCR) & CCR_CACHE_ENABLE);
 #endif
 
        compute_alias(&boot_cpu_data.icache);
index 4b60a0c325ecaa1820b7b6619cfc4ea89ec7e8bf..a45821818003fce80d501b59653ac35eedcc6875 100644 (file)
@@ -6,15 +6,16 @@ generic-y += cputime.h
 generic-y += div64.h
 generic-y += emergency-restart.h
 generic-y += exec.h
-generic-y += linkage.h
-generic-y += local64.h
-generic-y += mutex.h
+generic-y += hash.h
 generic-y += irq_regs.h
+generic-y += linkage.h
 generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += module.h
+generic-y += mutex.h
+generic-y += preempt.h
 generic-y += serial.h
 generic-y += trace_clock.h
 generic-y += types.h
 generic-y += word-at-a-time.h
-generic-y += preempt.h
-generic-y += hash.h
index dd3bef4b9896c8921f2257cf5fab24399722495d..05710393959f174bc0bf9a8596ef5fbf9bafa391 100644 (file)
@@ -32,7 +32,6 @@
 
 DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
 extern cpumask_t cpu_core_map[NR_CPUS];
-extern int sparc64_multi_core;
 
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
index 1754390a426fb1e3c8eef4f1b947b04271bc794c..a2d10fc64fafd34ace3614383ba0500612da706f 100644 (file)
@@ -42,8 +42,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
 #define topology_core_id(cpu)                  (cpu_data(cpu).core_id)
 #define topology_core_cpumask(cpu)             (&cpu_core_map[cpu])
 #define topology_thread_cpumask(cpu)           (&per_cpu(cpu_sibling_map, cpu))
-#define mc_capable()                           (sparc64_multi_core)
-#define smt_capable()                          (sparc64_multi_core)
 #endif /* CONFIG_SMP */
 
 extern cpumask_t cpu_core_map[NR_CPUS];
index 88aaaa57bb6439270e6674ec8ad0d536fb538556..e16c4157e1ae1a504c754838caf499404894a6ce 100644 (file)
@@ -99,11 +99,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return res->start;
 }
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       return pci_enable_resources(dev, mask);
-}
-
 /* in/out routines taken from pcic.c
  *
  * This probably belongs here rather than ioport.c because
index b90bf23e3aabf36950c03383afe215a8af6006ee..a1a4400d40258acbfa00b08b9672604e8cc22935 100644 (file)
@@ -896,10 +896,6 @@ void mdesc_fill_in_cpu_data(cpumask_t *mask)
 
        mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask);
 
-#ifdef CONFIG_SMP
-       sparc64_multi_core = 1;
-#endif
-
        hp = mdesc_grab();
 
        set_core_ids(hp);
index 32a280ec38c1d6edef71b5576ce474221726ec1e..d7b4967f8fa6209307854c367347f88d14103839 100644 (file)
@@ -58,9 +58,12 @@ void arch_cpu_idle(void)
 {
        if (tlb_type != hypervisor) {
                touch_nmi_watchdog();
+               local_irq_enable();
        } else {
                unsigned long pstate;
 
+               local_irq_enable();
+
                 /* The sun4v sleeping code requires that we have PSTATE.IE cleared over
                  * the cpu sleep hypervisor call.
                  */
@@ -82,7 +85,6 @@ void arch_cpu_idle(void)
                        : "=&r" (pstate)
                        : "i" (PSTATE_IE));
        }
-       local_irq_enable();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 6b39125eb9271d986b32896fcd35015cbd752ef8..9a690d39c01b50f2465263063246565479a0c126 100644 (file)
@@ -555,9 +555,6 @@ static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg)
 
                cpu_data(cpuid).core_id = portid + 1;
                cpu_data(cpuid).proc_id = portid;
-#ifdef CONFIG_SMP
-               sparc64_multi_core = 1;
-#endif
        } else {
                cpu_data(cpuid).dcache_size =
                        of_getintprop_default(dp, "dcache-size", 16 * 1024);
index b085311dcd0ea9f81840e1fc2550c4f870e984eb..9781048161ab8865a3ce203074d4067312989b95 100644 (file)
@@ -53,8 +53,6 @@
 
 #include "cpumap.h"
 
-int sparc64_multi_core __read_mostly;
-
 DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
        { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
index 87729fff13b96729cd6cadcc3825dba172ab1d7c..33a17e7b3ccd0fad8477d4c5b051cca1b24f248a 100644 (file)
@@ -189,7 +189,8 @@ linux_sparc_syscall32:
         mov    %i0, %l5                                ! IEU1
 5:     call    %l7                                     ! CTI   Group brk forced
         srl    %i5, 0, %o5                             ! IEU1
-       ba,a,pt %xcc, 3f
+       ba,pt   %xcc, 3f
+        sra    %o0, 0, %o0
 
        /* Linux native system calls enter here... */
        .align  32
@@ -217,7 +218,6 @@ linux_sparc_syscall:
 3:     stx     %o0, [%sp + PTREGS_OFF + PT_V9_I0]
 ret_sys_call:
        ldx     [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
-       sra     %o0, 0, %o0
        mov     %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
        sllx    %g2, 32, %g2
 
index c3d82b5f54ca8501960d9145990304d5b15e4a3c..3fddf64c7fc63ab81bb1ec0599b9cefa790ec6c8 100644 (file)
@@ -659,8 +659,7 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
                ft->clock_tick_ref = cpu_data(cpu).clock_tick;
        }
        if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
-           (val == CPUFREQ_RESUMECHANGE)) {
+           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
                cpu_data(cpu).clock_tick =
                        cpufreq_scale(ft->clock_tick_ref,
                                      ft->ref_freq,
@@ -733,7 +732,7 @@ void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
        irq_enter();
 
        local_cpu_data().irq0_irqs++;
-       kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
+       kstat_incr_irq_this_cpu(0);
 
        if (unlikely(!evt->event_handler)) {
                printk(KERN_WARNING
index 3b3a360b429a8ac78b5089a98c09027aa40634a3..f5d506fdddad3dea459aa97308e9a8872f34ffe8 100644 (file)
@@ -273,7 +273,7 @@ void __init pgtable_cache_init(void)
                prom_halt();
        }
 
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < ARRAY_SIZE(tsb_cache_names); i++) {
                unsigned long size = 8192 << i;
                const char *name = tsb_cache_names[i];
 
index 3793c75e45d982fb4ae72fb7a17c0f2478e98fea..0aa5675e7025e1f791da57ed9bc52133dd4121da 100644 (file)
@@ -11,6 +11,7 @@ generic-y += errno.h
 generic-y += exec.h
 generic-y += fb.h
 generic-y += fcntl.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -18,12 +19,14 @@ generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += msgbuf.h
 generic-y += mutex.h
 generic-y += param.h
 generic-y += parport.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sembuf.h
@@ -38,5 +41,3 @@ generic-y += termios.h
 generic-y += trace_clock.h
 generic-y += types.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index a97a6452b812cdb9681d49fb4130ab3403ff3d2d..077b7bc437e5f6a54e5ad28e42e89e524001dbf0 100644 (file)
@@ -1064,18 +1064,6 @@ char *__init pcibios_setup(char *str)
        return str;
 }
 
-/*
- * Enable memory address decoding, as appropriate, for the
- * device described by the 'dev' struct.
- *
- * This is called from the generic PCI layer, and can be called
- * for bridges or endpoints.
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       return pci_enable_resources(dev, mask);
-}
-
 /*
  * Called for each device after PCI setup is done.
  * We initialize the PCI device capabilities conservatively, assuming that
index 88a330dcdede1b06b85b1d7eba2da5580a97e99b..a5e4b6068213f4f147639a9ba428b120d8e9c886 100644 (file)
@@ -1,8 +1,28 @@
-generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h
-generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h
-generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h exec.h
-generic-y += switch_to.h clkdev.h
-generic-y += trace_clock.h
-generic-y += preempt.h
-generic-y += hash.h
 generic-y += barrier.h
+generic-y += bug.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += emergency-restart.h
+generic-y += exec.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += io.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += mcs_spinlock.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += preempt.h
+generic-y += sections.h
+generic-y += switch_to.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += xor.h
index 3ef4f9d9bf5deaf74f06d254f8d6b6c3fae75ba6..1e5fb872a4aa60d3292705b8bc34a69a9038d85a 100644 (file)
@@ -16,6 +16,7 @@ generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += futex.h
 generic-y += hardirq.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -24,6 +25,7 @@ generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += local.h
+generic-y += mcs_spinlock.h
 generic-y += mman.h
 generic-y += module.h
 generic-y += msgbuf.h
@@ -32,6 +34,7 @@ generic-y += parport.h
 generic-y += percpu.h
 generic-y += poll.h
 generic-y += posix_types.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sections.h
@@ -60,5 +63,3 @@ generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 7fab7e0b1a72d079abd896327f4837bafd1b072c..26237934ac87b861fa68d139cd46d3c2cc24d12f 100644 (file)
@@ -1583,6 +1583,20 @@ config EFI_STUB
 
          See Documentation/efi-stub.txt for more information.
 
+config EFI_MIXED
+       bool "EFI mixed-mode support"
+       depends on EFI_STUB && X86_64
+       ---help---
+          Enabling this feature allows a 64-bit kernel to be booted
+          on a 32-bit firmware, provided that your CPU supports 64-bit
+          mode.
+
+          Note that it is not possible to boot a mixed-mode enabled
+          kernel via the EFI boot stub - a bootloader that supports
+          the EFI handover protocol must be used.
+
+          If unsure, say N.
+
 config SECCOMP
        def_bool y
        prompt "Enable seccomp to safely compute untrusted bytecode"
index c026cca5602c6fe5c84619f0b43b2fe7c3bb2382..f3aaf231b4e590fad07b58b51583eb6693a924cd 100644 (file)
@@ -341,10 +341,6 @@ config X86_USE_3DNOW
        def_bool y
        depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
 
-config X86_OOSTORE
-       def_bool y
-       depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
-
 #
 # P6_NOPs are a relatively minor optimization that require a family >=
 # 6 processor, except that it is broken on certain VIA chips.
index 321a52ccf63ad58c982f5e8f6588f70267aae947..61bd2ad94281884f13b70f3bb9e397fdcef9338a 100644 (file)
@@ -81,6 +81,15 @@ config X86_PTDUMP
          kernel.
          If in doubt, say "N"
 
+config EFI_PGT_DUMP
+       bool "Dump the EFI pagetable"
+       depends on EFI && X86_PTDUMP
+       ---help---
+         Enable this if you want to dump the EFI page table before
+         enabling virtual mode. This can be used to debug miscellaneous
+         issues with the mapping of the EFI runtime regions into that
+         table.
+
 config DEBUG_RODATA
        bool "Write protect kernel read-only data structures"
        default y
index eeda43abed6ec8d48837abaa5f6c18a40c38785a..3b9348a0c1a496244575dced7f89303ae78b168d 100644 (file)
@@ -82,8 +82,8 @@ else
         KBUILD_AFLAGS += -m64
         KBUILD_CFLAGS += -m64
 
-        # Don't autogenerate MMX or SSE instructions
-        KBUILD_CFLAGS += -mno-mmx -mno-sse
+        # Don't autogenerate traditional x87, MMX or SSE instructions
+        KBUILD_CFLAGS += -mno-mmx -mno-sse -mno-80387 -mno-fp-ret-in-387
 
        # Use -mpreferred-stack-boundary=3 if supported.
        KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
@@ -152,6 +152,7 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI
 
 # does binutils support specific instructions?
 asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
+asinstr += $(call as-instr,crc32l %eax$(comma)%eax,-DCONFIG_AS_CRC32=1)
 avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
 avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
 
index 878df7e88cd4d9c4293d9540432fdd3d7c78fc6e..abb9eba61b500192cd816dd9283fe8c8fb70b858 100644 (file)
@@ -80,7 +80,7 @@ targets += voffset.h
 $(obj)/voffset.h: vmlinux FORCE
        $(call if_changed,voffset)
 
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi_pe_entry\|efi_stub_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
 
 quiet_cmd_zoffset = ZOFFSET $@
       cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
index a7677babf946dc406735d94512eca4765b31569d..1e6146137f8e56753aab7d68b0e0b45af3c5fed9 100644 (file)
 
 static efi_system_table_t *sys_table;
 
+static struct efi_config *efi_early;
+
+#define efi_call_early(f, ...)                                         \
+       efi_early->call(efi_early->f, __VA_ARGS__);
+
+#define BOOT_SERVICES(bits)                                            \
+static void setup_boot_services##bits(struct efi_config *c)            \
+{                                                                      \
+       efi_system_table_##bits##_t *table;                             \
+       efi_boot_services_##bits##_t *bt;                               \
+                                                                       \
+       table = (typeof(table))sys_table;                               \
+                                                                       \
+       c->text_output = table->con_out;                                \
+                                                                       \
+       bt = (typeof(bt))(unsigned long)(table->boottime);              \
+                                                                       \
+       c->allocate_pool = bt->allocate_pool;                           \
+       c->allocate_pages = bt->allocate_pages;                         \
+       c->get_memory_map = bt->get_memory_map;                         \
+       c->free_pool = bt->free_pool;                                   \
+       c->free_pages = bt->free_pages;                                 \
+       c->locate_handle = bt->locate_handle;                           \
+       c->handle_protocol = bt->handle_protocol;                       \
+       c->exit_boot_services = bt->exit_boot_services;                 \
+}
+BOOT_SERVICES(32);
+BOOT_SERVICES(64);
 
-#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
+static void efi_printk(efi_system_table_t *, char *);
+static void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
+
+static efi_status_t
+__file_size32(void *__fh, efi_char16_t *filename_16,
+             void **handle, u64 *file_sz)
+{
+       efi_file_handle_32_t *h, *fh = __fh;
+       efi_file_info_t *info;
+       efi_status_t status;
+       efi_guid_t info_guid = EFI_FILE_INFO_ID;
+       u32 info_sz;
+
+       status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
+                                EFI_FILE_MODE_READ, (u64)0);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table, "Failed to open file: ");
+               efi_char16_printk(sys_table, filename_16);
+               efi_printk(sys_table, "\n");
+               return status;
+       }
+
+       *handle = h;
+
+       info_sz = 0;
+       status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+                                &info_sz, NULL);
+       if (status != EFI_BUFFER_TOO_SMALL) {
+               efi_printk(sys_table, "Failed to get file info size\n");
+               return status;
+       }
+
+grow:
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               info_sz, (void **)&info);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table, "Failed to alloc mem for file info\n");
+               return status;
+       }
+
+       status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+                                &info_sz, info);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               efi_call_early(free_pool, info);
+               goto grow;
+       }
+
+       *file_sz = info->file_size;
+       efi_call_early(free_pool, info);
+
+       if (status != EFI_SUCCESS)
+               efi_printk(sys_table, "Failed to get initrd info\n");
+
+       return status;
+}
+
+static efi_status_t
+__file_size64(void *__fh, efi_char16_t *filename_16,
+             void **handle, u64 *file_sz)
+{
+       efi_file_handle_64_t *h, *fh = __fh;
+       efi_file_info_t *info;
+       efi_status_t status;
+       efi_guid_t info_guid = EFI_FILE_INFO_ID;
+       u32 info_sz;
 
+       status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
+                                EFI_FILE_MODE_READ, (u64)0);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table, "Failed to open file: ");
+               efi_char16_printk(sys_table, filename_16);
+               efi_printk(sys_table, "\n");
+               return status;
+       }
 
+       *handle = h;
+
+       info_sz = 0;
+       status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+                                &info_sz, NULL);
+       if (status != EFI_BUFFER_TOO_SMALL) {
+               efi_printk(sys_table, "Failed to get file info size\n");
+               return status;
+       }
+
+grow:
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               info_sz, (void **)&info);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table, "Failed to alloc mem for file info\n");
+               return status;
+       }
+
+       status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+                                &info_sz, info);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               efi_call_early(free_pool, info);
+               goto grow;
+       }
+
+       *file_sz = info->file_size;
+       efi_call_early(free_pool, info);
+
+       if (status != EFI_SUCCESS)
+               efi_printk(sys_table, "Failed to get initrd info\n");
+
+       return status;
+}
+static efi_status_t
+efi_file_size(efi_system_table_t *sys_table, void *__fh,
+             efi_char16_t *filename_16, void **handle, u64 *file_sz)
+{
+       if (efi_early->is64)
+               return __file_size64(__fh, filename_16, handle, file_sz);
+
+       return __file_size32(__fh, filename_16, handle, file_sz);
+}
+
+static inline efi_status_t
+efi_file_read(void *__fh, void *handle, unsigned long *size, void *addr)
+{
+       unsigned long func;
+
+       if (efi_early->is64) {
+               efi_file_handle_64_t *fh = __fh;
+
+               func = (unsigned long)fh->read;
+               return efi_early->call(func, handle, size, addr);
+       } else {
+               efi_file_handle_32_t *fh = __fh;
+
+               func = (unsigned long)fh->read;
+               return efi_early->call(func, handle, size, addr);
+       }
+}
+
+static inline efi_status_t efi_file_close(void *__fh, void *handle)
+{
+       if (efi_early->is64) {
+               efi_file_handle_64_t *fh = __fh;
+
+               return efi_early->call((unsigned long)fh->close, handle);
+       } else {
+               efi_file_handle_32_t *fh = __fh;
+
+               return efi_early->call((unsigned long)fh->close, handle);
+       }
+}
+
+static inline efi_status_t __open_volume32(void *__image, void **__fh)
+{
+       efi_file_io_interface_t *io;
+       efi_loaded_image_32_t *image = __image;
+       efi_file_handle_32_t *fh;
+       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+       efi_status_t status;
+       void *handle = (void *)(unsigned long)image->device_handle;
+       unsigned long func;
+
+       status = efi_call_early(handle_protocol, handle,
+                               &fs_proto, (void **)&io);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table, "Failed to handle fs_proto\n");
+               return status;
+       }
+
+       func = (unsigned long)io->open_volume;
+       status = efi_early->call(func, io, &fh);
+       if (status != EFI_SUCCESS)
+               efi_printk(sys_table, "Failed to open volume\n");
+
+       *__fh = fh;
+       return status;
+}
+
+static inline efi_status_t __open_volume64(void *__image, void **__fh)
+{
+       efi_file_io_interface_t *io;
+       efi_loaded_image_64_t *image = __image;
+       efi_file_handle_64_t *fh;
+       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+       efi_status_t status;
+       void *handle = (void *)(unsigned long)image->device_handle;
+       unsigned long func;
+
+       status = efi_call_early(handle_protocol, handle,
+                               &fs_proto, (void **)&io);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table, "Failed to handle fs_proto\n");
+               return status;
+       }
+
+       func = (unsigned long)io->open_volume;
+       status = efi_early->call(func, io, &fh);
+       if (status != EFI_SUCCESS)
+               efi_printk(sys_table, "Failed to open volume\n");
+
+       *__fh = fh;
+       return status;
+}
+
+static inline efi_status_t
+efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
+{
+       if (efi_early->is64)
+               return __open_volume64(__image, __fh);
+
+       return __open_volume32(__image, __fh);
+}
+
+static void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
+{
+       unsigned long output_string;
+       size_t offset;
+
+       if (efi_early->is64) {
+               struct efi_simple_text_output_protocol_64 *out;
+               u64 *func;
+
+               offset = offsetof(typeof(*out), output_string);
+               output_string = efi_early->text_output + offset;
+               func = (u64 *)output_string;
+
+               efi_early->call(*func, efi_early->text_output, str);
+       } else {
+               struct efi_simple_text_output_protocol_32 *out;
+               u32 *func;
+
+               offset = offsetof(typeof(*out), output_string);
+               output_string = efi_early->text_output + offset;
+               func = (u32 *)output_string;
+
+               efi_early->call(*func, efi_early->text_output, str);
+       }
+}
+
+#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
 
 static void find_bits(unsigned long mask, u8 *pos, u8 *size)
 {
@@ -47,105 +309,97 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
        *size = len;
 }
 
-static efi_status_t setup_efi_pci(struct boot_params *params)
+static efi_status_t
+__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
 {
-       efi_pci_io_protocol *pci;
+       struct pci_setup_rom *rom = NULL;
        efi_status_t status;
-       void **pci_handle;
-       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
-       unsigned long nr_pci, size = 0;
-       int i;
-       struct setup_data *data;
+       unsigned long size;
+       uint64_t attributes;
 
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+       status = efi_early->call(pci->attributes, pci,
+                                EfiPciIoAttributeOperationGet, 0, 0,
+                                &attributes);
+       if (status != EFI_SUCCESS)
+               return status;
 
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
+       if (!pci->romimage || !pci->romsize)
+               return EFI_INVALID_PARAMETER;
 
-       status = efi_call_phys5(sys_table->boottime->locate_handle,
-                               EFI_LOCATE_BY_PROTOCOL, &pci_proto,
-                               NULL, &size, pci_handle);
+       size = pci->romsize + sizeof(*rom);
 
-       if (status == EFI_BUFFER_TOO_SMALL) {
-               status = efi_call_phys3(sys_table->boottime->allocate_pool,
-                                       EFI_LOADER_DATA, size, &pci_handle);
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
+       if (status != EFI_SUCCESS)
+               return status;
 
-               if (status != EFI_SUCCESS)
-                       return status;
+       memset(rom, 0, sizeof(*rom));
 
-               status = efi_call_phys5(sys_table->boottime->locate_handle,
-                                       EFI_LOCATE_BY_PROTOCOL, &pci_proto,
-                                       NULL, &size, pci_handle);
-       }
+       rom->data.type = SETUP_PCI;
+       rom->data.len = size - sizeof(struct setup_data);
+       rom->data.next = 0;
+       rom->pcilen = pci->romsize;
+       *__rom = rom;
 
-       if (status != EFI_SUCCESS)
-               goto free_handle;
-
-       nr_pci = size / sizeof(void *);
-       for (i = 0; i < nr_pci; i++) {
-               void *h = pci_handle[i];
-               uint64_t attributes;
-               struct pci_setup_rom *rom;
+       status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+                                PCI_VENDOR_ID, 1, &(rom->vendor));
 
-               status = efi_call_phys3(sys_table->boottime->handle_protocol,
-                                       h, &pci_proto, &pci);
+       if (status != EFI_SUCCESS)
+               goto free_struct;
 
-               if (status != EFI_SUCCESS)
-                       continue;
+       status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+                                PCI_DEVICE_ID, 1, &(rom->devid));
 
-               if (!pci)
-                       continue;
+       if (status != EFI_SUCCESS)
+               goto free_struct;
 
-#ifdef CONFIG_X86_64
-               status = efi_call_phys4(pci->attributes, pci,
-                                       EfiPciIoAttributeOperationGet, 0,
-                                       &attributes);
-#else
-               status = efi_call_phys5(pci->attributes, pci,
-                                       EfiPciIoAttributeOperationGet, 0, 0,
-                                       &attributes);
-#endif
-               if (status != EFI_SUCCESS)
-                       continue;
+       status = efi_early->call(pci->get_location, pci, &(rom->segment),
+                                &(rom->bus), &(rom->device), &(rom->function));
 
-               if (!pci->romimage || !pci->romsize)
-                       continue;
+       if (status != EFI_SUCCESS)
+               goto free_struct;
 
-               size = pci->romsize + sizeof(*rom);
+       memcpy(rom->romdata, pci->romimage, pci->romsize);
+       return status;
 
-               status = efi_call_phys3(sys_table->boottime->allocate_pool,
-                               EFI_LOADER_DATA, size, &rom);
+free_struct:
+       efi_call_early(free_pool, rom);
+       return status;
+}
 
-               if (status != EFI_SUCCESS)
-                       continue;
+static efi_status_t
+setup_efi_pci32(struct boot_params *params, void **pci_handle,
+               unsigned long size)
+{
+       efi_pci_io_protocol_32 *pci = NULL;
+       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+       u32 *handles = (u32 *)(unsigned long)pci_handle;
+       efi_status_t status;
+       unsigned long nr_pci;
+       struct setup_data *data;
+       int i;
 
-               rom->data.type = SETUP_PCI;
-               rom->data.len = size - sizeof(struct setup_data);
-               rom->data.next = 0;
-               rom->pcilen = pci->romsize;
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
 
-               status = efi_call_phys5(pci->pci.read, pci,
-                                       EfiPciIoWidthUint16, PCI_VENDOR_ID,
-                                       1, &(rom->vendor));
+       while (data && data->next)
+               data = (struct setup_data *)(unsigned long)data->next;
 
-               if (status != EFI_SUCCESS)
-                       goto free_struct;
+       nr_pci = size / sizeof(u32);
+       for (i = 0; i < nr_pci; i++) {
+               struct pci_setup_rom *rom = NULL;
+               u32 h = handles[i];
 
-               status = efi_call_phys5(pci->pci.read, pci,
-                                       EfiPciIoWidthUint16, PCI_DEVICE_ID,
-                                       1, &(rom->devid));
+               status = efi_call_early(handle_protocol, h,
+                                       &pci_proto, (void **)&pci);
 
                if (status != EFI_SUCCESS)
-                       goto free_struct;
+                       continue;
 
-               status = efi_call_phys5(pci->get_location, pci,
-                                       &(rom->segment), &(rom->bus),
-                                       &(rom->device), &(rom->function));
+               if (!pci)
+                       continue;
 
+               status = __setup_efi_pci32(pci, &rom);
                if (status != EFI_SUCCESS)
-                       goto free_struct;
-
-               memcpy(rom->romdata, pci->romimage, pci->romsize);
+                       continue;
 
                if (data)
                        data->next = (unsigned long)rom;
@@ -154,105 +408,155 @@ static efi_status_t setup_efi_pci(struct boot_params *params)
 
                data = (struct setup_data *)rom;
 
-               continue;
-       free_struct:
-               efi_call_phys1(sys_table->boottime->free_pool, rom);
        }
 
-free_handle:
-       efi_call_phys1(sys_table->boottime->free_pool, pci_handle);
        return status;
 }
 
-/*
- * See if we have Graphics Output Protocol
- */
-static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
-                             unsigned long size)
+static efi_status_t
+__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
 {
-       struct efi_graphics_output_protocol *gop, *first_gop;
-       struct efi_pixel_bitmask pixel_info;
-       unsigned long nr_gops;
+       struct pci_setup_rom *rom;
        efi_status_t status;
-       void **gop_handle;
-       u16 width, height;
-       u32 fb_base, fb_size;
-       u32 pixels_per_scan_line;
-       int pixel_format;
-       int i;
+       unsigned long size;
+       uint64_t attributes;
 
-       status = efi_call_phys3(sys_table->boottime->allocate_pool,
-                               EFI_LOADER_DATA, size, &gop_handle);
+       status = efi_early->call(pci->attributes, pci,
+                                EfiPciIoAttributeOperationGet, 0,
+                                &attributes);
        if (status != EFI_SUCCESS)
                return status;
 
-       status = efi_call_phys5(sys_table->boottime->locate_handle,
-                               EFI_LOCATE_BY_PROTOCOL, proto,
-                               NULL, &size, gop_handle);
+       if (!pci->romimage || !pci->romsize)
+               return EFI_INVALID_PARAMETER;
+
+       size = pci->romsize + sizeof(*rom);
+
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
        if (status != EFI_SUCCESS)
-               goto free_handle;
+               return status;
 
-       first_gop = NULL;
+       rom->data.type = SETUP_PCI;
+       rom->data.len = size - sizeof(struct setup_data);
+       rom->data.next = 0;
+       rom->pcilen = pci->romsize;
+       *__rom = rom;
 
-       nr_gops = size / sizeof(void *);
-       for (i = 0; i < nr_gops; i++) {
-               struct efi_graphics_output_mode_info *info;
-               efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
-               bool conout_found = false;
-               void *dummy;
-               void *h = gop_handle[i];
+       status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+                                PCI_VENDOR_ID, 1, &(rom->vendor));
+
+       if (status != EFI_SUCCESS)
+               goto free_struct;
+
+       status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+                                PCI_DEVICE_ID, 1, &(rom->devid));
+
+       if (status != EFI_SUCCESS)
+               goto free_struct;
+
+       status = efi_early->call(pci->get_location, pci, &(rom->segment),
+                                &(rom->bus), &(rom->device), &(rom->function));
+
+       if (status != EFI_SUCCESS)
+               goto free_struct;
+
+       memcpy(rom->romdata, pci->romimage, pci->romsize);
+       return status;
+
+free_struct:
+       efi_call_early(free_pool, rom);
+       return status;
+
+}
+
+static efi_status_t
+setup_efi_pci64(struct boot_params *params, void **pci_handle,
+               unsigned long size)
+{
+       efi_pci_io_protocol_64 *pci = NULL;
+       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+       u64 *handles = (u64 *)(unsigned long)pci_handle;
+       efi_status_t status;
+       unsigned long nr_pci;
+       struct setup_data *data;
+       int i;
+
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+       while (data && data->next)
+               data = (struct setup_data *)(unsigned long)data->next;
+
+       nr_pci = size / sizeof(u64);
+       for (i = 0; i < nr_pci; i++) {
+               struct pci_setup_rom *rom = NULL;
+               u64 h = handles[i];
+
+               status = efi_call_early(handle_protocol, h,
+                                       &pci_proto, (void **)&pci);
 
-               status = efi_call_phys3(sys_table->boottime->handle_protocol,
-                                       h, proto, &gop);
                if (status != EFI_SUCCESS)
                        continue;
 
-               status = efi_call_phys3(sys_table->boottime->handle_protocol,
-                                       h, &conout_proto, &dummy);
+               if (!pci)
+                       continue;
 
-               if (status == EFI_SUCCESS)
-                       conout_found = true;
+               status = __setup_efi_pci64(pci, &rom);
+               if (status != EFI_SUCCESS)
+                       continue;
 
-               status = efi_call_phys4(gop->query_mode, gop,
-                                       gop->mode->mode, &size, &info);
-               if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
-                       /*
-                        * Systems that use the UEFI Console Splitter may
-                        * provide multiple GOP devices, not all of which are
-                        * backed by real hardware. The workaround is to search
-                        * for a GOP implementing the ConOut protocol, and if
-                        * one isn't found, to just fall back to the first GOP.
-                        */
-                       width = info->horizontal_resolution;
-                       height = info->vertical_resolution;
-                       fb_base = gop->mode->frame_buffer_base;
-                       fb_size = gop->mode->frame_buffer_size;
-                       pixel_format = info->pixel_format;
-                       pixel_info = info->pixel_information;
-                       pixels_per_scan_line = info->pixels_per_scan_line;
+               if (data)
+                       data->next = (unsigned long)rom;
+               else
+                       params->hdr.setup_data = (unsigned long)rom;
+
+               data = (struct setup_data *)rom;
 
-                       /*
-                        * Once we've found a GOP supporting ConOut,
-                        * don't bother looking any further.
-                        */
-                       first_gop = gop;
-                       if (conout_found)
-                               break;
-               }
        }
 
-       /* Did we find any GOPs? */
-       if (!first_gop)
+       return status;
+}
+
+static efi_status_t setup_efi_pci(struct boot_params *params)
+{
+       efi_status_t status;
+       void **pci_handle = NULL;
+       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+       unsigned long size = 0;
+
+       status = efi_call_early(locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL,
+                               &pci_proto, NULL, &size, pci_handle);
+
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               status = efi_call_early(allocate_pool,
+                                       EFI_LOADER_DATA,
+                                       size, (void **)&pci_handle);
+
+               if (status != EFI_SUCCESS)
+                       return status;
+
+               status = efi_call_early(locate_handle,
+                                       EFI_LOCATE_BY_PROTOCOL, &pci_proto,
+                                       NULL, &size, pci_handle);
+       }
+
+       if (status != EFI_SUCCESS)
                goto free_handle;
 
-       /* EFI framebuffer */
-       si->orig_video_isVGA = VIDEO_TYPE_EFI;
+       if (efi_early->is64)
+               status = setup_efi_pci64(params, pci_handle, size);
+       else
+               status = setup_efi_pci32(params, pci_handle, size);
 
-       si->lfb_width = width;
-       si->lfb_height = height;
-       si->lfb_base = fb_base;
-       si->pages = 1;
+free_handle:
+       efi_call_early(free_pool, pci_handle);
+       return status;
+}
 
+static void
+setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
+                struct efi_pixel_bitmask pixel_info, int pixel_format)
+{
        if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
                si->lfb_depth = 32;
                si->lfb_linelength = pixels_per_scan_line * 4;
@@ -297,62 +601,319 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
                si->rsvd_size = 0;
                si->rsvd_pos = 0;
        }
+}
+
+static efi_status_t
+__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
+             struct efi_graphics_output_mode_info **info,
+             unsigned long *size, u32 *fb_base)
+{
+       struct efi_graphics_output_protocol_mode_32 *mode;
+       efi_status_t status;
+       unsigned long m;
+
+       m = gop32->mode;
+       mode = (struct efi_graphics_output_protocol_mode_32 *)m;
+
+       status = efi_early->call(gop32->query_mode, gop32,
+                                mode->mode, size, info);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       *fb_base = mode->frame_buffer_base;
+       return status;
+}
+
+static efi_status_t
+setup_gop32(struct screen_info *si, efi_guid_t *proto,
+           unsigned long size, void **gop_handle)
+{
+       struct efi_graphics_output_protocol_32 *gop32, *first_gop;
+       unsigned long nr_gops;
+       u16 width, height;
+       u32 pixels_per_scan_line;
+       u32 fb_base;
+       struct efi_pixel_bitmask pixel_info;
+       int pixel_format;
+       efi_status_t status;
+       u32 *handles = (u32 *)(unsigned long)gop_handle;
+       int i;
+
+       first_gop = NULL;
+       gop32 = NULL;
+
+       nr_gops = size / sizeof(u32);
+       for (i = 0; i < nr_gops; i++) {
+               struct efi_graphics_output_mode_info *info = NULL;
+               efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+               bool conout_found = false;
+               void *dummy = NULL;
+               u32 h = handles[i];
+
+               status = efi_call_early(handle_protocol, h,
+                                       proto, (void **)&gop32);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               status = efi_call_early(handle_protocol, h,
+                                       &conout_proto, &dummy);
+               if (status == EFI_SUCCESS)
+                       conout_found = true;
+
+               status = __gop_query32(gop32, &info, &size, &fb_base);
+               if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+                       /*
+                        * Systems that use the UEFI Console Splitter may
+                        * provide multiple GOP devices, not all of which are
+                        * backed by real hardware. The workaround is to search
+                        * for a GOP implementing the ConOut protocol, and if
+                        * one isn't found, to just fall back to the first GOP.
+                        */
+                       width = info->horizontal_resolution;
+                       height = info->vertical_resolution;
+                       pixel_format = info->pixel_format;
+                       pixel_info = info->pixel_information;
+                       pixels_per_scan_line = info->pixels_per_scan_line;
+
+                       /*
+                        * Once we've found a GOP supporting ConOut,
+                        * don't bother looking any further.
+                        */
+                       first_gop = gop32;
+                       if (conout_found)
+                               break;
+               }
+       }
+
+       /* Did we find any GOPs? */
+       if (!first_gop)
+               goto out;
+
+       /* EFI framebuffer */
+       si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+       si->lfb_width = width;
+       si->lfb_height = height;
+       si->lfb_base = fb_base;
+       si->pages = 1;
+
+       setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
 
        si->lfb_size = si->lfb_linelength * si->lfb_height;
 
        si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+out:
+       return status;
+}
 
-free_handle:
-       efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
+static efi_status_t
+__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
+             struct efi_graphics_output_mode_info **info,
+             unsigned long *size, u32 *fb_base)
+{
+       struct efi_graphics_output_protocol_mode_64 *mode;
+       efi_status_t status;
+       unsigned long m;
+
+       m = gop64->mode;
+       mode = (struct efi_graphics_output_protocol_mode_64 *)m;
+
+       status = efi_early->call(gop64->query_mode, gop64,
+                                mode->mode, size, info);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       *fb_base = mode->frame_buffer_base;
+       return status;
+}
+
+static efi_status_t
+setup_gop64(struct screen_info *si, efi_guid_t *proto,
+           unsigned long size, void **gop_handle)
+{
+       struct efi_graphics_output_protocol_64 *gop64, *first_gop;
+       unsigned long nr_gops;
+       u16 width, height;
+       u32 pixels_per_scan_line;
+       u32 fb_base;
+       struct efi_pixel_bitmask pixel_info;
+       int pixel_format;
+       efi_status_t status;
+       u64 *handles = (u64 *)(unsigned long)gop_handle;
+       int i;
+
+       first_gop = NULL;
+       gop64 = NULL;
+
+       nr_gops = size / sizeof(u64);
+       for (i = 0; i < nr_gops; i++) {
+               struct efi_graphics_output_mode_info *info = NULL;
+               efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+               bool conout_found = false;
+               void *dummy = NULL;
+               u64 h = handles[i];
+
+               status = efi_call_early(handle_protocol, h,
+                                       proto, (void **)&gop64);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               status = efi_call_early(handle_protocol, h,
+                                       &conout_proto, &dummy);
+               if (status == EFI_SUCCESS)
+                       conout_found = true;
+
+               status = __gop_query64(gop64, &info, &size, &fb_base);
+               if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+                       /*
+                        * Systems that use the UEFI Console Splitter may
+                        * provide multiple GOP devices, not all of which are
+                        * backed by real hardware. The workaround is to search
+                        * for a GOP implementing the ConOut protocol, and if
+                        * one isn't found, to just fall back to the first GOP.
+                        */
+                       width = info->horizontal_resolution;
+                       height = info->vertical_resolution;
+                       pixel_format = info->pixel_format;
+                       pixel_info = info->pixel_information;
+                       pixels_per_scan_line = info->pixels_per_scan_line;
+
+                       /*
+                        * Once we've found a GOP supporting ConOut,
+                        * don't bother looking any further.
+                        */
+                       first_gop = gop64;
+                       if (conout_found)
+                               break;
+               }
+       }
+
+       /* Did we find any GOPs? */
+       if (!first_gop)
+               goto out;
+
+       /* EFI framebuffer */
+       si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+       si->lfb_width = width;
+       si->lfb_height = height;
+       si->lfb_base = fb_base;
+       si->pages = 1;
+
+       setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
+
+       si->lfb_size = si->lfb_linelength * si->lfb_height;
+
+       si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+out:
        return status;
 }
 
 /*
- * See if we have Universal Graphics Adapter (UGA) protocol
+ * See if we have Graphics Output Protocol
  */
-static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
                              unsigned long size)
 {
-       struct efi_uga_draw_protocol *uga, *first_uga;
-       unsigned long nr_ugas;
        efi_status_t status;
-       u32 width, height;
-       void **uga_handle = NULL;
-       int i;
+       void **gop_handle = NULL;
 
-       status = efi_call_phys3(sys_table->boottime->allocate_pool,
-                               EFI_LOADER_DATA, size, &uga_handle);
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               size, (void **)&gop_handle);
        if (status != EFI_SUCCESS)
                return status;
 
-       status = efi_call_phys5(sys_table->boottime->locate_handle,
-                               EFI_LOCATE_BY_PROTOCOL, uga_proto,
-                               NULL, &size, uga_handle);
+       status = efi_call_early(locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL,
+                               proto, NULL, &size, gop_handle);
        if (status != EFI_SUCCESS)
                goto free_handle;
 
+       if (efi_early->is64)
+               status = setup_gop64(si, proto, size, gop_handle);
+       else
+               status = setup_gop32(si, proto, size, gop_handle);
+
+free_handle:
+       efi_call_early(free_pool, gop_handle);
+       return status;
+}
+
+static efi_status_t
+setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+{
+       struct efi_uga_draw_protocol *uga = NULL, *first_uga;
+       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+       unsigned long nr_ugas;
+       u32 *handles = (u32 *)uga_handle;;
+       efi_status_t status;
+       int i;
+
        first_uga = NULL;
+       nr_ugas = size / sizeof(u32);
+       for (i = 0; i < nr_ugas; i++) {
+               efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
+               u32 w, h, depth, refresh;
+               void *pciio;
+               u32 handle = handles[i];
+
+               status = efi_call_early(handle_protocol, handle,
+                                       &uga_proto, (void **)&uga);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
+
+               status = efi_early->call((unsigned long)uga->get_mode, uga,
+                                        &w, &h, &depth, &refresh);
+               if (status == EFI_SUCCESS && (!first_uga || pciio)) {
+                       *width = w;
+                       *height = h;
+
+                       /*
+                        * Once we've found a UGA supporting PCIIO,
+                        * don't bother looking any further.
+                        */
+                       if (pciio)
+                               break;
 
-       nr_ugas = size / sizeof(void *);
+                       first_uga = uga;
+               }
+       }
+
+       return status;
+}
+
+static efi_status_t
+setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+{
+       struct efi_uga_draw_protocol *uga = NULL, *first_uga;
+       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+       unsigned long nr_ugas;
+       u64 *handles = (u64 *)uga_handle;;
+       efi_status_t status;
+       int i;
+
+       first_uga = NULL;
+       nr_ugas = size / sizeof(u64);
        for (i = 0; i < nr_ugas; i++) {
                efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
-               void *handle = uga_handle[i];
                u32 w, h, depth, refresh;
                void *pciio;
+               u64 handle = handles[i];
 
-               status = efi_call_phys3(sys_table->boottime->handle_protocol,
-                                       handle, uga_proto, &uga);
+               status = efi_call_early(handle_protocol, handle,
+                                       &uga_proto, (void **)&uga);
                if (status != EFI_SUCCESS)
                        continue;
 
-               efi_call_phys3(sys_table->boottime->handle_protocol,
-                              handle, &pciio_proto, &pciio);
+               efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
 
-               status = efi_call_phys5(uga->get_mode, uga, &w, &h,
-                                       &depth, &refresh);
+               status = efi_early->call((unsigned long)uga->get_mode, uga,
+                                        &w, &h, &depth, &refresh);
                if (status == EFI_SUCCESS && (!first_uga || pciio)) {
-                       width = w;
-                       height = h;
+                       *width = w;
+                       *height = h;
 
                        /*
                         * Once we've found a UGA supporting PCIIO,
@@ -365,7 +926,39 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
                }
        }
 
-       if (!first_uga)
+       return status;
+}
+
+/*
+ * See if we have Universal Graphics Adapter (UGA) protocol
+ */
+static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+                             unsigned long size)
+{
+       efi_status_t status;
+       u32 width, height;
+       void **uga_handle = NULL;
+
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               size, (void **)&uga_handle);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_early(locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL,
+                               uga_proto, NULL, &size, uga_handle);
+       if (status != EFI_SUCCESS)
+               goto free_handle;
+
+       height = 0;
+       width = 0;
+
+       if (efi_early->is64)
+               status = setup_uga64(uga_handle, size, &width, &height);
+       else
+               status = setup_uga32(uga_handle, size, &width, &height);
+
+       if (!width && !height)
                goto free_handle;
 
        /* EFI framebuffer */
@@ -384,9 +977,8 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
        si->rsvd_size = 8;
        si->rsvd_pos = 24;
 
-
 free_handle:
-       efi_call_phys1(sys_table->boottime->free_pool, uga_handle);
+       efi_call_early(free_pool, uga_handle);
        return status;
 }
 
@@ -404,29 +996,28 @@ void setup_graphics(struct boot_params *boot_params)
        memset(si, 0, sizeof(*si));
 
        size = 0;
-       status = efi_call_phys5(sys_table->boottime->locate_handle,
-                               EFI_LOCATE_BY_PROTOCOL, &graphics_proto,
-                               NULL, &size, gop_handle);
+       status = efi_call_early(locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL,
+                               &graphics_proto, NULL, &size, gop_handle);
        if (status == EFI_BUFFER_TOO_SMALL)
                status = setup_gop(si, &graphics_proto, size);
 
        if (status != EFI_SUCCESS) {
                size = 0;
-               status = efi_call_phys5(sys_table->boottime->locate_handle,
-                                       EFI_LOCATE_BY_PROTOCOL, &uga_proto,
-                                       NULL, &size, uga_handle);
+               status = efi_call_early(locate_handle,
+                                       EFI_LOCATE_BY_PROTOCOL,
+                                       &uga_proto, NULL, &size, uga_handle);
                if (status == EFI_BUFFER_TOO_SMALL)
                        setup_uga(si, &uga_proto, size);
        }
 }
 
-
 /*
  * Because the x86 boot code expects to be passed a boot_params we
  * need to create one ourselves (usually the bootloader would create
  * one for us).
  */
-struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
+struct boot_params *make_boot_params(struct efi_config *c)
 {
        struct boot_params *boot_params;
        struct sys_desc_table *sdt;
@@ -434,7 +1025,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
        struct setup_header *hdr;
        struct efi_info *efi;
        efi_loaded_image_t *image;
-       void *options;
+       void *options, *handle;
        efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
        int options_size = 0;
        efi_status_t status;
@@ -445,14 +1036,21 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
        unsigned long ramdisk_addr;
        unsigned long ramdisk_size;
 
-       sys_table = _table;
+       efi_early = c;
+       sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
+       handle = (void *)(unsigned long)efi_early->image_handle;
 
        /* Check if we were booted by the EFI firmware */
        if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
                return NULL;
 
-       status = efi_call_phys3(sys_table->boottime->handle_protocol,
-                               handle, &proto, (void *)&image);
+       if (efi_early->is64)
+               setup_boot_services64(efi_early);
+       else
+               setup_boot_services32(efi_early);
+
+       status = efi_call_early(handle_protocol, handle,
+                               &proto, (void *)&image);
        if (status != EFI_SUCCESS) {
                efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
                return NULL;
@@ -641,14 +1239,13 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
                sizeof(struct e820entry) * nr_desc;
 
        if (*e820ext) {
-               efi_call_phys1(sys_table->boottime->free_pool, *e820ext);
+               efi_call_early(free_pool, *e820ext);
                *e820ext = NULL;
                *e820ext_size = 0;
        }
 
-       status = efi_call_phys3(sys_table->boottime->allocate_pool,
-                               EFI_LOADER_DATA, size, e820ext);
-
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               size, (void **)e820ext);
        if (status == EFI_SUCCESS)
                *e820ext_size = size;
 
@@ -656,12 +1253,13 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
 }
 
 static efi_status_t exit_boot(struct boot_params *boot_params,
-                             void *handle)
+                             void *handle, bool is64)
 {
        struct efi_info *efi = &boot_params->efi_info;
        unsigned long map_sz, key, desc_size;
        efi_memory_desc_t *mem_map;
        struct setup_data *e820ext;
+       const char *signature;
        __u32 e820ext_size;
        __u32 nr_desc, prev_nr_desc;
        efi_status_t status;
@@ -691,11 +1289,13 @@ get_map:
                if (status != EFI_SUCCESS)
                        goto free_mem_map;
 
-               efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+               efi_call_early(free_pool, mem_map);
                goto get_map; /* Allocated memory, get map again */
        }
 
-       memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
+       signature = is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
+       memcpy(&efi->efi_loader_signature, signature, sizeof(__u32));
+
        efi->efi_systab = (unsigned long)sys_table;
        efi->efi_memdesc_size = desc_size;
        efi->efi_memdesc_version = desc_version;
@@ -708,8 +1308,7 @@ get_map:
 #endif
 
        /* Might as well exit boot services now */
-       status = efi_call_phys2(sys_table->boottime->exit_boot_services,
-                               handle, key);
+       status = efi_call_early(exit_boot_services, handle, key);
        if (status != EFI_SUCCESS) {
                /*
                 * ExitBootServices() will fail if any of the event
@@ -722,7 +1321,7 @@ get_map:
                        goto free_mem_map;
 
                called_exit = true;
-               efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+               efi_call_early(free_pool, mem_map);
                goto get_map;
        }
 
@@ -736,23 +1335,31 @@ get_map:
        return EFI_SUCCESS;
 
 free_mem_map:
-       efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+       efi_call_early(free_pool, mem_map);
        return status;
 }
 
-
 /*
  * On success we return a pointer to a boot_params structure, and NULL
  * on failure.
  */
-struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
+struct boot_params *efi_main(struct efi_config *c,
                             struct boot_params *boot_params)
 {
-       struct desc_ptr *gdt;
+       struct desc_ptr *gdt = NULL;
        efi_loaded_image_t *image;
        struct setup_header *hdr = &boot_params->hdr;
        efi_status_t status;
        struct desc_struct *desc;
+       void *handle;
+       efi_system_table_t *_table;
+       bool is64;
+
+       efi_early = c;
+
+       _table = (efi_system_table_t *)(unsigned long)efi_early->table;
+       handle = (void *)(unsigned long)efi_early->image_handle;
+       is64 = efi_early->is64;
 
        sys_table = _table;
 
@@ -760,13 +1367,17 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
        if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
                goto fail;
 
+       if (is64)
+               setup_boot_services64(efi_early);
+       else
+               setup_boot_services32(efi_early);
+
        setup_graphics(boot_params);
 
        setup_efi_pci(boot_params);
 
-       status = efi_call_phys3(sys_table->boottime->allocate_pool,
-                               EFI_LOADER_DATA, sizeof(*gdt),
-                               (void **)&gdt);
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               sizeof(*gdt), (void **)&gdt);
        if (status != EFI_SUCCESS) {
                efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
                goto fail;
@@ -797,7 +1408,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
                hdr->code32_start = bzimage_addr;
        }
 
-       status = exit_boot(boot_params, handle);
+       status = exit_boot(boot_params, handle, is64);
        if (status != EFI_SUCCESS)
                goto fail;
 
index 81b6b652b46a948440601964e4e0f114563f4f5d..c88c31ecad1231bb2fc45257a8d98bafe7bc519b 100644 (file)
@@ -37,6 +37,24 @@ struct efi_graphics_output_mode_info {
        u32 pixels_per_scan_line;
 } __packed;
 
+struct efi_graphics_output_protocol_mode_32 {
+       u32 max_mode;
+       u32 mode;
+       u32 info;
+       u32 size_of_info;
+       u64 frame_buffer_base;
+       u32 frame_buffer_size;
+} __packed;
+
+struct efi_graphics_output_protocol_mode_64 {
+       u32 max_mode;
+       u32 mode;
+       u64 info;
+       u64 size_of_info;
+       u64 frame_buffer_base;
+       u64 frame_buffer_size;
+} __packed;
+
 struct efi_graphics_output_protocol_mode {
        u32 max_mode;
        u32 mode;
@@ -46,6 +64,20 @@ struct efi_graphics_output_protocol_mode {
        unsigned long frame_buffer_size;
 } __packed;
 
+struct efi_graphics_output_protocol_32 {
+       u32 query_mode;
+       u32 set_mode;
+       u32 blt;
+       u32 mode;
+};
+
+struct efi_graphics_output_protocol_64 {
+       u64 query_mode;
+       u64 set_mode;
+       u64 blt;
+       u64 mode;
+};
+
 struct efi_graphics_output_protocol {
        void *query_mode;
        unsigned long set_mode;
@@ -53,10 +85,38 @@ struct efi_graphics_output_protocol {
        struct efi_graphics_output_protocol_mode *mode;
 };
 
+struct efi_uga_draw_protocol_32 {
+       u32 get_mode;
+       u32 set_mode;
+       u32 blt;
+};
+
+struct efi_uga_draw_protocol_64 {
+       u64 get_mode;
+       u64 set_mode;
+       u64 blt;
+};
+
 struct efi_uga_draw_protocol {
        void *get_mode;
        void *set_mode;
        void *blt;
 };
 
+struct efi_config {
+       u64 image_handle;
+       u64 table;
+       u64 allocate_pool;
+       u64 allocate_pages;
+       u64 get_memory_map;
+       u64 free_pool;
+       u64 free_pages;
+       u64 locate_handle;
+       u64 handle_protocol;
+       u64 exit_boot_services;
+       u64 text_output;
+       efi_status_t (*call)(unsigned long, ...);
+       bool is64;
+} __packed;
+
 #endif /* BOOT_COMPRESSED_EBOOT_H */
index cedc60de86eb71eb8d51f495f1f9d9b799efedf1..7ff3632806b18ec9a48bd0ae88bdc7a9e9dbe091 100644 (file)
@@ -1 +1,30 @@
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+
 #include "../../platform/efi/efi_stub_64.S"
+
+#ifdef CONFIG_EFI_MIXED
+       .code64
+       .text
+ENTRY(efi64_thunk)
+       push    %rbp
+       push    %rbx
+
+       subq    $16, %rsp
+       leaq    efi_exit32(%rip), %rax
+       movl    %eax, 8(%rsp)
+       leaq    efi_gdt64(%rip), %rax
+       movl    %eax, 4(%rsp)
+       movl    %eax, 2(%rax)           /* Fixup the gdt base address */
+       leaq    efi32_boot_gdt(%rip), %rax
+       movl    %eax, (%rsp)
+
+       call    __efi64_thunk
+
+       addq    $16, %rsp
+       pop     %rbx
+       pop     %rbp
+       ret
+ENDPROC(efi64_thunk)
+#endif /* CONFIG_EFI_MIXED */
index 9116aac232c746ae4f5262508fba437db9fbb431..de9d4200d305ba86eb48bb60f3a852b210fb2649 100644 (file)
@@ -42,26 +42,53 @@ ENTRY(startup_32)
 ENTRY(efi_pe_entry)
        add     $0x4, %esp
 
+       call    1f
+1:     popl    %esi
+       subl    $1b, %esi
+
+       popl    %ecx
+       movl    %ecx, efi32_config(%esi)        /* Handle */
+       popl    %ecx
+       movl    %ecx, efi32_config+8(%esi)      /* EFI System table pointer */
+
+       /* Relocate efi_config->call() */
+       leal    efi32_config(%esi), %eax
+       add     %esi, 88(%eax)
+       pushl   %eax
+
        call    make_boot_params
        cmpl    $0, %eax
-       je      1f
-       movl    0x4(%esp), %esi
-       movl    (%esp), %ecx
+       je      fail
+       popl    %ecx
        pushl   %eax
-       pushl   %esi
        pushl   %ecx
-       sub     $0x4, %esp
+       jmp     2f              /* Skip efi_config initialization */
 
-ENTRY(efi_stub_entry)
+ENTRY(efi32_stub_entry)
        add     $0x4, %esp
+       popl    %ecx
+       popl    %edx
+
+       call    1f
+1:     popl    %esi
+       subl    $1b, %esi
+
+       movl    %ecx, efi32_config(%esi)        /* Handle */
+       movl    %edx, efi32_config+8(%esi)      /* EFI System table pointer */
+
+       /* Relocate efi_config->call() */
+       leal    efi32_config(%esi), %eax
+       add     %esi, 88(%eax)
+       pushl   %eax
+2:
        call    efi_main
        cmpl    $0, %eax
        movl    %eax, %esi
        jne     2f
-1:
+fail:
        /* EFI init failed, so hang. */
        hlt
-       jmp     1b
+       jmp     fail
 2:
        call    3f
 3:
@@ -202,6 +229,15 @@ relocated:
        xorl    %ebx, %ebx
        jmp     *%eax
 
+#ifdef CONFIG_EFI_STUB
+       .data
+efi32_config:
+       .fill 11,8,0
+       .long efi_call_phys
+       .long 0
+       .byte 0
+#endif
+
 /*
  * Stack and heap for uncompression
  */
index c5c1ae0997e7b223128b009a220b899e22ffeb25..57e58a5fa21073de1c86f4ceee6b76e674d87399 100644 (file)
@@ -113,7 +113,8 @@ ENTRY(startup_32)
        lgdt    gdt(%ebp)
 
        /* Enable PAE mode */
-       movl    $(X86_CR4_PAE), %eax
+       movl    %cr4, %eax
+       orl     $X86_CR4_PAE, %eax
        movl    %eax, %cr4
 
  /*
@@ -178,6 +179,13 @@ ENTRY(startup_32)
         */
        pushl   $__KERNEL_CS
        leal    startup_64(%ebp), %eax
+#ifdef CONFIG_EFI_MIXED
+       movl    efi32_config(%ebp), %ebx
+       cmp     $0, %ebx
+       jz      1f
+       leal    handover_entry(%ebp), %eax
+1:
+#endif
        pushl   %eax
 
        /* Enter paged protected Mode, activating Long Mode */
@@ -188,6 +196,30 @@ ENTRY(startup_32)
        lret
 ENDPROC(startup_32)
 
+#ifdef CONFIG_EFI_MIXED
+       .org 0x190
+ENTRY(efi32_stub_entry)
+       add     $0x4, %esp              /* Discard return address */
+       popl    %ecx
+       popl    %edx
+       popl    %esi
+
+       leal    (BP_scratch+4)(%esi), %esp
+       call    1f
+1:     pop     %ebp
+       subl    $1b, %ebp
+
+       movl    %ecx, efi32_config(%ebp)
+       movl    %edx, efi32_config+8(%ebp)
+       sgdtl   efi32_boot_gdt(%ebp)
+
+       leal    efi32_config(%ebp), %eax
+       movl    %eax, efi_config(%ebp)
+
+       jmp     startup_32
+ENDPROC(efi32_stub_entry)
+#endif
+
        .code64
        .org 0x200
 ENTRY(startup_64)
@@ -209,26 +241,48 @@ ENTRY(startup_64)
        jmp     preferred_addr
 
 ENTRY(efi_pe_entry)
-       mov     %rcx, %rdi
-       mov     %rdx, %rsi
-       pushq   %rdi
-       pushq   %rsi
+       movq    %rcx, efi64_config(%rip)        /* Handle */
+       movq    %rdx, efi64_config+8(%rip) /* EFI System table pointer */
+
+       leaq    efi64_config(%rip), %rax
+       movq    %rax, efi_config(%rip)
+
+       call    1f
+1:     popq    %rbp
+       subq    $1b, %rbp
+
+       /*
+        * Relocate efi_config->call().
+        */
+       addq    %rbp, efi64_config+88(%rip)
+
+       movq    %rax, %rdi
        call    make_boot_params
        cmpq    $0,%rax
-       je      1f
-       mov     %rax, %rdx
-       popq    %rsi
-       popq    %rdi
+       je      fail
+       mov     %rax, %rsi
+       jmp     2f              /* Skip the relocation */
 
-ENTRY(efi_stub_entry)
+handover_entry:
+       call    1f
+1:     popq    %rbp
+       subq    $1b, %rbp
+
+       /*
+        * Relocate efi_config->call().
+        */
+       movq    efi_config(%rip), %rax
+       addq    %rbp, 88(%rax)
+2:
+       movq    efi_config(%rip), %rdi
        call    efi_main
        movq    %rax,%rsi
        cmpq    $0,%rax
        jne     2f
-1:
+fail:
        /* EFI init failed, so hang. */
        hlt
-       jmp     1b
+       jmp     fail
 2:
        call    3f
 3:
@@ -307,6 +361,20 @@ preferred_addr:
        leaq    relocated(%rbx), %rax
        jmp     *%rax
 
+#ifdef CONFIG_EFI_STUB
+       .org 0x390
+ENTRY(efi64_stub_entry)
+       movq    %rdi, efi64_config(%rip)        /* Handle */
+       movq    %rsi, efi64_config+8(%rip) /* EFI System table pointer */
+
+       leaq    efi64_config(%rip), %rax
+       movq    %rax, efi_config(%rip)
+
+       movq    %rdx, %rsi
+       jmp     handover_entry
+ENDPROC(efi64_stub_entry)
+#endif
+
        .text
 relocated:
 
@@ -372,6 +440,25 @@ gdt:
        .quad   0x0000000000000000      /* TS continued */
 gdt_end:
 
+#ifdef CONFIG_EFI_STUB
+efi_config:
+       .quad   0
+
+#ifdef CONFIG_EFI_MIXED
+       .global efi32_config
+efi32_config:
+       .fill   11,8,0
+       .quad   efi64_thunk
+       .byte   0
+#endif
+
+       .global efi64_config
+efi64_config:
+       .fill   11,8,0
+       .quad   efi_call6
+       .byte   1
+#endif /* CONFIG_EFI_STUB */
+
 /*
  * Stack and heap for uncompression
  */
index 100a9a10076a649e7e7008a3579867391ca16fa4..f0d0b20fe14982529a10d4cec1e8aff6ebf4d96d 100644 (file)
@@ -67,6 +67,13 @@ static int is_transmeta(void)
               cpu_vendor[2] == A32('M', 'x', '8', '6');
 }
 
+static int is_intel(void)
+{
+       return cpu_vendor[0] == A32('G', 'e', 'n', 'u') &&
+              cpu_vendor[1] == A32('i', 'n', 'e', 'I') &&
+              cpu_vendor[2] == A32('n', 't', 'e', 'l');
+}
+
 /* Returns a bitmask of which words we have error bits in */
 static int check_cpuflags(void)
 {
@@ -153,6 +160,19 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
                asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
 
                err = check_cpuflags();
+       } else if (err == 0x01 &&
+                  !(err_flags[0] & ~(1 << X86_FEATURE_PAE)) &&
+                  is_intel() && cpu.level == 6 &&
+                  (cpu.model == 9 || cpu.model == 13)) {
+               /* PAE is disabled on this Pentium M but can be forced */
+               if (cmdline_find_option_bool("forcepae")) {
+                       puts("WARNING: Forcing PAE in CPU flags\n");
+                       set_bit(X86_FEATURE_PAE, cpu.flags);
+                       err = check_cpuflags();
+               }
+               else {
+                       puts("WARNING: PAE disabled. Use parameter 'forcepae' to enable at your own risk!\n");
+               }
        }
 
        if (err_flags_ptr)
index ec3b8ba68096c5434d523c1182196f6ab42f8239..0ca9a5c362bc9681de69956f9c31ee9965d7bb10 100644 (file)
@@ -283,7 +283,7 @@ _start:
        # Part 2 of the header, from the old setup.S
 
                .ascii  "HdrS"          # header signature
-               .word   0x020c          # header version number (>= 0x0105)
+               .word   0x020d          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
                .globl realmode_swtch
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
@@ -350,7 +350,7 @@ cmd_line_ptr:       .long   0               # (Header version 0x0202 or later)
                                        # can be located anywhere in
                                        # low memory 0x10000 or higher.
 
-ramdisk_max:   .long 0x7fffffff
+initrd_addr_max: .long 0x7fffffff
                                        # (Header version 0x0203 or later)
                                        # The highest safe address for
                                        # the contents of an initrd
@@ -375,7 +375,8 @@ xloadflags:
 # define XLF0 0
 #endif
 
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64) && \
+       !defined(CONFIG_EFI_MIXED)
    /* kernel/boot_param/ramdisk could be loaded above 4g */
 # define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
 #else
@@ -383,10 +384,14 @@ xloadflags:
 #endif
 
 #ifdef CONFIG_EFI_STUB
-# ifdef CONFIG_X86_64
-#  define XLF23 XLF_EFI_HANDOVER_64            /* 64-bit EFI handover ok */
+# ifdef CONFIG_EFI_MIXED
+#  define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
 # else
-#  define XLF23 XLF_EFI_HANDOVER_32            /* 32-bit EFI handover ok */
+#  ifdef CONFIG_X86_64
+#   define XLF23 XLF_EFI_HANDOVER_64           /* 64-bit EFI handover ok */
+#  else
+#   define XLF23 XLF_EFI_HANDOVER_32           /* 32-bit EFI handover ok */
+#  endif
 # endif
 #else
 # define XLF23 0
@@ -426,13 +431,7 @@ pref_address:              .quad LOAD_PHYSICAL_ADDR        # preferred load addr
 #define INIT_SIZE VO_INIT_SIZE
 #endif
 init_size:             .long INIT_SIZE         # kernel initialization size
-handover_offset:
-#ifdef CONFIG_EFI_STUB
-                       .long 0x30              # offset to the handover
-                                               # protocol entry point
-#else
-                       .long 0
-#endif
+handover_offset:       .long 0                 # Filled in by build.c
 
 # End of setup header #####################################################
 
index 8e15b22391fc40ad9e0a981ef3176d76643e7c45..1a2f2121cada2a11a1b273bdc518b1dcce34ea99 100644 (file)
@@ -53,7 +53,8 @@ int is_big_kernel;
 
 #define PECOFF_RELOC_RESERVE 0x20
 
-unsigned long efi_stub_entry;
+unsigned long efi32_stub_entry;
+unsigned long efi64_stub_entry;
 unsigned long efi_pe_entry;
 unsigned long startup_64;
 
@@ -219,6 +220,52 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
        update_pecoff_section_header(".text", text_start, text_sz);
 }
 
+static int reserve_pecoff_reloc_section(int c)
+{
+       /* Reserve 0x20 bytes for .reloc section */
+       memset(buf+c, 0, PECOFF_RELOC_RESERVE);
+       return PECOFF_RELOC_RESERVE;
+}
+
+static void efi_stub_defaults(void)
+{
+       /* Defaults for old kernel */
+#ifdef CONFIG_X86_32
+       efi_pe_entry = 0x10;
+#else
+       efi_pe_entry = 0x210;
+       startup_64 = 0x200;
+#endif
+}
+
+static void efi_stub_entry_update(void)
+{
+       unsigned long addr = efi32_stub_entry;
+
+#ifdef CONFIG_X86_64
+       /* Yes, this is really how we defined it :( */
+       addr = efi64_stub_entry - 0x200;
+#endif
+
+#ifdef CONFIG_EFI_MIXED
+       if (efi32_stub_entry != addr)
+               die("32-bit and 64-bit EFI entry points do not match\n");
+#endif
+       put_unaligned_le32(addr, &buf[0x264]);
+}
+
+#else
+
+static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
+static inline void update_pecoff_text(unsigned int text_start,
+                                     unsigned int file_sz) {}
+static inline void efi_stub_defaults(void) {}
+static inline void efi_stub_entry_update(void) {}
+
+static inline int reserve_pecoff_reloc_section(int c)
+{
+       return 0;
+}
 #endif /* CONFIG_EFI_STUB */
 
 
@@ -250,7 +297,8 @@ static void parse_zoffset(char *fname)
        p = (char *)buf;
 
        while (p && *p) {
-               PARSE_ZOFS(p, efi_stub_entry);
+               PARSE_ZOFS(p, efi32_stub_entry);
+               PARSE_ZOFS(p, efi64_stub_entry);
                PARSE_ZOFS(p, efi_pe_entry);
                PARSE_ZOFS(p, startup_64);
 
@@ -271,15 +319,7 @@ int main(int argc, char ** argv)
        void *kernel;
        u32 crc = 0xffffffffUL;
 
-       /* Defaults for old kernel */
-#ifdef CONFIG_X86_32
-       efi_pe_entry = 0x10;
-       efi_stub_entry = 0x30;
-#else
-       efi_pe_entry = 0x210;
-       efi_stub_entry = 0x230;
-       startup_64 = 0x200;
-#endif
+       efi_stub_defaults();
 
        if (argc != 5)
                usage();
@@ -302,11 +342,7 @@ int main(int argc, char ** argv)
                die("Boot block hasn't got boot flag (0xAA55)");
        fclose(file);
 
-#ifdef CONFIG_EFI_STUB
-       /* Reserve 0x20 bytes for .reloc section */
-       memset(buf+c, 0, PECOFF_RELOC_RESERVE);
-       c += PECOFF_RELOC_RESERVE;
-#endif
+       c += reserve_pecoff_reloc_section(c);
 
        /* Pad unused space with zeros */
        setup_sectors = (c + 511) / 512;
@@ -315,9 +351,7 @@ int main(int argc, char ** argv)
        i = setup_sectors*512;
        memset(buf+c, 0, i-c);
 
-#ifdef CONFIG_EFI_STUB
        update_pecoff_setup_and_reloc(i);
-#endif
 
        /* Set the default root device */
        put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
@@ -342,14 +376,9 @@ int main(int argc, char ** argv)
        buf[0x1f1] = setup_sectors-1;
        put_unaligned_le32(sys_size, &buf[0x1f4]);
 
-#ifdef CONFIG_EFI_STUB
        update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
 
-#ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
-       efi_stub_entry -= 0x200;
-#endif
-       put_unaligned_le32(efi_stub_entry, &buf[0x264]);
-#endif
+       efi_stub_entry_update();
 
        crc = partial_crc32(buf, i, crc);
        if (fwrite(buf, 1, i, dest) != i)
index a7fef2621cc9a7f89a824a761413451c1d1f06b9..619e7f7426c6d2cf5416cd7179ed5c37c5d0340e 100644 (file)
@@ -60,7 +60,6 @@ CONFIG_CRASH_DUMP=y
 CONFIG_HIBERNATION=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_TRACE_RTC=y
-CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_DOCK=y
 CONFIG_CPU_FREQ=y
 # CONFIG_CPU_FREQ_STAT is not set
index c1119d4c1281dff554e5b0ebe06a4eb7948bab36..6181c69b786bd963107e698bf8e936529f05546f 100644 (file)
@@ -58,7 +58,6 @@ CONFIG_CRASH_DUMP=y
 CONFIG_HIBERNATION=y
 CONFIG_PM_DEBUG=y
 CONFIG_PM_TRACE_RTC=y
-CONFIG_ACPI_PROCFS=y
 CONFIG_ACPI_DOCK=y
 CONFIG_CPU_FREQ=y
 # CONFIG_CPU_FREQ_STAT is not set
index 7f669853317a3e940647319c21705ca951fb18ac..4acddc43ee0cc60ae92e1506caf1915409fd94cc 100644 (file)
@@ -5,3 +5,5 @@ genhdr-y += unistd_64.h
 genhdr-y += unistd_x32.h
 
 generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += mcs_spinlock.h
index 1d2091a226bcac5b55b05225816bf1f374860c3c..19b0ebafcd3e3f9d5a7aa5d5d9900de66d03a374 100644 (file)
@@ -93,9 +93,6 @@ static inline int is_vsmp_box(void)
        return 0;
 }
 #endif
-extern void xapic_wait_icr_idle(void);
-extern u32 safe_xapic_wait_icr_idle(void);
-extern void xapic_icr_write(u32, u32);
 extern int setup_profiling_timer(unsigned int);
 
 static inline void native_apic_mem_write(u32 reg, u32 v)
@@ -184,7 +181,6 @@ extern int x2apic_phys;
 extern int x2apic_preenabled;
 extern void check_x2apic(void);
 extern void enable_x2apic(void);
-extern void x2apic_icr_write(u32 low, u32 id);
 static inline int x2apic_enabled(void)
 {
        u64 msr;
@@ -221,7 +217,6 @@ static inline void x2apic_force_phys(void)
 {
 }
 
-#define        nox2apic        0
 #define        x2apic_preenabled 0
 #define        x2apic_supported()      0
 #endif
@@ -351,7 +346,7 @@ struct apic {
        int trampoline_phys_low;
        int trampoline_phys_high;
 
-       void (*wait_for_init_deassert)(atomic_t *deassert);
+       bool wait_for_init_deassert;
        void (*smp_callin_clear_local_apic)(void);
        void (*inquire_remote_apic)(int apicid);
 
@@ -517,13 +512,6 @@ extern int default_cpu_present_to_apicid(int mps_cpu);
 extern int default_check_phys_apicid_present(int phys_apicid);
 #endif
 
-static inline void default_wait_for_init_deassert(atomic_t *deassert)
-{
-       while (!atomic_read(deassert))
-               cpu_relax();
-       return;
-}
-
 extern void generic_bigsmp_probe(void);
 
 
index 04a48903b2eb31973080d60d36cfd93b3fc68a5f..69bbb484502089b6a01d93d58e4c16a3f90e14f9 100644 (file)
 #else
 # define smp_rmb()     barrier()
 #endif
-#ifdef CONFIG_X86_OOSTORE
-# define smp_wmb()     wmb()
-#else
-# define smp_wmb()     barrier()
-#endif
+#define smp_wmb()      barrier()
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
 #else /* !SMP */
 #define set_mb(var, value) do { var = value; barrier(); } while (0)
 #endif /* SMP */
 
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
 
 /*
  * For either of these options x86 doesn't have a strong TSO memory
index d86dc3deea6aafed8104025e1ffaec3515047e5f..e265ff95d16d6430a9986a39528d4c98d4d6b334 100644 (file)
@@ -37,7 +37,7 @@
 #define X86_FEATURE_PAT                (0*32+16) /* Page Attribute Table */
 #define X86_FEATURE_PSE36      (0*32+17) /* 36-bit PSEs */
 #define X86_FEATURE_PN         (0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLSH     (0*32+19) /* "clflush" CLFLUSH instruction */
+#define X86_FEATURE_CLFLUSH    (0*32+19) /* CLFLUSH instruction */
 #define X86_FEATURE_DS         (0*32+21) /* "dts" Debug Store */
 #define X86_FEATURE_ACPI       (0*32+22) /* ACPI via MSR */
 #define X86_FEATURE_MMX                (0*32+23) /* Multimedia Extensions */
 #define X86_FEATURE_INVPCID    (9*32+10) /* Invalidate Processor Context ID */
 #define X86_FEATURE_RTM                (9*32+11) /* Restricted Transactional Memory */
 #define X86_FEATURE_MPX                (9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_AVX512F    (9*32+16) /* AVX-512 Foundation */
 #define X86_FEATURE_RDSEED     (9*32+18) /* The RDSEED instruction */
 #define X86_FEATURE_ADX                (9*32+19) /* The ADCX and ADOX instructions */
 #define X86_FEATURE_SMAP       (9*32+20) /* Supervisor Mode Access Prevention */
+#define X86_FEATURE_CLFLUSHOPT (9*32+23) /* CLFLUSHOPT instruction */
+#define X86_FEATURE_AVX512PF   (9*32+26) /* AVX-512 Prefetch */
+#define X86_FEATURE_AVX512ER   (9*32+27) /* AVX-512 Exponential and Reciprocal */
+#define X86_FEATURE_AVX512CD   (9*32+28) /* AVX-512 Conflict Detection */
 
 /*
  * BUG word(s)
@@ -313,7 +318,7 @@ extern const char * const x86_power_flags[32];
 #define cpu_has_pmm_enabled    boot_cpu_has(X86_FEATURE_PMM_EN)
 #define cpu_has_ds             boot_cpu_has(X86_FEATURE_DS)
 #define cpu_has_pebs           boot_cpu_has(X86_FEATURE_PEBS)
-#define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLSH)
+#define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLUSH)
 #define cpu_has_bts            boot_cpu_has(X86_FEATURE_BTS)
 #define cpu_has_gbpages                boot_cpu_has(X86_FEATURE_GBPAGES)
 #define cpu_has_arch_perfmon   boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
diff --git a/arch/x86/include/asm/cputime.h b/arch/x86/include/asm/cputime.h
deleted file mode 100644 (file)
index 6d68ad7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
index 3d6b9f81cc683e63fbdac6c3243ab7069087e0cd..0869434eaf725e7a5aa5efb6f5ce8a62ed8176d3 100644 (file)
  */
 #define EFI_OLD_MEMMAP         EFI_ARCH_1
 
+#define EFI32_LOADER_SIGNATURE "EL32"
+#define EFI64_LOADER_SIGNATURE "EL64"
+
 #ifdef CONFIG_X86_32
 
-#define EFI_LOADER_SIGNATURE   "EL32"
 
 extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
@@ -57,8 +59,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #else /* !CONFIG_X86_32 */
 
-#define EFI_LOADER_SIGNATURE   "EL64"
-
 extern u64 efi_call0(void *fp);
 extern u64 efi_call1(void *fp, u64 arg1);
 extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
@@ -119,7 +119,6 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
 #endif /* CONFIG_X86_32 */
 
 extern int add_efi_memmap;
-extern unsigned long x86_efi_facility;
 extern struct efi_scratch efi_scratch;
 extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
 extern int efi_memblock_x86_reserve_range(void);
@@ -130,10 +129,13 @@ extern void efi_memory_uc(u64 addr, unsigned long size);
 extern void __init efi_map_region(efi_memory_desc_t *md);
 extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
 extern void efi_sync_low_kernel_mappings(void);
-extern void efi_setup_page_tables(void);
+extern int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages);
+extern void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages);
 extern void __init old_map_region(efi_memory_desc_t *md);
 extern void __init runtime_code_page_mkexec(void);
 extern void __init efi_runtime_mkexec(void);
+extern void __init efi_dump_pagetable(void);
+extern void __init efi_apply_memmap_quirks(void);
 
 struct efi_setup_data {
        u64 fw_vendor;
@@ -152,8 +154,40 @@ static inline bool efi_is_native(void)
        return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
 }
 
+static inline bool efi_runtime_supported(void)
+{
+       if (efi_is_native())
+               return true;
+
+       if (IS_ENABLED(CONFIG_EFI_MIXED) && !efi_enabled(EFI_OLD_MEMMAP))
+               return true;
+
+       return false;
+}
+
 extern struct console early_efi_console;
 extern void parse_efi_setup(u64 phys_addr, u32 data_len);
+
+#ifdef CONFIG_EFI_MIXED
+extern void efi_thunk_runtime_setup(void);
+extern efi_status_t efi_thunk_set_virtual_address_map(
+       void *phys_set_virtual_address_map,
+       unsigned long memory_map_size,
+       unsigned long descriptor_size,
+       u32 descriptor_version,
+       efi_memory_desc_t *virtual_map);
+#else
+static inline void efi_thunk_runtime_setup(void) {}
+static inline efi_status_t efi_thunk_set_virtual_address_map(
+       void *phys_set_virtual_address_map,
+       unsigned long memory_map_size,
+       unsigned long descriptor_size,
+       u32 descriptor_version,
+       efi_memory_desc_t *virtual_map)
+{
+       return EFI_SUCCESS;
+}
+#endif /* CONFIG_EFI_MIXED */
 #else
 /*
  * IF EFI is not configured, have the EFI calls return -ENOSYS.
index d3d74698dce9c09151a6421176224885454901df..1c7eefe3250295762c258a66af22a05d53882334 100644 (file)
@@ -145,10 +145,10 @@ static int fd_request_irq(void)
 {
        if (can_use_virtual_dma)
                return request_irq(FLOPPY_IRQ, floppy_hardint,
-                                  IRQF_DISABLED, "floppy", NULL);
+                                  0, "floppy", NULL);
        else
                return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                                  IRQF_DISABLED, "floppy", NULL);
+                                  0, "floppy", NULL);
 }
 
 static unsigned long dma_mem_alloc(unsigned long size)
index ab0ae1aa6d0af1c5d64edcd313e5283aa099c04f..230853da4ec09ea6590aed6d724e1fd13b9e356c 100644 (file)
@@ -33,6 +33,9 @@ typedef struct {
 #ifdef CONFIG_X86_MCE_THRESHOLD
        unsigned int irq_threshold_count;
 #endif
+#if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
+       unsigned int irq_hv_callback_count;
+#endif
 } ____cacheline_aligned irq_cpustat_t;
 
 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
index 34f69cb9350ae3ecf36e4b8cd8d410a6a7b67a0b..91d9c69a629e2731f25aa152de91dd17663ec619 100644 (file)
@@ -237,7 +237,7 @@ memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
 
 static inline void flush_write_buffers(void)
 {
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
        asm volatile("lock; addl $0,0(%%esp)": : :"memory");
 #endif
 }
index cd9c41938b8a1ba8f830c888a078e8395cf76af1..c163215abb9ad99ee1c9eac3210acfb0380614b6 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_X86_MSHYPER_H
 
 #include <linux/types.h>
+#include <linux/interrupt.h>
 #include <asm/hyperv.h>
 
 struct ms_hyperv_info {
@@ -16,6 +17,7 @@ void hyperv_callback_vector(void);
 #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);
+void hv_setup_vmbus_irq(void (*handler)(void));
+void hv_remove_vmbus_irq(void);
 
 #endif
index e139b13f2a33a3572d91e4f7297952e1bf8a1ffc..de36f22eb0b9e79db05711cd46196c0c072bb023 100644 (file)
@@ -214,6 +214,8 @@ do {                                                            \
 
 struct msr *msrs_alloc(void);
 void msrs_free(struct msr *msrs);
+int msr_set_bit(u32 msr, u8 bit);
+int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
index 86f9301903c818c632b227537b44142b71883c8d..5f2fc4441b11016608f476848e3a60bd1e08d7a5 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_X86_NMI_H
 #define _ASM_X86_NMI_H
 
+#include <linux/irq_work.h>
 #include <linux/pm.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -38,6 +39,8 @@ typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);
 struct nmiaction {
        struct list_head        list;
        nmi_handler_t           handler;
+       u64                     max_duration;
+       struct irq_work         irq_work;
        unsigned long           flags;
        const char              *name;
 };
index 1ac6114c9ea591e73c50d53d47d45592755d8c96..96ae4f4040bb359f8f3588f82f6595e41edbc501 100644 (file)
@@ -26,11 +26,6 @@ extern int pci_routeirq;
 extern int noioapicquirk;
 extern int noioapicreroute;
 
-/* scan a bus after allocating a pci_sysdata for it */
-extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
-                                           int node);
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
-
 #ifdef CONFIG_PCI
 
 #ifdef CONFIG_PCI_DOMAINS
@@ -70,7 +65,7 @@ extern unsigned long pci_mem_start;
 
 extern int pcibios_enabled;
 void pcibios_config_init(void);
-struct pci_bus *pcibios_scan_root(int bus);
+void pcibios_scan_root(int bus);
 
 void pcibios_set_master(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq, int active);
index 5ad38ad07890fc4ca8698aae41c6e60e48a451f4..b459ddf27d64149915fb2e2938f2392a8322d957 100644 (file)
         : (prot))
 
 #ifndef __ASSEMBLY__
-
 #include <asm/x86_init.h>
 
+void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
+
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
@@ -445,20 +446,10 @@ static inline int pte_same(pte_t a, pte_t b)
        return a.pte == b.pte;
 }
 
-static inline int pteval_present(pteval_t pteval)
-{
-       /*
-        * Yes Linus, _PAGE_PROTNONE == _PAGE_NUMA. Expressing it this
-        * way clearly states that the intent is that protnone and numa
-        * hinting ptes are considered present for the purposes of
-        * pagetable operations like zapping, protection changes, gup etc.
-        */
-       return pteval & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_NUMA);
-}
-
 static inline int pte_present(pte_t a)
 {
-       return pteval_present(pte_flags(a));
+       return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE |
+                              _PAGE_NUMA);
 }
 
 #define pte_accessible pte_accessible
index 1aa9ccd432236af7d5667657e4267c3a8ba218f6..708f19fb4fc788ea0a51838e43ea8ea50c9699d0 100644 (file)
@@ -382,9 +382,13 @@ static inline void update_page_count(int level, unsigned long pages) { }
  * as a pte too.
  */
 extern pte_t *lookup_address(unsigned long address, unsigned int *level);
+extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
+                                   unsigned int *level);
 extern phys_addr_t slow_virt_to_phys(void *__address);
 extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
                                   unsigned numpages, unsigned long page_flags);
+void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
+                              unsigned numpages);
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_X86_PGTABLE_DEFS_H */
index fdedd38fd0fc7feeabc26f8b366b525b65685904..a4ea02351f4d02bee5a43e78a9013b77ec94ea48 100644 (file)
@@ -449,6 +449,15 @@ struct stack_canary {
 };
 DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
 #endif
+/*
+ * per-CPU IRQ handling stacks
+ */
+struct irq_stack {
+       u32                     stack[THREAD_SIZE/sizeof(u32)];
+} __aligned(THREAD_SIZE);
+
+DECLARE_PER_CPU(struct irq_stack *, hardirq_stack);
+DECLARE_PER_CPU(struct irq_stack *, softirq_stack);
 #endif /* X86_64 */
 
 extern unsigned int xstate_size;
index 645cad2c95ff9c87ebd0592c95e891b7a53290fe..e820c080a4e99e45354fc7b6e5720d9f1933b241 100644 (file)
@@ -191,6 +191,14 @@ static inline void clflush(volatile void *__p)
        asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
 }
 
+static inline void clflushopt(volatile void *__p)
+{
+       alternative_io(".byte " __stringify(NOP_DS_PREFIX) "; clflush %P0",
+                      ".byte 0x66; clflush %P0",
+                      X86_FEATURE_CLFLUSHOPT,
+                      "+m" (*(volatile char __force *)__p));
+}
+
 #define nop() asm volatile ("nop")
 
 
index bf156ded74b56006a76cc02b8917984117af8afd..0f62f5482d91ec8fca86e884b6822fc467239dbc 100644 (file)
 # define LOCK_PTR_REG "D"
 #endif
 
-#if defined(CONFIG_X86_32) && \
-       (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE))
+#if defined(CONFIG_X86_32) && (defined(CONFIG_X86_PPRO_FENCE))
 /*
- * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock
+ * On PPro SMP, we use a locked operation to unlock
  * (PPro errata 66, 92)
  */
 # define UNLOCK_LOCK_PREFIX LOCK_PREFIX
index e1940c06ed022d8b9ad7988aaf76970afc92c4b5..47e5de25ba799f787d7f9344c28daa797fde47b7 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/compiler.h>
 #include <asm/page.h>
+#include <asm/percpu.h>
 #include <asm/types.h>
 
 /*
@@ -32,12 +33,6 @@ struct thread_info {
        mm_segment_t            addr_limit;
        struct restart_block    restart_block;
        void __user             *sysenter_return;
-#ifdef CONFIG_X86_32
-       unsigned long           previous_esp;   /* ESP of the previous stack in
-                                                  case of nested (IRQ) stacks
-                                               */
-       __u8                    supervisor_stack[0];
-#endif
        unsigned int            sig_on_uaccess_error:1;
        unsigned int            uaccess_err:1;  /* uaccess failed */
 };
@@ -153,9 +148,9 @@ struct thread_info {
 #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
 #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
 
-#ifdef CONFIG_X86_32
+#define STACK_WARN             (THREAD_SIZE/8)
+#define KERNEL_STACK_OFFSET    (5*(BITS_PER_LONG/8))
 
-#define STACK_WARN     (THREAD_SIZE/8)
 /*
  * macros/functions for gaining access to the thread information structure
  *
@@ -163,42 +158,6 @@ struct thread_info {
  */
 #ifndef __ASSEMBLY__
 
-#define current_stack_pointer ({               \
-       unsigned long sp;                       \
-       asm("mov %%esp,%0" : "=g" (sp));        \
-       sp;                                     \
-})
-
-/* how to get the thread information struct from C */
-static inline struct thread_info *current_thread_info(void)
-{
-       return (struct thread_info *)
-               (current_stack_pointer & ~(THREAD_SIZE - 1));
-}
-
-#else /* !__ASSEMBLY__ */
-
-/* how to get the thread information struct from ASM */
-#define GET_THREAD_INFO(reg)    \
-       movl $-THREAD_SIZE, reg; \
-       andl %esp, reg
-
-/* use this one if reg already contains %esp */
-#define GET_THREAD_INFO_WITH_ESP(reg) \
-       andl $-THREAD_SIZE, reg
-
-#endif
-
-#else /* X86_32 */
-
-#include <asm/percpu.h>
-#define KERNEL_STACK_OFFSET (5*8)
-
-/*
- * macros/functions for gaining access to the thread information structure
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-#ifndef __ASSEMBLY__
 DECLARE_PER_CPU(unsigned long, kernel_stack);
 
 static inline struct thread_info *current_thread_info(void)
@@ -213,8 +172,8 @@ static inline struct thread_info *current_thread_info(void)
 
 /* how to get the thread information struct from ASM */
 #define GET_THREAD_INFO(reg) \
-       movq PER_CPU_VAR(kernel_stack),reg ; \
-       subq $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg
+       _ASM_MOV PER_CPU_VAR(kernel_stack),reg ; \
+       _ASM_SUB $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg ;
 
 /*
  * Same if PER_CPU_VAR(kernel_stack) is, perhaps with some offset, already in
@@ -224,8 +183,6 @@ static inline struct thread_info *current_thread_info(void)
 
 #endif
 
-#endif /* !X86_32 */
-
 /*
  * Thread-synchronous status.
  *
index d35f24e231cd2429c8d17c0d5b3d722951d3e04b..0e8f04f2c26fda3935093b7040dac783e621d71b 100644 (file)
@@ -119,9 +119,10 @@ static inline void setup_node_to_cpumask_map(void) { }
 
 extern const struct cpumask *cpu_coregroup_mask(int cpu);
 
-#ifdef ENABLE_TOPO_DEFINES
 #define topology_physical_package_id(cpu)      (cpu_data(cpu).phys_proc_id)
 #define topology_core_id(cpu)                  (cpu_data(cpu).cpu_core_id)
+
+#ifdef ENABLE_TOPO_DEFINES
 #define topology_core_cpumask(cpu)             (per_cpu(cpu_core_map, cpu))
 #define topology_thread_cpumask(cpu)           (per_cpu(cpu_sibling_map, cpu))
 #endif
@@ -131,25 +132,7 @@ static inline void arch_fix_phys_package_id(int num, u32 slot)
 }
 
 struct pci_bus;
+int x86_pci_root_bus_node(int bus);
 void x86_pci_root_bus_resources(int bus, struct list_head *resources);
 
-#ifdef CONFIG_SMP
-#define mc_capable()   ((boot_cpu_data.x86_max_cores > 1) && \
-                       (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids))
-#define smt_capable()                  (smp_num_siblings > 1)
-#endif
-
-#ifdef CONFIG_NUMA
-extern int get_mp_bus_to_node(int busnum);
-extern void set_mp_bus_to_node(int busnum, int node);
-#else
-static inline int get_mp_bus_to_node(int busnum)
-{
-       return 0;
-}
-static inline void set_mp_bus_to_node(int busnum, int node)
-{
-}
-#endif
-
 #endif /* _ASM_X86_TOPOLOGY_H */
index c2a48139c3401b5d0202a83c676242119106b1f2..3f556c6a015769a1a53a2615e3a0cf26da1725a3 100644 (file)
@@ -23,6 +23,9 @@
 #  include <asm/unistd_64.h>
 #  include <asm/unistd_64_x32.h>
 #  define __ARCH_WANT_COMPAT_SYS_TIME
+#  define __ARCH_WANT_COMPAT_SYS_GETDENTS64
+#  define __ARCH_WANT_COMPAT_SYS_PREADV64
+#  define __ARCH_WANT_COMPAT_SYS_PWRITEV64
 
 # endif
 
index 554738963b28cf47dd76fa9947338bb1eae5a0d0..6c1d7411eb009a5a96ef55004fdedf60aa1ef822 100644 (file)
@@ -6,11 +6,14 @@
 
 #define XSTATE_CPUID           0x0000000d
 
-#define XSTATE_FP      0x1
-#define XSTATE_SSE     0x2
-#define XSTATE_YMM     0x4
-#define XSTATE_BNDREGS 0x8
-#define XSTATE_BNDCSR  0x10
+#define XSTATE_FP              0x1
+#define XSTATE_SSE             0x2
+#define XSTATE_YMM             0x4
+#define XSTATE_BNDREGS         0x8
+#define XSTATE_BNDCSR          0x10
+#define XSTATE_OPMASK          0x20
+#define XSTATE_ZMM_Hi256       0x40
+#define XSTATE_Hi16_ZMM                0x80
 
 #define XSTATE_FPSSE   (XSTATE_FP | XSTATE_SSE)
 
@@ -23,7 +26,8 @@
 #define XSAVE_YMM_OFFSET    (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
 
 /* Supported features which support lazy state saving */
-#define XSTATE_LAZY    (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
+#define XSTATE_LAZY    (XSTATE_FP | XSTATE_SSE | XSTATE_YMM                  \
+                       | XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
 
 /* Supported features which require eager state saving */
 #define XSTATE_EAGER   (XSTATE_BNDREGS | XSTATE_BNDCSR)
index c19fc60ff06272f733df17a03f8cbf577d69073f..4924f4be2b992198995a3bf328f011de65dc2230 100644 (file)
 #define THERM_LOG_THRESHOLD1           (1 << 9)
 
 /* MISC_ENABLE bits: architectural */
-#define MSR_IA32_MISC_ENABLE_FAST_STRING       (1ULL << 0)
-#define MSR_IA32_MISC_ENABLE_TCC               (1ULL << 1)
-#define MSR_IA32_MISC_ENABLE_EMON              (1ULL << 7)
-#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL       (1ULL << 11)
-#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL      (1ULL << 12)
-#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP        (1ULL << 16)
-#define MSR_IA32_MISC_ENABLE_MWAIT             (1ULL << 18)
-#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID       (1ULL << 22)
-#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE      (1ULL << 23)
-#define MSR_IA32_MISC_ENABLE_XD_DISABLE                (1ULL << 34)
+#define MSR_IA32_MISC_ENABLE_FAST_STRING_BIT           0
+#define MSR_IA32_MISC_ENABLE_FAST_STRING               (1ULL << MSR_IA32_MISC_ENABLE_FAST_STRING_BIT)
+#define MSR_IA32_MISC_ENABLE_TCC_BIT                   1
+#define MSR_IA32_MISC_ENABLE_TCC                       (1ULL << MSR_IA32_MISC_ENABLE_TCC_BIT)
+#define MSR_IA32_MISC_ENABLE_EMON_BIT                  7
+#define MSR_IA32_MISC_ENABLE_EMON                      (1ULL << MSR_IA32_MISC_ENABLE_EMON_BIT)
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT           11
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL               (1ULL << MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT)
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT          12
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL              (1ULL << MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT)
+#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT    16
+#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP                (1ULL << MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT)
+#define MSR_IA32_MISC_ENABLE_MWAIT_BIT                 18
+#define MSR_IA32_MISC_ENABLE_MWAIT                     (1ULL << MSR_IA32_MISC_ENABLE_MWAIT_BIT)
+#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT           22
+#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID               (1ULL << MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT);
+#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT          23
+#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE              (1ULL << MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT            34
+#define MSR_IA32_MISC_ENABLE_XD_DISABLE                        (1ULL << MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT)
 
 /* MISC_ENABLE bits: model-specific, meaning may vary from core to core */
-#define MSR_IA32_MISC_ENABLE_X87_COMPAT                (1ULL << 2)
-#define MSR_IA32_MISC_ENABLE_TM1               (1ULL << 3)
-#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE        (1ULL << 4)
-#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE   (1ULL << 6)
-#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK     (1ULL << 8)
-#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE  (1ULL << 9)
-#define MSR_IA32_MISC_ENABLE_FERR              (1ULL << 10)
-#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX    (1ULL << 10)
-#define MSR_IA32_MISC_ENABLE_TM2               (1ULL << 13)
-#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE  (1ULL << 19)
-#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK    (1ULL << 20)
-#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT       (1ULL << 24)
-#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE  (1ULL << 37)
-#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE     (1ULL << 38)
-#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE   (1ULL << 39)
+#define MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT            2
+#define MSR_IA32_MISC_ENABLE_X87_COMPAT                        (1ULL << MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT)
+#define MSR_IA32_MISC_ENABLE_TM1_BIT                   3
+#define MSR_IA32_MISC_ENABLE_TM1                       (1ULL << MSR_IA32_MISC_ENABLE_TM1_BIT)
+#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT    4
+#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE                (1ULL << MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT       6
+#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE           (1ULL << MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT         8
+#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK             (1ULL << MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT)
+#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT      9
+#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE          (1ULL << MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_FERR_BIT                  10
+#define MSR_IA32_MISC_ENABLE_FERR                      (1ULL << MSR_IA32_MISC_ENABLE_FERR_BIT)
+#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT                10
+#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX            (1ULL << MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT)
+#define MSR_IA32_MISC_ENABLE_TM2_BIT                   13
+#define MSR_IA32_MISC_ENABLE_TM2                       (1ULL << MSR_IA32_MISC_ENABLE_TM2_BIT)
+#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT      19
+#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE          (1ULL << MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT                20
+#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK            (1ULL << MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT)
+#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT           24
+#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT               (1ULL << MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT)
+#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT      37
+#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE          (1ULL << MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT         38
+#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE             (1ULL << MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT       39
+#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE           (1ULL << MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT)
 
 #define MSR_IA32_TSC_DEADLINE          0x000006E0
 
index 1dac94265b5978282262b77d4f496ae512701eb8..8e61d23b8f64679577682756272d1e2ff242de07 100644 (file)
@@ -53,10 +53,6 @@ EXPORT_SYMBOL(acpi_disabled);
 # include <asm/proto.h>
 #endif                         /* X86 */
 
-#define BAD_MADT_ENTRY(entry, end) (                                       \
-               (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
-               ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
 #define PREFIX                 "ACPI: "
 
 int acpi_noirq;                                /* skip ACPI IRQ initialization */
@@ -613,10 +609,10 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
        int nid;
 
        nid = acpi_get_node(handle);
-       if (nid == -1 || !node_online(nid))
-               return;
-       set_apicid_to_node(physid, nid);
-       numa_set_node(cpu, nid);
+       if (nid != -1) {
+               set_apicid_to_node(physid, nid);
+               numa_set_node(cpu, nid);
+       }
 #endif
 }
 
index dec8de4e1663fd6c99c2cfcbf18cd75d9551a9a0..f04dbb3069b8fda5168e7a95dc935baf4389f127 100644 (file)
@@ -22,6 +22,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
        {}
 };
 EXPORT_SYMBOL(amd_nb_misc_ids);
@@ -30,6 +31,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
        {}
 };
 
index fd972a3e4cbb0919221f6f69299a857972ef44e6..9fa8aa051f54b235ed516d32e2eca2c3c9d62b5e 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
 #include <linux/bitops.h>
-#include <linux/ioport.h>
 #include <linux/suspend.h>
 #include <asm/e820.h>
 #include <asm/io.h>
@@ -54,18 +53,6 @@ int fallback_aper_force __initdata;
 
 int fix_aperture __initdata = 1;
 
-static struct resource gart_resource = {
-       .name   = "GART",
-       .flags  = IORESOURCE_MEM,
-};
-
-static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
-{
-       gart_resource.start = aper_base;
-       gart_resource.end = aper_base + aper_size - 1;
-       insert_resource(&iomem_resource, &gart_resource);
-}
-
 /* This code runs before the PCI subsystem is initialized, so just
    access the northbridge directly. */
 
@@ -96,7 +83,6 @@ static u32 __init allocate_aperture(void)
        memblock_reserve(addr, aper_size);
        printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
                        aper_size >> 10, addr);
-       insert_aperture_resource((u32)addr, aper_size);
        register_nosave_region(addr >> PAGE_SHIFT,
                               (addr+aper_size) >> PAGE_SHIFT);
 
@@ -444,12 +430,8 @@ int __init gart_iommu_hole_init(void)
 
 out:
        if (!fix && !fallback_aper_force) {
-               if (last_aper_base) {
-                       unsigned long n = (32 * 1024 * 1024) << last_aper_order;
-
-                       insert_aperture_resource((u32)last_aper_base, n);
+               if (last_aper_base)
                        return 1;
-               }
                return 0;
        }
 
index 7f26c9a70a9e0ada12f46382d7ee2cd73b2d5f29..53e20531470ee1ee125c510bf0c26308f74820d3 100644 (file)
@@ -133,6 +133,10 @@ static inline void imcr_apic_to_pic(void)
  * +1=force-enable
  */
 static int force_enable_local_apic __initdata;
+
+/* Control whether x2APIC mode is enabled or not */
+static bool nox2apic __initdata;
+
 /*
  * APIC command line parameters
  */
@@ -162,8 +166,7 @@ int x2apic_mode;
 /* x2apic enabled before OS handover */
 int x2apic_preenabled;
 static int x2apic_disabled;
-static int nox2apic;
-static __init int setup_nox2apic(char *str)
+static int __init setup_nox2apic(char *str)
 {
        if (x2apic_enabled()) {
                int apicid = native_apic_msr_read(APIC_ID);
@@ -178,7 +181,7 @@ static __init int setup_nox2apic(char *str)
        } else
                setup_clear_cpu_cap(X86_FEATURE_X2APIC);
 
-       nox2apic = 1;
+       nox2apic = true;
 
        return 0;
 }
@@ -283,8 +286,12 @@ u32 native_safe_apic_wait_icr_idle(void)
 
 void native_apic_icr_write(u32 low, u32 id)
 {
+       unsigned long flags;
+
+       local_irq_save(flags);
        apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
        apic_write(APIC_ICR, low);
+       local_irq_restore(flags);
 }
 
 u64 native_apic_icr_read(void)
index 2c621a6b901a7642838c5a74a54be4bf3fcbe58a..7c1b29479513a1d78f79410915a4ee30e5d1c53e 100644 (file)
@@ -198,7 +198,7 @@ static struct apic apic_flat =  {
 
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-       .wait_for_init_deassert         = NULL,
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
 
@@ -314,7 +314,7 @@ static struct apic apic_physflat =  {
 
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-       .wait_for_init_deassert         = NULL,
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
 
index 191ce75c0e54b8f2808cce5f730f5d62c18dfa09..8c7c98249c205f0f596e7c0866e89444dc3d4bc8 100644 (file)
@@ -172,8 +172,7 @@ struct apic apic_noop = {
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 
-       .wait_for_init_deassert         = NULL,
-
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = NULL,
 
index 3e67f9e3d7ef1e8eb093d9e8398b21aaf1a7b93e..a5b45df8bc881cafbc2560f3b7ea72ef02aa7c73 100644 (file)
@@ -248,7 +248,7 @@ static const struct apic apic_numachip __refconst = {
        .wakeup_secondary_cpu           = numachip_wakeup_secondary,
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-       .wait_for_init_deassert         = NULL,
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = NULL, /* REMRD not supported */
 
index d50e3640d5aed53daf4110ef68193cf0cbdac826..e4840aa7a255b63db235ab5cecd07ecabf5c5013 100644 (file)
@@ -199,8 +199,7 @@ static struct apic apic_bigsmp = {
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 
-       .wait_for_init_deassert         = default_wait_for_init_deassert,
-
+       .wait_for_init_deassert         = true,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
 
index c55224731b2d7f0de89d6a37a00e71bd4d8792ec..6f8f8b348a39fbf378953936cc796d5e1842849f 100644 (file)
@@ -394,12 +394,6 @@ static void es7000_enable_apic_mode(void)
                WARN(1, "Command failed, status = %x\n", mip_status);
 }
 
-static void es7000_wait_for_init_deassert(atomic_t *deassert)
-{
-       while (!atomic_read(deassert))
-               cpu_relax();
-}
-
 static unsigned int es7000_get_apic_id(unsigned long x)
 {
        return (x >> 24) & 0xFF;
@@ -658,8 +652,7 @@ static struct apic __refdata apic_es7000_cluster = {
        .trampoline_phys_low            = 0x467,
        .trampoline_phys_high           = 0x469,
 
-       .wait_for_init_deassert         = NULL,
-
+       .wait_for_init_deassert         = false,
        /* Nothing to do for most platforms, since cleared by the INIT cycle: */
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
@@ -722,8 +715,7 @@ static struct apic __refdata apic_es7000 = {
        .trampoline_phys_low            = 0x467,
        .trampoline_phys_high           = 0x469,
 
-       .wait_for_init_deassert         = es7000_wait_for_init_deassert,
-
+       .wait_for_init_deassert         = true,
        /* Nothing to do for most platforms, since cleared by the INIT cycle: */
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
index 1e42e8f305ee2096ed52c20f6c569fe8a8339b7b..030ea1c04f72b3184e339ed840f7d13382641ba6 100644 (file)
@@ -505,8 +505,7 @@ static struct apic __refdata apic_numaq = {
        .trampoline_phys_high           = NUMAQ_TRAMPOLINE_PHYS_HIGH,
 
        /* We don't do anything here because we use NMI's to boot instead */
-       .wait_for_init_deassert         = NULL,
-
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = numaq_smp_callin_clear_local_apic,
        .inquire_remote_apic            = NULL,
 
index eb35ef9ee63f779bde870822a01dcc98bd503b01..cceb352c968c62b13404d3ce78478f64e7a5d3c5 100644 (file)
@@ -119,8 +119,7 @@ static struct apic apic_default = {
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 
-       .wait_for_init_deassert         = default_wait_for_init_deassert,
-
+       .wait_for_init_deassert         = true,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
 
index 00146f9b0254315acfb191015314fedf35fa9ab0..b656128611cd3ebd71af4ba0f053e72471845e21 100644 (file)
@@ -532,8 +532,7 @@ static struct apic apic_summit = {
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
 
-       .wait_for_init_deassert         = default_wait_for_init_deassert,
-
+       .wait_for_init_deassert         = true,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = default_inquire_remote_apic,
 
index cac85ee6913f70ca64f3a8656dbff5d5cc603348..e66766bf164191de15d7ea9bf7b62c6506b2d6f2 100644 (file)
@@ -279,7 +279,7 @@ static struct apic apic_x2apic_cluster = {
 
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-       .wait_for_init_deassert         = NULL,
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = NULL,
 
index de231e328cae310bf4a39a1fb70ebc83993bb67c..6d600ebf6c127f94c4bb194a9e8bb25f0c607ffe 100644 (file)
@@ -133,7 +133,7 @@ static struct apic apic_x2apic_phys = {
 
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-       .wait_for_init_deassert         = NULL,
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = NULL,
 
index d263b1307de1e5b30a114cc0f37c017197d5728f..7834389ba5be0952b5e673ff11d6a6c64cee106d 100644 (file)
@@ -396,7 +396,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
        .wakeup_secondary_cpu           = uv_wakeup_secondary,
        .trampoline_phys_low            = DEFAULT_TRAMPOLINE_PHYS_LOW,
        .trampoline_phys_high           = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-       .wait_for_init_deassert         = NULL,
+       .wait_for_init_deassert         = false,
        .smp_callin_clear_local_apic    = NULL,
        .inquire_remote_apic            = NULL,
 
index c67ffa6860642af5e487345f7fcf6badb8554f48..ce8b8ff0e0ef4e1915272431c9b543e303101264 100644 (file)
@@ -218,7 +218,7 @@ static void amd_k7_smp_check(struct cpuinfo_x86 *c)
         */
        WARN_ONCE(1, "WARNING: This combination of AMD"
                " processors is not suitable for SMP.\n");
-       add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE);
+       add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE);
 }
 
 static void init_amd_k7(struct cpuinfo_x86 *c)
@@ -233,9 +233,7 @@ static void init_amd_k7(struct cpuinfo_x86 *c)
        if (c->x86_model >= 6 && c->x86_model <= 10) {
                if (!cpu_has(c, X86_FEATURE_XMM)) {
                        printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
-                       rdmsr(MSR_K7_HWCR, l, h);
-                       l &= ~0x00008000;
-                       wrmsr(MSR_K7_HWCR, l, h);
+                       msr_clear_bit(MSR_K7_HWCR, 15);
                        set_cpu_cap(c, X86_FEATURE_XMM);
                }
        }
@@ -509,14 +507,8 @@ static void early_init_amd(struct cpuinfo_x86 *c)
 #endif
 
        /* F16h erratum 793, CVE-2013-6885 */
-       if (c->x86 == 0x16 && c->x86_model <= 0xf) {
-               u64 val;
-
-               rdmsrl(MSR_AMD64_LS_CFG, val);
-               if (!(val & BIT(15)))
-                       wrmsrl(MSR_AMD64_LS_CFG, val | BIT(15));
-       }
-
+       if (c->x86 == 0x16 && c->x86_model <= 0xf)
+               msr_set_bit(MSR_AMD64_LS_CFG, 15);
 }
 
 static const int amd_erratum_383[];
@@ -536,11 +528,8 @@ static void init_amd(struct cpuinfo_x86 *c)
         * Errata 63 for SH-B3 steppings
         * Errata 122 for all steppings (F+ have it disabled by default)
         */
-       if (c->x86 == 0xf) {
-               rdmsrl(MSR_K7_HWCR, value);
-               value |= 1 << 6;
-               wrmsrl(MSR_K7_HWCR, value);
-       }
+       if (c->x86 == 0xf)
+               msr_set_bit(MSR_K7_HWCR, 6);
 #endif
 
        early_init_amd(c);
@@ -623,14 +612,11 @@ static void init_amd(struct cpuinfo_x86 *c)
            (c->x86_model >= 0x10) && (c->x86_model <= 0x1f) &&
            !cpu_has(c, X86_FEATURE_TOPOEXT)) {
 
-               if (!rdmsrl_safe(0xc0011005, &value)) {
-                       value |= 1ULL << 54;
-                       wrmsrl_safe(0xc0011005, value);
+               if (msr_set_bit(0xc0011005, 54) > 0) {
                        rdmsrl(0xc0011005, value);
-                       if (value & (1ULL << 54)) {
+                       if (value & BIT_64(54)) {
                                set_cpu_cap(c, X86_FEATURE_TOPOEXT);
-                               printk(KERN_INFO FW_INFO "CPU: Re-enabling "
-                                 "disabled Topology Extensions Support\n");
+                               pr_info(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
                        }
                }
        }
@@ -709,19 +695,12 @@ static void init_amd(struct cpuinfo_x86 *c)
                 * Disable GART TLB Walk Errors on Fam10h. We do this here
                 * because this is always needed when GART is enabled, even in a
                 * kernel which has no MCE support built in.
-                * BIOS should disable GartTlbWlk Errors themself. If
-                * it doesn't do it here as suggested by the BKDG.
+                * BIOS should disable GartTlbWlk Errors already. If
+                * it doesn't, do it here as suggested by the BKDG.
                 *
                 * Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33012
                 */
-               u64 mask;
-               int err;
-
-               err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
-               if (err == 0) {
-                       mask |= (1 << 10);
-                       wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
-               }
+               msr_set_bit(MSR_AMD64_MCx_MASK(4), 10);
 
                /*
                 * On family 10h BIOS may not have properly enabled WC+ support,
@@ -733,10 +712,7 @@ static void init_amd(struct cpuinfo_x86 *c)
                 * NOTE: we want to use the _safe accessors so as not to #GP kvm
                 * guests on older kvm hosts.
                 */
-
-               rdmsrl_safe(MSR_AMD64_BU_CFG2, &value);
-               value &= ~(1ULL << 24);
-               wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
+               msr_clear_bit(MSR_AMD64_BU_CFG2, 24);
 
                if (cpu_has_amd_erratum(c, amd_erratum_383))
                        set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
index 8779edab684efdcd04fd93d22d79d4633c6fd4f9..d8fba5c15fbd8882f317daa2779c39ff4429b0d4 100644 (file)
@@ -8,236 +8,6 @@
 
 #include "cpu.h"
 
-#ifdef CONFIG_X86_OOSTORE
-
-static u32 power2(u32 x)
-{
-       u32 s = 1;
-
-       while (s <= x)
-               s <<= 1;
-
-       return s >>= 1;
-}
-
-
-/*
- * Set up an actual MCR
- */
-static void centaur_mcr_insert(int reg, u32 base, u32 size, int key)
-{
-       u32 lo, hi;
-
-       hi = base & ~0xFFF;
-       lo = ~(size-1);         /* Size is a power of 2 so this makes a mask */
-       lo &= ~0xFFF;           /* Remove the ctrl value bits */
-       lo |= key;              /* Attribute we wish to set */
-       wrmsr(reg+MSR_IDT_MCR0, lo, hi);
-       mtrr_centaur_report_mcr(reg, lo, hi);   /* Tell the mtrr driver */
-}
-
-/*
- * Figure what we can cover with MCR's
- *
- * Shortcut: We know you can't put 4Gig of RAM on a winchip
- */
-static u32 ramtop(void)
-{
-       u32 clip = 0xFFFFFFFFUL;
-       u32 top = 0;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long start, end;
-
-               if (e820.map[i].addr > 0xFFFFFFFFUL)
-                       continue;
-               /*
-                * Don't MCR over reserved space. Ignore the ISA hole
-                * we frob around that catastrophe already
-                */
-               if (e820.map[i].type == E820_RESERVED) {
-                       if (e820.map[i].addr >= 0x100000UL &&
-                           e820.map[i].addr < clip)
-                               clip = e820.map[i].addr;
-                       continue;
-               }
-               start = e820.map[i].addr;
-               end = e820.map[i].addr + e820.map[i].size;
-               if (start >= end)
-                       continue;
-               if (end > top)
-                       top = end;
-       }
-       /*
-        * Everything below 'top' should be RAM except for the ISA hole.
-        * Because of the limited MCR's we want to map NV/ACPI into our
-        * MCR range for gunk in RAM
-        *
-        * Clip might cause us to MCR insufficient RAM but that is an
-        * acceptable failure mode and should only bite obscure boxes with
-        * a VESA hole at 15Mb
-        *
-        * The second case Clip sometimes kicks in is when the EBDA is marked
-        * as reserved. Again we fail safe with reasonable results
-        */
-       if (top > clip)
-               top = clip;
-
-       return top;
-}
-
-/*
- * Compute a set of MCR's to give maximum coverage
- */
-static int centaur_mcr_compute(int nr, int key)
-{
-       u32 mem = ramtop();
-       u32 root = power2(mem);
-       u32 base = root;
-       u32 top = root;
-       u32 floor = 0;
-       int ct = 0;
-
-       while (ct < nr) {
-               u32 fspace = 0;
-               u32 high;
-               u32 low;
-
-               /*
-                * Find the largest block we will fill going upwards
-                */
-               high = power2(mem-top);
-
-               /*
-                * Find the largest block we will fill going downwards
-                */
-               low = base/2;
-
-               /*
-                * Don't fill below 1Mb going downwards as there
-                * is an ISA hole in the way.
-                */
-               if (base <= 1024*1024)
-                       low = 0;
-
-               /*
-                * See how much space we could cover by filling below
-                * the ISA hole
-                */
-
-               if (floor == 0)
-                       fspace = 512*1024;
-               else if (floor == 512*1024)
-                       fspace = 128*1024;
-
-               /* And forget ROM space */
-
-               /*
-                * Now install the largest coverage we get
-                */
-               if (fspace > high && fspace > low) {
-                       centaur_mcr_insert(ct, floor, fspace, key);
-                       floor += fspace;
-               } else if (high > low) {
-                       centaur_mcr_insert(ct, top, high, key);
-                       top += high;
-               } else if (low > 0) {
-                       base -= low;
-                       centaur_mcr_insert(ct, base, low, key);
-               } else
-                       break;
-               ct++;
-       }
-       /*
-        * We loaded ct values. We now need to set the mask. The caller
-        * must do this bit.
-        */
-       return ct;
-}
-
-static void centaur_create_optimal_mcr(void)
-{
-       int used;
-       int i;
-
-       /*
-        * Allocate up to 6 mcrs to mark as much of ram as possible
-        * as write combining and weak write ordered.
-        *
-        * To experiment with: Linux never uses stack operations for
-        * mmio spaces so we could globally enable stack operation wc
-        *
-        * Load the registers with type 31 - full write combining, all
-        * writes weakly ordered.
-        */
-       used = centaur_mcr_compute(6, 31);
-
-       /*
-        * Wipe unused MCRs
-        */
-       for (i = used; i < 8; i++)
-               wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-static void winchip2_create_optimal_mcr(void)
-{
-       u32 lo, hi;
-       int used;
-       int i;
-
-       /*
-        * Allocate up to 6 mcrs to mark as much of ram as possible
-        * as write combining, weak store ordered.
-        *
-        * Load the registers with type 25
-        *      8       -       weak write ordering
-        *      16      -       weak read ordering
-        *      1       -       write combining
-        */
-       used = centaur_mcr_compute(6, 25);
-
-       /*
-        * Mark the registers we are using.
-        */
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       for (i = 0; i < used; i++)
-               lo |= 1<<(9+i);
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-
-       /*
-        * Wipe unused MCRs
-        */
-
-       for (i = used; i < 8; i++)
-               wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-/*
- * Handle the MCR key on the Winchip 2.
- */
-static void winchip2_unprotect_mcr(void)
-{
-       u32 lo, hi;
-       u32 key;
-
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       lo &= ~0x1C0;   /* blank bits 8-6 */
-       key = (lo>>17) & 7;
-       lo |= key<<6;   /* replace with unlock key */
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-static void winchip2_protect_mcr(void)
-{
-       u32 lo, hi;
-
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       lo &= ~0x1C0;   /* blank bits 8-6 */
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-#endif /* CONFIG_X86_OOSTORE */
-
 #define ACE_PRESENT    (1 << 6)
 #define ACE_ENABLED    (1 << 7)
 #define ACE_FCR                (1 << 28)       /* MSR_VIA_FCR */
@@ -362,20 +132,6 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        fcr_clr = DPDC;
                        printk(KERN_NOTICE "Disabling bugged TSC.\n");
                        clear_cpu_cap(c, X86_FEATURE_TSC);
-#ifdef CONFIG_X86_OOSTORE
-                       centaur_create_optimal_mcr();
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        *
-                        * The C6 original lacks weak read order
-                        *
-                        * Note 0x120 is write only on Winchip 1
-                        */
-                       wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
-#endif
                        break;
                case 8:
                        switch (c->x86_mask) {
@@ -392,40 +148,12 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
                                  E2MMX|EAMD3D;
                        fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
-                       winchip2_unprotect_mcr();
-                       winchip2_create_optimal_mcr();
-                       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        */
-                       lo |= 31;
-                       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       winchip2_protect_mcr();
-#endif
                        break;
                case 9:
                        name = "3";
                        fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
                                  E2MMX|EAMD3D;
                        fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
-                       winchip2_unprotect_mcr();
-                       winchip2_create_optimal_mcr();
-                       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        */
-                       lo |= 31;
-                       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       winchip2_protect_mcr();
-#endif
                        break;
                default:
                        name = "??";
index 8e28bf2fc3ef4a15bf672dee29bc6729552556f2..a135239badb7fd4762ebf939ae755183660641b2 100644 (file)
@@ -1025,7 +1025,8 @@ __setup("show_msr=", setup_show_msr);
 
 static __init int setup_noclflush(char *arg)
 {
-       setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
+       setup_clear_cpu_cap(X86_FEATURE_CLFLUSH);
+       setup_clear_cpu_cap(X86_FEATURE_CLFLUSHOPT);
        return 1;
 }
 __setup("noclflush", setup_noclflush);
@@ -1078,6 +1079,10 @@ static __init int setup_disablecpuid(char *arg)
 }
 __setup("clearcpuid=", setup_disablecpuid);
 
+DEFINE_PER_CPU(unsigned long, kernel_stack) =
+       (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
+EXPORT_PER_CPU_SYMBOL(kernel_stack);
+
 #ifdef CONFIG_X86_64
 struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
 struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
@@ -1094,10 +1099,6 @@ DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
        &init_task;
 EXPORT_PER_CPU_SYMBOL(current_task);
 
-DEFINE_PER_CPU(unsigned long, kernel_stack) =
-       (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
-EXPORT_PER_CPU_SYMBOL(kernel_stack);
-
 DEFINE_PER_CPU(char *, irq_stack_ptr) =
        init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
 
index 5cd9bfabd6450e6743dc03479dad8cba38f9eec9..897d6201ef10b25ca98b3ea66ab4ff1706d5c81d 100644 (file)
@@ -31,11 +31,8 @@ static void early_init_intel(struct cpuinfo_x86 *c)
 
        /* Unmask CPUID levels if masked: */
        if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) {
-               rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-
-               if (misc_enable & MSR_IA32_MISC_ENABLE_LIMIT_CPUID) {
-                       misc_enable &= ~MSR_IA32_MISC_ENABLE_LIMIT_CPUID;
-                       wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+               if (msr_clear_bit(MSR_IA32_MISC_ENABLE,
+                                 MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) > 0) {
                        c->cpuid_level = cpuid_eax(0);
                        get_cpu_cap(c);
                }
@@ -129,16 +126,10 @@ static void early_init_intel(struct cpuinfo_x86 *c)
         * Ingo Molnar reported a Pentium D (model 6) and a Xeon
         * (model 2) with the same problem.
         */
-       if (c->x86 == 15) {
-               rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-
-               if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) {
-                       printk(KERN_INFO "kmemcheck: Disabling fast string operations\n");
-
-                       misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING;
-                       wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-               }
-       }
+       if (c->x86 == 15)
+               if (msr_clear_bit(MSR_IA32_MISC_ENABLE,
+                                 MSR_IA32_MISC_ENABLE_FAST_STRING_BIT) > 0)
+                       pr_info("kmemcheck: Disabling fast string operations\n");
 #endif
 
        /*
@@ -195,10 +186,16 @@ static void intel_smp_check(struct cpuinfo_x86 *c)
        }
 }
 
-static void intel_workarounds(struct cpuinfo_x86 *c)
+static int forcepae;
+static int __init forcepae_setup(char *__unused)
 {
-       unsigned long lo, hi;
+       forcepae = 1;
+       return 1;
+}
+__setup("forcepae", forcepae_setup);
 
+static void intel_workarounds(struct cpuinfo_x86 *c)
+{
 #ifdef CONFIG_X86_F00F_BUG
        /*
         * All current models of Pentium and Pentium with MMX technology CPUs
@@ -224,17 +221,27 @@ static void intel_workarounds(struct cpuinfo_x86 *c)
        if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
                clear_cpu_cap(c, X86_FEATURE_SEP);
 
+       /*
+        * PAE CPUID issue: many Pentium M report no PAE but may have a
+        * functionally usable PAE implementation.
+        * Forcefully enable PAE if kernel parameter "forcepae" is present.
+        */
+       if (forcepae) {
+               printk(KERN_WARNING "PAE forced!\n");
+               set_cpu_cap(c, X86_FEATURE_PAE);
+               add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE);
+       }
+
        /*
         * P4 Xeon errata 037 workaround.
         * Hardware prefetcher may cause stale data to be loaded into the cache.
         */
        if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
-               rdmsr(MSR_IA32_MISC_ENABLE, lo, hi);
-               if ((lo & MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE) == 0) {
-                       printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
-                       printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
-                       lo |= MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE;
-                       wrmsr(MSR_IA32_MISC_ENABLE, lo, hi);
+               if (msr_set_bit(MSR_IA32_MISC_ENABLE,
+                               MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
+                   > 0) {
+                       pr_info("CPU: C0 stepping P4 Xeon detected.\n");
+                       pr_info("CPU: Disabling hardware prefetching (Errata 037)\n");
                }
        }
 
index 9f7ca266864a47cbb5484fead33a063d48f01f27..76f98fe5b35c4a2f3860b762b54f039cb7ad642c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/hardirq.h>
 #include <linux/efi.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/processor.h>
 #include <asm/hypervisor.h>
 #include <asm/hyperv.h>
 #include <asm/irq_regs.h>
 #include <asm/i8259.h>
 #include <asm/apic.h>
+#include <asm/timer.h>
 
 struct ms_hyperv_info ms_hyperv;
 EXPORT_SYMBOL_GPL(ms_hyperv);
 
+#if IS_ENABLED(CONFIG_HYPERV)
+static void (*vmbus_handler)(void);
+
+void hyperv_vector_handler(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       irq_enter();
+       exit_idle();
+
+       inc_irq_stat(irq_hv_callback_count);
+       if (vmbus_handler)
+               vmbus_handler();
+
+       irq_exit();
+       set_irq_regs(old_regs);
+}
+
+void hv_setup_vmbus_irq(void (*handler)(void))
+{
+       vmbus_handler = handler;
+       /*
+        * Setup the IDT for hypervisor callback. Prevent reallocation
+        * at module reload.
+        */
+       if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
+               alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
+                               hyperv_callback_vector);
+}
+
+void hv_remove_vmbus_irq(void)
+{
+       /* We have no way to deallocate the interrupt gate */
+       vmbus_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
+EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
+#endif
+
 static uint32_t  __init ms_hyperv_platform(void)
 {
        u32 eax;
@@ -105,6 +146,11 @@ static void __init ms_hyperv_init_platform(void)
 
        if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
                clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+
+#ifdef CONFIG_X86_IO_APIC
+       no_timer_check = 1;
+#endif
+
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -113,41 +159,3 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
        .init_platform          = ms_hyperv_init_platform,
 };
 EXPORT_SYMBOL(x86_hyper_ms_hyperv);
-
-#if IS_ENABLED(CONFIG_HYPERV)
-static int vmbus_irq = -1;
-static irq_handler_t vmbus_isr;
-
-void hv_register_vmbus_handler(int irq, irq_handler_t handler)
-{
-       /*
-        * Setup the IDT for hypervisor callback.
-        */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
-
-       vmbus_irq = irq;
-       vmbus_isr = handler;
-}
-
-void hyperv_vector_handler(struct pt_regs *regs)
-{
-       struct pt_regs *old_regs = set_irq_regs(regs);
-       struct irq_desc *desc;
-
-       irq_enter();
-       exit_idle();
-
-       desc = irq_to_desc(vmbus_irq);
-
-       if (desc)
-               generic_handle_irq_desc(vmbus_irq, desc);
-
-       irq_exit();
-       set_irq_regs(old_regs);
-}
-#else
-void hv_register_vmbus_handler(int irq, irq_handler_t handler)
-{
-}
-#endif
-EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
index 79f9f848bee4b1c021b80bed07e0dcbcec88a20b..ae407f7226c89961fde14ddd6d932f174c64d8fc 100644 (file)
@@ -892,7 +892,6 @@ static void x86_pmu_enable(struct pmu *pmu)
                 * hw_perf_group_sched_in() or x86_pmu_enable()
                 *
                 * step1: save events moving to new counters
-                * step2: reprogram moved events into new counters
                 */
                for (i = 0; i < n_running; i++) {
                        event = cpuc->event_list[i];
@@ -918,6 +917,9 @@ static void x86_pmu_enable(struct pmu *pmu)
                        x86_pmu_stop(event, PERF_EF_UPDATE);
                }
 
+               /*
+                * step2: reprogram moved events into new counters
+                */
                for (i = 0; i < cpuc->n_events; i++) {
                        event = cpuc->event_list[i];
                        hwc = &event->hw;
@@ -1043,7 +1045,7 @@ static int x86_pmu_add(struct perf_event *event, int flags)
        /*
         * If group events scheduling transaction was started,
         * skip the schedulability test here, it will be performed
-        * at commit time (->commit_txn) as a whole
+        * at commit time (->commit_txn) as a whole.
         */
        if (cpuc->group_flag & PERF_EVENT_TXN)
                goto done_collect;
@@ -1058,6 +1060,10 @@ static int x86_pmu_add(struct perf_event *event, int flags)
        memcpy(cpuc->assign, assign, n*sizeof(int));
 
 done_collect:
+       /*
+        * Commit the collect_events() state. See x86_pmu_del() and
+        * x86_pmu_*_txn().
+        */
        cpuc->n_events = n;
        cpuc->n_added += n - n0;
        cpuc->n_txn += n - n0;
@@ -1183,28 +1189,38 @@ static void x86_pmu_del(struct perf_event *event, int flags)
         * If we're called during a txn, we don't need to do anything.
         * The events never got scheduled and ->cancel_txn will truncate
         * the event_list.
+        *
+        * XXX assumes any ->del() called during a TXN will only be on
+        * an event added during that same TXN.
         */
        if (cpuc->group_flag & PERF_EVENT_TXN)
                return;
 
+       /*
+        * Not a TXN, therefore cleanup properly.
+        */
        x86_pmu_stop(event, PERF_EF_UPDATE);
 
        for (i = 0; i < cpuc->n_events; i++) {
-               if (event == cpuc->event_list[i]) {
+               if (event == cpuc->event_list[i])
+                       break;
+       }
 
-                       if (i >= cpuc->n_events - cpuc->n_added)
-                               --cpuc->n_added;
+       if (WARN_ON_ONCE(i == cpuc->n_events)) /* called ->del() without ->add() ? */
+               return;
 
-                       if (x86_pmu.put_event_constraints)
-                               x86_pmu.put_event_constraints(cpuc, event);
+       /* If we have a newly added event; make sure to decrease n_added. */
+       if (i >= cpuc->n_events - cpuc->n_added)
+               --cpuc->n_added;
 
-                       while (++i < cpuc->n_events)
-                               cpuc->event_list[i-1] = cpuc->event_list[i];
+       if (x86_pmu.put_event_constraints)
+               x86_pmu.put_event_constraints(cpuc, event);
+
+       /* Delete the array entry. */
+       while (++i < cpuc->n_events)
+               cpuc->event_list[i-1] = cpuc->event_list[i];
+       --cpuc->n_events;
 
-                       --cpuc->n_events;
-                       break;
-               }
-       }
        perf_event_update_userpage(event);
 }
 
@@ -1598,7 +1614,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
 {
        __this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN);
        /*
-        * Truncate the collected events.
+        * Truncate collected array by the number of events added in this
+        * transaction. See x86_pmu_add() and x86_pmu_*_txn().
         */
        __this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn));
        __this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn));
@@ -1609,6 +1626,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
  * Commit group events scheduling transaction
  * Perform the group schedulability test as a whole
  * Return 0 if success
+ *
+ * Does not cancel the transaction on failure; expects the caller to do this.
  */
 static int x86_pmu_commit_txn(struct pmu *pmu)
 {
index 4972c244d0bc2fbe445706943e0248073fd17a26..3b2f9bdd974be198d0622e306ddbba427add2d25 100644 (file)
@@ -130,9 +130,11 @@ struct cpu_hw_events {
        unsigned long           running[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
        int                     enabled;
 
-       int                     n_events;
-       int                     n_added;
-       int                     n_txn;
+       int                     n_events; /* the # of events in the below arrays */
+       int                     n_added;  /* the # last events in the below arrays;
+                                            they've never been enabled yet */
+       int                     n_txn;    /* the # last events in the below arrays;
+                                            added in the current transaction */
        int                     assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
        u64                     tags[X86_PMC_IDX_MAX];
        struct perf_event       *event_list[X86_PMC_IDX_MAX]; /* in enabled order */
index c88f7f4b03ee063ba090ec1e53c864fa4279fdec..bd2253d40cffe16363569384084bdf6d6d73e7f5 100644 (file)
@@ -66,6 +66,47 @@ DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
 DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
 DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
 
+static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+static void uncore_pmu_event_read(struct perf_event *event);
+
+static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
+{
+       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
+}
+
+static struct intel_uncore_box *
+uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
+{
+       struct intel_uncore_box *box;
+
+       box = *per_cpu_ptr(pmu->box, cpu);
+       if (box)
+               return box;
+
+       raw_spin_lock(&uncore_box_lock);
+       list_for_each_entry(box, &pmu->box_list, list) {
+               if (box->phys_id == topology_physical_package_id(cpu)) {
+                       atomic_inc(&box->refcnt);
+                       *per_cpu_ptr(pmu->box, cpu) = box;
+                       break;
+               }
+       }
+       raw_spin_unlock(&uncore_box_lock);
+
+       return *per_cpu_ptr(pmu->box, cpu);
+}
+
+static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
+{
+       /*
+        * perf core schedules event on the basis of cpu, uncore events are
+        * collected by one of the cpus inside a physical package.
+        */
+       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+}
+
 static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
 {
        u64 count;
@@ -1639,6 +1680,349 @@ static struct intel_uncore_type *snb_msr_uncores[] = {
        &snb_uncore_cbox,
        NULL,
 };
+
+enum {
+       SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+       { /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK          0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET          0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE            0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS          0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE     0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES         0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+       .name = "format",
+       .attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
+       resource_size_t addr;
+       u32 pci_dword;
+
+       pci_read_config_dword(pdev, where, &pci_dword);
+       addr = pci_dword;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       pci_read_config_dword(pdev, where + 4, &pci_dword);
+       addr |= ((resource_size_t)pci_dword << 32);
+#endif
+
+       addr &= ~(PAGE_SIZE - 1);
+
+       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+       box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+       int idx, base;
+
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       pmu = uncore_event_to_pmu(event);
+       /* no device found for this pmu */
+       if (pmu->func_id < 0)
+               return -ENOENT;
+
+       /* Sampling not supported yet */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       /* unsupported modes and filters */
+       if (event->attr.exclude_user   ||
+           event->attr.exclude_kernel ||
+           event->attr.exclude_hv     ||
+           event->attr.exclude_idle   ||
+           event->attr.exclude_host   ||
+           event->attr.exclude_guest  ||
+           event->attr.sample_period) /* no sampling */
+               return -EINVAL;
+
+       /*
+        * Place all uncore events for a particular physical package
+        * onto a single cpu
+        */
+       if (event->cpu < 0)
+               return -EINVAL;
+
+       /* check only supported bits are set */
+       if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+               return -EINVAL;
+
+       box = uncore_pmu_to_box(pmu, event->cpu);
+       if (!box || box->cpu < 0)
+               return -EINVAL;
+
+       event->cpu = box->cpu;
+
+       event->hw.idx = -1;
+       event->hw.last_tag = ~0ULL;
+       event->hw.extra_reg.idx = EXTRA_REG_NONE;
+       event->hw.branch_reg.idx = EXTRA_REG_NONE;
+       /*
+        * check event is known (whitelist, determines counter)
+        */
+       switch (cfg) {
+       case SNB_UNCORE_PCI_IMC_DATA_READS:
+               base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+               idx = UNCORE_PMC_IDX_FIXED;
+               break;
+       case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+               base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+               idx = UNCORE_PMC_IDX_FIXED + 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* must be done before validate_group */
+       event->hw.event_base = base;
+       event->hw.config = cfg;
+       event->hw.idx = idx;
+
+       /* no group validation needed, we have free running counters */
+
+       return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       u64 count;
+
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       event->hw.state = 0;
+       box->n_active++;
+
+       list_add_tail(&event->active_entry, &box->active_list);
+
+       count = snb_uncore_imc_read_counter(box, event);
+       local64_set(&event->hw.prev_count, count);
+
+       if (box->n_active == 1)
+               uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               box->n_active--;
+
+               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+               hwc->state |= PERF_HES_STOPPED;
+
+               list_del(&event->active_entry);
+
+               if (box->n_active == 0)
+                       uncore_pmu_cancel_hrtimer(box);
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               /*
+                * Drain the remaining delta count out of a event
+                * that we are disabling:
+                */
+               uncore_perf_event_update(box, event);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
+}
+
+static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!box)
+               return -ENODEV;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_ARCH;
+
+       snb_uncore_imc_event_start(event, 0);
+
+       box->n_events++;
+
+       return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       int i;
+
+       snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+       for (i = 0; i < box->n_events; i++) {
+               if (event == box->event_list[i]) {
+                       --box->n_events;
+                       break;
+               }
+       }
+}
+
+static int snb_pci2phy_map_init(int devid)
+{
+       struct pci_dev *dev = NULL;
+       int bus;
+
+       dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+       if (!dev)
+               return -ENOTTY;
+
+       bus = dev->bus->number;
+
+       pcibus_to_physid[bus] = 0;
+
+       pci_dev_put(dev);
+
+       return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+       .task_ctx_nr    = perf_invalid_context,
+       .event_init     = snb_uncore_imc_event_init,
+       .add            = snb_uncore_imc_event_add,
+       .del            = snb_uncore_imc_event_del,
+       .start          = snb_uncore_imc_event_start,
+       .stop           = snb_uncore_imc_event_stop,
+       .read           = uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+       .init_box       = snb_uncore_imc_init_box,
+       .enable_box     = snb_uncore_imc_enable_box,
+       .disable_box    = snb_uncore_imc_disable_box,
+       .disable_event  = snb_uncore_imc_disable_event,
+       .enable_event   = snb_uncore_imc_enable_event,
+       .hw_config      = snb_uncore_imc_hw_config,
+       .read_counter   = snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .fixed_ctr_bits = 32,
+       .fixed_ctr      = SNB_UNCORE_PCI_IMC_CTR_BASE,
+       .event_descs    = snb_uncore_imc_events,
+       .format_group   = &snb_uncore_imc_format_group,
+       .perf_ctr       = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+       .event_mask     = SNB_UNCORE_PCI_IMC_EVENT_MASK,
+       .ops            = &snb_uncore_imc_ops,
+       .pmu            = &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+       [SNB_PCI_UNCORE_IMC]    = &snb_uncore_imc,
+       NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(snb_uncore_pci_ids) = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ivb_uncore_pci_ids) = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hsw_uncore_pci_ids) = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+       .name           = "snb_uncore",
+       .id_table       = snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+       .name           = "ivb_uncore",
+       .id_table       = ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+       .name           = "hsw_uncore",
+       .id_table       = hsw_uncore_pci_ids,
+};
+
 /* end of Sandy Bridge uncore support */
 
 /* Nehalem uncore support */
@@ -2789,6 +3173,7 @@ again:
 static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
 {
        struct intel_uncore_box *box;
+       struct perf_event *event;
        unsigned long flags;
        int bit;
 
@@ -2801,19 +3186,27 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
         */
        local_irq_save(flags);
 
+       /*
+        * handle boxes with an active event list as opposed to active
+        * counters
+        */
+       list_for_each_entry(event, &box->active_list, active_entry) {
+               uncore_perf_event_update(box, event);
+       }
+
        for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX)
                uncore_perf_event_update(box, box->events[bit]);
 
        local_irq_restore(flags);
 
-       hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL));
+       hrtimer_forward_now(hrtimer, ns_to_ktime(box->hrtimer_duration));
        return HRTIMER_RESTART;
 }
 
 static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
 {
        __hrtimer_start_range_ns(&box->hrtimer,
-                       ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0,
+                       ns_to_ktime(box->hrtimer_duration), 0,
                        HRTIMER_MODE_REL_PINNED, 0);
 }
 
@@ -2847,43 +3240,12 @@ static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
        box->cpu = -1;
        box->phys_id = -1;
 
-       return box;
-}
-
-static struct intel_uncore_box *
-uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
-{
-       struct intel_uncore_box *box;
-
-       box = *per_cpu_ptr(pmu->box, cpu);
-       if (box)
-               return box;
-
-       raw_spin_lock(&uncore_box_lock);
-       list_for_each_entry(box, &pmu->box_list, list) {
-               if (box->phys_id == topology_physical_package_id(cpu)) {
-                       atomic_inc(&box->refcnt);
-                       *per_cpu_ptr(pmu->box, cpu) = box;
-                       break;
-               }
-       }
-       raw_spin_unlock(&uncore_box_lock);
-
-       return *per_cpu_ptr(pmu->box, cpu);
-}
+       /* set default hrtimer timeout */
+       box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
 
-static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
-{
-       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
-}
+       INIT_LIST_HEAD(&box->active_list);
 
-static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
-{
-       /*
-        * perf core schedules event on the basis of cpu, uncore events are
-        * collected by one of the cpus inside a physical package.
-        */
-       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+       return box;
 }
 
 static int
@@ -3279,16 +3641,21 @@ static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
 {
        int ret;
 
-       pmu->pmu = (struct pmu) {
-               .attr_groups    = pmu->type->attr_groups,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = uncore_pmu_event_init,
-               .add            = uncore_pmu_event_add,
-               .del            = uncore_pmu_event_del,
-               .start          = uncore_pmu_event_start,
-               .stop           = uncore_pmu_event_stop,
-               .read           = uncore_pmu_event_read,
-       };
+       if (!pmu->type->pmu) {
+               pmu->pmu = (struct pmu) {
+                       .attr_groups    = pmu->type->attr_groups,
+                       .task_ctx_nr    = perf_invalid_context,
+                       .event_init     = uncore_pmu_event_init,
+                       .add            = uncore_pmu_event_add,
+                       .del            = uncore_pmu_event_del,
+                       .start          = uncore_pmu_event_start,
+                       .stop           = uncore_pmu_event_stop,
+                       .read           = uncore_pmu_event_read,
+               };
+       } else {
+               pmu->pmu = *pmu->type->pmu;
+               pmu->pmu.attr_groups = pmu->type->attr_groups;
+       }
 
        if (pmu->type->num_boxes == 1) {
                if (strlen(pmu->type->name) > 0)
@@ -3334,6 +3701,8 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
        if (!pmus)
                return -ENOMEM;
 
+       type->pmus = pmus;
+
        type->unconstrainted = (struct event_constraint)
                __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
                                0, type->num_counters, 0, 0);
@@ -3369,7 +3738,6 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
        }
 
        type->pmu_group = &uncore_pmu_attr_group;
-       type->pmus = pmus;
        return 0;
 fail:
        uncore_type_exit(type);
@@ -3501,6 +3869,28 @@ static int __init uncore_pci_init(void)
                pci_uncores = ivt_pci_uncores;
                uncore_pci_driver = &ivt_uncore_pci_driver;
                break;
+       case 42: /* Sandy Bridge */
+               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC);
+               if (ret)
+                       return ret;
+               pci_uncores = snb_pci_uncores;
+               uncore_pci_driver = &snb_uncore_pci_driver;
+               break;
+       case 58: /* Ivy Bridge */
+               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC);
+               if (ret)
+                       return ret;
+               pci_uncores = snb_pci_uncores;
+               uncore_pci_driver = &ivb_uncore_pci_driver;
+               break;
+       case 60: /* Haswell */
+       case 69: /* Haswell Celeron */
+               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC);
+               if (ret)
+                       return ret;
+               pci_uncores = snb_pci_uncores;
+               uncore_pci_driver = &hsw_uncore_pci_driver;
+               break;
        default:
                return 0;
        }
@@ -3772,7 +4162,7 @@ static void __init uncore_cpu_setup(void *dummy)
 
 static int __init uncore_cpu_init(void)
 {
-       int ret, cpu, max_cores;
+       int ret, max_cores;
 
        max_cores = boot_cpu_data.x86_max_cores;
        switch (boot_cpu_data.x86_model) {
@@ -3816,29 +4206,6 @@ static int __init uncore_cpu_init(void)
        if (ret)
                return ret;
 
-       get_online_cpus();
-
-       for_each_online_cpu(cpu) {
-               int i, phys_id = topology_physical_package_id(cpu);
-
-               for_each_cpu(i, &uncore_cpu_mask) {
-                       if (phys_id == topology_physical_package_id(i)) {
-                               phys_id = -1;
-                               break;
-                       }
-               }
-               if (phys_id < 0)
-                       continue;
-
-               uncore_cpu_prepare(cpu, phys_id);
-               uncore_event_init_cpu(cpu);
-       }
-       on_each_cpu(uncore_cpu_setup, NULL, 1);
-
-       register_cpu_notifier(&uncore_cpu_nb);
-
-       put_online_cpus();
-
        return 0;
 }
 
@@ -3867,6 +4234,41 @@ static int __init uncore_pmus_register(void)
        return 0;
 }
 
+static void __init uncore_cpumask_init(void)
+{
+       int cpu;
+
+       /*
+        * ony invoke once from msr or pci init code
+        */
+       if (!cpumask_empty(&uncore_cpu_mask))
+               return;
+
+       get_online_cpus();
+
+       for_each_online_cpu(cpu) {
+               int i, phys_id = topology_physical_package_id(cpu);
+
+               for_each_cpu(i, &uncore_cpu_mask) {
+                       if (phys_id == topology_physical_package_id(i)) {
+                               phys_id = -1;
+                               break;
+                       }
+               }
+               if (phys_id < 0)
+                       continue;
+
+               uncore_cpu_prepare(cpu, phys_id);
+               uncore_event_init_cpu(cpu);
+       }
+       on_each_cpu(uncore_cpu_setup, NULL, 1);
+
+       register_cpu_notifier(&uncore_cpu_nb);
+
+       put_online_cpus();
+}
+
+
 static int __init intel_uncore_init(void)
 {
        int ret;
@@ -3885,6 +4287,7 @@ static int __init intel_uncore_init(void)
                uncore_pci_exit();
                goto fail;
        }
+       uncore_cpumask_init();
 
        uncore_pmus_register();
        return 0;
index a80ab71a883de06be3cbed3a8c0848aa1dfff69a..90236f0c94a90679506973efe6e56c51bfb9bb2f 100644 (file)
@@ -6,6 +6,7 @@
 
 #define UNCORE_PMU_NAME_LEN            32
 #define UNCORE_PMU_HRTIMER_INTERVAL    (60LL * NSEC_PER_SEC)
+#define UNCORE_SNB_IMC_HRTIMER_INTERVAL (5ULL * NSEC_PER_SEC)
 
 #define UNCORE_FIXED_EVENT             0xff
 #define UNCORE_PMC_IDX_MAX_GENERIC     8
@@ -440,6 +441,7 @@ struct intel_uncore_type {
        struct intel_uncore_ops *ops;
        struct uncore_event_desc *event_descs;
        const struct attribute_group *attr_groups[4];
+       struct pmu *pmu; /* for custom pmu ops */
 };
 
 #define pmu_group attr_groups[0]
@@ -488,8 +490,11 @@ struct intel_uncore_box {
        u64 tags[UNCORE_PMC_IDX_MAX];
        struct pci_dev *pci_dev;
        struct intel_uncore_pmu *pmu;
+       u64 hrtimer_duration; /* hrtimer timeout for this box */
        struct hrtimer hrtimer;
        struct list_head list;
+       struct list_head active_list;
+       void *io_addr;
        struct intel_uncore_extra_reg shared_regs[0];
 };
 
index 3486e6660357e7b365f59c279d748b188a6e72e4..5d466b7d8609814355c90e2cf09ced760debd458 100644 (file)
@@ -1257,7 +1257,24 @@ again:
                        pass++;
                        goto again;
                }
-
+               /*
+                * Perf does test runs to see if a whole group can be assigned
+                * together succesfully.  There can be multiple rounds of this.
+                * Unfortunately, p4_pmu_swap_config_ts touches the hwc->config
+                * bits, such that the next round of group assignments will
+                * cause the above p4_should_swap_ts to pass instead of fail.
+                * This leads to counters exclusive to thread0 being used by
+                * thread1.
+                *
+                * Solve this with a cheap hack, reset the idx back to -1 to
+                * force a new lookup (p4_next_cntr) to get the right counter
+                * for the right thread.
+                *
+                * This probably doesn't comply with the general spirit of how
+                * perf wants to work, but P4 is special. :-(
+                */
+               if (p4_should_swap_ts(hwc->config, cpu))
+                       hwc->idx = -1;
                p4_pmu_swap_config_ts(hwc, cpu);
                if (assign)
                        assign[i] = cntr_idx;
@@ -1322,6 +1339,7 @@ static __initconst const struct x86_pmu p4_pmu = {
 __init int p4_pmu_init(void)
 {
        unsigned int low, high;
+       int i, reg;
 
        /* If we get stripped -- indexing fails */
        BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC);
@@ -1340,5 +1358,19 @@ __init int p4_pmu_init(void)
 
        x86_pmu = p4_pmu;
 
+       /*
+        * Even though the counters are configured to interrupt a particular
+        * logical processor when an overflow happens, testing has shown that
+        * on kdump kernels (which uses a single cpu), thread1's counter
+        * continues to run and will report an NMI on thread0.  Due to the
+        * overflow bug, this leads to a stream of unknown NMIs.
+        *
+        * Solve this by zero'ing out the registers to mimic a reset.
+        */
+       for (i = 0; i < x86_pmu.num_counters; i++) {
+               reg = x86_pmu_config_addr(i);
+               wrmsrl_safe(reg, 0ULL);
+       }
+
        return 0;
 }
index a57902efe2d597be4af85c9d52d995360d54dadb..507de80665942b87a148e032fd8aeedfeb76c70b 100644 (file)
@@ -57,9 +57,7 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
 {
 #ifdef CONFIG_X86_32
        struct pt_regs fixed_regs;
-#endif
 
-#ifdef CONFIG_X86_32
        if (!user_mode_vm(regs)) {
                crash_fixup_ss_esp(&fixed_regs, regs);
                regs = &fixed_regs;
index f2a1770ca176381b843f9ab6f08327e55a9a3d6c..5abd4cd4230c69f3ff4730e97a1297be40013c44 100644 (file)
 
 #include <asm/stacktrace.h>
 
+static void *is_irq_stack(void *p, void *irq)
+{
+       if (p < irq || p >= (irq + THREAD_SIZE))
+               return NULL;
+       return irq + THREAD_SIZE;
+}
+
+
+static void *is_hardirq_stack(unsigned long *stack, int cpu)
+{
+       void *irq = per_cpu(hardirq_stack, cpu);
+
+       return is_irq_stack(stack, irq);
+}
+
+static void *is_softirq_stack(unsigned long *stack, int cpu)
+{
+       void *irq = per_cpu(softirq_stack, cpu);
+
+       return is_irq_stack(stack, irq);
+}
 
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
 {
+       const unsigned cpu = get_cpu();
        int graph = 0;
+       u32 *prev_esp;
 
        if (!task)
                task = current;
@@ -30,7 +53,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long dummy;
 
                stack = &dummy;
-               if (task && task != current)
+               if (task != current)
                        stack = (unsigned long *)task->thread.sp;
        }
 
@@ -39,18 +62,31 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
 
        for (;;) {
                struct thread_info *context;
+               void *end_stack;
+
+               end_stack = is_hardirq_stack(stack, cpu);
+               if (!end_stack)
+                       end_stack = is_softirq_stack(stack, cpu);
 
-               context = (struct thread_info *)
-                       ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-               bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
+               context = task_thread_info(task);
+               bp = ops->walk_stack(context, stack, bp, ops, data,
+                                    end_stack, &graph);
 
-               stack = (unsigned long *)context->previous_esp;
+               /* Stop if not on irq stack */
+               if (!end_stack)
+                       break;
+
+               /* The previous esp is saved on the bottom of the stack */
+               prev_esp = (u32 *)(end_stack - THREAD_SIZE);
+               stack = (unsigned long *)*prev_esp;
                if (!stack)
                        break;
+
                if (ops->stack(data, "IRQ") < 0)
                        break;
                touch_nmi_watchdog();
        }
+       put_cpu();
 }
 EXPORT_SYMBOL(dump_trace);
 
index addb207dab92d11ebe4d48650babe07db36a1539..346b1df2412e238a35a558f66ec2b210b4710bf7 100644 (file)
@@ -104,6 +104,45 @@ in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
        return (stack >= irq_stack && stack < irq_stack_end);
 }
 
+static const unsigned long irq_stack_size =
+       (IRQ_STACK_SIZE - 64) / sizeof(unsigned long);
+
+enum stack_type {
+       STACK_IS_UNKNOWN,
+       STACK_IS_NORMAL,
+       STACK_IS_EXCEPTION,
+       STACK_IS_IRQ,
+};
+
+static enum stack_type
+analyze_stack(int cpu, struct task_struct *task,
+             unsigned long *stack, unsigned long **stack_end, char **id)
+{
+       unsigned long *irq_stack;
+       unsigned long addr;
+       unsigned used = 0;
+
+       addr = ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+       if ((unsigned long)task_stack_page(task) == addr)
+               return STACK_IS_NORMAL;
+
+       *stack_end = in_exception_stack(cpu, (unsigned long)stack,
+                                        &used, id);
+       if (*stack_end)
+               return STACK_IS_EXCEPTION;
+
+       *stack_end = (unsigned long *)per_cpu(irq_stack_ptr, cpu);
+       if (!*stack_end)
+               return STACK_IS_UNKNOWN;
+
+       irq_stack = *stack_end - irq_stack_size;
+
+       if (in_irq_stack(stack, irq_stack, *stack_end))
+               return STACK_IS_IRQ;
+
+       return STACK_IS_UNKNOWN;
+}
+
 /*
  * x86-64 can have up to three kernel stacks:
  * process stack
@@ -116,12 +155,11 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                const struct stacktrace_ops *ops, void *data)
 {
        const unsigned cpu = get_cpu();
-       unsigned long *irq_stack_end =
-               (unsigned long *)per_cpu(irq_stack_ptr, cpu);
-       unsigned used = 0;
        struct thread_info *tinfo;
-       int graph = 0;
+       unsigned long *irq_stack;
        unsigned long dummy;
+       int graph = 0;
+       int done = 0;
 
        if (!task)
                task = current;
@@ -143,49 +181,60 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
         * exceptions
         */
        tinfo = task_thread_info(task);
-       for (;;) {
+       while (!done) {
+               unsigned long *stack_end;
+               enum stack_type stype;
                char *id;
-               unsigned long *estack_end;
-               estack_end = in_exception_stack(cpu, (unsigned long)stack,
-                                               &used, &id);
 
-               if (estack_end) {
+               stype = analyze_stack(cpu, task, stack, &stack_end, &id);
+
+               /* Default finish unless specified to continue */
+               done = 1;
+
+               switch (stype) {
+
+               /* Break out early if we are on the thread stack */
+               case STACK_IS_NORMAL:
+                       break;
+
+               case STACK_IS_EXCEPTION:
+
                        if (ops->stack(data, id) < 0)
                                break;
 
                        bp = ops->walk_stack(tinfo, stack, bp, ops,
-                                            data, estack_end, &graph);
+                                            data, stack_end, &graph);
                        ops->stack(data, "<EOE>");
                        /*
                         * We link to the next stack via the
                         * second-to-last pointer (index -2 to end) in the
                         * exception stack:
                         */
-                       stack = (unsigned long *) estack_end[-2];
-                       continue;
-               }
-               if (irq_stack_end) {
-                       unsigned long *irq_stack;
-                       irq_stack = irq_stack_end -
-                               (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);
-
-                       if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
-                               if (ops->stack(data, "IRQ") < 0)
-                                       break;
-                               bp = ops->walk_stack(tinfo, stack, bp,
-                                       ops, data, irq_stack_end, &graph);
-                               /*
-                                * We link to the next stack (which would be
-                                * the process stack normally) the last
-                                * pointer (index -1 to end) in the IRQ stack:
-                                */
-                               stack = (unsigned long *) (irq_stack_end[-1]);
-                               irq_stack_end = NULL;
-                               ops->stack(data, "EOI");
-                               continue;
-                       }
+                       stack = (unsigned long *) stack_end[-2];
+                       done = 0;
+                       break;
+
+               case STACK_IS_IRQ:
+
+                       if (ops->stack(data, "IRQ") < 0)
+                               break;
+                       bp = ops->walk_stack(tinfo, stack, bp,
+                                    ops, data, stack_end, &graph);
+                       /*
+                        * We link to the next stack (which would be
+                        * the process stack normally) the last
+                        * pointer (index -1 to end) in the IRQ stack:
+                        */
+                       stack = (unsigned long *) (stack_end[-1]);
+                       irq_stack = stack_end - irq_stack_size;
+                       ops->stack(data, "EOI");
+                       done = 0;
+                       break;
+
+               case STACK_IS_UNKNOWN:
+                       ops->stack(data, "UNK");
+                       break;
                }
-               break;
        }
 
        /*
index bc4a088f902396721e08a2d7314a451b7597eb1c..6d7d5a1260a68aca347b2b3d056a6d24dbf94f42 100644 (file)
@@ -203,18 +203,15 @@ static void __init intel_remapping_check(int num, int slot, int func)
        revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
 
        /*
-        * Revision 13 of all triggering devices id in this quirk have
-        * a problem draining interrupts when irq remapping is enabled,
-        * and should be flagged as broken.  Additionally revisions 0x12
-        * and 0x22 of device id 0x3405 has this problem.
+        * Revision <= 13 of all triggering devices id in this quirk
+        * have a problem draining interrupts when irq remapping is
+        * enabled, and should be flagged as broken. Additionally
+        * revision 0x22 of device id 0x3405 has this problem.
         */
-       if (revision == 0x13)
+       if (revision <= 0x13)
                set_irq_remapping_broken();
-       else if ((device == 0x3405) &&
-           ((revision == 0x12) ||
-            (revision == 0x22)))
+       else if (device == 0x3405 && revision == 0x22)
                set_irq_remapping_broken();
-
 }
 
 /*
index 81ba27679f18ec6100bd167c3739608631a7c475..f36bd42d6f0c8b5fc5cd75dcf133b35a1f6bfe3b 100644 (file)
@@ -544,6 +544,10 @@ ENDPROC(early_idt_handlers)
        /* This is global to keep gas from relaxing the jumps */
 ENTRY(early_idt_handler)
        cld
+
+       cmpl $2,(%esp)          # X86_TRAP_NMI
+       je is_nmi               # Ignore NMI
+
        cmpl $2,%ss:early_recursion_flag
        je hlt_loop
        incl %ss:early_recursion_flag
@@ -594,8 +598,9 @@ ex_entry:
        pop %edx
        pop %ecx
        pop %eax
-       addl $8,%esp            /* drop vector number and error code */
        decl %ss:early_recursion_flag
+is_nmi:
+       addl $8,%esp            /* drop vector number and error code */
        iret
 ENDPROC(early_idt_handler)
 
index e1aabdb314c83740dd686eb4c70a6f40c312e258..a468c0a65c42e00df4e10afd9921d81a53dbba3d 100644 (file)
@@ -343,6 +343,9 @@ early_idt_handlers:
 ENTRY(early_idt_handler)
        cld
 
+       cmpl $2,(%rsp)          # X86_TRAP_NMI
+       je is_nmi               # Ignore NMI
+
        cmpl $2,early_recursion_flag(%rip)
        jz  1f
        incl early_recursion_flag(%rip)
@@ -405,8 +408,9 @@ ENTRY(early_idt_handler)
        popq %rdx
        popq %rcx
        popq %rax
-       addq $16,%rsp           # drop vector number and error code
        decl early_recursion_flag(%rip)
+is_nmi:
+       addq $16,%rsp           # drop vector number and error code
        INTERRUPT_RETURN
 ENDPROC(early_idt_handler)
 
index da85a8e830a12d65e9d2f8a7f1db39b5477e9e85..014618dbaa7b4df9a925ffdae1d2975b07eca672 100644 (file)
@@ -521,7 +521,7 @@ static int hpet_setup_irq(struct hpet_dev *dev)
 {
 
        if (request_irq(dev->irq, hpet_interrupt_handler,
-                       IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
+                       IRQF_TIMER | IRQF_NOBALANCING,
                        dev->name, dev))
                return -1;
 
@@ -699,7 +699,7 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
                /* FIXME: add schedule_work_on() */
                schedule_delayed_work_on(cpu, &work.work, 0);
                wait_for_completion(&work.complete);
-               destroy_timer_on_stack(&work.work.timer);
+               destroy_delayed_work_on_stack(&work.work);
                break;
        case CPU_DEAD:
                if (hdev) {
index e8368c6dd2a2988c2d9d68cacc7030554424ad70..d5dd808144190ffd1d443229b4dbbd56740fface 100644 (file)
@@ -86,10 +86,19 @@ EXPORT_SYMBOL(__kernel_fpu_begin);
 
 void __kernel_fpu_end(void)
 {
-       if (use_eager_fpu())
-               math_state_restore();
-       else
+       if (use_eager_fpu()) {
+               /*
+                * For eager fpu, most the time, tsk_used_math() is true.
+                * Restore the user math as we are done with the kernel usage.
+                * At few instances during thread exit, signal handling etc,
+                * tsk_used_math() is false. Those few places will take proper
+                * actions, so we don't need to restore the math here.
+                */
+               if (likely(tsk_used_math(current)))
+                       math_state_restore();
+       } else {
                stts();
+       }
 }
 EXPORT_SYMBOL(__kernel_fpu_end);
 
index d99f31d9a750216204a0c61faef3e489818ef925..42805fac009215ac5c70bdd71fdc2ad5d72dfa89 100644 (file)
@@ -124,6 +124,12 @@ int arch_show_interrupts(struct seq_file *p, int prec)
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
        seq_printf(p, "  Machine check polls\n");
+#endif
+#if defined(CONFIG_HYPERV) || defined(CONFIG_XEN)
+       seq_printf(p, "%*s: ", prec, "THR");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
+       seq_printf(p, "  Hypervisor callback interrupts\n");
 #endif
        seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
 #if defined(CONFIG_X86_IO_APIC)
index d7fcbedc9c43fa9659b7f2f2c687b8402a826dd2..63ce838e5a5423ad3f425368f1c5adffb8c8356e 100644 (file)
@@ -55,16 +55,8 @@ static inline int check_stack_overflow(void) { return 0; }
 static inline void print_stack_overflow(void) { }
 #endif
 
-/*
- * per-CPU IRQ handling contexts (thread information and stack)
- */
-union irq_ctx {
-       struct thread_info      tinfo;
-       u32                     stack[THREAD_SIZE/sizeof(u32)];
-} __attribute__((aligned(THREAD_SIZE)));
-
-static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
-static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
+DEFINE_PER_CPU(struct irq_stack *, hardirq_stack);
+DEFINE_PER_CPU(struct irq_stack *, softirq_stack);
 
 static void call_on_stack(void *func, void *stack)
 {
@@ -77,14 +69,26 @@ static void call_on_stack(void *func, void *stack)
                     : "memory", "cc", "edx", "ecx", "eax");
 }
 
+/* how to get the current stack pointer from C */
+#define current_stack_pointer ({               \
+       unsigned long sp;                       \
+       asm("mov %%esp,%0" : "=g" (sp));        \
+       sp;                                     \
+})
+
+static inline void *current_stack(void)
+{
+       return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1));
+}
+
 static inline int
 execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
 {
-       union irq_ctx *curctx, *irqctx;
-       u32 *isp, arg1, arg2;
+       struct irq_stack *curstk, *irqstk;
+       u32 *isp, *prev_esp, arg1, arg2;
 
-       curctx = (union irq_ctx *) current_thread_info();
-       irqctx = __this_cpu_read(hardirq_ctx);
+       curstk = (struct irq_stack *) current_stack();
+       irqstk = __this_cpu_read(hardirq_stack);
 
        /*
         * this is where we switch to the IRQ stack. However, if we are
@@ -92,13 +96,14 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
         * handler) we can't do that and just have to keep using the
         * current stack (which is the irq stack already after all)
         */
-       if (unlikely(curctx == irqctx))
+       if (unlikely(curstk == irqstk))
                return 0;
 
-       /* build the stack frame on the IRQ stack */
-       isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
-       irqctx->tinfo.task = curctx->tinfo.task;
-       irqctx->tinfo.previous_esp = current_stack_pointer;
+       isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
+
+       /* Save the next esp at the bottom of the stack */
+       prev_esp = (u32 *)irqstk;
+       *prev_esp = current_stack_pointer;
 
        if (unlikely(overflow))
                call_on_stack(print_stack_overflow, isp);
@@ -118,46 +123,40 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
  */
 void irq_ctx_init(int cpu)
 {
-       union irq_ctx *irqctx;
+       struct irq_stack *irqstk;
 
-       if (per_cpu(hardirq_ctx, cpu))
+       if (per_cpu(hardirq_stack, cpu))
                return;
 
-       irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+       irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
                                               THREADINFO_GFP,
                                               THREAD_SIZE_ORDER));
-       memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
-       irqctx->tinfo.cpu               = cpu;
-       irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
-
-       per_cpu(hardirq_ctx, cpu) = irqctx;
+       per_cpu(hardirq_stack, cpu) = irqstk;
 
-       irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+       irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
                                               THREADINFO_GFP,
                                               THREAD_SIZE_ORDER));
-       memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
-       irqctx->tinfo.cpu               = cpu;
-       irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
-
-       per_cpu(softirq_ctx, cpu) = irqctx;
+       per_cpu(softirq_stack, cpu) = irqstk;
 
        printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
-              cpu, per_cpu(hardirq_ctx, cpu),  per_cpu(softirq_ctx, cpu));
+              cpu, per_cpu(hardirq_stack, cpu),  per_cpu(softirq_stack, cpu));
 }
 
 void do_softirq_own_stack(void)
 {
-       struct thread_info *curctx;
-       union irq_ctx *irqctx;
-       u32 *isp;
+       struct thread_info *curstk;
+       struct irq_stack *irqstk;
+       u32 *isp, *prev_esp;
 
-       curctx = current_thread_info();
-       irqctx = __this_cpu_read(softirq_ctx);
-       irqctx->tinfo.task = curctx->task;
-       irqctx->tinfo.previous_esp = current_stack_pointer;
+       curstk = current_stack();
+       irqstk = __this_cpu_read(softirq_stack);
 
        /* build the stack frame on the softirq stack */
-       isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
+       isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
+
+       /* Push the previous esp onto the stack */
+       prev_esp = (u32 *)irqstk;
+       *prev_esp = current_stack_pointer;
 
        call_on_stack(__do_softirq, isp);
 }
index 18be189368bbfdbf55cc2e7492c0e7b3b2514403..e69f9882bf95a942ae1ce0f75efbf07301c9adc3 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mm.h>
 #include <linux/gfp.h>
 #include <linux/jump_label.h>
+#include <linux/random.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -43,13 +44,52 @@ do {                                                        \
 } while (0)
 #endif
 
+#ifdef CONFIG_RANDOMIZE_BASE
+static unsigned long module_load_offset;
+static int randomize_modules = 1;
+
+/* Mutex protects the module_load_offset. */
+static DEFINE_MUTEX(module_kaslr_mutex);
+
+static int __init parse_nokaslr(char *p)
+{
+       randomize_modules = 0;
+       return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
+static unsigned long int get_module_load_offset(void)
+{
+       if (randomize_modules) {
+               mutex_lock(&module_kaslr_mutex);
+               /*
+                * Calculate the module_load_offset the first time this
+                * code is called. Once calculated it stays the same until
+                * reboot.
+                */
+               if (module_load_offset == 0)
+                       module_load_offset =
+                               (get_random_int() % 1024 + 1) * PAGE_SIZE;
+               mutex_unlock(&module_kaslr_mutex);
+       }
+       return module_load_offset;
+}
+#else
+static unsigned long int get_module_load_offset(void)
+{
+       return 0;
+}
+#endif
+
 void *module_alloc(unsigned long size)
 {
        if (PAGE_ALIGN(size) > MODULES_LEN)
                return NULL;
-       return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-                               GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,
-                               NUMA_NO_NODE, __builtin_return_address(0));
+       return __vmalloc_node_range(size, 1,
+                                   MODULES_VADDR + get_module_load_offset(),
+                                   MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
+                                   PAGE_KERNEL_EXEC, NUMA_NO_NODE,
+                                   __builtin_return_address(0));
 }
 
 #ifdef CONFIG_X86_32
index 6fcb49ce50a1260d1f4bfdf0b5a065dd4f6d77c7..b4872b999a713d7fc08f7578b672d804a30dd13e 100644 (file)
@@ -87,6 +87,7 @@ __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,
@@ -95,6 +96,20 @@ static int __init nmi_warning_debugfs(void)
 }
 fs_initcall(nmi_warning_debugfs);
 
+static void nmi_max_handler(struct irq_work *w)
+{
+       struct nmiaction *a = container_of(w, struct nmiaction, irq_work);
+       int remainder_ns, decimal_msecs;
+       u64 whole_msecs = ACCESS_ONCE(a->max_duration);
+
+       remainder_ns = do_div(whole_msecs, (1000 * 1000));
+       decimal_msecs = remainder_ns / 1000;
+
+       printk_ratelimited(KERN_INFO
+               "INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
+               a->handler, whole_msecs, decimal_msecs);
+}
+
 static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
 {
        struct nmi_desc *desc = nmi_to_desc(type);
@@ -110,26 +125,20 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
         * to handle those situations.
         */
        list_for_each_entry_rcu(a, &desc->head, list) {
-               u64 before, delta, whole_msecs;
-               int remainder_ns, decimal_msecs, thishandled;
+               int thishandled;
+               u64 delta;
 
-               before = sched_clock();
+               delta = sched_clock();
                thishandled = a->handler(type, regs);
                handled += thishandled;
-               delta = sched_clock() - before;
+               delta = sched_clock() - delta;
                trace_nmi_handler(a->handler, (int)delta, thishandled);
 
-               if (delta < nmi_longest_ns)
+               if (delta < nmi_longest_ns || delta < a->max_duration)
                        continue;
 
-               nmi_longest_ns = delta;
-               whole_msecs = delta;
-               remainder_ns = do_div(whole_msecs, (1000 * 1000));
-               decimal_msecs = remainder_ns / 1000;
-               printk_ratelimited(KERN_INFO
-                       "INFO: NMI handler (%ps) took too long to run: "
-                       "%lld.%03d msecs\n", a->handler, whole_msecs,
-                       decimal_msecs);
+               a->max_duration = delta;
+               irq_work_queue(&a->irq_work);
        }
 
        rcu_read_unlock();
@@ -146,6 +155,8 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
        if (!action->handler)
                return -EINVAL;
 
+       init_irq_work(&action->irq_work, nmi_max_handler);
+
        spin_lock_irqsave(&desc->lock, flags);
 
        /*
index 3fb8d95ab8b5ea3635ddb1f0d9f9c12e3a348285..4505e2a950d81f479663df20ce787dbad5f293b0 100644 (file)
@@ -298,10 +298,7 @@ void arch_cpu_idle_dead(void)
  */
 void arch_cpu_idle(void)
 {
-       if (cpuidle_idle_call())
-               x86_idle();
-       else
-               local_irq_enable();
+       x86_idle();
 }
 
 /*
index 0de43e98ce08604afa886ceba8e17b7c66583e97..7bc86bbe748599b92c2b9b2b221f98b10224c5b2 100644 (file)
@@ -314,6 +314,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         */
        arch_end_context_switch(next_p);
 
+       this_cpu_write(kernel_stack,
+                 (unsigned long)task_stack_page(next_p) +
+                 THREAD_SIZE - KERNEL_STACK_OFFSET);
+
        /*
         * Restore %gs if needed (which is common)
         */
index 7461f50d5bb1e15dbf39d7f43a758138b0fad019..678c0ada3b3ce5f94135c7076cf59800850ca474 100644 (file)
@@ -184,14 +184,14 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs)
 {
        unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1);
        unsigned long sp = (unsigned long)&regs->sp;
-       struct thread_info *tinfo;
+       u32 *prev_esp;
 
        if (context == (sp & ~(THREAD_SIZE - 1)))
                return sp;
 
-       tinfo = (struct thread_info *)context;
-       if (tinfo->previous_esp)
-               return tinfo->previous_esp;
+       prev_esp = (u32 *)(context);
+       if (prev_esp)
+               return (unsigned long)prev_esp;
 
        return (unsigned long)regs;
 }
index 7c6acd4b8995e532f5422a03a7fb65c716cbf35d..ff898bbf579d7f34ce7b8c98a5482f72e4d338bf 100644 (file)
@@ -529,7 +529,7 @@ static void quirk_amd_nb_node(struct pci_dev *dev)
                return;
 
        pci_read_config_dword(nb_ht, 0x60, &val);
-       node = val & 7;
+       node = pcibus_to_node(dev->bus) | (val & 7);
        /*
         * Some hardware may return an invalid node ID,
         * so check it first:
index c752cb43e52f192f431a5f2ab91b9366e42ef5b0..654b46574b916c20ac4472aace3ffe4165f131fd 100644 (file)
@@ -464,9 +464,12 @@ void __attribute__((weak)) mach_reboot_fixups(void)
  * 2) If still alive, write to the keyboard controller
  * 3) If still alive, write to the ACPI reboot register again
  * 4) If still alive, write to the keyboard controller again
+ * 5) If still alive, call the EFI runtime service to reboot
+ * 6) If still alive, write to the PCI IO port 0xCF9 to reboot
+ * 7) If still alive, inform BIOS to do a proper reboot
  *
  * If the machine is still alive at this stage, it gives up. We default to
- * following the same pattern, except that if we're still alive after (4) we'll
+ * following the same pattern, except that if we're still alive after (7) we'll
  * try to force a triple fault and then cycle between hitting the keyboard
  * controller and doing that
  */
@@ -502,7 +505,7 @@ static void native_machine_emergency_restart(void)
                                attempt = 1;
                                reboot_type = BOOT_ACPI;
                        } else {
-                               reboot_type = BOOT_TRIPLE;
+                               reboot_type = BOOT_EFI;
                        }
                        break;
 
@@ -510,13 +513,15 @@ static void native_machine_emergency_restart(void)
                        load_idt(&no_idt);
                        __asm__ __volatile__("int3");
 
+                       /* We're probably dead after this, but... */
                        reboot_type = BOOT_KBD;
                        break;
 
                case BOOT_BIOS:
                        machine_real_restart(MRR_BIOS);
 
-                       reboot_type = BOOT_KBD;
+                       /* We're probably dead after this, but... */
+                       reboot_type = BOOT_TRIPLE;
                        break;
 
                case BOOT_ACPI:
@@ -530,7 +535,7 @@ static void native_machine_emergency_restart(void)
                                                 EFI_RESET_WARM :
                                                 EFI_RESET_COLD,
                                                 EFI_SUCCESS, 0, NULL);
-                       reboot_type = BOOT_KBD;
+                       reboot_type = BOOT_CF9_COND;
                        break;
 
                case BOOT_CF9:
@@ -548,7 +553,7 @@ static void native_machine_emergency_restart(void)
                                outb(cf9|reboot_code, 0xcf9);
                                udelay(50);
                        }
-                       reboot_type = BOOT_KBD;
+                       reboot_type = BOOT_BIOS;
                        break;
                }
        }
index 06853e6703541f8349106e17330f86621fa984db..fa511acff7e6c24bbb216de1615569e6bca31db9 100644 (file)
@@ -926,11 +926,11 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_EFI
        if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
                     "EL32", 4)) {
-               set_bit(EFI_BOOT, &x86_efi_facility);
+               set_bit(EFI_BOOT, &efi.flags);
        } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
                     "EL64", 4)) {
-               set_bit(EFI_BOOT, &x86_efi_facility);
-               set_bit(EFI_64BIT, &x86_efi_facility);
+               set_bit(EFI_BOOT, &efi.flags);
+               set_bit(EFI_64BIT, &efi.flags);
        }
 
        if (efi_enabled(EFI_BOOT))
@@ -1239,14 +1239,8 @@ void __init setup_arch(char **cmdline_p)
        register_refined_jiffies(CLOCK_TICK_RATE);
 
 #ifdef CONFIG_EFI
-       /* Once setup is done above, unmap the EFI memory map on
-        * mismatched firmware/kernel archtectures since there is no
-        * support for runtime services.
-        */
-       if (efi_enabled(EFI_BOOT) && !efi_is_native()) {
-               pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
-               efi_unmap_memmap();
-       }
+       if (efi_enabled(EFI_BOOT))
+               efi_apply_memmap_quirks();
 #endif
 }
 
index a32da804252e374b5d266e6788653f24fc98705d..34826934d4a7b37da39ae7556d04be37cae55ee8 100644 (file)
@@ -122,8 +122,9 @@ static void smp_callin(void)
         * Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
         */
        cpuid = smp_processor_id();
-       if (apic->wait_for_init_deassert && cpuid != 0)
-               apic->wait_for_init_deassert(&init_deasserted);
+       if (apic->wait_for_init_deassert && cpuid)
+               while (!atomic_read(&init_deasserted))
+                       cpu_relax();
 
        /*
         * (This works even if the APIC is not enabled.)
@@ -701,11 +702,15 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
        int id;
        int boot_error;
 
+       preempt_disable();
+
        /*
         * Wake up AP by INIT, INIT, STARTUP sequence.
         */
-       if (cpu)
-               return wakeup_secondary_cpu_via_init(apicid, start_ip);
+       if (cpu) {
+               boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip);
+               goto out;
+       }
 
        /*
         * Wake up BSP by nmi.
@@ -725,6 +730,9 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
                boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
        }
 
+out:
+       preempt_enable();
+
        return boot_error;
 }
 
@@ -758,10 +766,10 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 #else
        clear_tsk_thread_flag(idle, TIF_FORK);
        initial_gs = per_cpu_offset(cpu);
+#endif
        per_cpu(kernel_stack, cpu) =
                (unsigned long)task_stack_page(idle) -
                KERNEL_STACK_OFFSET + THREAD_SIZE;
-#endif
        early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
        initial_code = (unsigned long)start_secondary;
        stack_start  = idle->thread.sp;
@@ -1379,7 +1387,7 @@ static inline void mwait_play_dead(void)
 
        if (!this_cpu_has(X86_FEATURE_MWAIT))
                return;
-       if (!this_cpu_has(X86_FEATURE_CLFLSH))
+       if (!this_cpu_has(X86_FEATURE_CLFLUSH))
                return;
        if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF)
                return;
index 24d3c91e9812f6f37be6b138deb8e0b6b23a30dd..bf7ef5ce29dff7f89d8e93fb8bee4119f445379b 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/time.h>
 
 #ifdef CONFIG_X86_64
-DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
+__visible DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
 #endif
 
 unsigned long profile_pc(struct pt_regs *regs)
@@ -62,7 +62,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
+       .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
        .name = "timer"
 };
 
index cfbe99f888300d819b53552a7668ab9bd12c3708..7a9296ab88340991436dfb91d6db70e7a17a529e 100644 (file)
@@ -914,8 +914,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                tsc_khz_ref = tsc_khz;
        }
        if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-                       (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
-                       (val == CPUFREQ_RESUMECHANGE)) {
+                       (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
                *lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
 
                tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
index c6976257eff51281e023c264b355f166ce56dd5c..e5503d8aec1dac41f6ff7f97eb77e43beee6f38b 100644 (file)
@@ -263,7 +263,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                F(TSC) | F(MSR) | F(PAE) | F(MCE) |
                F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) |
                F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
-               F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLSH) |
+               F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLUSH) |
                0 /* Reserved, DS, ACPI */ | F(MMX) |
                F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) |
                0 /* HTT, TM, Reserved, PBE */;
index e81df8fce0275781a654f356fe77e38129d5210a..2de1bc09a8d40a0508e7e364bc1de301215cc7c5 100644 (file)
@@ -3002,10 +3002,8 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
        /* instruction emulation calls kvm_set_cr8() */
        r = cr_interception(svm);
-       if (irqchip_in_kernel(svm->vcpu.kvm)) {
-               clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+       if (irqchip_in_kernel(svm->vcpu.kvm))
                return r;
-       }
        if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
                return r;
        kvm_run->exit_reason = KVM_EXIT_SET_TPR;
@@ -3567,6 +3565,8 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
        if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
                return;
 
+       clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+
        if (irr == -1)
                return;
 
index 3056702e81fbc553d3d7986889bc31ef4bb4bd3f..ff4fa51a5b1f5c0ddffcfa64ce72556b012b084b 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <linux/hash.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
 
 static inline u32 crc32_u32(u32 crc, u32 val)
 {
+#ifdef CONFIG_AS_CRC32
        asm ("crc32l %1,%0\n" : "+r" (crc) : "rm" (val));
+#else
+       asm (".byte 0xf2, 0x0f, 0x38, 0xf1, 0xc1" : "+a" (crc) : "c" (val));
+#endif
        return crc;
 }
 
@@ -49,19 +54,18 @@ static u32 intel_crc4_2_hash(const void *data, u32 len, u32 seed)
        u32 i, tmp = 0;
 
        for (i = 0; i < len / 4; i++)
-               seed = crc32_u32(*p32++, seed);
+               seed = crc32_u32(seed, *p32++);
 
-       switch (3 - (len & 0x03)) {
-       case 0:
+       switch (len & 3) {
+       case 3:
                tmp |= *((const u8 *) p32 + 2) << 16;
                /* fallthrough */
-       case 1:
+       case 2:
                tmp |= *((const u8 *) p32 + 1) << 8;
                /* fallthrough */
-       case 2:
+       case 1:
                tmp |= *((const u8 *) p32);
-               seed = crc32_u32(tmp, seed);
-       default:
+               seed = crc32_u32(seed, tmp);
                break;
        }
 
@@ -74,12 +78,12 @@ static u32 intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed)
        u32 i;
 
        for (i = 0; i < len; i++)
-               seed = crc32_u32(*p32++, seed);
+               seed = crc32_u32(seed, *p32++);
 
        return seed;
 }
 
-void setup_arch_fast_hash(struct fast_hash_ops *ops)
+void __init setup_arch_fast_hash(struct fast_hash_ops *ops)
 {
        if (cpu_has_xmm4_2) {
                ops->hash  = intel_crc4_2_hash;
index e78761d6b7f87811ea7f20feab53a72656547e1b..a404b4b7553319cd7d517355bf340784de344562 100644 (file)
@@ -4,7 +4,7 @@
 #undef memcpy
 #undef memset
 
-void *memcpy(void *to, const void *from, size_t n)
+__visible void *memcpy(void *to, const void *from, size_t n)
 {
 #ifdef CONFIG_X86_USE_3DNOW
        return __memcpy3d(to, from, n);
@@ -14,13 +14,13 @@ void *memcpy(void *to, const void *from, size_t n)
 }
 EXPORT_SYMBOL(memcpy);
 
-void *memset(void *s, int c, size_t count)
+__visible void *memset(void *s, int c, size_t count)
 {
        return __memset(s, c, count);
 }
 EXPORT_SYMBOL(memset);
 
-void *memmove(void *dest, const void *src, size_t n)
+__visible void *memmove(void *dest, const void *src, size_t n)
 {
        int d0,d1,d2,d3,d4,d5;
        char *ret = dest;
index 8f8eebdca7d4cadc249405e8a0c50108e34edc3b..db9db446b71a66fe5bd59de47232e8fa69e8c96e 100644 (file)
@@ -8,7 +8,7 @@ struct msr *msrs_alloc(void)
 
        msrs = alloc_percpu(struct msr);
        if (!msrs) {
-               pr_warning("%s: error allocating msrs\n", __func__);
+               pr_warn("%s: error allocating msrs\n", __func__);
                return NULL;
        }
 
@@ -21,3 +21,90 @@ void msrs_free(struct msr *msrs)
        free_percpu(msrs);
 }
 EXPORT_SYMBOL(msrs_free);
+
+/**
+ * Read an MSR with error handling
+ *
+ * @msr: MSR to read
+ * @m: value to read into
+ *
+ * It returns read data only on success, otherwise it doesn't change the output
+ * argument @m.
+ *
+ */
+int msr_read(u32 msr, struct msr *m)
+{
+       int err;
+       u64 val;
+
+       err = rdmsrl_safe(msr, &val);
+       if (!err)
+               m->q = val;
+
+       return err;
+}
+
+/**
+ * Write an MSR with error handling
+ *
+ * @msr: MSR to write
+ * @m: value to write
+ */
+int msr_write(u32 msr, struct msr *m)
+{
+       return wrmsrl_safe(msr, m->q);
+}
+
+static inline int __flip_bit(u32 msr, u8 bit, bool set)
+{
+       struct msr m, m1;
+       int err = -EINVAL;
+
+       if (bit > 63)
+               return err;
+
+       err = msr_read(msr, &m);
+       if (err)
+               return err;
+
+       m1 = m;
+       if (set)
+               m1.q |=  BIT_64(bit);
+       else
+               m1.q &= ~BIT_64(bit);
+
+       if (m1.q == m.q)
+               return 0;
+
+       err = msr_write(msr, &m);
+       if (err)
+               return err;
+
+       return 1;
+}
+
+/**
+ * Set @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already set.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_set_bit(u32 msr, u8 bit)
+{
+       return __flip_bit(msr, bit, true);
+}
+
+/**
+ * Clear @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already cleared.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_clear_bit(u32 msr, u8 bit)
+{
+       return __flip_bit(msr, bit, false);
+}
index 0002a3a33081c77134569c1872e5a70684dbd646..20621d753d5fb4564dddbf960999158a82bc0707 100644 (file)
@@ -30,6 +30,7 @@ struct pg_state {
        unsigned long start_address;
        unsigned long current_address;
        const struct addr_marker *marker;
+       bool to_dmesg;
 };
 
 struct addr_marker {
@@ -88,10 +89,28 @@ static struct addr_marker address_markers[] = {
 #define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)
 #define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT)
 
+#define pt_dump_seq_printf(m, to_dmesg, fmt, args...)          \
+({                                                             \
+       if (to_dmesg)                                   \
+               printk(KERN_INFO fmt, ##args);                  \
+       else                                                    \
+               if (m)                                          \
+                       seq_printf(m, fmt, ##args);             \
+})
+
+#define pt_dump_cont_printf(m, to_dmesg, fmt, args...)         \
+({                                                             \
+       if (to_dmesg)                                   \
+               printk(KERN_CONT fmt, ##args);                  \
+       else                                                    \
+               if (m)                                          \
+                       seq_printf(m, fmt, ##args);             \
+})
+
 /*
  * Print a readable form of a pgprot_t to the seq_file
  */
-static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
+static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
 {
        pgprotval_t pr = pgprot_val(prot);
        static const char * const level_name[] =
@@ -99,47 +118,47 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
 
        if (!pgprot_val(prot)) {
                /* Not present */
-               seq_printf(m, "                          ");
+               pt_dump_cont_printf(m, dmsg, "                          ");
        } else {
                if (pr & _PAGE_USER)
-                       seq_printf(m, "USR ");
+                       pt_dump_cont_printf(m, dmsg, "USR ");
                else
-                       seq_printf(m, "    ");
+                       pt_dump_cont_printf(m, dmsg, "    ");
                if (pr & _PAGE_RW)
-                       seq_printf(m, "RW ");
+                       pt_dump_cont_printf(m, dmsg, "RW ");
                else
-                       seq_printf(m, "ro ");
+                       pt_dump_cont_printf(m, dmsg, "ro ");
                if (pr & _PAGE_PWT)
-                       seq_printf(m, "PWT ");
+                       pt_dump_cont_printf(m, dmsg, "PWT ");
                else
-                       seq_printf(m, "    ");
+                       pt_dump_cont_printf(m, dmsg, "    ");
                if (pr & _PAGE_PCD)
-                       seq_printf(m, "PCD ");
+                       pt_dump_cont_printf(m, dmsg, "PCD ");
                else
-                       seq_printf(m, "    ");
+                       pt_dump_cont_printf(m, dmsg, "    ");
 
                /* Bit 9 has a different meaning on level 3 vs 4 */
                if (level <= 3) {
                        if (pr & _PAGE_PSE)
-                               seq_printf(m, "PSE ");
+                               pt_dump_cont_printf(m, dmsg, "PSE ");
                        else
-                               seq_printf(m, "    ");
+                               pt_dump_cont_printf(m, dmsg, "    ");
                } else {
                        if (pr & _PAGE_PAT)
-                               seq_printf(m, "pat ");
+                               pt_dump_cont_printf(m, dmsg, "pat ");
                        else
-                               seq_printf(m, "    ");
+                               pt_dump_cont_printf(m, dmsg, "    ");
                }
                if (pr & _PAGE_GLOBAL)
-                       seq_printf(m, "GLB ");
+                       pt_dump_cont_printf(m, dmsg, "GLB ");
                else
-                       seq_printf(m, "    ");
+                       pt_dump_cont_printf(m, dmsg, "    ");
                if (pr & _PAGE_NX)
-                       seq_printf(m, "NX ");
+                       pt_dump_cont_printf(m, dmsg, "NX ");
                else
-                       seq_printf(m, "x  ");
+                       pt_dump_cont_printf(m, dmsg, "x  ");
        }
-       seq_printf(m, "%s\n", level_name[level]);
+       pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);
 }
 
 /*
@@ -178,7 +197,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
                st->current_prot = new_prot;
                st->level = level;
                st->marker = address_markers;
-               seq_printf(m, "---[ %s ]---\n", st->marker->name);
+               pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
+                                  st->marker->name);
        } else if (prot != cur || level != st->level ||
                   st->current_address >= st->marker[1].start_address) {
                const char *unit = units;
@@ -188,17 +208,17 @@ static void note_page(struct seq_file *m, struct pg_state *st,
                /*
                 * Now print the actual finished series
                 */
-               seq_printf(m, "0x%0*lx-0x%0*lx   ",
-                          width, st->start_address,
-                          width, st->current_address);
+               pt_dump_seq_printf(m, st->to_dmesg,  "0x%0*lx-0x%0*lx   ",
+                                  width, st->start_address,
+                                  width, st->current_address);
 
                delta = (st->current_address - st->start_address) >> 10;
                while (!(delta & 1023) && unit[1]) {
                        delta >>= 10;
                        unit++;
                }
-               seq_printf(m, "%9lu%c ", delta, *unit);
-               printk_prot(m, st->current_prot, st->level);
+               pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", delta, *unit);
+               printk_prot(m, st->current_prot, st->level, st->to_dmesg);
 
                /*
                 * We print markers for special areas of address space,
@@ -207,7 +227,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
                 */
                if (st->current_address >= st->marker[1].start_address) {
                        st->marker++;
-                       seq_printf(m, "---[ %s ]---\n", st->marker->name);
+                       pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
+                                          st->marker->name);
                }
 
                st->start_address = st->current_address;
@@ -296,7 +317,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
 #define pgd_none(a)  pud_none(__pud(pgd_val(a)))
 #endif
 
-static void walk_pgd_level(struct seq_file *m)
+void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
 {
 #ifdef CONFIG_X86_64
        pgd_t *start = (pgd_t *) &init_level4_pgt;
@@ -304,9 +325,12 @@ static void walk_pgd_level(struct seq_file *m)
        pgd_t *start = swapper_pg_dir;
 #endif
        int i;
-       struct pg_state st;
+       struct pg_state st = {};
 
-       memset(&st, 0, sizeof(st));
+       if (pgd) {
+               start = pgd;
+               st.to_dmesg = true;
+       }
 
        for (i = 0; i < PTRS_PER_PGD; i++) {
                st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
@@ -331,7 +355,7 @@ static void walk_pgd_level(struct seq_file *m)
 
 static int ptdump_show(struct seq_file *m, void *v)
 {
-       walk_pgd_level(m);
+       ptdump_walk_pgd_level(m, NULL);
        return 0;
 }
 
index 6dea040cc3a1d794c60466fb9e78eaa552b8806e..8e57229926779eb9db2afad3e5b277def75d4e0a 100644 (file)
@@ -584,8 +584,13 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
 
        if (error_code & PF_INSTR) {
                unsigned int level;
+               pgd_t *pgd;
+               pte_t *pte;
 
-               pte_t *pte = lookup_address(address, &level);
+               pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK);
+               pgd += pgd_index(address);
+
+               pte = lookup_address_in_pgd(pgd, address, &level);
 
                if (pte && pte_present(*pte) && !pte_exec(*pte))
                        printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
@@ -1020,13 +1025,17 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
+ *
+ * This function must have noinline because both callers
+ * {,trace_}do_page_fault() have notrace on. Having this an actual function
+ * guarantees there's a function trace entry.
  */
-static void __kprobes
-__do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes noinline
+__do_page_fault(struct pt_regs *regs, unsigned long error_code,
+               unsigned long address)
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
-       unsigned long address;
        struct mm_struct *mm;
        int fault;
        unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -1034,9 +1043,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
        tsk = current;
        mm = tsk->mm;
 
-       /* Get the faulting address: */
-       address = read_cr2();
-
        /*
         * Detect and handle instructions that would cause a page fault for
         * both a tracked kernel page and a userspace page.
@@ -1248,32 +1254,50 @@ good_area:
        up_read(&mm->mmap_sem);
 }
 
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
 do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+       unsigned long address = read_cr2(); /* Get the faulting address */
        enum ctx_state prev_state;
 
+       /*
+        * We must have this function tagged with __kprobes, notrace and call
+        * read_cr2() before calling anything else. To avoid calling any kind
+        * of tracing machinery before we've observed the CR2 value.
+        *
+        * exception_{enter,exit}() contain all sorts of tracepoints.
+        */
+
        prev_state = exception_enter();
-       __do_page_fault(regs, error_code);
+       __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
 
-static void trace_page_fault_entries(struct pt_regs *regs,
+#ifdef CONFIG_TRACING
+static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
                                     unsigned long error_code)
 {
        if (user_mode(regs))
-               trace_page_fault_user(read_cr2(), regs, error_code);
+               trace_page_fault_user(address, regs, error_code);
        else
-               trace_page_fault_kernel(read_cr2(), regs, error_code);
+               trace_page_fault_kernel(address, regs, error_code);
 }
 
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
 trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+       /*
+        * The exception_enter and tracepoint processing could
+        * trigger another page faults (user space callchain
+        * reading) and destroy the original cr2 value, so read
+        * the faulting address now.
+        */
+       unsigned long address = read_cr2();
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
-       trace_page_fault_entries(regs, error_code);
-       __do_page_fault(regs, error_code);
+       trace_page_fault_entries(address, regs, error_code);
+       __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
+#endif /* CONFIG_TRACING */
index b3b19f46c0164c7169c9259a68836afbaeae1943..ae242a7c11c7473cfeb163b78d54fa62005b8e44 100644 (file)
@@ -126,8 +126,8 @@ within(unsigned long addr, unsigned long start, unsigned long end)
  * @vaddr:     virtual start address
  * @size:      number of bytes to flush
  *
- * clflush is an unordered instruction which needs fencing with mfence
- * to avoid ordering issues.
+ * clflushopt is an unordered instruction which needs fencing with mfence or
+ * sfence to avoid ordering issues.
  */
 void clflush_cache_range(void *vaddr, unsigned int size)
 {
@@ -136,11 +136,11 @@ void clflush_cache_range(void *vaddr, unsigned int size)
        mb();
 
        for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size)
-               clflush(vaddr);
+               clflushopt(vaddr);
        /*
         * Flush any possible final partial cacheline:
         */
-       clflush(vend);
+       clflushopt(vend);
 
        mb();
 }
@@ -323,8 +323,12 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
        return prot;
 }
 
-static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
-                                     unsigned int *level)
+/*
+ * Lookup the page table entry for a virtual address in a specific pgd.
+ * Return a pointer to the entry and the level of the mapping.
+ */
+pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
+                            unsigned int *level)
 {
        pud_t *pud;
        pmd_t *pmd;
@@ -365,7 +369,7 @@ static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
  */
 pte_t *lookup_address(unsigned long address, unsigned int *level)
 {
-        return __lookup_address_in_pgd(pgd_offset_k(address), address, level);
+        return lookup_address_in_pgd(pgd_offset_k(address), address, level);
 }
 EXPORT_SYMBOL_GPL(lookup_address);
 
@@ -373,7 +377,7 @@ static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address,
                                  unsigned int *level)
 {
         if (cpa->pgd)
-               return __lookup_address_in_pgd(cpa->pgd + pgd_index(address),
+               return lookup_address_in_pgd(cpa->pgd + pgd_index(address),
                                               address, level);
 
         return lookup_address(address, level);
@@ -692,6 +696,18 @@ static bool try_to_free_pmd_page(pmd_t *pmd)
        return true;
 }
 
+static bool try_to_free_pud_page(pud_t *pud)
+{
+       int i;
+
+       for (i = 0; i < PTRS_PER_PUD; i++)
+               if (!pud_none(pud[i]))
+                       return false;
+
+       free_page((unsigned long)pud);
+       return true;
+}
+
 static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
 {
        pte_t *pte = pte_offset_kernel(pmd, start);
@@ -805,6 +821,16 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
         */
 }
 
+static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
+{
+       pgd_t *pgd_entry = root + pgd_index(addr);
+
+       unmap_pud_range(pgd_entry, addr, end);
+
+       if (try_to_free_pud_page((pud_t *)pgd_page_vaddr(*pgd_entry)))
+               pgd_clear(pgd_entry);
+}
+
 static int alloc_pte_page(pmd_t *pmd)
 {
        pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK);
@@ -999,9 +1025,8 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
 static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
 {
        pgprot_t pgprot = __pgprot(_KERNPG_TABLE);
-       bool allocd_pgd = false;
-       pgd_t *pgd_entry;
        pud_t *pud = NULL;      /* shut up gcc */
+       pgd_t *pgd_entry;
        int ret;
 
        pgd_entry = cpa->pgd + pgd_index(addr);
@@ -1015,7 +1040,6 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
                        return -1;
 
                set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE));
-               allocd_pgd = true;
        }
 
        pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr);
@@ -1023,19 +1047,11 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
 
        ret = populate_pud(cpa, addr, pgd_entry, pgprot);
        if (ret < 0) {
-               unmap_pud_range(pgd_entry, addr,
+               unmap_pgd_range(cpa->pgd, addr,
                                addr + (cpa->numpages << PAGE_SHIFT));
-
-               if (allocd_pgd) {
-                       /*
-                        * If I allocated this PUD page, I can just as well
-                        * free it in this error path.
-                        */
-                       pgd_clear(pgd_entry);
-                       free_page((unsigned long)pud);
-               }
                return ret;
        }
+
        cpa->numpages = ret;
        return 0;
 }
@@ -1377,10 +1393,10 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
        cache = cache_attr(mask_set);
 
        /*
-        * On success we use clflush, when the CPU supports it to
-        * avoid the wbindv. If the CPU does not support it and in the
+        * On success we use CLFLUSH, when the CPU supports it to
+        * avoid the WBINVD. If the CPU does not support it and in the
         * error case we fall back to cpa_flush_all (which uses
-        * wbindv):
+        * WBINVD):
         */
        if (!ret && cpu_has_clflush) {
                if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
@@ -1861,6 +1877,12 @@ out:
        return retval;
 }
 
+void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
+                              unsigned numpages)
+{
+       unmap_pgd_range(root, address, address + (numpages << PAGE_SHIFT));
+}
+
 /*
  * The testcases use internal knowledge of the implementation that shouldn't
  * be exposed to the rest of the kernel. Include these directly here.
index 1953e9c9391aecf6ae4cddb4d65baae045fd2911..66338a60aa6ef961c6017731b6fd6d9d169736e1 100644 (file)
@@ -52,12 +52,18 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
        int i, j;
 
        for (i = 0; i < slit->locality_count; i++) {
-               if (pxm_to_node(i) == NUMA_NO_NODE)
+               const int from_node = pxm_to_node(i);
+
+               if (from_node == NUMA_NO_NODE)
                        continue;
+
                for (j = 0; j < slit->locality_count; j++) {
-                       if (pxm_to_node(j) == NUMA_NO_NODE)
+                       const int to_node = pxm_to_node(j);
+
+                       if (to_node == NUMA_NO_NODE)
                                continue;
-                       numa_set_distance(pxm_to_node(i), pxm_to_node(j),
+
+                       numa_set_distance(from_node, to_node,
                                slit->entry[slit->locality_count * i + j]);
                }
        }
index 877b9a1b21523183d06973b60a9beb2459fff895..01495755701bd3d068db95df291ef71096d9cf33 100644 (file)
@@ -140,7 +140,7 @@ bpf_slow_path_byte_msh:
        push    %r9;                                            \
        push    SKBDATA;                                        \
 /* rsi already has offset */                                   \
-       mov     $SIZE,%ecx;     /* size */                      \
+       mov     $SIZE,%edx;     /* size */                      \
        call    bpf_internal_load_pointer_neg_helper;           \
        test    %rax,%rax;                                      \
        pop     SKBDATA;                                        \
index 4f25ec0775526f45133d9087bc13fd4f76dfb24e..01edac6c5e1867c489b8e99dab52761dcd5b849a 100644 (file)
@@ -218,9 +218,8 @@ static void teardown_mcfg_map(struct pci_root_info *info)
 }
 #endif
 
-static acpi_status
-resource_to_addr(struct acpi_resource *resource,
-                       struct acpi_resource_address64 *addr)
+static acpi_status resource_to_addr(struct acpi_resource *resource,
+                                   struct acpi_resource_address64 *addr)
 {
        acpi_status status;
        struct acpi_resource_memory24 *memory24;
@@ -265,8 +264,7 @@ resource_to_addr(struct acpi_resource *resource,
        return AE_ERROR;
 }
 
-static acpi_status
-count_resource(struct acpi_resource *acpi_res, void *data)
+static acpi_status count_resource(struct acpi_resource *acpi_res, void *data)
 {
        struct pci_root_info *info = data;
        struct acpi_resource_address64 addr;
@@ -278,8 +276,7 @@ count_resource(struct acpi_resource *acpi_res, void *data)
        return AE_OK;
 }
 
-static acpi_status
-setup_resource(struct acpi_resource *acpi_res, void *data)
+static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
 {
        struct pci_root_info *info = data;
        struct resource *res;
@@ -435,9 +432,9 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
        __release_pci_root_info(info);
 }
 
-static void
-probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
-                   int busnum, int domain)
+static void probe_pci_root_info(struct pci_root_info *info,
+                               struct acpi_device *device,
+                               int busnum, int domain)
 {
        size_t size;
 
@@ -473,16 +470,13 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
        struct acpi_device *device = root->device;
-       struct pci_root_info *info = NULL;
+       struct pci_root_info *info;
        int domain = root->segment;
        int busnum = root->secondary.start;
        LIST_HEAD(resources);
-       struct pci_bus *bus = NULL;
+       struct pci_bus *bus;
        struct pci_sysdata *sd;
        int node;
-#ifdef CONFIG_ACPI_NUMA
-       int pxm;
-#endif
 
        if (pci_ignore_seg)
                domain = 0;
@@ -494,19 +488,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
                return NULL;
        }
 
-       node = -1;
-#ifdef CONFIG_ACPI_NUMA
-       pxm = acpi_get_pxm(device->handle);
-       if (pxm >= 0)
-               node = pxm_to_node(pxm);
-       if (node != -1)
-               set_mp_bus_to_node(busnum, node);
-       else
-#endif
-               node = get_mp_bus_to_node(busnum);
+       node = acpi_get_node(device->handle);
+       if (node == NUMA_NO_NODE)
+               node = x86_pci_root_bus_node(busnum);
 
-       if (node != -1 && !node_online(node))
-               node = -1;
+       if (node != NUMA_NO_NODE && !node_online(node))
+               node = NUMA_NO_NODE;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
@@ -519,15 +506,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
        sd->domain = domain;
        sd->node = node;
        sd->companion = device;
-       /*
-        * Maybe the desired pci bus has been already scanned. In such case
-        * it is unnecessary to scan the pci bus with the given domain,busnum.
-        */
+
        bus = pci_find_bus(domain, busnum);
        if (bus) {
                /*
-                * If the desired bus exits, the content of bus->sysdata will
-                * be replaced by sd.
+                * If the desired bus has been scanned already, replace
+                * its bus->sysdata.
                 */
                memcpy(bus->sysdata, sd, sizeof(*sd));
                kfree(info);
@@ -572,15 +556,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
                        pcie_bus_configure_settings(child);
        }
 
-       if (bus && node != -1) {
-#ifdef CONFIG_ACPI_NUMA
-               if (pxm >= 0)
-                       dev_printk(KERN_DEBUG, &bus->dev,
-                                  "on NUMA node %d (pxm %d)\n", node, pxm);
-#else
+       if (bus && node != NUMA_NO_NODE)
                dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
-#endif
-       }
 
        return bus;
 }
index a48be98e9ded5a48be34fd8139d37a97a3748cc4..a313a7fb6b862e26b893ad8f5058e8767bf146c1 100644 (file)
@@ -44,15 +44,6 @@ static struct pci_root_info __init *find_pci_root_info(int node, int link)
        return NULL;
 }
 
-static void __init set_mp_bus_range_to_node(int min_bus, int max_bus, int node)
-{
-#ifdef CONFIG_NUMA
-       int j;
-
-       for (j = min_bus; j <= max_bus; j++)
-               set_mp_bus_to_node(j, node);
-#endif
-}
 /**
  * early_fill_mp_bus_to_node()
  * called before pcibios_scan_root and pci_scan_bus
@@ -117,7 +108,6 @@ static int __init early_fill_mp_bus_info(void)
                min_bus = (reg >> 16) & 0xff;
                max_bus = (reg >> 24) & 0xff;
                node = (reg >> 4) & 0x07;
-               set_mp_bus_range_to_node(min_bus, max_bus, node);
                link = (reg >> 8) & 0x03;
 
                info = alloc_pci_root_info(min_bus, max_bus, node, link);
index c2735feb2508148ec16efab887ec1aab2dcc0aec..f3a2cfc14125bbb387d7eae474304a59cf8b2ef1 100644 (file)
@@ -10,9 +10,6 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
 {
        struct pci_root_info *info;
 
-       if (list_empty(&pci_root_infos))
-               return NULL;
-
        list_for_each_entry(info, &pci_root_infos, list)
                if (info->busn.start == bus)
                        return info;
@@ -20,6 +17,16 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
        return NULL;
 }
 
+int x86_pci_root_bus_node(int bus)
+{
+       struct pci_root_info *info = x86_find_pci_root_info(bus);
+
+       if (!info)
+               return NUMA_NO_NODE;
+
+       return info->node;
+}
+
 void x86_pci_root_bus_resources(int bus, struct list_head *resources)
 {
        struct pci_root_info *info = x86_find_pci_root_info(bus);
index 981c2dbd72cc45e6d77a98dab694d87b0523696a..d491deddebae580d0afa6fb64e62fd9b44b3d665 100644 (file)
@@ -456,19 +456,25 @@ void __init dmi_check_pciprobe(void)
        dmi_check_system(pciprobe_dmi_table);
 }
 
-struct pci_bus *pcibios_scan_root(int busnum)
+void pcibios_scan_root(int busnum)
 {
-       struct pci_bus *bus = NULL;
+       struct pci_bus *bus;
+       struct pci_sysdata *sd;
+       LIST_HEAD(resources);
 
-       while ((bus = pci_find_next_bus(bus)) != NULL) {
-               if (bus->number == busnum) {
-                       /* Already scanned */
-                       return bus;
-               }
+       sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+       if (!sd) {
+               printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busnum);
+               return;
+       }
+       sd->node = x86_pci_root_bus_node(busnum);
+       x86_pci_root_bus_resources(busnum, &resources);
+       printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
+       bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
+       if (!bus) {
+               pci_free_resource_list(&resources);
+               kfree(sd);
        }
-
-       return pci_scan_bus_on_node(busnum, &pci_root_ops,
-                                       get_mp_bus_to_node(busnum));
 }
 
 void __init pcibios_set_cache_line_size(void)
@@ -677,105 +683,3 @@ int pci_ext_cfg_avail(void)
        else
                return 0;
 }
-
-struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
-{
-       LIST_HEAD(resources);
-       struct pci_bus *bus = NULL;
-       struct pci_sysdata *sd;
-
-       /*
-        * Allocate per-root-bus (not per bus) arch-specific data.
-        * TODO: leak; this memory is never freed.
-        * It's arguable whether it's worth the trouble to care.
-        */
-       sd = kzalloc(sizeof(*sd), GFP_KERNEL);
-       if (!sd) {
-               printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
-               return NULL;
-       }
-       sd->node = node;
-       x86_pci_root_bus_resources(busno, &resources);
-       printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
-       bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
-       if (!bus) {
-               pci_free_resource_list(&resources);
-               kfree(sd);
-       }
-
-       return bus;
-}
-
-struct pci_bus *pci_scan_bus_with_sysdata(int busno)
-{
-       return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
-}
-
-/*
- * NUMA info for PCI busses
- *
- * Early arch code is responsible for filling in reasonable values here.
- * A node id of "-1" means "use current node".  In other words, if a bus
- * has a -1 node id, it's not tightly coupled to any particular chunk
- * of memory (as is the case on some Nehalem systems).
- */
-#ifdef CONFIG_NUMA
-
-#define BUS_NR 256
-
-#ifdef CONFIG_X86_64
-
-static int mp_bus_to_node[BUS_NR] = {
-       [0 ... BUS_NR - 1] = -1
-};
-
-void set_mp_bus_to_node(int busnum, int node)
-{
-       if (busnum >= 0 &&  busnum < BUS_NR)
-               mp_bus_to_node[busnum] = node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
-       int node = -1;
-
-       if (busnum < 0 || busnum > (BUS_NR - 1))
-               return node;
-
-       node = mp_bus_to_node[busnum];
-
-       /*
-        * let numa_node_id to decide it later in dma_alloc_pages
-        * if there is no ram on that node
-        */
-       if (node != -1 && !node_online(node))
-               node = -1;
-
-       return node;
-}
-
-#else /* CONFIG_X86_32 */
-
-static int mp_bus_to_node[BUS_NR] = {
-       [0 ... BUS_NR - 1] = -1
-};
-
-void set_mp_bus_to_node(int busnum, int node)
-{
-       if (busnum >= 0 &&  busnum < BUS_NR)
-       mp_bus_to_node[busnum] = (unsigned char) node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
-       int node;
-
-       if (busnum < 0 || busnum > (BUS_NR - 1))
-               return 0;
-       node = mp_bus_to_node[busnum];
-       return node;
-}
-
-#endif /* CONFIG_X86_32 */
-
-#endif /* CONFIG_NUMA */
index bca9e85daaa55d04d3e174657264920280be4636..94ae9ae9574fe1678eab5f65c219293a871c8c8a 100644 (file)
@@ -25,9 +25,9 @@ static void pci_fixup_i450nx(struct pci_dev *d)
                dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno,
                        suba, subb);
                if (busno)
-                       pci_scan_bus_with_sysdata(busno);       /* Bus A */
+                       pcibios_scan_root(busno);       /* Bus A */
                if (suba < subb)
-                       pci_scan_bus_with_sysdata(suba+1);      /* Bus B */
+                       pcibios_scan_root(suba+1);      /* Bus B */
        }
        pcibios_last_bus = -1;
 }
@@ -42,7 +42,7 @@ static void pci_fixup_i450gx(struct pci_dev *d)
        u8 busno;
        pci_read_config_byte(d, 0x4a, &busno);
        dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno);
-       pci_scan_bus_with_sysdata(busno);
+       pcibios_scan_root(busno);
        pcibios_last_bus = -1;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
@@ -313,9 +313,10 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,       PCI_DEVICE_ID_INTEL_MCH_PC1,    pcie_r
  * IORESOURCE_ROM_SHADOW is used to associate the boot video
  * card with this copy. On laptops this copy has to be used since
  * the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
+ * See pci_map_rom() for use of this flag. Before marking the device
+ * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set
+ * by either arch cde or vga-arbitration, if so only apply the fixup to this
+ * already determined primary video card.
  */
 
 static void pci_fixup_video(struct pci_dev *pdev)
@@ -346,12 +347,13 @@ static void pci_fixup_video(struct pci_dev *pdev)
                }
                bus = bus->parent;
        }
-       pci_read_config_word(pdev, PCI_COMMAND, &config);
-       if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
-               pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
-               dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
-               if (!vga_default_device())
+       if (!vga_default_device() || pdev == vga_default_device()) {
+               pci_read_config_word(pdev, PCI_COMMAND, &config);
+               if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+                       pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+                       dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
                        vga_set_default_device(pdev);
+               }
        }
 }
 DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
index 372e9b8989b322e891cacc192744419a80940d8a..84112f55dd7a95d83232d9416b7e9196a55dee30 100644 (file)
@@ -136,13 +136,9 @@ static void __init pirq_peer_trick(void)
                busmap[e->bus] = 1;
        }
        for (i = 1; i < 256; i++) {
-               int node;
                if (!busmap[i] || pci_find_bus(0, i))
                        continue;
-               node = get_mp_bus_to_node(i);
-               if (pci_scan_bus_on_node(i, &pci_root_ops, node))
-                       printk(KERN_INFO "PCI: Discovered primary peer "
-                              "bus %02x [IRQ]\n", i);
+               pcibios_scan_root(i);
        }
        pcibios_last_bus = -1;
 }
index 4db96fb1c23260394bb7c4f44775ee1c1f0c6f2d..5b662c0faf8c2e1848d15d4dced105db9988c7c8 100644 (file)
@@ -37,19 +37,17 @@ int __init pci_legacy_init(void)
 void pcibios_scan_specific_bus(int busn)
 {
        int devfn;
-       long node;
        u32 l;
 
        if (pci_find_bus(0, busn))
                return;
 
-       node = get_mp_bus_to_node(busn);
        for (devfn = 0; devfn < 256; devfn += 8) {
                if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
                    l != 0x0000 && l != 0xffff) {
                        DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
                        printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
-                       pci_scan_bus_on_node(busn, &pci_root_ops, node);
+                       pcibios_scan_root(busn);
                        return;
                }
        }
index 72c229f9ebcf68aca50cd7bbb5f668c009df8c5e..080eb0374fff199ce4f933a1d4a770974e9863ca 100644 (file)
@@ -135,11 +135,11 @@ static void pci_fixup_i450nx(struct pci_dev *d)
                        pxb, busno, suba, subb);
                if (busno) {
                        /* Bus A */
-                       pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
+                       pcibios_scan_root(QUADLOCAL2BUS(quad, busno));
                }
                if (suba < subb) {
                        /* Bus B */
-                       pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1));
+                       pcibios_scan_root(QUADLOCAL2BUS(quad, suba+1));
                }
        }
        pcibios_last_bus = -1;
@@ -159,7 +159,7 @@ int __init pci_numaq_init(void)
                                continue;
                        printk("Scanning PCI bus %d for quad %d\n", 
                                QUADLOCAL2BUS(quad,0), quad);
-                       pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
+                       pcibios_scan_root(QUADLOCAL2BUS(quad, 0));
                }
        return 0;
 }
index 3e6d2a6db86681d3a1731f7a7956711bdcd36e50..cd9d4d1681d28e6ec75550da99bd716d4608715e 100644 (file)
@@ -78,8 +78,8 @@ int __init pci_visws_init(void)
                "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0);
 
        raw_pci_ops = &pci_direct_conf1;
-       pci_scan_bus_with_sysdata(pci_bus0);
-       pci_scan_bus_with_sysdata(pci_bus1);
+       pcibios_scan_root(pci_bus0);
+       pcibios_scan_root(pci_bus1);
        pci_fixup_irqs(pci_common_swizzle, visws_map_irq);
        pcibios_resource_survey();
        /* Request bus scan */
index b7b0b35c198127dfed4c73dae046665a42ba5561..d51045afcaaf5e386ca101d889d4462f197afa93 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
 obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
+obj-$(CONFIG_EFI_MIXED)                += efi_thunk_$(BITS).o
index 1a201ac7cef8a1f7f4ce5cff2a8f8dbc6b540c00..3781dd39e8bd55a03b8acd779113f40c151442b4 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/tlbflush.h>
 #include <asm/x86_init.h>
 #include <asm/rtc.h>
+#include <asm/uv/uv.h>
 
 #define EFI_DEBUG
 
@@ -67,9 +68,7 @@ struct efi_memory_map memmap;
 static struct efi efi_phys __initdata;
 static efi_system_table_t efi_systab __initdata;
 
-unsigned long x86_efi_facility;
-
-static __initdata efi_config_table_type_t arch_tables[] = {
+static efi_config_table_type_t arch_tables[] __initdata = {
 #ifdef CONFIG_X86_UV
        {UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab},
 #endif
@@ -78,16 +77,7 @@ static __initdata efi_config_table_type_t arch_tables[] = {
 
 u64 efi_setup;         /* efi setup_data physical address */
 
-/*
- * Returns 1 if 'facility' is enabled, 0 otherwise.
- */
-int efi_enabled(int facility)
-{
-       return test_bit(facility, &x86_efi_facility) != 0;
-}
-EXPORT_SYMBOL(efi_enabled);
-
-static bool __initdata disable_runtime = false;
+static bool disable_runtime __initdata = false;
 static int __init setup_noefi(char *arg)
 {
        disable_runtime = true;
@@ -256,27 +246,12 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
        return status;
 }
 
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
-                                            efi_time_cap_t *tc)
-{
-       unsigned long flags;
-       efi_status_t status;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       efi_call_phys_prelog();
-       status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm),
-                               virt_to_phys(tc));
-       efi_call_phys_epilog();
-       spin_unlock_irqrestore(&rtc_lock, flags);
-       return status;
-}
-
 int efi_set_rtc_mmss(const struct timespec *now)
 {
        unsigned long nowtime = now->tv_sec;
-       efi_status_t    status;
-       efi_time_t      eft;
-       efi_time_cap_t  cap;
+       efi_status_t    status;
+       efi_time_t      eft;
+       efi_time_cap_t  cap;
        struct rtc_time tm;
 
        status = efi.get_time(&eft, &cap);
@@ -294,9 +269,8 @@ int efi_set_rtc_mmss(const struct timespec *now)
                eft.second = tm.tm_sec;
                eft.nanosecond = 0;
        } else {
-               printk(KERN_ERR
-                      "%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
-                      __FUNCTION__, nowtime);
+               pr_err("%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
+                      __func__, nowtime);
                return -1;
        }
 
@@ -412,8 +386,7 @@ static void __init print_efi_memmap(void)
             p < memmap.map_end;
             p += memmap.desc_size, i++) {
                md = p;
-               pr_info("mem%02u: type=%u, attr=0x%llx, "
-                       "range=[0x%016llx-0x%016llx) (%lluMB)\n",
+               pr_info("mem%02u: type=%u, attr=0x%llx, range=[0x%016llx-0x%016llx) (%lluMB)\n",
                        i, md->type, md->attribute, md->phys_addr,
                        md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
                        (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
@@ -445,9 +418,8 @@ void __init efi_reserve_boot_services(void)
                        memblock_is_region_reserved(start, size)) {
                        /* Could not reserve, skip it */
                        md->num_pages = 0;
-                       memblock_dbg("Could not reserve boot range "
-                                       "[0x%010llx-0x%010llx]\n",
-                                               start, start+size-1);
+                       memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
+                                    start, start+size-1);
                } else
                        memblock_reserve(start, size);
        }
@@ -455,7 +427,7 @@ void __init efi_reserve_boot_services(void)
 
 void __init efi_unmap_memmap(void)
 {
-       clear_bit(EFI_MEMMAP, &x86_efi_facility);
+       clear_bit(EFI_MEMMAP, &efi.flags);
        if (memmap.map) {
                early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
                memmap.map = NULL;
@@ -466,9 +438,6 @@ void __init efi_free_boot_services(void)
 {
        void *p;
 
-       if (!efi_is_native())
-               return;
-
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                efi_memory_desc_t *md = p;
                unsigned long long start = md->phys_addr;
@@ -583,45 +552,82 @@ static int __init efi_systab_init(void *phys)
                return -EINVAL;
        }
        if ((efi.systab->hdr.revision >> 16) == 0)
-               pr_err("Warning: System table version "
-                      "%d.%02d, expected 1.00 or greater!\n",
+               pr_err("Warning: System table version %d.%02d, expected 1.00 or greater!\n",
                       efi.systab->hdr.revision >> 16,
                       efi.systab->hdr.revision & 0xffff);
 
+       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
        return 0;
 }
 
-static int __init efi_runtime_init(void)
+static int __init efi_runtime_init32(void)
 {
-       efi_runtime_services_t *runtime;
+       efi_runtime_services_32_t *runtime;
+
+       runtime = early_ioremap((unsigned long)efi.systab->runtime,
+                       sizeof(efi_runtime_services_32_t));
+       if (!runtime) {
+               pr_err("Could not map the runtime service table!\n");
+               return -ENOMEM;
+       }
 
        /*
-        * Check out the runtime services table. We need to map
-        * the runtime services table so that we can grab the physical
-        * address of several of the EFI runtime functions, needed to
-        * set the firmware into virtual mode.
+        * We will only need *early* access to the following two
+        * EFI runtime services before set_virtual_address_map
+        * is invoked.
         */
+       efi_phys.set_virtual_address_map =
+                       (efi_set_virtual_address_map_t *)
+                       (unsigned long)runtime->set_virtual_address_map;
+       early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
+
+       return 0;
+}
+
+static int __init efi_runtime_init64(void)
+{
+       efi_runtime_services_64_t *runtime;
+
        runtime = early_ioremap((unsigned long)efi.systab->runtime,
-                               sizeof(efi_runtime_services_t));
+                       sizeof(efi_runtime_services_64_t));
        if (!runtime) {
                pr_err("Could not map the runtime service table!\n");
                return -ENOMEM;
        }
+
        /*
-        * We will only need *early* access to the following
-        * two EFI runtime services before set_virtual_address_map
+        * We will only need *early* access to the following two
+        * EFI runtime services before set_virtual_address_map
         * is invoked.
         */
-       efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
        efi_phys.set_virtual_address_map =
-               (efi_set_virtual_address_map_t *)
-               runtime->set_virtual_address_map;
+                       (efi_set_virtual_address_map_t *)
+                       (unsigned long)runtime->set_virtual_address_map;
+       early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
+
+       return 0;
+}
+
+static int __init efi_runtime_init(void)
+{
+       int rv;
+
        /*
-        * Make efi_get_time can be called before entering
-        * virtual mode.
+        * Check out the runtime services table. We need to map
+        * the runtime services table so that we can grab the physical
+        * address of several of the EFI runtime functions, needed to
+        * set the firmware into virtual mode.
         */
-       efi.get_time = phys_efi_get_time;
-       early_iounmap(runtime, sizeof(efi_runtime_services_t));
+       if (efi_enabled(EFI_64BIT))
+               rv = efi_runtime_init64();
+       else
+               rv = efi_runtime_init32();
+
+       if (rv)
+               return rv;
+
+       set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 
        return 0;
 }
@@ -640,6 +646,8 @@ static int __init efi_memmap_init(void)
        if (add_efi_memmap)
                do_add_efi_memmap();
 
+       set_bit(EFI_MEMMAP, &efi.flags);
+
        return 0;
 }
 
@@ -722,7 +730,7 @@ void __init efi_init(void)
        if (efi_systab_init(efi_phys.systab))
                return;
 
-       set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
+       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
 
        efi.config_table = (unsigned long)efi.systab->tables;
        efi.fw_vendor    = (unsigned long)efi.systab->fw_vendor;
@@ -750,24 +758,21 @@ void __init efi_init(void)
        if (efi_config_init(arch_tables))
                return;
 
-       set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
-
        /*
         * Note: We currently don't support runtime services on an EFI
         * that doesn't match the kernel 32/64-bit mode.
         */
 
-       if (!efi_is_native())
+       if (!efi_runtime_supported())
                pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
        else {
                if (disable_runtime || efi_runtime_init())
                        return;
-               set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
        }
        if (efi_memmap_init())
                return;
 
-       set_bit(EFI_MEMMAP, &x86_efi_facility);
+       set_bit(EFI_MEMMAP, &efi.flags);
 
        print_efi_memmap();
 }
@@ -844,6 +849,22 @@ void __init old_map_region(efi_memory_desc_t *md)
                       (unsigned long long)md->phys_addr);
 }
 
+static void native_runtime_setup(void)
+{
+       efi.get_time = virt_efi_get_time;
+       efi.set_time = virt_efi_set_time;
+       efi.get_wakeup_time = virt_efi_get_wakeup_time;
+       efi.set_wakeup_time = virt_efi_set_wakeup_time;
+       efi.get_variable = virt_efi_get_variable;
+       efi.get_next_variable = virt_efi_get_next_variable;
+       efi.set_variable = virt_efi_set_variable;
+       efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+       efi.reset_system = virt_efi_reset_system;
+       efi.query_variable_info = virt_efi_query_variable_info;
+       efi.update_capsule = virt_efi_update_capsule;
+       efi.query_capsule_caps = virt_efi_query_capsule_caps;
+}
+
 /* Merge contiguous regions of the same type and attribute */
 static void __init efi_merge_regions(void)
 {
@@ -891,8 +912,9 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
        }
 }
 
-static int __init save_runtime_map(void)
+static void __init save_runtime_map(void)
 {
+#ifdef CONFIG_KEXEC
        efi_memory_desc_t *md;
        void *tmp, *p, *q = NULL;
        int count = 0;
@@ -914,38 +936,44 @@ static int __init save_runtime_map(void)
        }
 
        efi_runtime_map_setup(q, count, memmap.desc_size);
+       return;
 
-       return 0;
 out:
        kfree(q);
-       return -ENOMEM;
+       pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
+#endif
 }
 
-/*
- * Map efi regions which were passed via setup_data. The virt_addr is a fixed
- * addr which was used in first kernel of a kexec boot.
- */
-static void __init efi_map_regions_fixed(void)
+static void *realloc_pages(void *old_memmap, int old_shift)
 {
-       void *p;
-       efi_memory_desc_t *md;
+       void *ret;
 
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               md = p;
-               efi_map_region_fixed(md); /* FIXME: add error handling */
-               get_systab_virt_addr(md);
-       }
+       ret = (void *)__get_free_pages(GFP_KERNEL, old_shift + 1);
+       if (!ret)
+               goto out;
 
+       /*
+        * A first-time allocation doesn't have anything to copy.
+        */
+       if (!old_memmap)
+               return ret;
+
+       memcpy(ret, old_memmap, PAGE_SIZE << old_shift);
+
+out:
+       free_pages((unsigned long)old_memmap, old_shift);
+       return ret;
 }
 
 /*
- * Map efi memory ranges for runtime serivce and update new_memmap with virtual
- * addresses.
+ * Map the efi memory ranges of the runtime services and update new_mmap with
+ * virtual addresses.
  */
-static void * __init efi_map_regions(int *count)
+static void * __init efi_map_regions(int *count, int *pg_shift)
 {
+       void *p, *new_memmap = NULL;
+       unsigned long left = 0;
        efi_memory_desc_t *md;
-       void *p, *tmp, *new_memmap = NULL;
 
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
@@ -960,20 +988,80 @@ static void * __init efi_map_regions(int *count)
                efi_map_region(md);
                get_systab_virt_addr(md);
 
-               tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size,
-                              GFP_KERNEL);
-               if (!tmp)
-                       goto out;
-               new_memmap = tmp;
+               if (left < memmap.desc_size) {
+                       new_memmap = realloc_pages(new_memmap, *pg_shift);
+                       if (!new_memmap)
+                               return NULL;
+
+                       left += PAGE_SIZE << *pg_shift;
+                       (*pg_shift)++;
+               }
+
                memcpy(new_memmap + (*count * memmap.desc_size), md,
                       memmap.desc_size);
+
+               left -= memmap.desc_size;
                (*count)++;
        }
 
        return new_memmap;
-out:
-       kfree(new_memmap);
-       return NULL;
+}
+
+static void __init kexec_enter_virtual_mode(void)
+{
+#ifdef CONFIG_KEXEC
+       efi_memory_desc_t *md;
+       void *p;
+
+       efi.systab = NULL;
+
+       /*
+        * We don't do virtual mode, since we don't do runtime services, on
+        * non-native EFI
+        */
+       if (!efi_is_native()) {
+               efi_unmap_memmap();
+               return;
+       }
+
+       /*
+       * Map efi regions which were passed via setup_data. The virt_addr is a
+       * fixed addr which was used in first kernel of a kexec boot.
+       */
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
+               efi_map_region_fixed(md); /* FIXME: add error handling */
+               get_systab_virt_addr(md);
+       }
+
+       save_runtime_map();
+
+       BUG_ON(!efi.systab);
+
+       efi_sync_low_kernel_mappings();
+
+       /*
+        * Now that EFI is in virtual mode, update the function
+        * pointers in the runtime service table to the new virtual addresses.
+        *
+        * Call EFI services through wrapper functions.
+        */
+       efi.runtime_version = efi_systab.hdr.revision;
+
+       native_runtime_setup();
+
+       efi.set_virtual_address_map = NULL;
+
+       if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
+               runtime_code_page_mkexec();
+
+       /* clean DUMMY object */
+       efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
+                        EFI_VARIABLE_NON_VOLATILE |
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                        EFI_VARIABLE_RUNTIME_ACCESS,
+                        0, NULL);
+#endif
 }
 
 /*
@@ -995,57 +1083,53 @@ out:
  *
  * Specially for kexec boot, efi runtime maps in previous kernel should
  * be passed in via setup_data. In that case runtime ranges will be mapped
- * to the same virtual addresses as the first kernel.
+ * to the same virtual addresses as the first kernel, see
+ * kexec_enter_virtual_mode().
  */
-void __init efi_enter_virtual_mode(void)
+static void __init __efi_enter_virtual_mode(void)
 {
-       efi_status_t status;
+       int count = 0, pg_shift = 0;
        void *new_memmap = NULL;
-       int err, count = 0;
+       efi_status_t status;
 
        efi.systab = NULL;
 
-       /*
-        * We don't do virtual mode, since we don't do runtime services, on
-        * non-native EFI
-        */
-       if (!efi_is_native()) {
-               efi_unmap_memmap();
+       efi_merge_regions();
+       new_memmap = efi_map_regions(&count, &pg_shift);
+       if (!new_memmap) {
+               pr_err("Error reallocating memory, EFI runtime non-functional!\n");
                return;
        }
 
-       if (efi_setup) {
-               efi_map_regions_fixed();
-       } else {
-               efi_merge_regions();
-               new_memmap = efi_map_regions(&count);
-               if (!new_memmap) {
-                       pr_err("Error reallocating memory, EFI runtime non-functional!\n");
-                       return;
-               }
-       }
-
-       err = save_runtime_map();
-       if (err)
-               pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
+       save_runtime_map();
 
        BUG_ON(!efi.systab);
 
-       efi_setup_page_tables();
+       if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
+               return;
+
        efi_sync_low_kernel_mappings();
+       efi_dump_pagetable();
 
-       if (!efi_setup) {
+       if (efi_is_native()) {
                status = phys_efi_set_virtual_address_map(
-                       memmap.desc_size * count,
-                       memmap.desc_size,
-                       memmap.desc_version,
-                       (efi_memory_desc_t *)__pa(new_memmap));
-
-               if (status != EFI_SUCCESS) {
-                       pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
-                                status);
-                       panic("EFI call to SetVirtualAddressMap() failed!");
-               }
+                               memmap.desc_size * count,
+                               memmap.desc_size,
+                               memmap.desc_version,
+                               (efi_memory_desc_t *)__pa(new_memmap));
+       } else {
+               status = efi_thunk_set_virtual_address_map(
+                               efi_phys.set_virtual_address_map,
+                               memmap.desc_size * count,
+                               memmap.desc_size,
+                               memmap.desc_version,
+                               (efi_memory_desc_t *)__pa(new_memmap));
+       }
+
+       if (status != EFI_SUCCESS) {
+               pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
+                        status);
+               panic("EFI call to SetVirtualAddressMap() failed!");
        }
 
        /*
@@ -1055,23 +1139,43 @@ void __init efi_enter_virtual_mode(void)
         * Call EFI services through wrapper functions.
         */
        efi.runtime_version = efi_systab.hdr.revision;
-       efi.get_time = virt_efi_get_time;
-       efi.set_time = virt_efi_set_time;
-       efi.get_wakeup_time = virt_efi_get_wakeup_time;
-       efi.set_wakeup_time = virt_efi_set_wakeup_time;
-       efi.get_variable = virt_efi_get_variable;
-       efi.get_next_variable = virt_efi_get_next_variable;
-       efi.set_variable = virt_efi_set_variable;
-       efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
-       efi.reset_system = virt_efi_reset_system;
+
+       if (efi_is_native())
+               native_runtime_setup();
+       else
+               efi_thunk_runtime_setup();
+
        efi.set_virtual_address_map = NULL;
-       efi.query_variable_info = virt_efi_query_variable_info;
-       efi.update_capsule = virt_efi_update_capsule;
-       efi.query_capsule_caps = virt_efi_query_capsule_caps;
 
        efi_runtime_mkexec();
 
-       kfree(new_memmap);
+       /*
+        * We mapped the descriptor array into the EFI pagetable above but we're
+        * not unmapping it here. Here's why:
+        *
+        * We're copying select PGDs from the kernel page table to the EFI page
+        * table and when we do so and make changes to those PGDs like unmapping
+        * stuff from them, those changes appear in the kernel page table and we
+        * go boom.
+        *
+        * From setup_real_mode():
+        *
+        * ...
+        * trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd;
+        *
+        * In this particular case, our allocation is in PGD 0 of the EFI page
+        * table but we've copied that PGD from PGD[272] of the EFI page table:
+        *
+        *      pgd_index(__PAGE_OFFSET = 0xffff880000000000) = 272
+        *
+        * where the direct memory mapping in kernel space is.
+        *
+        * new_memmap's VA comes from that direct mapping and thus clearing it,
+        * it would get cleared in the kernel page table too.
+        *
+        * efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift);
+        */
+       free_pages((unsigned long)new_memmap, pg_shift);
 
        /* clean DUMMY object */
        efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
@@ -1081,6 +1185,14 @@ void __init efi_enter_virtual_mode(void)
                         0, NULL);
 }
 
+void __init efi_enter_virtual_mode(void)
+{
+       if (efi_setup)
+               kexec_enter_virtual_mode();
+       else
+               __efi_enter_virtual_mode();
+}
+
 /*
  * Convenience functions to obtain memory types and attributes
  */
@@ -1118,9 +1230,8 @@ u64 efi_mem_attributes(unsigned long phys_addr)
 }
 
 /*
- * Some firmware has serious problems when using more than 50% of the EFI
- * variable store, i.e. it triggers bugs that can brick machines. Ensure that
- * we never use more than this safe limit.
+ * Some firmware implementations refuse to boot if there's insufficient space
+ * in the variable store. Ensure that we never use more than a safe limit.
  *
  * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
  * store.
@@ -1139,10 +1250,9 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
                return status;
 
        /*
-        * Some firmware implementations refuse to boot if there's insufficient
-        * space in the variable store. We account for that by refusing the
-        * write if permitting it would reduce the available space to under
-        * 5KB. This figure was provided by Samsung, so should be safe.
+        * We account for that by refusing the write if permitting it would
+        * reduce the available space to under 5KB. This figure was provided by
+        * Samsung, so should be safe.
         */
        if ((remaining_size - size < EFI_MIN_RESERVE) &&
                !efi_no_storage_paranoia) {
@@ -1205,8 +1315,27 @@ static int __init parse_efi_cmdline(char *str)
                str++;
 
        if (!strncmp(str, "old_map", 7))
-               set_bit(EFI_OLD_MEMMAP, &x86_efi_facility);
+               set_bit(EFI_OLD_MEMMAP, &efi.flags);
 
        return 0;
 }
 early_param("efi", parse_efi_cmdline);
+
+void __init efi_apply_memmap_quirks(void)
+{
+       /*
+        * Once setup is done earlier, unmap the EFI memory map on mismatched
+        * firmware/kernel architectures since there is no support for runtime
+        * services.
+        */
+       if (!efi_runtime_supported()) {
+               pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
+               efi_unmap_memmap();
+       }
+
+       /*
+        * UV doesn't support the new EFI pagetable mapping yet.
+        */
+       if (is_uv_system())
+               set_bit(EFI_OLD_MEMMAP, &efi.flags);
+}
index 0b74cdf7f816aa0e4e6f26c020821266f51aefdb..9ee3491e31fbab7f6643462395d31c6f9f36f1b4 100644 (file)
 static unsigned long efi_rt_eflags;
 
 void efi_sync_low_kernel_mappings(void) {}
-void efi_setup_page_tables(void) {}
+void __init efi_dump_pagetable(void) {}
+int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
+{
+       return 0;
+}
+void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) {}
 
 void __init efi_map_region(efi_memory_desc_t *md)
 {
index 0c2a234fef1e48794a14e13aad812a5b468c6605..290d397e1dd9125e408a1ee140fe4d3ced51a33d 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/cacheflush.h>
 #include <asm/fixmap.h>
 #include <asm/realmode.h>
+#include <asm/time.h>
 
 static pgd_t *save_pgd __initdata;
 static unsigned long efi_flags __initdata;
@@ -58,7 +59,8 @@ struct efi_scratch {
        u64 prev_cr3;
        pgd_t *efi_pgt;
        bool use_pgd;
-};
+       u64 phys_stack;
+} __packed;
 
 static void __init early_code_mapping_set_exec(int executable)
 {
@@ -137,12 +139,64 @@ void efi_sync_low_kernel_mappings(void)
                sizeof(pgd_t) * num_pgds);
 }
 
-void efi_setup_page_tables(void)
+int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 {
+       unsigned long text;
+       struct page *page;
+       unsigned npages;
+       pgd_t *pgd;
+
+       if (efi_enabled(EFI_OLD_MEMMAP))
+               return 0;
+
        efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd;
+       pgd = __va(efi_scratch.efi_pgt);
 
-       if (!efi_enabled(EFI_OLD_MEMMAP))
-               efi_scratch.use_pgd = true;
+       /*
+        * It can happen that the physical address of new_memmap lands in memory
+        * which is not mapped in the EFI page table. Therefore we need to go
+        * and ident-map those pages containing the map before calling
+        * phys_efi_set_virtual_address_map().
+        */
+       if (kernel_map_pages_in_pgd(pgd, pa_memmap, pa_memmap, num_pages, _PAGE_NX)) {
+               pr_err("Error ident-mapping new memmap (0x%lx)!\n", pa_memmap);
+               return 1;
+       }
+
+       efi_scratch.use_pgd = true;
+
+       /*
+        * When making calls to the firmware everything needs to be 1:1
+        * mapped and addressable with 32-bit pointers. Map the kernel
+        * text and allocate a new stack because we can't rely on the
+        * stack pointer being < 4GB.
+        */
+       if (!IS_ENABLED(CONFIG_EFI_MIXED))
+               return 0;
+
+       page = alloc_page(GFP_KERNEL|__GFP_DMA32);
+       if (!page)
+               panic("Unable to allocate EFI runtime stack < 4GB\n");
+
+       efi_scratch.phys_stack = virt_to_phys(page_address(page));
+       efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */
+
+       npages = (_end - _text) >> PAGE_SHIFT;
+       text = __pa(_text);
+
+       if (kernel_map_pages_in_pgd(pgd, text >> PAGE_SHIFT, text, npages, 0)) {
+               pr_err("Failed to map kernel text 1:1\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages)
+{
+       pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
+
+       kernel_unmap_pages_in_pgd(pgd, pa_memmap, num_pages);
 }
 
 static void __init __map_region(efi_memory_desc_t *md, u64 va)
@@ -173,6 +227,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
         */
        __map_region(md, md->phys_addr);
 
+       /*
+        * Enforce the 1:1 mapping as the default virtual address when
+        * booting in EFI mixed mode, because even though we may be
+        * running a 64-bit kernel, the firmware may only be 32-bit.
+        */
+       if (!efi_is_native () && IS_ENABLED(CONFIG_EFI_MIXED)) {
+               md->virt_addr = md->phys_addr;
+               return;
+       }
+
        efi_va -= size;
 
        /* Is PA 2M-aligned? */
@@ -242,3 +306,299 @@ void __init efi_runtime_mkexec(void)
        if (__supported_pte_mask & _PAGE_NX)
                runtime_code_page_mkexec();
 }
+
+void __init efi_dump_pagetable(void)
+{
+#ifdef CONFIG_EFI_PGT_DUMP
+       pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
+
+       ptdump_walk_pgd_level(NULL, pgd);
+#endif
+}
+
+#ifdef CONFIG_EFI_MIXED
+extern efi_status_t efi64_thunk(u32, ...);
+
+#define runtime_service32(func)                                                 \
+({                                                                      \
+       u32 table = (u32)(unsigned long)efi.systab;                      \
+       u32 *rt, *___f;                                                  \
+                                                                        \
+       rt = (u32 *)(table + offsetof(efi_system_table_32_t, runtime));  \
+       ___f = (u32 *)(*rt + offsetof(efi_runtime_services_32_t, func)); \
+       *___f;                                                           \
+})
+
+/*
+ * Switch to the EFI page tables early so that we can access the 1:1
+ * runtime services mappings which are not mapped in any other page
+ * tables. This function must be called before runtime_service32().
+ *
+ * Also, disable interrupts because the IDT points to 64-bit handlers,
+ * which aren't going to function correctly when we switch to 32-bit.
+ */
+#define efi_thunk(f, ...)                                              \
+({                                                                     \
+       efi_status_t __s;                                               \
+       unsigned long flags;                                            \
+       u32 func;                                                       \
+                                                                       \
+       efi_sync_low_kernel_mappings();                                 \
+       local_irq_save(flags);                                          \
+                                                                       \
+       efi_scratch.prev_cr3 = read_cr3();                              \
+       write_cr3((unsigned long)efi_scratch.efi_pgt);                  \
+       __flush_tlb_all();                                              \
+                                                                       \
+       func = runtime_service32(f);                                    \
+       __s = efi64_thunk(func, __VA_ARGS__);                   \
+                                                                       \
+       write_cr3(efi_scratch.prev_cr3);                                \
+       __flush_tlb_all();                                              \
+       local_irq_restore(flags);                                       \
+                                                                       \
+       __s;                                                            \
+})
+
+efi_status_t efi_thunk_set_virtual_address_map(
+       void *phys_set_virtual_address_map,
+       unsigned long memory_map_size,
+       unsigned long descriptor_size,
+       u32 descriptor_version,
+       efi_memory_desc_t *virtual_map)
+{
+       efi_status_t status;
+       unsigned long flags;
+       u32 func;
+
+       efi_sync_low_kernel_mappings();
+       local_irq_save(flags);
+
+       efi_scratch.prev_cr3 = read_cr3();
+       write_cr3((unsigned long)efi_scratch.efi_pgt);
+       __flush_tlb_all();
+
+       func = (u32)(unsigned long)phys_set_virtual_address_map;
+       status = efi64_thunk(func, memory_map_size, descriptor_size,
+                            descriptor_version, virtual_map);
+
+       write_cr3(efi_scratch.prev_cr3);
+       __flush_tlb_all();
+       local_irq_restore(flags);
+
+       return status;
+}
+
+static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+       efi_status_t status;
+       u32 phys_tm, phys_tc;
+
+       spin_lock(&rtc_lock);
+
+       phys_tm = virt_to_phys(tm);
+       phys_tc = virt_to_phys(tc);
+
+       status = efi_thunk(get_time, phys_tm, phys_tc);
+
+       spin_unlock(&rtc_lock);
+
+       return status;
+}
+
+static efi_status_t efi_thunk_set_time(efi_time_t *tm)
+{
+       efi_status_t status;
+       u32 phys_tm;
+
+       spin_lock(&rtc_lock);
+
+       phys_tm = virt_to_phys(tm);
+
+       status = efi_thunk(set_time, phys_tm);
+
+       spin_unlock(&rtc_lock);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
+                         efi_time_t *tm)
+{
+       efi_status_t status;
+       u32 phys_enabled, phys_pending, phys_tm;
+
+       spin_lock(&rtc_lock);
+
+       phys_enabled = virt_to_phys(enabled);
+       phys_pending = virt_to_phys(pending);
+       phys_tm = virt_to_phys(tm);
+
+       status = efi_thunk(get_wakeup_time, phys_enabled,
+                            phys_pending, phys_tm);
+
+       spin_unlock(&rtc_lock);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+       efi_status_t status;
+       u32 phys_tm;
+
+       spin_lock(&rtc_lock);
+
+       phys_tm = virt_to_phys(tm);
+
+       status = efi_thunk(set_wakeup_time, enabled, phys_tm);
+
+       spin_unlock(&rtc_lock);
+
+       return status;
+}
+
+
+static efi_status_t
+efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
+                      u32 *attr, unsigned long *data_size, void *data)
+{
+       efi_status_t status;
+       u32 phys_name, phys_vendor, phys_attr;
+       u32 phys_data_size, phys_data;
+
+       phys_data_size = virt_to_phys(data_size);
+       phys_vendor = virt_to_phys(vendor);
+       phys_name = virt_to_phys(name);
+       phys_attr = virt_to_phys(attr);
+       phys_data = virt_to_phys(data);
+
+       status = efi_thunk(get_variable, phys_name, phys_vendor,
+                          phys_attr, phys_data_size, phys_data);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+                      u32 attr, unsigned long data_size, void *data)
+{
+       u32 phys_name, phys_vendor, phys_data;
+       efi_status_t status;
+
+       phys_name = virt_to_phys(name);
+       phys_vendor = virt_to_phys(vendor);
+       phys_data = virt_to_phys(data);
+
+       /* If data_size is > sizeof(u32) we've got problems */
+       status = efi_thunk(set_variable, phys_name, phys_vendor,
+                          attr, data_size, phys_data);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_get_next_variable(unsigned long *name_size,
+                           efi_char16_t *name,
+                           efi_guid_t *vendor)
+{
+       efi_status_t status;
+       u32 phys_name_size, phys_name, phys_vendor;
+
+       phys_name_size = virt_to_phys(name_size);
+       phys_vendor = virt_to_phys(vendor);
+       phys_name = virt_to_phys(name);
+
+       status = efi_thunk(get_next_variable, phys_name_size,
+                          phys_name, phys_vendor);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_get_next_high_mono_count(u32 *count)
+{
+       efi_status_t status;
+       u32 phys_count;
+
+       phys_count = virt_to_phys(count);
+       status = efi_thunk(get_next_high_mono_count, phys_count);
+
+       return status;
+}
+
+static void
+efi_thunk_reset_system(int reset_type, efi_status_t status,
+                      unsigned long data_size, efi_char16_t *data)
+{
+       u32 phys_data;
+
+       phys_data = virt_to_phys(data);
+
+       efi_thunk(reset_system, reset_type, status, data_size, phys_data);
+}
+
+static efi_status_t
+efi_thunk_update_capsule(efi_capsule_header_t **capsules,
+                        unsigned long count, unsigned long sg_list)
+{
+       /*
+        * To properly support this function we would need to repackage
+        * 'capsules' because the firmware doesn't understand 64-bit
+        * pointers.
+        */
+       return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
+                             u64 *remaining_space,
+                             u64 *max_variable_size)
+{
+       efi_status_t status;
+       u32 phys_storage, phys_remaining, phys_max;
+
+       if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+
+       phys_storage = virt_to_phys(storage_space);
+       phys_remaining = virt_to_phys(remaining_space);
+       phys_max = virt_to_phys(max_variable_size);
+
+       status = efi_thunk(query_variable_info, attr, phys_storage,
+                          phys_remaining, phys_max);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_query_capsule_caps(efi_capsule_header_t **capsules,
+                            unsigned long count, u64 *max_size,
+                            int *reset_type)
+{
+       /*
+        * To properly support this function we would need to repackage
+        * 'capsules' because the firmware doesn't understand 64-bit
+        * pointers.
+        */
+       return EFI_UNSUPPORTED;
+}
+
+void efi_thunk_runtime_setup(void)
+{
+       efi.get_time = efi_thunk_get_time;
+       efi.set_time = efi_thunk_set_time;
+       efi.get_wakeup_time = efi_thunk_get_wakeup_time;
+       efi.set_wakeup_time = efi_thunk_set_wakeup_time;
+       efi.get_variable = efi_thunk_get_variable;
+       efi.get_next_variable = efi_thunk_get_next_variable;
+       efi.set_variable = efi_thunk_set_variable;
+       efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
+       efi.reset_system = efi_thunk_reset_system;
+       efi.query_variable_info = efi_thunk_query_variable_info;
+       efi.update_capsule = efi_thunk_update_capsule;
+       efi.query_capsule_caps = efi_thunk_query_capsule_caps;
+}
+#endif /* CONFIG_EFI_MIXED */
index 88073b1402988b49eb6c5e95f9f801a14d40f144..e0984ef0374b87a4dcf9d770b812feff2825285d 100644 (file)
@@ -7,6 +7,10 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+#include <asm/page_types.h>
 
 #define SAVE_XMM                       \
        mov %rsp, %rax;                 \
@@ -164,7 +168,169 @@ ENTRY(efi_call6)
        ret
 ENDPROC(efi_call6)
 
+#ifdef CONFIG_EFI_MIXED
+
+/*
+ * We run this function from the 1:1 mapping.
+ *
+ * This function must be invoked with a 1:1 mapped stack.
+ */
+ENTRY(__efi64_thunk)
+       movl    %ds, %eax
+       push    %rax
+       movl    %es, %eax
+       push    %rax
+       movl    %ss, %eax
+       push    %rax
+
+       subq    $32, %rsp
+       movl    %esi, 0x0(%rsp)
+       movl    %edx, 0x4(%rsp)
+       movl    %ecx, 0x8(%rsp)
+       movq    %r8, %rsi
+       movl    %esi, 0xc(%rsp)
+       movq    %r9, %rsi
+       movl    %esi,  0x10(%rsp)
+
+       sgdt    save_gdt(%rip)
+
+       leaq    1f(%rip), %rbx
+       movq    %rbx, func_rt_ptr(%rip)
+
+       /* Switch to gdt with 32-bit segments */
+       movl    64(%rsp), %eax
+       lgdt    (%rax)
+
+       leaq    efi_enter32(%rip), %rax
+       pushq   $__KERNEL_CS
+       pushq   %rax
+       lretq
+
+1:     addq    $32, %rsp
+
+       lgdt    save_gdt(%rip)
+
+       pop     %rbx
+       movl    %ebx, %ss
+       pop     %rbx
+       movl    %ebx, %es
+       pop     %rbx
+       movl    %ebx, %ds
+
+       /*
+        * Convert 32-bit status code into 64-bit.
+        */
+       test    %rax, %rax
+       jz      1f
+       movl    %eax, %ecx
+       andl    $0x0fffffff, %ecx
+       andl    $0xf0000000, %eax
+       shl     $32, %rax
+       or      %rcx, %rax
+1:
+       ret
+ENDPROC(__efi64_thunk)
+
+ENTRY(efi_exit32)
+       movq    func_rt_ptr(%rip), %rax
+       push    %rax
+       mov     %rdi, %rax
+       ret
+ENDPROC(efi_exit32)
+
+       .code32
+/*
+ * EFI service pointer must be in %edi.
+ *
+ * The stack should represent the 32-bit calling convention.
+ */
+ENTRY(efi_enter32)
+       movl    $__KERNEL_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %ss
+
+       /* Reload pgtables */
+       movl    %cr3, %eax
+       movl    %eax, %cr3
+
+       /* Disable paging */
+       movl    %cr0, %eax
+       btrl    $X86_CR0_PG_BIT, %eax
+       movl    %eax, %cr0
+
+       /* Disable long mode via EFER */
+       movl    $MSR_EFER, %ecx
+       rdmsr
+       btrl    $_EFER_LME, %eax
+       wrmsr
+
+       call    *%edi
+
+       /* We must preserve return value */
+       movl    %eax, %edi
+
+       /*
+        * Some firmware will return with interrupts enabled. Be sure to
+        * disable them before we switch GDTs.
+        */
+       cli
+
+       movl    68(%esp), %eax
+       movl    %eax, 2(%eax)
+       lgdtl   (%eax)
+
+       movl    %cr4, %eax
+       btsl    $(X86_CR4_PAE_BIT), %eax
+       movl    %eax, %cr4
+
+       movl    %cr3, %eax
+       movl    %eax, %cr3
+
+       movl    $MSR_EFER, %ecx
+       rdmsr
+       btsl    $_EFER_LME, %eax
+       wrmsr
+
+       xorl    %eax, %eax
+       lldt    %ax
+
+       movl    72(%esp), %eax
+       pushl   $__KERNEL_CS
+       pushl   %eax
+
+       /* Enable paging */
+       movl    %cr0, %eax
+       btsl    $X86_CR0_PG_BIT, %eax
+       movl    %eax, %cr0
+       lret
+ENDPROC(efi_enter32)
+
+       .data
+       .balign 8
+       .global efi32_boot_gdt
+efi32_boot_gdt:        .word   0
+               .quad   0
+
+save_gdt:      .word   0
+               .quad   0
+func_rt_ptr:   .quad   0
+
+       .global efi_gdt64
+efi_gdt64:
+       .word   efi_gdt64_end - efi_gdt64
+       .long   0                       /* Filled out by user */
+       .word   0
+       .quad   0x0000000000000000      /* NULL descriptor */
+       .quad   0x00af9a000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf92000000ffff      /* __KERNEL_DS */
+       .quad   0x0080890000000000      /* TS descriptor */
+       .quad   0x0000000000000000      /* TS continued */
+efi_gdt64_end:
+#endif /* CONFIG_EFI_MIXED */
+
        .data
 ENTRY(efi_scratch)
        .fill 3,8,0
        .byte 0
+       .quad 0
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
new file mode 100644 (file)
index 0000000..8806fa7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Intel Corporation; author Matt Fleming
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+       .text
+       .code64
+ENTRY(efi64_thunk)
+       push    %rbp
+       push    %rbx
+
+       /*
+        * Switch to 1:1 mapped 32-bit stack pointer.
+        */
+       movq    %rsp, efi_saved_sp(%rip)
+       movq    efi_scratch+25(%rip), %rsp
+
+       /*
+        * Calculate the physical address of the kernel text.
+        */
+       movq    $__START_KERNEL_map, %rax
+       subq    phys_base(%rip), %rax
+
+       /*
+        * Push some physical addresses onto the stack. This is easier
+        * to do now in a code64 section while the assembler can address
+        * 64-bit values. Note that all the addresses on the stack are
+        * 32-bit.
+        */
+       subq    $16, %rsp
+       leaq    efi_exit32(%rip), %rbx
+       subq    %rax, %rbx
+       movl    %ebx, 8(%rsp)
+       leaq    efi_gdt64(%rip), %rbx
+       subq    %rax, %rbx
+       movl    %ebx, 2(%ebx)
+       movl    %ebx, 4(%rsp)
+       leaq    efi_gdt32(%rip), %rbx
+       subq    %rax, %rbx
+       movl    %ebx, 2(%ebx)
+       movl    %ebx, (%rsp)
+
+       leaq    __efi64_thunk(%rip), %rbx
+       subq    %rax, %rbx
+       call    *%rbx
+
+       movq    efi_saved_sp(%rip), %rsp
+       pop     %rbx
+       pop     %rbp
+       retq
+ENDPROC(efi64_thunk)
+
+       .data
+efi_gdt32:
+       .word   efi_gdt32_end - efi_gdt32
+       .long   0                       /* Filled out above */
+       .word   0
+       .quad   0x0000000000000000      /* NULL descriptor */
+       .quad   0x00cf9a000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf93000000ffff      /* __KERNEL_DS */
+efi_gdt32_end:
+
+efi_saved_sp:          .quad 0
index 39febb214e8c748ffd245c409c3b0cea31d3cebd..9471b9456f259762baf47c05a742d8401146b81e 100644 (file)
@@ -88,7 +88,7 @@ struct ts5500_sbc {
 static const struct {
        const char * const string;
        const ssize_t offset;
-} ts5500_signatures[] __initdata = {
+} ts5500_signatures[] __initconst = {
        { "TS-5x00 AMD Elan", 0xb14 },
 };
 
index 7d01b8c56c0029a59aa9b5b9e33036728ea7c77e..cc04e67bfd0589966e1c4b4b2fa29079c439ae24 100644 (file)
 #define smp_rmb()      barrier()
 #endif /* CONFIG_X86_PPRO_FENCE */
 
-#ifdef CONFIG_X86_OOSTORE
-#define smp_wmb()      wmb()
-#else /* CONFIG_X86_OOSTORE */
 #define smp_wmb()      barrier()
-#endif /* CONFIG_X86_OOSTORE */
 
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
index fd14be1d1472204afc041a5bef320b2f7c7275af..9206ac7961a596798a1302b808bcf1fd6f119272 100644 (file)
@@ -2,6 +2,8 @@
 # Building vDSO images for x86.
 #
 
+KBUILD_CFLAGS += $(DISABLE_LTO)
+
 VDSO64-$(CONFIG_X86_64)                := y
 VDSOX32-$(CONFIG_X86_X32_ABI)  := y
 VDSO32-$(CONFIG_X86_32)                := y
@@ -35,7 +37,8 @@ export CPPFLAGS_vdso.lds += -P -C
 
 VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
                        -Wl,--no-undefined \
-                       -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+                       -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \
+                       $(DISABLE_LTO)
 
 $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
 
@@ -127,7 +130,7 @@ vdso32.so-$(VDSO32-y)               += sysenter
 vdso32-images                  = $(vdso32.so-y:%=vdso32-%.so)
 
 CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1
 
 # This makes sure the $(obj) subdirectory exists even though vdso32/
 # is not a kbuild sub-make subdirectory.
@@ -181,7 +184,8 @@ quiet_cmd_vdso = VDSO    $@
                       -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
                 sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
 
-VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
+               $(LTO_CFLAGS)
 GCOV_PROFILE := n
 
 #
index 256282e7888b118b02e61d657f78ae8490bf0fe4..2423ef04ffea596fd43eeb918f290003277fbb21 100644 (file)
@@ -365,7 +365,7 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
 /* Assume pteval_t is equivalent to all the other *val_t types. */
 static pteval_t pte_mfn_to_pfn(pteval_t val)
 {
-       if (pteval_present(val)) {
+       if (val & _PAGE_PRESENT) {
                unsigned long mfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
                unsigned long pfn = mfn_to_pfn(mfn);
 
@@ -381,7 +381,7 @@ static pteval_t pte_mfn_to_pfn(pteval_t val)
 
 static pteval_t pte_pfn_to_mfn(pteval_t val)
 {
-       if (pteval_present(val)) {
+       if (val & _PAGE_PRESENT) {
                unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
                pteval_t flags = val & PTE_FLAGS_MASK;
                unsigned long mfn;
index 581521c843a576d4264567e90c11dfaf645d6238..4d3acc34a998e5aca97d58c9573e822a29905626 100644 (file)
@@ -183,7 +183,7 @@ __visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
 
        local_irq_save(flags);
 
-       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+       kstat_incr_irq_this_cpu(irq);
 out:
        cpumask_clear_cpu(cpu, &waiting_cpus);
        w->lock = NULL;
index 0a337e4a8370aefce9d310c47bf75053316a1d5a..c3d20ba6eb86d6f7d42102f076f6085bcbe096c8 100644 (file)
@@ -9,6 +9,7 @@ generic-y += errno.h
 generic-y += exec.h
 generic-y += fcntl.h
 generic-y += hardirq.h
+generic-y += hash.h
 generic-y += ioctl.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
@@ -17,7 +18,9 @@ generic-y += kvm_para.h
 generic-y += linkage.h
 generic-y += local.h
 generic-y += local64.h
+generic-y += mcs_spinlock.h
 generic-y += percpu.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sections.h
@@ -27,5 +30,3 @@ generic-y += termios.h
 generic-y += topology.h
 generic-y += trace_clock.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
index 482868a2de6ebde7995002509445859bf7a002b0..3eee94f621ebd723195d326965cb6afc6998c85f 100644 (file)
@@ -155,18 +155,6 @@ void __init init_IRQ(void)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_chip *chip = irq_data_get_irq_chip(data);
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       if (chip->irq_set_affinity)
-               chip->irq_set_affinity(data, cpumask_of(cpu), false);
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
 /*
  * The CPU has been marked offline.  Migrate IRQs off this CPU.  If
  * the affinity settings do not allow other CPUs, force them onto any
@@ -175,10 +163,9 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
 void migrate_irqs(void)
 {
        unsigned int i, cpu = smp_processor_id();
-       struct irq_desc *desc;
 
-       for_each_irq_desc(i, desc) {
-               struct irq_data *data = irq_desc_get_irq_data(desc);
+       for_each_active_irq(i) {
+               struct irq_data *data = irq_get_irq_data(i);
                unsigned int newcpu;
 
                if (irqd_is_per_cpu(data))
@@ -194,11 +181,8 @@ void migrate_irqs(void)
                                            i, cpu);
 
                        cpumask_setall(data->affinity);
-                       newcpu = cpumask_any_and(data->affinity,
-                                                cpu_online_mask);
                }
-
-               route_irq(data, i, newcpu);
+               irq_set_affinity(i, data->affinity);
        }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
index 853f92749202cbfe5b252d557f667b7f970ac872..bfe16d5af9f91a7eec049420e3f5b080476dc503 100644 (file)
@@ -693,20 +693,11 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
        if (!uninit_q)
                return NULL;
 
-       uninit_q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
-       if (!uninit_q->flush_rq)
-               goto out_cleanup_queue;
-
        q = blk_init_allocated_queue(uninit_q, rfn, lock);
        if (!q)
-               goto out_free_flush_rq;
-       return q;
+               blk_cleanup_queue(uninit_q);
 
-out_free_flush_rq:
-       kfree(uninit_q->flush_rq);
-out_cleanup_queue:
-       blk_cleanup_queue(uninit_q);
-       return NULL;
+       return q;
 }
 EXPORT_SYMBOL(blk_init_queue_node);
 
@@ -717,9 +708,13 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
        if (!q)
                return NULL;
 
-       if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+       q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
+       if (!q->flush_rq)
                return NULL;
 
+       if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+               goto fail;
+
        q->request_fn           = rfn;
        q->prep_rq_fn           = NULL;
        q->unprep_rq_fn         = NULL;
@@ -742,12 +737,16 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
        /* init elevator */
        if (elevator_init(q, NULL)) {
                mutex_unlock(&q->sysfs_lock);
-               return NULL;
+               goto fail;
        }
 
        mutex_unlock(&q->sysfs_lock);
 
        return q;
+
+fail:
+       kfree(q->flush_rq);
+       return NULL;
 }
 EXPORT_SYMBOL(blk_init_allocated_queue);
 
index c68613bb4c79b718b87dd5dc90b3a8cdd307c3fc..dbf4502b1d6779eadd1573f28f75def4e26a031a 100644 (file)
@@ -65,7 +65,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
         * be resued after dying flag is set
         */
        if (q->mq_ops) {
-               blk_mq_insert_request(q, rq, at_head, true);
+               blk_mq_insert_request(rq, at_head, true, false);
                return;
        }
 
index 66e2b697f5db1299b20d8018232fbcd191b279b8..43e6b4755e9a7e74e05479a83d42fbd88762e9f4 100644 (file)
@@ -137,17 +137,20 @@ static void mq_flush_run(struct work_struct *work)
        rq = container_of(work, struct request, mq_flush_work);
 
        memset(&rq->csd, 0, sizeof(rq->csd));
-       blk_mq_run_request(rq, true, false);
+       blk_mq_insert_request(rq, false, true, false);
 }
 
-static bool blk_flush_queue_rq(struct request *rq)
+static bool blk_flush_queue_rq(struct request *rq, bool add_front)
 {
        if (rq->q->mq_ops) {
                INIT_WORK(&rq->mq_flush_work, mq_flush_run);
                kblockd_schedule_work(rq->q, &rq->mq_flush_work);
                return false;
        } else {
-               list_add_tail(&rq->queuelist, &rq->q->queue_head);
+               if (add_front)
+                       list_add(&rq->queuelist, &rq->q->queue_head);
+               else
+                       list_add_tail(&rq->queuelist, &rq->q->queue_head);
                return true;
        }
 }
@@ -193,7 +196,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
 
        case REQ_FSEQ_DATA:
                list_move_tail(&rq->flush.list, &q->flush_data_in_flight);
-               queued = blk_flush_queue_rq(rq);
+               queued = blk_flush_queue_rq(rq, true);
                break;
 
        case REQ_FSEQ_DONE:
@@ -326,7 +329,7 @@ static bool blk_kick_flush(struct request_queue *q)
        q->flush_rq->rq_disk = first_rq->rq_disk;
        q->flush_rq->end_io = flush_end_io;
 
-       return blk_flush_queue_rq(q->flush_rq);
+       return blk_flush_queue_rq(q->flush_rq, false);
 }
 
 static void flush_data_end_io(struct request *rq, int error)
@@ -411,7 +414,7 @@ void blk_insert_flush(struct request *rq)
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
                if (q->mq_ops) {
-                       blk_mq_run_request(rq, false, true);
+                       blk_mq_insert_request(rq, false, false, true);
                } else
                        list_add_tail(&rq->queuelist, &q->queue_head);
                return;
index 3146befb56aaac7b925428d0afee89c9e083094a..136ef8643bbade3dd2d5d84e35183c749bc00399 100644 (file)
@@ -11,7 +11,7 @@
 #include "blk-mq.h"
 
 static LIST_HEAD(blk_mq_cpu_notify_list);
-static DEFINE_SPINLOCK(blk_mq_cpu_notify_lock);
+static DEFINE_RAW_SPINLOCK(blk_mq_cpu_notify_lock);
 
 static int blk_mq_main_cpu_notify(struct notifier_block *self,
                                  unsigned long action, void *hcpu)
@@ -19,12 +19,12 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self,
        unsigned int cpu = (unsigned long) hcpu;
        struct blk_mq_cpu_notifier *notify;
 
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
 
        list_for_each_entry(notify, &blk_mq_cpu_notify_list, list)
                notify->notify(notify->data, action, cpu);
 
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
        return NOTIFY_OK;
 }
 
@@ -32,16 +32,16 @@ void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
        BUG_ON(!notifier->notify);
 
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
        list_add_tail(&notifier->list, &blk_mq_cpu_notify_list);
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
 }
 
 void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
        list_del(&notifier->list);
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
 }
 
 void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
index 1fa9dd153fde22a976483ef3b5da3ec39f0f458e..883f7208901585ab1ee02891a3ad5b67599a4243 100644 (file)
@@ -73,8 +73,8 @@ static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
                set_bit(ctx->index_hw, hctx->ctx_map);
 }
 
-static struct request *blk_mq_alloc_rq(struct blk_mq_hw_ctx *hctx, gfp_t gfp,
-                                      bool reserved)
+static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
+                                             gfp_t gfp, bool reserved)
 {
        struct request *rq;
        unsigned int tag;
@@ -193,12 +193,6 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
        ctx->rq_dispatched[rw_is_sync(rw_flags)]++;
 }
 
-static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
-                                             gfp_t gfp, bool reserved)
-{
-       return blk_mq_alloc_rq(hctx, gfp, reserved);
-}
-
 static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
                                                   int rw, gfp_t gfp,
                                                   bool reserved)
@@ -289,38 +283,10 @@ void blk_mq_free_request(struct request *rq)
        __blk_mq_free_request(hctx, ctx, rq);
 }
 
-static void blk_mq_bio_endio(struct request *rq, struct bio *bio, int error)
-{
-       if (error)
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-               error = -EIO;
-
-       if (unlikely(rq->cmd_flags & REQ_QUIET))
-               set_bit(BIO_QUIET, &bio->bi_flags);
-
-       /* don't actually finish bio if it's part of flush sequence */
-       if (!(rq->cmd_flags & REQ_FLUSH_SEQ))
-               bio_endio(bio, error);
-}
-
-void blk_mq_end_io(struct request *rq, int error)
+bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes)
 {
-       struct bio *bio = rq->bio;
-       unsigned int bytes = 0;
-
-       trace_block_rq_complete(rq->q, rq);
-
-       while (bio) {
-               struct bio *next = bio->bi_next;
-
-               bio->bi_next = NULL;
-               bytes += bio->bi_iter.bi_size;
-               blk_mq_bio_endio(rq, bio, error);
-               bio = next;
-       }
-
-       blk_account_io_completion(rq, bytes);
+       if (blk_update_request(rq, error, blk_rq_bytes(rq)))
+               return true;
 
        blk_account_io_done(rq);
 
@@ -328,8 +294,9 @@ void blk_mq_end_io(struct request *rq, int error)
                rq->end_io(rq, error);
        else
                blk_mq_free_request(rq);
+       return false;
 }
-EXPORT_SYMBOL(blk_mq_end_io);
+EXPORT_SYMBOL(blk_mq_end_io_partial);
 
 static void __blk_mq_complete_request_remote(void *data)
 {
@@ -730,60 +697,27 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
        blk_mq_add_timer(rq);
 }
 
-void blk_mq_insert_request(struct request_queue *q, struct request *rq,
-                          bool at_head, bool run_queue)
+void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
+               bool async)
 {
+       struct request_queue *q = rq->q;
        struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx, *current_ctx;
+       struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
+
+       current_ctx = blk_mq_get_ctx(q);
+       if (!cpu_online(ctx->cpu))
+               rq->mq_ctx = ctx = current_ctx;
 
-       ctx = rq->mq_ctx;
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
-       if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+       if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA) &&
+           !(rq->cmd_flags & (REQ_FLUSH_SEQ))) {
                blk_insert_flush(rq);
        } else {
-               current_ctx = blk_mq_get_ctx(q);
-
-               if (!cpu_online(ctx->cpu)) {
-                       ctx = current_ctx;
-                       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-                       rq->mq_ctx = ctx;
-               }
                spin_lock(&ctx->lock);
                __blk_mq_insert_request(hctx, rq, at_head);
                spin_unlock(&ctx->lock);
-
-               blk_mq_put_ctx(current_ctx);
-       }
-
-       if (run_queue)
-               __blk_mq_run_hw_queue(hctx);
-}
-EXPORT_SYMBOL(blk_mq_insert_request);
-
-/*
- * This is a special version of blk_mq_insert_request to bypass FLUSH request
- * check. Should only be used internally.
- */
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async)
-{
-       struct request_queue *q = rq->q;
-       struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx, *current_ctx;
-
-       current_ctx = blk_mq_get_ctx(q);
-
-       ctx = rq->mq_ctx;
-       if (!cpu_online(ctx->cpu)) {
-               ctx = current_ctx;
-               rq->mq_ctx = ctx;
        }
-       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
-       /* ctx->cpu might be offline */
-       spin_lock(&ctx->lock);
-       __blk_mq_insert_request(hctx, rq, false);
-       spin_unlock(&ctx->lock);
 
        blk_mq_put_ctx(current_ctx);
 
@@ -926,6 +860,8 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
        ctx = blk_mq_get_ctx(q);
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
+       if (is_sync)
+               rw |= REQ_SYNC;
        trace_block_getrq(q, bio, rw);
        rq = __blk_mq_alloc_request(hctx, GFP_ATOMIC, false);
        if (likely(rq))
index ed0035cd458ee8f78691a8f95415a8665707ca11..72beba1f9d55efa827e8667535a7f2956dd2b924 100644 (file)
@@ -23,7 +23,6 @@ struct blk_mq_ctx {
 };
 
 void __blk_mq_complete_request(struct request *rq);
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async);
 void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
 void blk_mq_init_flush(struct request_queue *q);
 void blk_mq_drain_queue(struct request_queue *q);
index b3138fbb46a4bc4ede53190263d2d8b54e310b42..0a0a90f52d26f3e72c48c68c56cbc93d6b4d3973 100644 (file)
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/spmi/Kconfig"
+
 source "drivers/hsi/Kconfig"
 
 source "drivers/pps/Kconfig"
@@ -170,4 +172,6 @@ source "drivers/phy/Kconfig"
 
 source "drivers/powercap/Kconfig"
 
+source "drivers/mcb/Kconfig"
+
 endmenu
index 8e3b8b06c0b2e26a90308b9f15457bfa9da06b13..e3ced91b1784af3881de45870427a37a2d2dc029 100644 (file)
@@ -66,6 +66,7 @@ obj-$(CONFIG_ATA)             += ata/
 obj-$(CONFIG_TARGET_CORE)      += target/
 obj-$(CONFIG_MTD)              += mtd/
 obj-$(CONFIG_SPI)              += spi/
+obj-$(CONFIG_SPMI)             += spmi/
 obj-y                          += hsi/
 obj-y                          += net/
 obj-$(CONFIG_ATM)              += atm/
@@ -155,3 +156,4 @@ obj-$(CONFIG_IPACK_BUS)             += ipack/
 obj-$(CONFIG_NTB)              += ntb/
 obj-$(CONFIG_FMC)              += fmc/
 obj-$(CONFIG_POWERCAP)         += powercap/
+obj-$(CONFIG_MCB)              += mcb/
index 4770de5707b9b9eb0a4c27f14c7ec9ad13035257..c205653e96447b12ab9ed163715bf9d64c0cd230 100644 (file)
@@ -43,19 +43,6 @@ config ACPI_SLEEP
        depends on SUSPEND || HIBERNATION
        default y
 
-config ACPI_PROCFS
-       bool "Deprecated /proc/acpi files"
-       depends on PROC_FS
-       help
-         For backwards compatibility, this option allows
-         deprecated /proc/acpi/ files to exist, even when
-         they have been replaced by functions in /sys.
-
-         This option has no effect on /proc/acpi/ files
-         and functions which do not yet exist in /sys.
-
-         Say N to delete /proc/acpi/ files that have moved to /sys/
-
 config ACPI_EC_DEBUGFS
        tristate "EC read/write access through /sys/kernel/debug/ec"
        default n
@@ -115,7 +102,7 @@ config ACPI_BUTTON
 
 config ACPI_VIDEO
        tristate "Video"
-       depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
+       depends on X86 && BACKLIGHT_CLASS_DEVICE
        depends on INPUT
        select THERMAL
        help
@@ -343,6 +330,19 @@ config ACPI_BGRT
          data from the firmware boot splash. It will appear under
          /sys/firmware/acpi/bgrt/ .
 
+config ACPI_REDUCED_HARDWARE_ONLY
+       bool "Hardware-reduced ACPI support only" if EXPERT
+       def_bool n
+       depends on ACPI
+       help
+       This config item changes the way the ACPI code is built.  When this
+       option is selected, the kernel will use a specialized version of
+       ACPICA that ONLY supports the ACPI "reduced hardware" mode.  The
+       resulting kernel will be smaller but it will also be restricted to
+       running in ACPI reduced hardware mode ONLY.
+
+       If you are unsure what to do, do not enable this option.
+
 source "drivers/acpi/apei/Kconfig"
 
 config ACPI_EXTLOG
index 6f190bc2b8b784bf7e09425b77c560fa60f04b90..2c01c1da29ce39f637136a12a512f2a473333233 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/acpi.h>
+#include "battery.h"
 
 #define PREFIX "ACPI: "
 
@@ -57,6 +58,7 @@ struct acpi_ac {
        struct power_supply charger;
        struct platform_device *pdev;
        unsigned long long state;
+       struct notifier_block battery_nb;
 };
 
 #define to_acpi_ac(x) container_of(x, struct acpi_ac, charger)
@@ -152,6 +154,26 @@ static void acpi_ac_notify_handler(acpi_handle handle, u32 event, void *data)
        return;
 }
 
+static int acpi_ac_battery_notify(struct notifier_block *nb,
+                                 unsigned long action, void *data)
+{
+       struct acpi_ac *ac = container_of(nb, struct acpi_ac, battery_nb);
+       struct acpi_bus_event *event = (struct acpi_bus_event *)data;
+
+       /*
+        * On HP Pavilion dv6-6179er AC status notifications aren't triggered
+        * when adapter is plugged/unplugged. However, battery status
+        * notifcations are triggered when battery starts charging or
+        * discharging. Re-reading AC status triggers lost AC notifications,
+        * if AC status has changed.
+        */
+       if (strcmp(event->device_class, ACPI_BATTERY_CLASS) == 0 &&
+           event->type == ACPI_BATTERY_NOTIFY_STATUS)
+               acpi_ac_get_state(ac);
+
+       return NOTIFY_OK;
+}
+
 static int thinkpad_e530_quirk(const struct dmi_system_id *d)
 {
        ac_sleep_before_get_state_ms = 1000;
@@ -215,6 +237,8 @@ static int acpi_ac_probe(struct platform_device *pdev)
               acpi_device_name(adev), acpi_device_bid(adev),
               ac->state ? "on-line" : "off-line");
 
+       ac->battery_nb.notifier_call = acpi_ac_battery_notify;
+       register_acpi_notifier(&ac->battery_nb);
 end:
        if (result)
                kfree(ac);
@@ -261,6 +285,7 @@ static int acpi_ac_remove(struct platform_device *pdev)
        ac = platform_get_drvdata(pdev);
        if (ac->charger.dev)
                power_supply_unregister(&ac->charger);
+       unregister_acpi_notifier(&ac->battery_nb);
 
        kfree(ac);
 
index 84190ed89c04bb74f1a69d0c8d72fe23efbfacc2..961b45d18a5de484243da61ee0e40625956c3265 100644 (file)
@@ -18,8 +18,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 ACPI_MODULE_NAME("cmos rtc");
 
 static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
index 6745fe137b9ea541ae729429035eaeca8fc8fc07..69e29f409d4c69952bf3655daeec25bbfeff085e 100644 (file)
@@ -33,6 +33,13 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_GENERAL_UART_RTS_OVRD     BIT(3)
 #define LPSS_SW_LTR                    0x10
 #define LPSS_AUTO_LTR                  0x14
+#define LPSS_LTR_SNOOP_REQ             BIT(15)
+#define LPSS_LTR_SNOOP_MASK            0x0000FFFF
+#define LPSS_LTR_SNOOP_LAT_1US         0x800
+#define LPSS_LTR_SNOOP_LAT_32US                0xC00
+#define LPSS_LTR_SNOOP_LAT_SHIFT       5
+#define LPSS_LTR_SNOOP_LAT_CUTOFF      3000
+#define LPSS_LTR_MAX_VAL               0x3FF
 #define LPSS_TX_INT                    0x20
 #define LPSS_TX_INT_MASK               BIT(1)
 
@@ -102,6 +109,16 @@ static struct lpss_device_desc lpt_sdio_dev_desc = {
        .ltr_required = true,
 };
 
+static struct lpss_shared_clock pwm_clock = {
+       .name = "pwm_clk",
+       .rate = 25000000,
+};
+
+static struct lpss_device_desc byt_pwm_dev_desc = {
+       .clk_required = true,
+       .shared_clock = &pwm_clock,
+};
+
 static struct lpss_shared_clock uart_clock = {
        .name = "uart_clk",
        .rate = 44236800,
@@ -157,6 +174,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
        { "INT33C7", },
 
        /* BayTrail LPSS devices */
+       { "80860F09", (unsigned long)&byt_pwm_dev_desc },
        { "80860F0A", (unsigned long)&byt_uart_dev_desc },
        { "80860F0E", (unsigned long)&byt_spi_dev_desc },
        { "80860F14", (unsigned long)&byt_sdio_dev_desc },
@@ -315,6 +333,17 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
        return ret;
 }
 
+static u32 __lpss_reg_read(struct lpss_private_data *pdata, unsigned int reg)
+{
+       return readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+}
+
+static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata,
+                            unsigned int reg)
+{
+       writel(val, pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+}
+
 static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
 {
        struct acpi_device *adev;
@@ -336,7 +365,7 @@ static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
                ret = -ENODEV;
                goto out;
        }
-       *val = readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+       *val = __lpss_reg_read(pdata, reg);
 
  out:
        spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -389,6 +418,37 @@ static struct attribute_group lpss_attr_group = {
        .name = "lpss_ltr",
 };
 
+static void acpi_lpss_set_ltr(struct device *dev, s32 val)
+{
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+       u32 ltr_mode, ltr_val;
+
+       ltr_mode = __lpss_reg_read(pdata, LPSS_GENERAL);
+       if (val < 0) {
+               if (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) {
+                       ltr_mode &= ~LPSS_GENERAL_LTR_MODE_SW;
+                       __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
+               }
+               return;
+       }
+       ltr_val = __lpss_reg_read(pdata, LPSS_SW_LTR) & ~LPSS_LTR_SNOOP_MASK;
+       if (val >= LPSS_LTR_SNOOP_LAT_CUTOFF) {
+               ltr_val |= LPSS_LTR_SNOOP_LAT_32US;
+               val = LPSS_LTR_MAX_VAL;
+       } else if (val > LPSS_LTR_MAX_VAL) {
+               ltr_val |= LPSS_LTR_SNOOP_LAT_32US | LPSS_LTR_SNOOP_REQ;
+               val >>= LPSS_LTR_SNOOP_LAT_SHIFT;
+       } else {
+               ltr_val |= LPSS_LTR_SNOOP_LAT_1US | LPSS_LTR_SNOOP_REQ;
+       }
+       ltr_val |= val;
+       __lpss_reg_write(ltr_val, pdata, LPSS_SW_LTR);
+       if (!(ltr_mode & LPSS_GENERAL_LTR_MODE_SW)) {
+               ltr_mode |= LPSS_GENERAL_LTR_MODE_SW;
+               __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
+       }
+}
+
 static int acpi_lpss_platform_notify(struct notifier_block *nb,
                                     unsigned long action, void *data)
 {
@@ -426,9 +486,29 @@ static struct notifier_block acpi_lpss_nb = {
        .notifier_call = acpi_lpss_platform_notify,
 };
 
+static void acpi_lpss_bind(struct device *dev)
+{
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+       if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
+               return;
+
+       if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE)
+               dev->power.set_latency_tolerance = acpi_lpss_set_ltr;
+       else
+               dev_err(dev, "MMIO size insufficient to access LTR\n");
+}
+
+static void acpi_lpss_unbind(struct device *dev)
+{
+       dev->power.set_latency_tolerance = NULL;
+}
+
 static struct acpi_scan_handler lpss_handler = {
        .ids = acpi_lpss_device_ids,
        .attach = acpi_lpss_create_device,
+       .bind = acpi_lpss_bind,
+       .unbind = acpi_lpss_unbind,
 };
 
 void __init acpi_lpss_init(void)
index df96a0fe48905aa77d5ac17248195c0c1fcb9221..37d73024b82e4f9a7df2820e331bd873e0805947 100644 (file)
@@ -408,28 +408,14 @@ static int acpi_pad_pur(acpi_handle handle)
        return num;
 }
 
-/* Notify firmware how many CPUs are idle */
-static void acpi_pad_ost(acpi_handle handle, int stat,
-       uint32_t idle_cpus)
-{
-       union acpi_object params[3] = {
-               {.type = ACPI_TYPE_INTEGER,},
-               {.type = ACPI_TYPE_INTEGER,},
-               {.type = ACPI_TYPE_BUFFER,},
-       };
-       struct acpi_object_list arg_list = {3, params};
-
-       params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
-       params[1].integer.value =  stat;
-       params[2].buffer.length = 4;
-       params[2].buffer.pointer = (void *)&idle_cpus;
-       acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-}
-
 static void acpi_pad_handle_notify(acpi_handle handle)
 {
        int num_cpus;
        uint32_t idle_cpus;
+       struct acpi_buffer param = {
+               .length = 4,
+               .pointer = (void *)&idle_cpus,
+       };
 
        mutex_lock(&isolated_cpus_lock);
        num_cpus = acpi_pad_pur(handle);
@@ -439,7 +425,7 @@ static void acpi_pad_handle_notify(acpi_handle handle)
        }
        acpi_pad_idle_cpus(num_cpus);
        idle_cpus = acpi_pad_idle_cpus_num();
-       acpi_pad_ost(handle, 0, idle_cpus);
+       acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY, 0, &param);
        mutex_unlock(&isolated_cpus_lock);
 }
 
index 438304086ff1bb117f946f79038ff586a80df9c5..b7ed86a20427e43080db1f4238afba5864e426a6 100644 (file)
@@ -122,6 +122,8 @@ acpi-y +=           \
        rsaddr.o        \
        rscalc.o        \
        rscreate.o      \
+       rsdump.o        \
+       rsdumpinfo.o    \
        rsinfo.o        \
        rsio.o          \
        rsirq.o         \
@@ -132,8 +134,6 @@ acpi-y +=           \
        rsutils.o       \
        rsxface.o
 
-acpi-$(ACPI_FUTURE_USAGE) += rsdump.o rsdumpinfo.o
-
 acpi-y +=              \
        tbfadt.o        \
        tbfind.o        \
index 8a6c4a0d22db7b2dc5b8250c91880a60e74bfbb3..6f1c616910acad10e379a320933cb10be08f9d94 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2bf3ca2b8a7a653f16fa97264e95063abd1fa3e0..68a91eb0fa483f24b55218770c4bed079873d3e6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,8 @@ ACPI_HW_DEPENDENT_RETURN_VOID(void
                                                   char *block_arg))
 ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void))
 
+void acpi_db_execute_test(char *type_arg);
+
 /*
  * dbconvert - miscellaneous conversion routines
  */
index 427db72a6302f4b53f32a71d44a8a0f0ef170b27..5b472c43c31da376e14e039f4583521e68b184da 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0fb0adf435d667593c29b2f0785cb5a5c3a35e8c..68ec61fff1886872da7143ec804013ab5b504656 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ed1aa384df2fd7680268c569a0388434b76d7d4..8f40bb972ae3907a0eec7c50b7d2e39a48a231cb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * to simplify maintenance of the code.
  */
 #ifdef DEFINE_ACPI_GLOBALS
-#define ACPI_EXTERN
-#define ACPI_INIT_GLOBAL(a,b) a=b
+#define ACPI_GLOBAL(type,name) \
+       extern type name; \
+       type name
+
+#define ACPI_INIT_GLOBAL(type,name,value) \
+       type name=value
+
 #else
-#define ACPI_EXTERN extern
-#define ACPI_INIT_GLOBAL(a,b) a
+#define ACPI_GLOBAL(type,name) \
+       extern type name
+
+#define ACPI_INIT_GLOBAL(type,name,value) \
+       extern type name
 #endif
 
 #ifdef DEFINE_ACPI_GLOBALS
@@ -82,7 +90,7 @@
  * 5) Allow unresolved references (invalid target name) in package objects
  * 6) Enable warning messages for behavior that is not ACPI spec compliant
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE);
 
 /*
  * Automatically serialize ALL control methods? Default is FALSE, meaning
@@ -90,25 +98,25 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
  * Only change this if the ASL code is poorly written and cannot handle
  * reentrancy even though methods are marked "NotSerialized".
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_all_methods_serialized, FALSE);
 
 /*
  * Create the predefined _OSI method in the namespace? Default is TRUE
  * because ACPI CA is fully compatible with other ACPI implementations.
  * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE);
 
 /*
  * Optionally use default values for the ACPI register widths. Set this to
  * TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE);
 
 /*
  * Optionally enable output from the AML Debug Object.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE);
 
 /*
  * Optionally copy the entire DSDT to local memory (instead of simply
@@ -116,7 +124,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
  * DSDT, creating the need for this option. Default is FALSE, do not copy
  * the DSDT.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE);
 
 /*
  * Optionally ignore an XSDT if present and use the RSDT instead.
@@ -124,7 +132,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
  * of the RSDT, the XSDT has been found to be corrupt or ill-formed on
  * some machines. Default behavior is to use the XSDT if present.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE);
 
 /*
  * Optionally use 32-bit FADT addresses if and when there is a conflict
@@ -134,7 +142,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
  * some machines have been found to have a corrupted non-zero 64-bit
  * address. Default is FALSE, do not favor the 32-bit addresses.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE);
 
 /*
  * Optionally truncate I/O addresses to 16 bits. Provides compatibility
@@ -142,47 +150,28 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
  * this value is set to TRUE if any Windows OSI strings have been
  * requested by the BIOS.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE);
 
 /*
  * Disable runtime checking and repair of values returned by control methods.
  * Use only if the repair is causing a problem on a particular machine.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
+ACPI_INIT_GLOBAL(u8, 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_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE);
 
 /*
  * We keep track of the latest version of Windows that has been requested by
  * the BIOS.
  */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_osi_data, 0);
-
-/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
-
-struct acpi_table_fadt acpi_gbl_FADT;
-u32 acpi_current_gpe_count;
-u32 acpi_gbl_trace_flags;
-acpi_name acpi_gbl_trace_method_name;
-u8 acpi_gbl_system_awake_and_running;
-
-/*
- * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
- * that the ACPI hardware is no longer required. A flag in the FADT indicates
- * a reduced HW machine, and that flag is duplicated here for convenience.
- */
-u8 acpi_gbl_reduced_hardware;
+ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0);
 
 #endif                         /* DEFINE_ACPI_GLOBALS */
 
-/* Do not disassemble buffers to resource descriptors */
-
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
-
 /*****************************************************************************
  *
  * ACPI Table globals
@@ -190,37 +179,36 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
  ****************************************************************************/
 
 /*
- * acpi_gbl_root_table_list is the master list of ACPI tables that were
- * found in the RSDT/XSDT.
+ * Master list of all ACPI tables that were found in the RSDT/XSDT.
  */
-ACPI_EXTERN struct acpi_table_list acpi_gbl_root_table_list;
+ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list);
+
+/* DSDT information. Used to check for DSDT corruption */
+
+ACPI_GLOBAL(struct acpi_table_header *, acpi_gbl_DSDT);
+ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header);
 
 #if (!ACPI_REDUCED_HARDWARE)
-ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
+ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS);
 
 #endif                         /* !ACPI_REDUCED_HARDWARE */
 
 /* These addresses are calculated from the FADT Event Block addresses */
 
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_status;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
-
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_status);
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable);
 
-/* DSDT information. Used to check for DSDT corruption */
-
-ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN struct acpi_table_header acpi_gbl_original_dsdt_header;
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status);
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable);
 
 /*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is
  * determined by the revision of the DSDT: If the DSDT revision is less than
  * 2, use only the lower 32 bits of the internal 64-bit Integer.
  */
-ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
-ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
-ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
+ACPI_GLOBAL(u8, acpi_gbl_integer_bit_width);
+ACPI_GLOBAL(u8, acpi_gbl_integer_byte_width);
+ACPI_GLOBAL(u8, acpi_gbl_integer_nybble_width);
 
 /*****************************************************************************
  *
@@ -233,36 +221,36 @@ ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
  * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
  * (The table maps local handles to the real OS handles)
  */
-ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
+ACPI_GLOBAL(struct acpi_mutex_info, acpi_gbl_mutex_info[ACPI_NUM_MUTEX]);
 
 /*
  * Global lock mutex is an actual AML mutex object
  * Global lock semaphore works in conjunction with the actual global lock
  * Global lock spinlock is used for "pending" handshake
  */
-ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
-ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
-ACPI_EXTERN acpi_spinlock acpi_gbl_global_lock_pending_lock;
-ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
-ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
-ACPI_EXTERN u8 acpi_gbl_global_lock_present;
-ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
+ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_global_lock_mutex);
+ACPI_GLOBAL(acpi_semaphore, acpi_gbl_global_lock_semaphore);
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_global_lock_pending_lock);
+ACPI_GLOBAL(u16, acpi_gbl_global_lock_handle);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_acquired);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_present);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending);
 
 /*
  * Spinlocks are used for interfaces that can be possibly called at
  * interrupt level
  */
-ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock;   /* For GPE data structs and registers */
-ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock;      /* For ACPI H/W except GPE registers */
-ACPI_EXTERN acpi_spinlock acpi_gbl_reference_count_lock;
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock); /* For GPE data structs and registers */
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock);    /* For ACPI H/W except GPE registers */
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock);
 
 /* Mutex for _OSI support */
 
-ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+ACPI_GLOBAL(acpi_mutex, acpi_gbl_osi_mutex);
 
 /* Reader/Writer lock is used for namespace walk and dynamic table unload */
 
-ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
+ACPI_GLOBAL(struct acpi_rw_lock, acpi_gbl_namespace_rw_lock);
 
 /*****************************************************************************
  *
@@ -272,70 +260,69 @@ ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
 
 /* Object caches */
 
-ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_namespace_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_state_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_ext_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_operand_cache);
+
+/* System */
+
+ACPI_INIT_GLOBAL(u32, acpi_gbl_startup_flags, 0);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_shutdown, TRUE);
 
 /* Global handlers */
 
-ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
-ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
-ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
-ACPI_EXTERN acpi_table_handler acpi_gbl_table_handler;
-ACPI_EXTERN void *acpi_gbl_table_handler_context;
-ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
-ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
-ACPI_EXTERN struct acpi_sci_handler_info *acpi_gbl_sci_handler_list;
+ACPI_GLOBAL(struct acpi_global_notify_handler, acpi_gbl_global_notify[2]);
+ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler);
+ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler);
+ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler);
+ACPI_GLOBAL(void *, acpi_gbl_table_handler_context);
+ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk);
+ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler);
+ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list);
 
 /* Owner ID support */
 
-ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
-ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
-ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
+ACPI_GLOBAL(u32, acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS]);
+ACPI_GLOBAL(u8, acpi_gbl_last_owner_id_index);
+ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset);
 
 /* Initialization sequencing */
 
-ACPI_EXTERN u8 acpi_gbl_reg_methods_executed;
+ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed);
 
 /* Misc */
 
-ACPI_EXTERN u32 acpi_gbl_original_mode;
-ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
-ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
-ACPI_EXTERN u32 acpi_gbl_ps_find_count;
-ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
-ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
-ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
-ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
-ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
-ACPI_EXTERN struct acpi_address_range
-    *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
-
-#ifndef DEFINE_ACPI_GLOBALS
-
-/* Other miscellaneous */
-
-extern u8 acpi_gbl_shutdown;
-extern u32 acpi_gbl_startup_flags;
+ACPI_GLOBAL(u32, acpi_gbl_original_mode);
+ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location);
+ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count);
+ACPI_GLOBAL(u32, acpi_gbl_ps_find_count);
+ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save);
+ACPI_GLOBAL(u8, acpi_gbl_debugger_configuration);
+ACPI_GLOBAL(u8, acpi_gbl_step_to_next_call);
+ACPI_GLOBAL(u8, acpi_gbl_acpi_hardware_present);
+ACPI_GLOBAL(u8, acpi_gbl_events_initialized);
+ACPI_GLOBAL(struct acpi_interface_info *, acpi_gbl_supported_interfaces);
+ACPI_GLOBAL(struct acpi_address_range *,
+           acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]);
+
+/* Other miscellaneous, declared and initialized in utglobal */
+
 extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
 extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS];
 extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS];
-extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
 extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
-
-#endif
+extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
 
 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
 
-/* Lists for tracking memory allocations */
+/* Lists for tracking memory allocations (debug only) */
 
-ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
-ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
-ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
-ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
+ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_global_list);
+ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_ns_node_list);
+ACPI_GLOBAL(u8, acpi_gbl_display_final_mem_stats);
+ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking);
 #endif
 
 /*****************************************************************************
@@ -350,22 +337,23 @@ ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
 #define NUM_PREDEFINED_NAMES            9
 #endif
 
-ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
-ACPI_EXTERN union acpi_operand_object *acpi_gbl_module_code_list;
+ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_fadt_gpe_device);
+ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_module_code_list);
 
 extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
 extern const struct acpi_predefined_names
     acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES];
 
 #ifdef ACPI_DEBUG_OUTPUT
-ACPI_EXTERN u32 acpi_gbl_current_node_count;
-ACPI_EXTERN u32 acpi_gbl_current_node_size;
-ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count;
-ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer;
-ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer;
-ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
+ACPI_GLOBAL(u32, acpi_gbl_current_node_count);
+ACPI_GLOBAL(u32, acpi_gbl_current_node_size);
+ACPI_GLOBAL(u32, acpi_gbl_max_concurrent_node_count);
+ACPI_GLOBAL(acpi_size *, acpi_gbl_entry_stack_pointer);
+ACPI_GLOBAL(acpi_size *, acpi_gbl_lowest_stack_pointer);
+ACPI_GLOBAL(u32, acpi_gbl_deepest_nesting);
+ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0);
 #endif
 
 /*****************************************************************************
@@ -374,11 +362,11 @@ ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
  *
  ****************************************************************************/
 
-ACPI_EXTERN struct acpi_thread_state *acpi_gbl_current_walk_list;
+ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list);
 
 /* Control method single step flag */
 
-ACPI_EXTERN u8 acpi_gbl_cm_single_step;
+ACPI_GLOBAL(u8, acpi_gbl_cm_single_step);
 
 /*****************************************************************************
  *
@@ -388,8 +376,9 @@ ACPI_EXTERN u8 acpi_gbl_cm_single_step;
 
 extern struct acpi_bit_register_info
     acpi_gbl_bit_register_info[ACPI_NUM_BITREG];
-ACPI_EXTERN u8 acpi_gbl_sleep_type_a;
-ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
+
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b);
 
 /*****************************************************************************
  *
@@ -399,14 +388,15 @@ ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
 
 #if (!ACPI_REDUCED_HARDWARE)
 
-ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
-ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
-ACPI_EXTERN struct acpi_gpe_block_info
-    *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler;
-ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
-ACPI_EXTERN struct acpi_fixed_event_handler
-    acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
+ACPI_GLOBAL(u8, acpi_gbl_all_gpes_initialized);
+ACPI_GLOBAL(struct acpi_gpe_xrupt_info *, acpi_gbl_gpe_xrupt_list_head);
+ACPI_GLOBAL(struct acpi_gpe_block_info *,
+           acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]);
+ACPI_GLOBAL(acpi_gbl_event_handler, acpi_gbl_global_event_handler);
+ACPI_GLOBAL(void *, acpi_gbl_global_event_handler_context);
+ACPI_GLOBAL(struct acpi_fixed_event_handler,
+           acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]);
+
 extern struct acpi_fixed_event_info
     acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
 
@@ -418,23 +408,19 @@ extern struct acpi_fixed_event_info
  *
  ****************************************************************************/
 
-/* Procedure nesting level for debug output */
-
-extern u32 acpi_gbl_nesting_level;
-
 /* Event counters */
 
-ACPI_EXTERN u32 acpi_method_count;
-ACPI_EXTERN u32 acpi_gpe_count;
-ACPI_EXTERN u32 acpi_sci_count;
-ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS];
+ACPI_GLOBAL(u32, acpi_method_count);
+ACPI_GLOBAL(u32, acpi_gpe_count);
+ACPI_GLOBAL(u32, acpi_sci_count);
+ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]);
 
 /* Support for dynamic control method tracing mechanism */
 
-ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level);
+ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer);
+ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_level);
+ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_layer);
 
 /*****************************************************************************
  *
@@ -442,61 +428,64 @@ ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
  *
  ****************************************************************************/
 
-ACPI_EXTERN u8 acpi_gbl_db_output_flags;
+ACPI_GLOBAL(u8, acpi_gbl_db_output_flags);
 
 #ifdef ACPI_DISASSEMBLER
 
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
+/* Do not disassemble buffers to resource descriptors */
+
+ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
 
-ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
-ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
-ACPI_EXTERN u8 acpi_gbl_num_external_methods;
-ACPI_EXTERN u32 acpi_gbl_resolved_external_methods;
-ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
-ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
+ACPI_GLOBAL(u8, acpi_gbl_num_external_methods);
+ACPI_GLOBAL(u32, acpi_gbl_resolved_external_methods);
+ACPI_GLOBAL(struct acpi_external_list *, acpi_gbl_external_list);
+ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
 #endif
 
 #ifdef ACPI_DEBUGGER
 
-extern u8 acpi_gbl_method_executing;
-extern u8 acpi_gbl_abort_method;
-extern u8 acpi_gbl_db_terminate_threads;
+ACPI_INIT_GLOBAL(u8, acpi_gbl_db_terminate_threads, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
 
-ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
-ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
-ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
-ACPI_EXTERN u8 acpi_gbl_db_opt_no_region_support;
-ACPI_EXTERN u8 acpi_gbl_db_output_to_file;
-ACPI_EXTERN char *acpi_gbl_db_buffer;
-ACPI_EXTERN char *acpi_gbl_db_filename;
-ACPI_EXTERN u32 acpi_gbl_db_debug_level;
-ACPI_EXTERN u32 acpi_gbl_db_console_debug_level;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_db_scope_node;
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_tables);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_stats);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_ini_methods);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
+ACPI_GLOBAL(u8, acpi_gbl_db_output_to_file);
+ACPI_GLOBAL(char *, acpi_gbl_db_buffer);
+ACPI_GLOBAL(char *, acpi_gbl_db_filename);
+ACPI_GLOBAL(u32, acpi_gbl_db_debug_level);
+ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node);
 
-ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS];
-ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS];
+ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]);
+ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
 
 /* These buffers should all be the same size */
 
-ACPI_EXTERN char acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE];
+ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]);
 
 /*
  * Statistic globals
  */
-ACPI_EXTERN u16 acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
-ACPI_EXTERN u16 acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
-ACPI_EXTERN u16 acpi_gbl_obj_type_count_misc;
-ACPI_EXTERN u16 acpi_gbl_node_type_count_misc;
-ACPI_EXTERN u32 acpi_gbl_num_nodes;
-ACPI_EXTERN u32 acpi_gbl_num_objects;
-
-ACPI_EXTERN u32 acpi_gbl_size_of_parse_tree;
-ACPI_EXTERN u32 acpi_gbl_size_of_method_trees;
-ACPI_EXTERN u32 acpi_gbl_size_of_node_entries;
-ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
+ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1]);
+ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1]);
+ACPI_GLOBAL(u16, acpi_gbl_obj_type_count_misc);
+ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
+ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
+ACPI_GLOBAL(u32, acpi_gbl_num_objects);
+
+ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects);
 
 #endif                         /* ACPI_DEBUGGER */
 
@@ -508,7 +497,7 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
 
 #ifdef ACPI_APPLICATION
 
-ACPI_FILE ACPI_INIT_GLOBAL(acpi_gbl_debug_file, NULL);
+ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL);
 
 #endif                         /* ACPI_APPLICATION */
 
index 6357e932bfd9d20cf6640dd1a87c86e95969bac2..2ad2351a983321e31c1a4aa6983dfd0dfe419c09 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8af8c9bdeb3552b115617b3507c7b0d1ef602c59..c54267748be5bae1f85d0f123919bce602a0df66 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,10 @@ typedef const struct acpi_exdump_info {
 #define ACPI_EXD_PACKAGE                11
 #define ACPI_EXD_FIELD                  12
 #define ACPI_EXD_REFERENCE              13
+#define ACPI_EXD_LIST                   14     /* Operand object list */
+#define ACPI_EXD_HDLR_LIST              15     /* Address Handler list */
+#define ACPI_EXD_RGN_LIST               16     /* Region list */
+#define ACPI_EXD_NODE                   17     /* Namespace Node */
 
 /* restore default alignment */
 
index d95ca5449aceb119361c2e83b441de76097b3306..52a21dafb54039ca3c3d62bb22328acfb7a3321a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2a86c65d873bb6625d3a028b24d299fb2b6101ce..4bceb11c7380d118020b512a93a267c4c6b3114a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ACPI_SET64(ptr, val)            (*ACPI_CAST64 (ptr) = (u64) (val))
 
 /*
- * printf() format helpers
+ * printf() format helpers. These macros are workarounds for the difficulties
+ * with emitting 64-bit integers and 64-bit pointers with the same code
+ * for both 32-bit and 64-bit hosts.
  */
-
-/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */
-
 #define ACPI_FORMAT_UINT64(i)           ACPI_HIDWORD(i), ACPI_LODWORD(i)
 
 #if ACPI_MACHINE_WIDTH == 64
 #define ACPI_FORMAT_NATIVE_UINT(i)      ACPI_FORMAT_UINT64(i)
+#define ACPI_FORMAT_TO_UINT(i)          ACPI_FORMAT_UINT64(i)
+#define ACPI_PRINTF_UINT                 "0x%8.8X%8.8X"
+
 #else
-#define ACPI_FORMAT_NATIVE_UINT(i)      0, (i)
+#define ACPI_FORMAT_NATIVE_UINT(i)      0, (u32) (i)
+#define ACPI_FORMAT_TO_UINT(i)          (u32) (i)
+#define ACPI_PRINTF_UINT                 "0x%8.8X"
 #endif
 
 /*
index e6138ac4a16054038275fc81f2f616cd70c26d5d..ee1c040f321c621bc33ed8dd66c2c9426e6f3801 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cc7ab6dd724e6234a835d0321c8cb4b6106796f4..1a4d61805ebc64a83bc9242414536f7fecfb25cf 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3fc9ca7e8aa3e6afee0933d1ac82efe33c8ba04d..dda0e6affcf1ccb1199320ff4ede74f471ebbad5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index aed319318835f3c9b47a53acbb9618da37629c83..6168b85463edc1b0b68b5405a8e64ed449b2bdd8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f600aded7261cde6762b3fee5d9b9a6a790664b8..a48d713e95991d52389bafb62bc401c497e9df89 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
  *
  * Return Package types
  *
- * 1) PTYPE1 packages do not contain sub-packages.
+ * 1) PTYPE1 packages do not contain subpackages.
  *
  * ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types:
  *      object type
@@ -63,8 +63,8 @@
  *      (Used for _PRW)
  *
  *
- * 2) PTYPE2 packages contain a Variable-length number of sub-packages. Each
- *    of the different types describe the contents of each of the sub-packages.
+ * 2) PTYPE2 packages contain a Variable-length number of subpackages. Each
+ *    of the different types describe the contents of each of the subpackages.
  *
  * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length
  *      parent package is allowed:
@@ -560,7 +560,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
 
        /*
         * For _HPX, a single package is returned, containing a variable-length number
-        * of sub-packages. Each sub-package contains a PCI record setting.
+        * of subpackages. Each subpackage contains a PCI record setting.
         * There are several different type of record settings, of different
         * lengths, but all elements of all settings are Integers.
         */
@@ -698,6 +698,12 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
          METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
        PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
 
+       {{"_PRP", METHOD_0ARGS,
+         METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Str, 1 Int/Str/Pkg */
+       PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1,
+                    ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING |
+                    ACPI_RTYPE_PACKAGE | ACPI_RTYPE_REFERENCE, 1, 0),
+
        {{"_PRS", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
 
index ff97430455cbe923d3bad4f453635371b9388867..4b008e8884a111326fe17f5a1f5ee2adc028f8f6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fc83c0a5ca70fe228857d1336d967a91dd0765fa..5d2989a1b68c965a8649243b20837dd5104f74a5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c54f42c64fe2ca78ae7d9269b96c69ad2461c552..5fa4b202769790e81a9ff39964957fc5860cb844 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index be8180c17d7e772ec520dae60dc43b514c5295c1..ceeec0b7ccb1764b1e8bc1bd4b7e91ef1f7b372c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@ extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[];
 
 /* Strings used by the disassembler and debugger resource dump routines */
 
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
 
 extern const char *acpi_gbl_bm_decode[];
 extern const char *acpi_gbl_config_decode[];
index 48a3e331b72d7e7c8214969217d4e57e3c535d3e..5908ccec6aea8b5858338cf5b2a7de95bdbb118d 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 87c26366d1dfa8a9e65d8931f067d28330d8aa57..f3f834408441c34e40ab88127bb83d30c2e2aa0c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index afdc6df17abf12fa37311484b48e00ba0ff67bca..720b1cdda7113665da0883681c3b0765a4d63245 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eb56b66444b5e3d671572b6290a1245473e7d165..8daf9de82b73431d630d0e31f5f86abdaa8baa84 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e7a57c554e84f9d0f60c0bb558df4e288d495894..3661c8e90540fb8715ec7a24795394bc1609b016 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 14424200d246c8538bcde5070072100528dcf1dd..96644d5ac0e1fa3852cdcb28f934cdf259f92e4e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 81a78ba843112d335613fc55a2d0d2ae39e6bc3f..2c6d42c2bc01a4b7f10fcb1424479a6dbab8b667 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c4b0b365723758fe5181e26eaeaa7cb5314f18d3..b67522df01ace08274a2ce93d5c555e31a4aa75f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b1746a68dad11b8ac3a7b37bdb213f1e7265ee17..a1e7e6b6fcf7f89a8c87a5153d7c58bd8f0e80ec 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5205edcf2c019d1936c81af2d77a8f4e732d9c0d..6c0759c0db470ab520be6accf81e66ee87ed6e58 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d7f53fb2979ab9a602f11af4a9a1478e60f59c3d..9f74795e226853e516dc4525b7f9b09420ef57bc 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1bbb22fd6fa02f005893fc691eedfb8d0981246e..f7f5107e754da79f4b2459cc3e2c648cda9fb489 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2dbe109727c84c0b8d26029d479937ac3155b303..bd7811c64169f8aa2c4be03fd61ef1d9bdffee6f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7f569d57302758dcec3643d489f715f794625f78..2ac28d297305c5ec6183ff81b4e38f4d1ce7b9c8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d67891de1b545b43f33dca806d784dda884cfedb..9d6e2c1de1f89e5f6420ddfa52d1863766f8d986 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ecb12e2137ffb4ff736541891122afcf145b4f61..24f7d5ea678a0420570fd6e8711108905083cee2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 83cd45f4a8703f5cba5a613c2bad0030112759d8..c7bffff9ed32c97e4c35f8ef5fa0c1372c82687a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4c67193a9fa731f0f616023ffb642547d38795df..3393a73ca0d68f8d9c219cfd6d374f9ef09a5c92 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a9cb4a1a4bb8ce6b2c203c7c16360556decd3ada..955f83da68a52cee8c8fa672b09910155ac35ca6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a31e549e64cc7a95b77b516596b3f86a3aeae3fb..caaed3c673fdf369d8ce686507630fb035172995 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a3e2f38aadf64783cd3dfd03f1f6bc0140a87b85..ae779c1e871dbf5eaa8c422b970d2f78dfbfd972 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4d764e847a08a7174202166ae5e360e0b2d2b811..17e4bbfdb096c2e9c522b2a387abfed80943d2aa 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e3157313eb2786e2098b7c6fa5f4a3c58c40d293..78ac29351c9e1736880471724849c2028dd5b5c7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a5687540e9a66e5ba20bfeb9772ad5351b20bc61..5d594eb2e5ecb6c627587daffaac0f0e5dcf35d3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 144cbb9b73bc7238460be80e22a62a95aa2042e3..9957297d15805f2b1691d2b251d89031fd404bb5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -314,6 +314,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
 {
        union acpi_operand_object *handler_obj;
        union acpi_operand_object *obj_desc;
+       union acpi_operand_object *start_desc;
        union acpi_operand_object **last_obj_ptr;
        acpi_adr_space_setup region_setup;
        void **region_context;
@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
        /* Find this region in the handler's list */
 
        obj_desc = handler_obj->address_space.region_list;
+       start_desc = obj_desc;
        last_obj_ptr = &handler_obj->address_space.region_list;
 
        while (obj_desc) {
@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
 
                last_obj_ptr = &obj_desc->region.next;
                obj_desc = obj_desc->region.next;
+
+               /* Prevent infinite loop if list is corrupted */
+
+               if (obj_desc == start_desc) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Circular handler list in region object %p",
+                                   region_obj));
+                       return_VOID;
+               }
        }
 
        /* If we get here, the region was not in the handler's region list */
index 8354c4f7f10c55c604765a92020abd2d30547de9..1b148a440d67f545ebf1db7d12829de790b0a234 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9e9e3454d8932c9c44f853bbe3d05edffeb38130..4d8a709c1fc4505b4ea176e0347142a43eed0fba 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 23a7fadca4122992c7f652c32674843de13500f9..a734b27da0615e7bf73a6454183605931bce48b0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 39d06af5e347e234ad285f77848e22b8bef101d6..e286640ad4ff9e02974bc9d7c9c1d2a64fd58a92 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5713da77c665b01a5e9dcdbd91abc70a11f4228a..20a1392ffe06fd59eecc04b6dfe17a86aa96200d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -583,6 +583,18 @@ acpi_install_gpe_block(acpi_handle gpe_device,
                goto unlock_and_exit;
        }
 
+       /* Validate the parent device */
+
+       if (node->type != ACPI_TYPE_DEVICE) {
+               status = AE_TYPE;
+               goto unlock_and_exit;
+       }
+
+       if (node->object) {
+               status = AE_ALREADY_EXISTS;
+               goto unlock_and_exit;
+       }
+
        /*
         * For user-installed GPE Block Devices, the gpe_block_base_number
         * is always zero
@@ -666,6 +678,13 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
                goto unlock_and_exit;
        }
 
+       /* Validate the parent device */
+
+       if (node->type != ACPI_TYPE_DEVICE) {
+               status = AE_TYPE;
+               goto unlock_and_exit;
+       }
+
        /* Get the device_object attached to the node */
 
        obj_desc = acpi_ns_get_attached_object(node);
index 02ed75ac56cd5454adc527b09e3ebe63a329ae0e..2d6f187939c703db962bac5fbfad6ca9c9140bfa 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 06d216c8d43ab18edc0fb1f66def077014b2aa3f..8ba1464efd112a8f89a48eabbf7fd343c87ab3b6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 69e4a8cc9b71728f98b1aad402a0a44538033457..c545386fee96cd825f20a5099e1f82aeae39bc85 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3c2e6dcdad3e6abcbb60e1afacf3e0717c55a0d8..95d23dabcfbbe00e4221818b468c8e92483f5942 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 81c72a4ecd823eaca8542135aea5396d7d6d5626..4cfc3d3b5c97ddbddf19450f86759d5f32fb2dab 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4d046faac48cbb09b2c0aa6c4a0c5e8550333ec5..973fdae00f9479ddd160a8d3fff96e9367b26619 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -94,12 +94,13 @@ static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
        {ACPI_EXD_BUFFER, 0, NULL}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_package[5] = {
+static struct acpi_exdump_info acpi_ex_dump_package[6] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_package), NULL},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(package.node), "Parent Node"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(package.flags), "Flags"},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(package.count), "Elements"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(package.elements), "Element List"},
@@ -108,11 +109,11 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
 
 static struct acpi_exdump_info acpi_ex_dump_device[4] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
         "System Notify"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
-        "Device Notify"}
+        "Device Notify"},
+       {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(device.handler), "Handler"}
 };
 
 static struct acpi_exdump_info acpi_ex_dump_event[2] = {
@@ -142,17 +143,18 @@ static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_region[7] = {
+static struct acpi_exdump_info acpi_ex_dump_region[8] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region), NULL},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.space_id), "Space Id"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.flags), "Flags"},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(region.node), "Parent Node"},
        {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(region.address), "Address"},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(region.length), "Length"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.handler), "Handler"},
+       {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(region.handler), "Handler"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.next), "Next"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_power[5] = {
+static struct acpi_exdump_info acpi_ex_dump_power[6] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_power), NULL},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.system_level),
         "System Level"},
@@ -161,7 +163,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]),
         "System Notify"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
-        "Device Notify"}
+        "Device Notify"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.handler), "Handler"}
 };
 
 static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
@@ -225,7 +228,7 @@ static struct acpi_exdump_info acpi_ex_dump_reference[8] = {
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.value), "Value"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(reference.node), "Node"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"},
        {ACPI_EXD_REFERENCE, 0, NULL}
 };
@@ -234,16 +237,16 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_address_handler),
         NULL},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(address_space.space_id), "Space Id"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.next), "Next"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.region_list),
+       {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(address_space.next), "Next"},
+       {ACPI_EXD_RGN_LIST, ACPI_EXD_OFFSET(address_space.region_list),
         "Region List"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.node), "Node"},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(address_space.node), "Node"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"}
 };
 
 static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(notify.node), "Node"},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"},
@@ -252,14 +255,31 @@ static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"}
 };
 
+static struct acpi_exdump_info acpi_ex_dump_extra[6] = {
+       {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_extra), NULL},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.method_REG), "_REG Method"},
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(extra.scope_node), "Scope Node"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.region_context),
+        "Region Context"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.aml_start), "Aml Start"},
+       {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(extra.aml_length), "Aml Length"}
+};
+
+static struct acpi_exdump_info acpi_ex_dump_data[3] = {
+       {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_data), NULL},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.handler), "Handler"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.pointer), "Raw Data"}
+};
+
 /* Miscellaneous tables */
 
-static struct acpi_exdump_info acpi_ex_dump_common[4] = {
+static struct acpi_exdump_info acpi_ex_dump_common[5] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_common), NULL},
        {ACPI_EXD_TYPE, 0, NULL},
        {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(common.reference_count),
         "Reference Count"},
-       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"}
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"},
+       {ACPI_EXD_LIST, ACPI_EXD_OFFSET(common.next_object), "Object List"}
 };
 
 static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
@@ -274,15 +294,17 @@ static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
         "Field Bit Offset"},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(common_field.base_byte_offset),
         "Base Byte Offset"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
+       {ACPI_EXD_NODE, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_node[5] = {
+static struct acpi_exdump_info acpi_ex_dump_node[7] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL},
        {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"},
        {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"},
-       {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(child), "Child List"},
-       {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(peer), "Next Peer"}
+       {ACPI_EXD_LIST, ACPI_EXD_NSOFFSET(object), "Object List"},
+       {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(parent), "Parent"},
+       {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(child), "Child"},
+       {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(peer), "Peer"}
 };
 
 /* Dispatch table, indexed by object type */
@@ -315,7 +337,9 @@ static struct acpi_exdump_info *acpi_ex_dump_info[] = {
        acpi_ex_dump_address_handler,
        NULL,
        NULL,
-       NULL
+       NULL,
+       acpi_ex_dump_extra,
+       acpi_ex_dump_data
 };
 
 /*******************************************************************************
@@ -340,6 +364,10 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
        char *name;
        const char *reference_name;
        u8 count;
+       union acpi_operand_object *start;
+       union acpi_operand_object *data = NULL;
+       union acpi_operand_object *next;
+       struct acpi_namespace_node *node;
 
        if (!info) {
                acpi_os_printf
@@ -363,9 +391,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
 
                case ACPI_EXD_TYPE:
 
-                       acpi_ex_out_string("Type",
-                                          acpi_ut_get_object_type_name
-                                          (obj_desc));
+                       acpi_os_printf("%20s : %2.2X [%s]\n", "Type",
+                                      obj_desc->common.type,
+                                      acpi_ut_get_object_type_name(obj_desc));
                        break;
 
                case ACPI_EXD_UINT8:
@@ -433,6 +461,121 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
                        acpi_ex_dump_reference_obj(obj_desc);
                        break;
 
+               case ACPI_EXD_LIST:
+
+                       start = *ACPI_CAST_PTR(void *, target);
+                       next = start;
+
+                       acpi_os_printf("%20s : %p", name, next);
+                       if (next) {
+                               acpi_os_printf("(%s %2.2X)",
+                                              acpi_ut_get_object_type_name
+                                              (next), next->common.type);
+
+                               while (next->common.next_object) {
+                                       if ((next->common.type ==
+                                            ACPI_TYPE_LOCAL_DATA) && !data) {
+                                               data = next;
+                                       }
+
+                                       next = next->common.next_object;
+                                       acpi_os_printf("->%p(%s %2.2X)", next,
+                                                      acpi_ut_get_object_type_name
+                                                      (next),
+                                                      next->common.type);
+
+                                       if ((next == start) || (next == data)) {
+                                               acpi_os_printf
+                                                   ("\n**** Error: Object list appears to be circular linked");
+                                               break;
+                                       }
+                               }
+                       }
+
+                       acpi_os_printf("\n", next);
+                       break;
+
+               case ACPI_EXD_HDLR_LIST:
+
+                       start = *ACPI_CAST_PTR(void *, target);
+                       next = start;
+
+                       acpi_os_printf("%20s : %p", name, next);
+                       if (next) {
+                               acpi_os_printf("(%s %2.2X)",
+                                              acpi_ut_get_object_type_name
+                                              (next), next->common.type);
+
+                               while (next->address_space.next) {
+                                       if ((next->common.type ==
+                                            ACPI_TYPE_LOCAL_DATA) && !data) {
+                                               data = next;
+                                       }
+
+                                       next = next->address_space.next;
+                                       acpi_os_printf("->%p(%s %2.2X)", next,
+                                                      acpi_ut_get_object_type_name
+                                                      (next),
+                                                      next->common.type);
+
+                                       if ((next == start) || (next == data)) {
+                                               acpi_os_printf
+                                                   ("\n**** Error: Handler list appears to be circular linked");
+                                               break;
+                                       }
+                               }
+                       }
+
+                       acpi_os_printf("\n", next);
+                       break;
+
+               case ACPI_EXD_RGN_LIST:
+
+                       start = *ACPI_CAST_PTR(void *, target);
+                       next = start;
+
+                       acpi_os_printf("%20s : %p", name, next);
+                       if (next) {
+                               acpi_os_printf("(%s %2.2X)",
+                                              acpi_ut_get_object_type_name
+                                              (next), next->common.type);
+
+                               while (next->region.next) {
+                                       if ((next->common.type ==
+                                            ACPI_TYPE_LOCAL_DATA) && !data) {
+                                               data = next;
+                                       }
+
+                                       next = next->region.next;
+                                       acpi_os_printf("->%p(%s %2.2X)", next,
+                                                      acpi_ut_get_object_type_name
+                                                      (next),
+                                                      next->common.type);
+
+                                       if ((next == start) || (next == data)) {
+                                               acpi_os_printf
+                                                   ("\n**** Error: Region list appears to be circular linked");
+                                               break;
+                                       }
+                               }
+                       }
+
+                       acpi_os_printf("\n", next);
+                       break;
+
+               case ACPI_EXD_NODE:
+
+                       node =
+                           *ACPI_CAST_PTR(struct acpi_namespace_node *,
+                                          target);
+
+                       acpi_os_printf("%20s : %p", name, node);
+                       if (node) {
+                               acpi_os_printf(" [%4.4s]", node->name.ascii);
+                       }
+                       acpi_os_printf("\n");
+                       break;
+
                default:
 
                        acpi_os_printf("**** Invalid table opcode [%X] ****\n",
@@ -821,10 +964,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
        }
 
        acpi_os_printf("%20s : %4.4s\n", "Name", acpi_ut_get_node_name(node));
-       acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type));
-       acpi_ex_out_pointer("Attached Object",
-                           acpi_ns_get_attached_object(node));
-       acpi_ex_out_pointer("Parent", node->parent);
+       acpi_os_printf("%20s : %2.2X [%s]\n", "Type",
+                      node->type, acpi_ut_get_type_name(node->type));
 
        acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node),
                            acpi_ex_dump_node);
@@ -1017,22 +1158,26 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
                               ((struct acpi_namespace_node *)obj_desc)->
                               object);
 
-               acpi_ex_dump_object_descriptor(((struct acpi_namespace_node *)
-                                               obj_desc)->object, flags);
-               return_VOID;
+               obj_desc = ((struct acpi_namespace_node *)obj_desc)->object;
+               goto dump_object;
        }
 
        if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
-               acpi_os_printf
-                   ("ExDumpObjectDescriptor: %p is not an ACPI operand object: [%s]\n",
-                    obj_desc, acpi_ut_get_descriptor_name(obj_desc));
+               acpi_os_printf("%p is not an ACPI operand object: [%s]\n",
+                              obj_desc, acpi_ut_get_descriptor_name(obj_desc));
                return_VOID;
        }
 
-       if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
+       /* Validate the object type */
+
+       if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) {
+               acpi_os_printf("Not a known object type: %2.2X\n",
+                              obj_desc->common.type);
                return_VOID;
        }
 
+dump_object:
+
        /* Common Fields */
 
        acpi_ex_dump_object(obj_desc, acpi_ex_dump_common);
@@ -1040,6 +1185,22 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
        /* Object-specific fields */
 
        acpi_ex_dump_object(obj_desc, acpi_ex_dump_info[obj_desc->common.type]);
+
+       if (obj_desc->common.type == ACPI_TYPE_REGION) {
+               obj_desc = obj_desc->common.next_object;
+               if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) {
+                       acpi_os_printf
+                           ("Secondary object is not a known object type: %2.2X\n",
+                            obj_desc->common.type);
+
+                       return_VOID;
+               }
+
+               acpi_os_printf("\nExtra attached Object (%p):\n", obj_desc);
+               acpi_ex_dump_object(obj_desc,
+                                   acpi_ex_dump_info[obj_desc->common.type]);
+       }
+
        return_VOID;
 }
 
index cfd875243421473d23ac1f9e0350488041cfc617..68d97441432cca3140d2151a50af3384b034464a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 49fb742d61b98b1f18484f6f1783cba553447555..1d1b27a96c5bb1c35cf5cacb58fc8cf26746d47e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 65d93607f3681d845a87a4f721cdddb8728df660..2207e624f5388e110c80e9f744352bc7a928c8d7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7be0205ad06797a1037977c6757a879f28bb1810..b49ea2a95f4f99f5afde46ee9a1394d16078d675 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 14689dec496095ae2735c197a5ff749aa823f212..dbb03b544e8c46a23637e2283fc808f523342a84 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d74cea416ca05beaa9af14e9d0af3a1fd0aa3c89..1b8e941044079214882a75c7ad7a18a564ef9643 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d6fa0fce1fc91e74b197490b0f1f180d386b9545..2ede656ee26a5837912440f5ba8cc27896428ca2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bc042adf880496ffce63da79852b574e1a97c9f2..363767cf01e5af3c09e4401fc78166ae4aa78ece 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4459e32c683d3c9e78bdf6bf807048b05e52a4a4..29e9e99f7fe3010b17f4b4ef0e991d72a6d2f39a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5a588611ab484f12e33966fcbdf4ce2a03ffdc4e..ee3f872870bc77d0d6d599037fbbb7a735982581 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9d28867e60dc8b2c907e8cc76c92d10d95caa68e..cd5288a257a91fe9e6b5b80c55383151fef6cf6f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7ca6925a87cad08adea5abad1d1ec43dcf974d49..ab060261b43e66e9ab3c69b20ee0f88c169bf092 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1606524312e3a4f4219d47f7513390abc9986f75..3cde553bcbe182d06e277d26fbd188d4f9fd7237 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index be3f66973ee809637c30ada74e2ca706e0185795..3af8de3fcea43824a635112871850c0c0d5e1f94 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f0b09bf9887d605ee78e03a7a9aa2c84f2a4c98c..daf49f7ea311385a1342327ef732015f3a384f13 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 20d809d90c5b8f113e7b0f3c56fcafa58893dda2..04bd16c08f9e5fc08cf330475c44660d19b02ab3 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 26e371073b1aa881b1bac40a0b6579da0f5a2c12..fd11018b01687feb839b9253a460395500cca8de 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6578dee2e51b276f33154cdc4b2fa868f94245d5..841caed11c08a4d8a018c7562c6d40cfca6cdb47 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 99dc7b287d555d4baf37f4422649b3281b243b87..5b16c5484bee2555b49c5cfdb54b2b0dceede93b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3d36df828f520b1c196783453905c3f05f34543c..1e66d960fc118fcb3cdcc8faf68660fede2e6c6d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 414076818d40ee234d05970e5675023d1bff5b20..858fdd6be5982ee205c0bbff92f1d71d95dacf15 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 96540506058fcc94351e2980feab2adf990d9ad6..2e6caabba07a1852b766164231da39527a5e5f44 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0889a629505f857582c4f02bd65a8256cf3fe87e..e701d8c33dbfb376b6683b4357a4a268f41f659a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 12e6cff54f7885558d898c35c0a7375282139c5c..e0fd9b4978cd6a22af964a3165d26cfd62ea032f 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e3828cc4361bfa46ed25d9b4374545758542b22c..d590693eb54ecb3701962617d2f8b36f82105c73 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3c498dc1636ecd27cb439de4e0f72a44c9bb5ec6..76ab5c1a814eb3d1696dd298fb940ffe1c4e04a8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eab70d58852a674fadb1881df67fbc0ad9717aa1..6b919127cd9dcf650ba0bf52faa7c8f95a201aa0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b4b47db2dee271a82ec4f3f6537f194c7c982ef8..96d007df65ec15d537db26319d472938d988ff1e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 15dddc10fc9ba5dc1cfd78b5f962ab1c21a45e1f..6921c7f3d208f290ed0a1db3a0ce72181bf6537f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 14f65f6345b9a2de465cbe06d6047dc40f2c9576..f1249e3463bedc78122250d4f63a5e531588ef93 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fd1ff54cda1911a1e520440afd8a48125d927069..607eb9e5150de6261a849b285e58dc9fdffc636b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 74b24c82707e733fe944029382f13f3c4d1b4e50..80fcfc8c9c1b79039dae19cf05ee5974a4a9ceed 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index acd2964c26906f995b159bd382a42ce000cfa2c3..b55642c4ee585c5fe5b61d25cbd0fd7f4ddbcbc4 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 48b9c6f1264351b27b7232af13a810c98553eec1..3d88ef4a3e0d2afd93cd9b575adb9d7e49da9cd4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 283762511b73abcbb87e0a7aa6c9f21ba3f88dcd..42d37109aa5d0fdbb18bc0f72ddb9ffe50e364a1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 963ceef063f8c0de739da154b3330dd95f809895..e634a05974db6a52d4e6bfc2e25996703074c4a8 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3a0423af968cb7e0e57313d91c4dadcadb1cfaac..5b74677bf74dddfb48d160f390b0aada33eea458 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 89ec645e7730ac6765c8013d82d08c51947da550..7ae521ce8d3f3c09d0f58f95cf4bf52a59d4c91f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 90a0380fb8a04b51fd508817247531303825d18a..7eee0a6f02f60d28b96754338ad47120f272fe14 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7a736f4d1fd8184953a023ae70cbc95c56f27024..fe54a8c73b8c8f1618c12badbe62d07ec73c7ea7 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -222,13 +222,19 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
                }
        }
 
-       /* Clear the entry in all cases */
+       /* Clear the Node entry in all cases */
 
        node->object = NULL;
        if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) {
+
+               /* Unlink object from front of possible object list */
+
                node->object = obj_desc->common.next_object;
+
+               /* Handle possible 2-descriptor object */
+
                if (node->object &&
-                   ((node->object)->common.type != ACPI_TYPE_LOCAL_DATA)) {
+                   (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) {
                        node->object = node->object->common.next_object;
                }
        }
index 177857340271c4775a26e772df6e29d2c1e8d5ae..e83cff31754bba937e292433e796922eecbfeb45 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d2855d9857c48e84a0149eaccbd5208dad2a6536..392910ffbed9ac92e16953b76ad42768a4276846 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3d5391f9bcb5561ffa888407271dd64d2fcb026c..68f725839eb6d61bf129664922b1b22d7bdb0d05 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -132,12 +132,12 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
         * Decode the type of the expected package contents
         *
         * PTYPE1 packages contain no subpackages
-        * PTYPE2 packages contain sub-packages
+        * PTYPE2 packages contain subpackages
         */
        switch (package->ret_info.type) {
        case ACPI_PTYPE1_FIXED:
                /*
-                * The package count is fixed and there are no sub-packages
+                * The package count is fixed and there are no subpackages
                 *
                 * If package is too small, exit.
                 * If package is larger than expected, issue warning but continue
@@ -169,7 +169,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
 
        case ACPI_PTYPE1_VAR:
                /*
-                * The package count is variable, there are no sub-packages, and all
+                * The package count is variable, there are no subpackages, and all
                 * elements must be of the same type
                 */
                for (i = 0; i < count; i++) {
@@ -185,7 +185,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
 
        case ACPI_PTYPE1_OPTION:
                /*
-                * The package count is variable, there are no sub-packages. There are
+                * The package count is variable, there are no subpackages. There are
                 * a fixed number of required elements, and a variable number of
                 * optional elements.
                 *
@@ -242,7 +242,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
                elements++;
                count--;
 
-               /* Examine the sub-packages */
+               /* Examine the subpackages */
 
                status =
                    acpi_ns_check_package_list(info, package, elements, count);
@@ -250,7 +250,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
 
        case ACPI_PTYPE2_PKG_COUNT:
 
-               /* First element is the (Integer) count of sub-packages to follow */
+               /* First element is the (Integer) count of subpackages to follow */
 
                status = acpi_ns_check_object_type(info, elements,
                                                   ACPI_RTYPE_INTEGER, 0);
@@ -270,7 +270,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
                count = expected_count;
                elements++;
 
-               /* Examine the sub-packages */
+               /* Examine the subpackages */
 
                status =
                    acpi_ns_check_package_list(info, package, elements, count);
@@ -283,9 +283,9 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
        case ACPI_PTYPE2_FIX_VAR:
                /*
                 * These types all return a single Package that consists of a
-                * variable number of sub-Packages.
+                * variable number of subpackages.
                 *
-                * First, ensure that the first element is a sub-Package. If not,
+                * First, ensure that the first element is a subpackage. If not,
                 * the BIOS may have incorrectly returned the object as a single
                 * package instead of a Package of Packages (a common error if
                 * there is only one entry). We may be able to repair this by
@@ -310,7 +310,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
                        count = 1;
                }
 
-               /* Examine the sub-packages */
+               /* Examine the subpackages */
 
                status =
                    acpi_ns_check_package_list(info, package, elements, count);
@@ -370,9 +370,9 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
        u32 j;
 
        /*
-        * Validate each sub-Package in the parent Package
+        * Validate each subpackage in the parent Package
         *
-        * NOTE: assumes list of sub-packages contains no NULL elements.
+        * NOTE: assumes list of subpackages contains no NULL elements.
         * Any NULL elements should have been removed by earlier call
         * to acpi_ns_remove_null_elements.
         */
@@ -389,7 +389,7 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
                        return (status);
                }
 
-               /* Examine the different types of expected sub-packages */
+               /* Examine the different types of expected subpackages */
 
                info->parent_package = sub_package;
                switch (package->ret_info.type) {
@@ -450,14 +450,14 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
 
                case ACPI_PTYPE2_FIXED:
 
-                       /* Each sub-package has a fixed length */
+                       /* Each subpackage has a fixed length */
 
                        expected_count = package->ret_info2.count;
                        if (sub_package->package.count < expected_count) {
                                goto package_too_small;
                        }
 
-                       /* Check the type of each sub-package element */
+                       /* Check the type of each subpackage element */
 
                        for (j = 0; j < expected_count; j++) {
                                status =
@@ -475,14 +475,14 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
 
                case ACPI_PTYPE2_MIN:
 
-                       /* Each sub-package has a variable but minimum length */
+                       /* Each subpackage has a variable but minimum length */
 
                        expected_count = package->ret_info.count1;
                        if (sub_package->package.count < expected_count) {
                                goto package_too_small;
                        }
 
-                       /* Check the type of each sub-package element */
+                       /* Check the type of each subpackage element */
 
                        status =
                            acpi_ns_check_package_elements(info, sub_elements,
@@ -531,7 +531,7 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
                                (*sub_elements)->integer.value = expected_count;
                        }
 
-                       /* Check the type of each sub-package element */
+                       /* Check the type of each subpackage element */
 
                        status =
                            acpi_ns_check_package_elements(info,
@@ -557,10 +557,10 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
 
 package_too_small:
 
-       /* The sub-package count was smaller than required */
+       /* The subpackage count was smaller than required */
 
        ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
-                             "Return Sub-Package[%u] is too small - found %u elements, expected %u",
+                             "Return SubPackage[%u] is too small - found %u elements, expected %u",
                              i, sub_package->package.count, expected_count));
 
        return (AE_AML_OPERAND_VALUE);
index a05afff50eb9cc6e9e515ef745fb8b0ae8fd7779..7e417aa5c91e2784cec2187e04efa31d103ce1c0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -207,13 +207,30 @@ acpi_ns_simple_repair(struct acpi_evaluate_info *info,
         * this predefined name. Either one return value is expected, or none,
         * for both methods and other objects.
         *
-        * Exit now if there is no return object. Warning if one was expected.
+        * Try to fix if there was no return object. Warning if failed to fix.
         */
        if (!return_object) {
                if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
-                                             ACPI_WARN_ALWAYS,
-                                             "Missing expected return value"));
+                       if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
+                               ACPI_WARN_PREDEFINED((AE_INFO,
+                                                     info->full_pathname,
+                                                     ACPI_WARN_ALWAYS,
+                                                     "Found unexpected NULL package element"));
+
+                               status =
+                                   acpi_ns_repair_null_element(info,
+                                                               expected_btypes,
+                                                               package_index,
+                                                               return_object_ptr);
+                               if (ACPI_SUCCESS(status)) {
+                                       return (AE_OK); /* Repair was successful */
+                               }
+                       } else {
+                               ACPI_WARN_PREDEFINED((AE_INFO,
+                                                     info->full_pathname,
+                                                     ACPI_WARN_ALWAYS,
+                                                     "Missing expected return value"));
+                       }
 
                        return (AE_AML_NO_RETURN_VALUE);
                }
@@ -448,7 +465,7 @@ acpi_ns_repair_null_element(struct acpi_evaluate_info * info,
  * RETURN:      None.
  *
  * DESCRIPTION: Remove all NULL package elements from packages that contain
- *              a variable number of sub-packages. For these types of
+ *              a variable number of subpackages. For these types of
  *              packages, NULL elements can be safely removed.
  *
  *****************************************************************************/
@@ -469,7 +486,7 @@ acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
        /*
         * We can safely remove all NULL elements from these package types:
         * PTYPE1_VAR packages contain a variable number of simple data types.
-        * PTYPE2 packages contain a variable number of sub-packages.
+        * PTYPE2 packages contain a variable number of subpackages.
         */
        switch (package_type) {
        case ACPI_PTYPE1_VAR:
index 6a25d320b169ea9671385a0c825ecf9dadd290d9..b09e6bef72b88471352fede319e0c690591efd97 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -432,8 +432,8 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
  * 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
+ *              3. A subpackage count of zero means _CST is meaningless
+ *              4. Count must match the number of C state subpackages
  *
  *****************************************************************************/
 
@@ -611,6 +611,7 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
        union acpi_operand_object **top_object_list;
        union acpi_operand_object **sub_object_list;
        union acpi_operand_object *obj_desc;
+       union acpi_operand_object *sub_package;
        u32 element_count;
        u32 index;
 
@@ -619,8 +620,17 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
        top_object_list = package_object->package.elements;
        element_count = package_object->package.count;
 
-       for (index = 0; index < element_count; index++) {
-               sub_object_list = (*top_object_list)->package.elements;
+       /* Examine each subpackage */
+
+       for (index = 0; index < element_count; index++, top_object_list++) {
+               sub_package = *top_object_list;
+               sub_object_list = sub_package->package.elements;
+
+               /* Check for minimum required element count */
+
+               if (sub_package->package.count < 4) {
+                       continue;
+               }
 
                /*
                 * If the BIOS has erroneously reversed the _PRT source_name (index 2)
@@ -634,15 +644,12 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
                        sub_object_list[2] = obj_desc;
                        info->return_flags |= ACPI_OBJECT_REPAIRED;
 
-                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                       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);
@@ -679,7 +686,7 @@ acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
        u32 i;
 
        /*
-        * Entries (sub-packages) in the _PSS Package must be sorted by power
+        * Entries (subpackages) in the _PSS Package must be sorted by power
         * dissipation, in descending order. If it appears that the list is
         * incorrectly sorted, sort it. We sort by cpu_frequency, since this
         * should be proportional to the power.
@@ -767,9 +774,9 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
  *
  * 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
+ *              start_index         - Index of the first subpackage
+ *              expected_count      - Minimum length of each subpackage
+ *              sort_index          - Subpackage entry to sort on
  *              sort_direction      - Ascending or descending
  *              sort_key_name       - Name of the sort_index field
  *
@@ -805,7 +812,7 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
        }
 
        /*
-        * NOTE: assumes list of sub-packages contains no NULL elements.
+        * NOTE: assumes list of subpackages contains no NULL elements.
         * Any NULL elements should have been removed by earlier call
         * to acpi_ns_remove_null_elements.
         */
@@ -832,7 +839,7 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
                        return (AE_AML_OPERAND_TYPE);
                }
 
-               /* Each sub-package must have the minimum length */
+               /* Each subpackage must have the minimum length */
 
                if ((*outer_elements)->package.count < expected_count) {
                        return (AE_AML_PACKAGE_LIMIT);
index 47420faef073b4dada9fa8dc26252639c3213849..af1cc42a8aa183bbae45f2b3794e1acfec888f51 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4a0665b6bcc11c6c6eb8aad3ee62be15b6122694..4a5e3f5c0ff78afede734885a02da7da73f25d44 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e81f15ef659a5c85dbf19e020b20a7ae75523dcd..4758a1f2ce22abb098193bf59495eb75324efdf8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1f0c28ba50df353de078c6ae47f70cbee05f025f..4bd558bf10d226efa496b9974c08395530aae9f3 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_get_data
+ * FUNCTION:    acpi_get_data_full
  *
  * PARAMETERS:  obj_handle          - Namespace node
  *              handler             - Handler used in call to attach_data
  *              data                - Where the data is returned
+ *              callback            - function to execute before returning
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node
+ *              and execute a callback before returning.
  *
  ******************************************************************************/
 acpi_status
-acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
+acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler,
+                  void **data, void (*callback)(void *))
 {
        struct acpi_namespace_node *node;
        acpi_status status;
@@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
        }
 
        status = acpi_ns_get_attached_data(node, handler, data);
+       if (ACPI_SUCCESS(status) && callback) {
+               callback(*data);
+       }
 
 unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return (status);
 }
 
+ACPI_EXPORT_SYMBOL(acpi_get_data_full)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_get_data
+ *
+ * PARAMETERS:  obj_handle          - Namespace node
+ *              handler             - Handler used in call to attach_data
+ *              data                - Where the data is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
+{
+       return acpi_get_data_full(obj_handle, handler, data, NULL);
+}
+
 ACPI_EXPORT_SYMBOL(acpi_get_data)
index 3a4bd3ff49a365827f2bc70dff2250c40082ea19..8c6c11ce9760b889dca1c9442cade74c7ae90054 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0e6d79e462d4f8c7233dc77ad37ad6f893faaea9..dae9401be7a2d6cef946f4d3ca3fab173165cea6 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 91a5a69db80c316552e13f9704eb9435f9b94a30..314d314340ae8a9151f254ba7b65715baeaf5bdb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 065b44ae538f28b7595fe9af1870b5c824052237..646d1a3f6e27b7e5695aaec30746ba4bd4c9aa53 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 95dc608a66a85b3b01e5a461b58a39f4a02b20f7..af1f46cd37a5ad3620a165351eac2f061da104e0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1b659e59710ab525d85cbd6674c900b3da746f36..1755d2ac5656ae5c975e73b04e912741cef8fdf4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b0c9787dbe6194971f62f39e7c419ee1c389226e..0d8d37ffd04d34d1a8a638d05f511a52f6047969 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 79d9a28dedefe4fd6c69fdae5291a3c51106e5e6..6d27b597394e907055417402cb7f35bab3ed63d1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6a4b6fb39f32e197767a46aeef54711ad9df2bfc..32d250feea214acbef13cc8afab6af017bc47d0b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 877dc0de8df3e19da7057a8fd99042eb2d6f80b6..0b64181e772090fec84aeb2494781459a43fedeb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 91fa73a6e55e7245ff9147b769a0a32f3c509864..3cd48802eede240750a45a3e4a57c3475fc58e99 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index abd65624754f20175721dea4e570e7fa0a2d887c..9cb07e1e76d9dba5a0b4403350e436606c48bcf4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fcb7a840e996bdee6a3db496a296e44edd54d6f0..e135acaa5e1c2cb89ae522d2b8f0b9c4d53f4851 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f3a9276ac665035adefb27e949fa842a6a629802..916fd095ff342b53a11b0c57d16110bd5f108889 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b60c9cf82862f9e94dfb254b6a30b003e2dd5426..689556744b034d82ac43c72bfcd70b4f515fbe83 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -636,7 +636,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
 
        for (index = 0; index < number_of_elements; index++) {
 
-               /* Dereference the sub-package */
+               /* Dereference the subpackage */
 
                package_element = *top_object_list;
 
index 3a2ace93e62cf5d11690a4a4a907ae5539007f9e..75d3690506570d824d4d25d1280c48bdbbe6731f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -273,7 +273,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                 */
                user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4);
 
-               /* Each sub-package must be of length 4 */
+               /* Each subpackage must be of length 4 */
 
                if ((*top_object_list)->package.count != 4) {
                        ACPI_ERROR((AE_INFO,
@@ -283,7 +283,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                }
 
                /*
-                * Dereference the sub-package.
+                * Dereference the subpackage.
                 * The sub_object_list will now point to an array of the four IRQ
                 * elements: [Address, Pin, Source, source_index]
                 */
@@ -292,7 +292,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                /* 1) First subobject: Dereference the PRT.Address */
 
                obj_desc = sub_object_list[0];
-               if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+               if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
                        ACPI_ERROR((AE_INFO,
                                    "(PRT[%u].Address) Need Integer, found %s",
                                    index,
@@ -305,7 +305,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                /* 2) Second subobject: Dereference the PRT.Pin */
 
                obj_desc = sub_object_list[1];
-               if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+               if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
                        ACPI_ERROR((AE_INFO,
                                    "(PRT[%u].Pin) Need Integer, found %s",
                                    index,
@@ -394,7 +394,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                /* 4) Fourth subobject: Dereference the PRT.source_index */
 
                obj_desc = sub_object_list[3];
-               if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+               if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
                        ACPI_ERROR((AE_INFO,
                                    "(PRT[%u].SourceIndex) Need Integer, found %s",
                                    index,
index 8a2d4986b0aa576695ed2f479703cfa8dc4fd139..c3c56b5a9788319cec129216882bd4d9cf8faebc 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
 
 #define _COMPONENT          ACPI_RESOURCES
 ACPI_MODULE_NAME("rsdump")
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
 /* Local prototypes */
 static void acpi_rs_out_string(char *title, char *value);
 
index 46192bd5365335e97120269519c097fd6c2aa7be..2f9332d5c973047c2e9362bfd921a1d2aafb9514 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
 #define _COMPONENT          ACPI_RESOURCES
 ACPI_MODULE_NAME("rsdumpinfo")
 
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
 #define ACPI_RSD_OFFSET(f)          (u8) ACPI_OFFSET (union acpi_resource_data,f)
 #define ACPI_PRT_OFFSET(f)          (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
 #define ACPI_RSD_TABLE_SIZE(name)   (sizeof(name) / sizeof (struct acpi_rsdump_info))
index 41fed78e0de62f84f0d30e74d1560643e28d872a..9d3f8a9a24bd1819e8b5ea932df087550aa12f55 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -132,8 +132,7 @@ struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = {
        acpi_rs_convert_uart_serial_bus,
 };
 
-#ifdef ACPI_FUTURE_USAGE
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
 
 /* Dispatch table for resource dump functions */
 
@@ -168,7 +167,6 @@ struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = {
 };
 #endif
 
-#endif                         /* ACPI_FUTURE_USAGE */
 /*
  * Base sizes for external AML resource descriptors, indexed by internal type.
  * Includes size of the descriptor header (1 byte for small descriptors,
index ca183755a6f9bb3923065906fc00b2d8b82b8a1f..19d64873290ab63a1bb209bb26c3eefab767d103 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 364decc1028ac39aa20030a392693eea66ed291b..3461f7db26dfb561803f1b24f4205b8d93690efe 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6053aa182093e75b070ecd89bd318348d6f2b62f..77291293af64c5bf6f8ed509790a98088aad6035 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ebc773a1b350b4386cb3896f464efe957e9a379d..eab4483ff5f8e5b44b7f5c2f22b0275925ea7cd1 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c99cec9cefdec4ee20305ed6e5ff578b60960f58..41eea4bc089c55c1858467284ff9f43011a9b178 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fe49fc43e10f54b726debec50b6f4c54c4cd24a9..9e8407223d9575ca5dc3d63927c235cf328dd40a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 14a7982c9961088ae50c0283bfefb4b4b5ccb488..897a5ceb042009682b2ce109614a695c2f7531f2 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 01e476988aaee38f7529e71d091310cd1e7afae5..877ab9202133fd76c65a003daf7592e2486cfb38 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8f89263ac47e28cfecce4304a16b79406ba5c71f..ec14588254d433e63e1b17352f16f3702b9a09f6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e4f4f02d49e7cf58f4acc9db842d741bb46a9301..c12003947bd53c09ed4c63603f93736b19f911e3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 634357d51fe9b4a30103f5cb1169a97d1da72b7f..e3040947e9a00fff25b9cedc13813d27d8ebaf59 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -292,10 +292,11 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
                new_table = acpi_os_map_memory(new_address, new_table_length);
                if (!new_table) {
                        ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
-                                       "%4.4s %p Attempted physical table override failed",
+                                       "%4.4s " ACPI_PRINTF_UINT
+                                       " Attempted physical table override failed",
                                        table_header->signature,
-                                       ACPI_CAST_PTR(void,
-                                                     table_desc->address)));
+                                       ACPI_FORMAT_TO_UINT(table_desc->
+                                                           address)));
                        return (NULL);
                }
 
@@ -308,11 +309,11 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
 
 finish_override:
 
-       ACPI_INFO((AE_INFO,
-                  "%4.4s %p %s table override, new table: %p",
+       ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
+                  " %s table override, new table: " ACPI_PRINTF_UINT,
                   table_header->signature,
-                  ACPI_CAST_PTR(void, table_desc->address),
-                  override_type, new_table));
+                  ACPI_FORMAT_TO_UINT(table_desc->address),
+                  override_type, ACPI_FORMAT_TO_UINT(new_table)));
 
        /* We can now unmap/delete the original table (if fully mapped) */
 
index 6866e767ba90947359ca432bcba8643a92c0069d..df3bb20ea3255c9cf745e8ad8e84f4eaae0292f4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -128,15 +128,17 @@ acpi_tb_print_table_header(acpi_physical_address address,
        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.
+        * The reason that we use ACPI_PRINTF_UINT and ACPI_FORMAT_TO_UINT is to
+        * support both 32-bit and 64-bit hosts/addresses in a consistent manner.
+        * The %p specifier does not emit uniform output on all hosts. On some,
+        * leading zeros are not supported.
         */
        if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
 
                /* FACS only has signature and length fields */
 
-               ACPI_INFO((AE_INFO, "%4.4s %p %06X",
-                          header->signature, ACPI_CAST_PTR(void, address),
+               ACPI_INFO((AE_INFO, "%-4.4s " ACPI_PRINTF_UINT " %06X",
+                          header->signature, ACPI_FORMAT_TO_UINT(address),
                           header->length));
        } else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) {
 
@@ -147,8 +149,9 @@ acpi_tb_print_table_header(acpi_physical_address address,
                                          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 %06X (v%.2d %6.6s)",
-                          ACPI_CAST_PTR(void, address),
+               ACPI_INFO((AE_INFO,
+                          "RSDP " ACPI_PRINTF_UINT " %06X (v%.2d %-6.6s)",
+                          ACPI_FORMAT_TO_UINT(address),
                           (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
                            revision >
                            0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
@@ -162,8 +165,9 @@ acpi_tb_print_table_header(acpi_physical_address address,
                acpi_tb_cleanup_table_header(&local_header, header);
 
                ACPI_INFO((AE_INFO,
-                          "%4.4s %p %06X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
-                          local_header.signature, ACPI_CAST_PTR(void, address),
+                          "%-4.4s " ACPI_PRINTF_UINT
+                          " %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)",
+                          local_header.signature, ACPI_FORMAT_TO_UINT(address),
                           local_header.length, local_header.revision,
                           local_header.oem_id, local_header.oem_table_id,
                           local_header.oem_revision,
index 6412d3c301cb62d480b9c753a0dbbf2b7af612f3..a4702eee91a820d131960754c14da6aa62f50939 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index db826eaadd1c7300a58fde06d0d29df463ad97a8..a1593159d9ea4faeb3d0d61b8731974a1af05676 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 60b5a871833cce325393e516562d2574476d304b..0909420fc776510c1d4fef5278112391a5ad0f4d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e4e1468877c3a27f2db6899098765ccaa2f42eaa..65ab8fed3d5e504011328030cd192b663b1ed507 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2c2b6ae5dfc4ab1fb3dbd20adc670f7214a4a7ed..a1acec9d2ef36b20539ad32f9f0c37dcb79dcab3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1851762fc5b522371cbde01980956457ed91c37d..efac83c606dce04470b9b2c09487a882afff7565 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 11fde93be120af0291b3e60d049f90fe0e3502d3..3c16997406535dc2e85445af0fd1b60cd0db2610 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cacd2fd9e665592ac64241be9fc6f4afd2cdc100..78fde0aac487ee585d2da9dfe0294126ad545a65 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index edff4e653d9a06f3b9312c6512ca2a937c9ab0e6..270c16464dd948181f98755f8e1f13809c9acf13 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -535,10 +535,10 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
 
        case ACPI_TYPE_LOCAL_REFERENCE:
 
-               /* TBD: should validate incoming handle */
+               /* An incoming reference is defined to be a namespace node */
 
-               internal_object->reference.class = ACPI_REFCLASS_NAME;
-               internal_object->reference.node =
+               internal_object->reference.class = ACPI_REFCLASS_REFOF;
+               internal_object->reference.object =
                    external_object->reference.handle;
                break;
 
index d971c8631263b3dd8f0b9ec05269122b78c24391..21a20ac5b1e1aec4f8654b03caab01ba26466c8a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b3f31dd89a45d90f66ab25a617960f56505501d4..fbfa9eca011f8457ba0fecd5e1bed00b69466022 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c07d2227ea42587937ecf7bf37d88e91a6f65a66..a3516de213fa5c1bfa5a45dd368c8c06d50aab19 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
        union acpi_operand_object *handler_desc;
        union acpi_operand_object *second_desc;
        union acpi_operand_object *next_desc;
+       union acpi_operand_object *start_desc;
        union acpi_operand_object **last_obj_ptr;
 
        ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
@@ -235,10 +236,11 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                        if (handler_desc) {
                                next_desc =
                                    handler_desc->address_space.region_list;
+                               start_desc = next_desc;
                                last_obj_ptr =
                                    &handler_desc->address_space.region_list;
 
-                               /* Remove the region object from the handler's list */
+                               /* Remove the region object from the handler list */
 
                                while (next_desc) {
                                        if (next_desc == object) {
@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                                                break;
                                        }
 
-                                       /* Walk the linked list of handler */
+                                       /* Walk the linked list of handlers */
 
                                        last_obj_ptr = &next_desc->region.next;
                                        next_desc = next_desc->region.next;
+
+                                       /* Prevent infinite loop if list is corrupted */
+
+                                       if (next_desc == start_desc) {
+                                               ACPI_ERROR((AE_INFO,
+                                                           "Circular region list in address handler object %p",
+                                                           handler_desc));
+                                               return_VOID;
+                                       }
                                }
 
                                if (handler_desc->address_space.handler_flags &
index 154fdcaa5830dc61d9cbcda341dc5a1e94069a94..8e544d4688cd827c6a3b05ab734f81775ef7fd9d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 16fb90506db72ea16d0e9bf81696bba1d9c4ccfa..8fed1482d228b2409e2a5beddd623f71d9e0de61 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3cf7b597edb9357e0e05864cacaa88d55942c609..0403dcaabaf20f49b9d0141c7b4762f6cb1b8bfc 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 030cb0dc673c881dadcb6f62980869e985c16d61..f3abeae9d2f87b69650e324cd66a2ea799cc1a93 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,31 +55,27 @@ ACPI_MODULE_NAME("utglobal")
  * Static global variable initialization.
  *
  ******************************************************************************/
-/*
- * We want the debug switches statically initialized so they
- * are already set when the debugger is entered.
- */
-/* Debug switch - level and trace mask */
+/* Debug output control masks */
 u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
 
-/* Debug switch - layer (component) mask */
-
 u32 acpi_dbg_layer = 0;
-u32 acpi_gbl_nesting_level = 0;
 
-/* Debugger globals */
+/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
 
-u8 acpi_gbl_db_terminate_threads = FALSE;
-u8 acpi_gbl_abort_method = FALSE;
-u8 acpi_gbl_method_executing = FALSE;
+struct acpi_table_fadt acpi_gbl_FADT;
+u32 acpi_gbl_trace_flags;
+acpi_name acpi_gbl_trace_method_name;
+u8 acpi_gbl_system_awake_and_running;
+u32 acpi_current_gpe_count;
 
-/* System flags */
-
-u32 acpi_gbl_startup_flags = 0;
-
-/* System starts uninitialized */
+/*
+ * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
+ * that the ACPI hardware is no longer required. A flag in the FADT indicates
+ * a reduced HW machine, and that flag is duplicated here for convenience.
+ */
+u8 acpi_gbl_reduced_hardware;
 
-u8 acpi_gbl_shutdown = TRUE;
+/* Various state name strings */
 
 const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
        "\\_S0_",
@@ -335,7 +331,6 @@ acpi_status acpi_ut_init_globals(void)
 
        acpi_gbl_DSDT = NULL;
        acpi_gbl_cm_single_step = FALSE;
-       acpi_gbl_db_terminate_threads = FALSE;
        acpi_gbl_shutdown = FALSE;
        acpi_gbl_ns_lookup_count = 0;
        acpi_gbl_ps_find_count = 0;
@@ -382,6 +377,10 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_disable_mem_tracking = FALSE;
 #endif
 
+#ifdef ACPI_DEBUGGER
+       acpi_gbl_db_terminate_threads = FALSE;
+#endif
+
        return_ACPI_STATUS(AE_OK);
 }
 
index bfca7b4b6731621016b11996d5a8158ecb0f825d..4b12880e5b11eec311eb4d2d554f5f2132c90088 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c5d1ac44c07dd2bf87bfdeec43fc719cce2a3c78..5f56fc49021ecf9f198baec7370e940441ecfc06 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5c26ad420344437dbc9b3294531ff82d91a2eec0..dc6e96547f1836c6d3d4b29af712adf27b52a46f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 909fe66e19349b207bf48527e41c0e07f3918cbb..d44dee6ee10a15b61cbd05573a79f0c3300243c2 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 02f9101b65e47c29dc974020a8701322c9dc3824..2e2bb14e1099c1315051aaccd96f42fe277ec1bc 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 08c32324558449001af0c8ad6374c4286f73d43f..82717fff9ffc34bff4161483808f39788ccdae67 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 517af700399da1e0c8f16c96baab96e7cad6299b..dfa9009bfc8704856242b15063fbc23971eb1181 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8856bd37bc763f2a94c157acb513aefa82342875..685766fc6ca8ae2dbbc4fbe648f08e4f7cd1fcb8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utosi")
 
+/******************************************************************************
+ *
+ * ACPICA policy for new _OSI strings:
+ *
+ * It is the stated policy of ACPICA that new _OSI strings will be integrated
+ * into this module as soon as possible after they are defined. It is strongly
+ * recommended that all ACPICA hosts mirror this policy and integrate any
+ * changes to this module as soon as possible. There are several historical
+ * reasons behind this policy:
+ *
+ * 1) New BIOSs tend to test only the case where the host responds TRUE to
+ *    the latest version of Windows, which would respond to the latest/newest
+ *    _OSI string. Not responding TRUE to the latest version of Windows will
+ *    risk executing untested code paths throughout the DSDT and SSDTs.
+ *
+ * 2) If a new _OSI string is recognized only after a significant delay, this
+ *    has the potential to cause problems on existing working machines because
+ *    of the possibility that a new and different path through the ASL code
+ *    will be executed.
+ *
+ * 3) New _OSI strings are tending to come out about once per year. A delay
+ *    in recognizing a new string for a significant amount of time risks the
+ *    release of another string which only compounds the initial problem.
+ *
+ *****************************************************************************/
 /*
  * Strings supported by the _OSI predefined control method (which is
  * implemented internally within this module.)
@@ -74,6 +99,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
        {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2},  /* Windows Vista SP2 - Added 09/2010 */
        {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7},      /* Windows 7 and Server 2008 R2 - Added 09/2009 */
        {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8},      /* Windows 8 and Server 2012 - Added 08/2012 */
+       {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8},      /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
 
        /* Feature Group Strings */
 
index eb3aca761369c2ccb30d2d0c4465f107fa5da389..36bec57ebd23fb93b5b198ef59414ce7a6dac6bd 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2b1ce4cd32073fc23e6bcb7d6c5666d156ae6432..db30caff130ad2520f4dc1bd5c7ffb3a988b12bb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2c2accb9e53494fde7c60fe580a2cc267e99528c..14cb6c0c8be2b67df5a2693681c2028245b2363f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utresrc")
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
 /*
  * Strings used to decode resource descriptors.
  * Used by both the disassembler and the debugger resource dump routines
index 03c4c2febd84c54b19eaa0cf397cd5e03549449d..1cc97a752c15a320b276d68594f5244a1c22ad29 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 45c0eb26b33d5ade96f7d8d6d4f83fd7747ff88b..77219336c7e01f78c67003a1fc93e48d56e3197b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c0027773cccb250b4d40ea0f5c7621ec6b98ba98..7d0ee969d781310cf12fa122584fdd294539244a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,8 @@ acpi_ut_free_and_track(void *allocation,
        }
 
        acpi_os_free(debug_block);
-       ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation));
+       ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
+                         allocation, debug_block));
        return_VOID;
 }
 
index be322c83643a832a66a3af591aa0c66b270f7db5..502a8492dc83720b41420895d2614da46a96e63f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f7edb88f60544b57f6a4097a93bd5d2f2e783a9a..edd861102f1bf07e8515b6af8621c921cee85283 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 246ef68681f4a4c866bcc28388cf3d383b819b32..13380d8184626e174cebba1950d27d0dbaa08274 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 312299721ba147ca0128517fbbbab407c416240f..2a0f9e04d3a4b128f71143d1e8788c6976388c16 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3650b21832279a91568266208059296fadfab94c..c4dac71509605985ae872a3f524f4dd51881eabc 100644 (file)
@@ -12,7 +12,7 @@ config ACPI_APEI
 
 config ACPI_APEI_GHES
        bool "APEI Generic Hardware Error Source"
-       depends on ACPI_APEI && X86
+       depends on ACPI_APEI
        select ACPI_HED
        select IRQ_WORK
        select GENERIC_ALLOCATOR
index 797a6938d0515edb7ce7e5ce3f4f1648c538e515..9a2c63b2005038476e5a5e77360fd836aad3f25f 100644 (file)
 #include <linux/acpi.h>
 #include <linux/power_supply.h>
 
+#include "battery.h"
+
 #define PREFIX "ACPI: "
 
 #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
 
-#define ACPI_BATTERY_CLASS             "battery"
 #define ACPI_BATTERY_DEVICE_NAME       "Battery"
-#define ACPI_BATTERY_NOTIFY_STATUS     0x80
-#define ACPI_BATTERY_NOTIFY_INFO       0x81
-#define ACPI_BATTERY_NOTIFY_THRESHOLD   0x82
 
 /* Battery power unit: 0 means mW, 1 means mA */
 #define ACPI_BATTERY_POWER_UNIT_MA     1
@@ -736,6 +734,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        dev_name(&device->dev), event,
                                        acpi_battery_present(battery));
+       acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
        /* acpi_battery_update could remove power_supply object */
        if (old && battery->bat.dev)
                power_supply_changed(&battery->bat);
diff --git a/drivers/acpi/battery.h b/drivers/acpi/battery.h
new file mode 100644 (file)
index 0000000..6c08497
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ACPI_BATTERY_H
+#define __ACPI_BATTERY_H
+
+#define ACPI_BATTERY_CLASS "battery"
+
+#define ACPI_BATTERY_NOTIFY_STATUS     0x80
+#define ACPI_BATTERY_NOTIFY_INFO       0x81
+#define ACPI_BATTERY_NOTIFY_THRESHOLD   0x82
+
+#endif
index fcb59c21c68d5c53696a29749d88792f58bc4a64..e7e5844c87d0c8de87379ae7ea6eef8ad91cb79f 100644 (file)
@@ -311,9 +311,7 @@ static void acpi_bus_osc_support(void)
        capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;
 #endif
 
-#ifdef ACPI_HOTPLUG_OST
        capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
-#endif
 
        if (!ghes_disable)
                capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
@@ -340,60 +338,77 @@ static void acpi_bus_osc_support(void)
  */
 static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 {
-       struct acpi_device *device = NULL;
+       struct acpi_device *adev;
        struct acpi_driver *driver;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
-                         type, handle));
+       acpi_status status;
+       u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
 
        switch (type) {
-
        case ACPI_NOTIFY_BUS_CHECK:
-               /* TBD */
+               acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
-               /* TBD */
+               acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
                break;
 
        case ACPI_NOTIFY_DEVICE_WAKE:
-               /* TBD */
+               acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
-               /* TBD */
+               acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
+               acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
                /* TBD: Exactly what does 'light' mean? */
                break;
 
        case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-               /* TBD */
+               acpi_handle_err(handle, "Device cannot be configured due "
+                               "to a frequency mismatch\n");
                break;
 
        case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-               /* TBD */
+               acpi_handle_err(handle, "Device cannot be configured due "
+                               "to a bus mode mismatch\n");
                break;
 
        case ACPI_NOTIFY_POWER_FAULT:
-               /* TBD */
+               acpi_handle_err(handle, "Device has suffered a power fault\n");
                break;
 
        default:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Received unknown/unsupported notification [%08x]\n",
-                                 type));
-               break;
+               acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+               ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
+               goto err;
        }
 
-       acpi_bus_get_device(handle, &device);
-       if (device) {
-               driver = device->driver;
-               if (driver && driver->ops.notify &&
-                   (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
-                       driver->ops.notify(device, type);
+       adev = acpi_bus_get_acpi_device(handle);
+       if (!adev)
+               goto err;
+
+       driver = adev->driver;
+       if (driver && driver->ops.notify &&
+           (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
+               driver->ops.notify(adev, type);
+
+       switch (type) {
+       case ACPI_NOTIFY_BUS_CHECK:
+       case ACPI_NOTIFY_DEVICE_CHECK:
+       case ACPI_NOTIFY_EJECT_REQUEST:
+               status = acpi_hotplug_schedule(adev, type);
+               if (ACPI_SUCCESS(status))
+                       return;
+       default:
+               break;
        }
+       acpi_bus_put_acpi_device(adev);
+       return;
+
+ err:
+       acpi_evaluate_ost(handle, type, ost_code, NULL);
 }
 
 /* --------------------------------------------------------------------------
index 714e957a871a8034ed18be2104b8c107d0b4ced9..db35594d4df7a072a76e0c2fb879c324efdcedb8 100644 (file)
@@ -302,6 +302,10 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
                        input_sync(input);
 
                        pm_wakeup_event(&device->dev, 0);
+                       acpi_bus_generate_netlink_event(
+                                       device->pnp.device_class,
+                                       dev_name(&device->dev),
+                                       event, ++button->pushed);
                }
                break;
        default:
index 368f9ddb8480777420b2d5633facfeb238db1e27..63119d09b35432e3200a33c0202c9e7cb7ec2f15 100644 (file)
@@ -31,8 +31,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define _COMPONENT                     ACPI_CONTAINER_COMPONENT
 ACPI_MODULE_NAME("container");
 
@@ -68,6 +66,9 @@ static int container_device_attach(struct acpi_device *adev,
        struct device *dev;
        int ret;
 
+       if (adev->flags.is_dock_station)
+               return 0;
+
        cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
        if (!cdev)
                return -ENOMEM;
index c14a00d3dca61e5d943c41d5fe11fb90669550a6..d047739f3380f2d0e53304002499205abe08abd1 100644 (file)
@@ -901,14 +901,29 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
 int acpi_subsys_prepare(struct device *dev)
 {
        /*
-        * Follow PCI and resume devices suspended at run time before running
-        * their system suspend callbacks.
+        * Devices having power.ignore_children set may still be necessary for
+        * suspending their children in the next phase of device suspend.
         */
-       pm_runtime_resume(dev);
+       if (dev->power.ignore_children)
+               pm_runtime_resume(dev);
+
        return pm_generic_prepare(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
 
+/**
+ * acpi_subsys_suspend - Run the device driver's suspend callback.
+ * @dev: Device to handle.
+ *
+ * Follow PCI and resume devices suspended at run time before running their
+ * system suspend callbacks.
+ */
+int acpi_subsys_suspend(struct device *dev)
+{
+       pm_runtime_resume(dev);
+       return pm_generic_suspend(dev);
+}
+
 /**
  * acpi_subsys_suspend_late - Suspend device using ACPI.
  * @dev: Device to suspend.
@@ -937,6 +952,23 @@ int acpi_subsys_resume_early(struct device *dev)
        return ret ? ret : pm_generic_resume_early(dev);
 }
 EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
+
+/**
+ * acpi_subsys_freeze - Run the device driver's freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze(struct device *dev)
+{
+       /*
+        * This used to be done in acpi_subsys_prepare() for all devices and
+        * some drivers may depend on it, so do it here.  Ideally, however,
+        * runtime-suspended devices should not be touched during freeze/thaw
+        * transitions.
+        */
+       pm_runtime_resume(dev);
+       return pm_generic_freeze(dev);
+}
+
 #endif /* CONFIG_PM_SLEEP */
 
 static struct dev_pm_domain acpi_general_pm_domain = {
@@ -947,8 +979,11 @@ static struct dev_pm_domain acpi_general_pm_domain = {
 #endif
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
+               .suspend = acpi_subsys_suspend,
                .suspend_late = acpi_subsys_suspend_late,
                .resume_early = acpi_subsys_resume_early,
+               .freeze = acpi_subsys_freeze,
+               .poweroff = acpi_subsys_suspend,
                .poweroff_late = acpi_subsys_suspend_late,
                .restore_early = acpi_subsys_resume_early,
 #endif
index 5bfd769fc91fa5bfd0890a146a4eed13ac342ff0..f0fc6260266bfe852a7228b7f64bf8db40ce4bb9 100644 (file)
@@ -1,7 +1,9 @@
 /*
  *  dock.c - ACPI dock station driver
  *
- *  Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ *  Copyright (C) 2006, 2014, Intel Corp.
+ *  Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -35,8 +37,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
 
 ACPI_MODULE_NAME("dock");
@@ -68,15 +68,10 @@ struct dock_station {
 };
 static LIST_HEAD(dock_stations);
 static int dock_station_count;
-static DEFINE_MUTEX(hotplug_lock);
 
 struct dock_dependent_device {
        struct list_head list;
-       acpi_handle handle;
-       const struct acpi_dock_ops *hp_ops;
-       void *hp_context;
-       unsigned int hp_refcount;
-       void (*hp_release)(void *);
+       struct acpi_device *adev;
 };
 
 #define DOCK_DOCKING   0x00000001
@@ -98,13 +93,13 @@ enum dock_callback_type {
  *****************************************************************************/
 /**
  * add_dock_dependent_device - associate a device with the dock station
- * @ds: The dock station
- * @handle: handle of the dependent device
+ * @ds: Dock station.
+ * @adev: Dependent ACPI device object.
  *
  * Add the dependent device to the dock's dependent device list.
  */
-static int __init
-add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+static int add_dock_dependent_device(struct dock_station *ds,
+                                    struct acpi_device *adev)
 {
        struct dock_dependent_device *dd;
 
@@ -112,180 +107,120 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
        if (!dd)
                return -ENOMEM;
 
-       dd->handle = handle;
+       dd->adev = adev;
        INIT_LIST_HEAD(&dd->list);
        list_add_tail(&dd->list, &ds->dependent_devices);
 
        return 0;
 }
 
-static void remove_dock_dependent_devices(struct dock_station *ds)
+static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
+                              enum dock_callback_type cb_type)
 {
-       struct dock_dependent_device *dd, *aux;
+       struct acpi_device *adev = dd->adev;
 
-       list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
-               list_del(&dd->list);
-               kfree(dd);
-       }
-}
+       acpi_lock_hp_context();
 
-/**
- * dock_init_hotplug - Initialize a hotplug device on a docking station.
- * @dd: Dock-dependent device.
- * @ops: Dock operations to attach to the dependent device.
- * @context: Data to pass to the @ops callbacks and @release.
- * @init: Optional initialization routine to run after setting up context.
- * @release: Optional release routine to run on removal.
- */
-static int dock_init_hotplug(struct dock_dependent_device *dd,
-                            const struct acpi_dock_ops *ops, void *context,
-                            void (*init)(void *), void (*release)(void *))
-{
-       int ret = 0;
+       if (!adev->hp)
+               goto out;
 
-       mutex_lock(&hotplug_lock);
-       if (WARN_ON(dd->hp_context)) {
-               ret = -EEXIST;
-       } else {
-               dd->hp_refcount = 1;
-               dd->hp_ops = ops;
-               dd->hp_context = context;
-               dd->hp_release = release;
-               if (init)
-                       init(context);
-       }
-       mutex_unlock(&hotplug_lock);
-       return ret;
-}
+       if (cb_type == DOCK_CALL_FIXUP) {
+               void (*fixup)(struct acpi_device *);
 
-/**
- * dock_release_hotplug - Decrement hotplug reference counter of dock device.
- * @dd: Dock-dependent device.
- *
- * Decrement the reference counter of @dd and if 0, detach its hotplug
- * operations from it, reset its context pointer and run the optional release
- * routine if present.
- */
-static void dock_release_hotplug(struct dock_dependent_device *dd)
-{
-       mutex_lock(&hotplug_lock);
-       if (dd->hp_context && !--dd->hp_refcount) {
-               void (*release)(void *) = dd->hp_release;
-               void *context = dd->hp_context;
-
-               dd->hp_ops = NULL;
-               dd->hp_context = NULL;
-               dd->hp_release = NULL;
-               if (release)
-                       release(context);
-       }
-       mutex_unlock(&hotplug_lock);
-}
+               fixup = adev->hp->fixup;
+               if (fixup) {
+                       acpi_unlock_hp_context();
+                       fixup(adev);
+                       return;
+               }
+       } else if (cb_type == DOCK_CALL_UEVENT) {
+               void (*uevent)(struct acpi_device *, u32);
+
+               uevent = adev->hp->uevent;
+               if (uevent) {
+                       acpi_unlock_hp_context();
+                       uevent(adev, event);
+                       return;
+               }
+       } else {
+               int (*notify)(struct acpi_device *, u32);
 
-static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
-                              enum dock_callback_type cb_type)
-{
-       acpi_notify_handler cb = NULL;
-       bool run = false;
-
-       mutex_lock(&hotplug_lock);
-
-       if (dd->hp_context) {
-               run = true;
-               dd->hp_refcount++;
-               if (dd->hp_ops) {
-                       switch (cb_type) {
-                       case DOCK_CALL_FIXUP:
-                               cb = dd->hp_ops->fixup;
-                               break;
-                       case DOCK_CALL_UEVENT:
-                               cb = dd->hp_ops->uevent;
-                               break;
-                       default:
-                               cb = dd->hp_ops->handler;
-                       }
+               notify = adev->hp->notify;
+               if (notify) {
+                       acpi_unlock_hp_context();
+                       notify(adev, event);
+                       return;
                }
        }
 
-       mutex_unlock(&hotplug_lock);
+ out:
+       acpi_unlock_hp_context();
+}
 
-       if (!run)
-               return;
+static struct dock_station *find_dock_station(acpi_handle handle)
+{
+       struct dock_station *ds;
 
-       if (cb)
-               cb(dd->handle, event, dd->hp_context);
+       list_for_each_entry(ds, &dock_stations, sibling)
+               if (ds->handle == handle)
+                       return ds;
 
-       dock_release_hotplug(dd);
+       return NULL;
 }
 
 /**
  * find_dock_dependent_device - get a device dependent on this dock
  * @ds: the dock station
- * @handle: the acpi_handle of the device we want
+ * @adev: ACPI device object to find.
  *
  * iterate over the dependent device list for this dock.  If the
  * dependent device matches the handle, return.
  */
 static struct dock_dependent_device *
-find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
 {
        struct dock_dependent_device *dd;
 
        list_for_each_entry(dd, &ds->dependent_devices, list)
-               if (handle == dd->handle)
+               if (adev == dd->adev)
                        return dd;
 
        return NULL;
 }
 
-/*****************************************************************************
- *                         Dock functions                                    *
- *****************************************************************************/
-static int __init is_battery(acpi_handle handle)
+void register_dock_dependent_device(struct acpi_device *adev,
+                                   acpi_handle dshandle)
 {
-       struct acpi_device_info *info;
-       int ret = 1;
+       struct dock_station *ds = find_dock_station(dshandle);
 
-       if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
-               return 0;
-       if (!(info->valid & ACPI_VALID_HID))
-               ret = 0;
-       else
-               ret = !strcmp("PNP0C0A", info->hardware_id.string);
-
-       kfree(info);
-       return ret;
+       if (ds && !find_dock_dependent_device(ds, adev))
+               add_dock_dependent_device(ds, adev);
 }
 
-/* Check whether ACPI object is an ejectable battery or disk bay */
-static bool __init is_ejectable_bay(acpi_handle handle)
-{
-       if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
-               return true;
-
-       return acpi_bay_match(handle);
-}
+/*****************************************************************************
+ *                         Dock functions                                    *
+ *****************************************************************************/
 
 /**
  * is_dock_device - see if a device is on a dock station
- * @handle: acpi handle of the device
+ * @adev: ACPI device object to check.
  *
  * If this device is either the dock station itself,
  * or is a device dependent on the dock station, then it
  * is a dock device
  */
-int is_dock_device(acpi_handle handle)
+int is_dock_device(struct acpi_device *adev)
 {
        struct dock_station *dock_station;
 
        if (!dock_station_count)
                return 0;
 
-       if (acpi_dock_match(handle))
+       if (acpi_dock_match(adev->handle))
                return 1;
 
        list_for_each_entry(dock_station, &dock_stations, sibling)
-               if (find_dock_dependent_device(dock_station, handle))
+               if (find_dock_dependent_device(dock_station, adev))
                        return 1;
 
        return 0;
@@ -312,43 +247,6 @@ static int dock_present(struct dock_station *ds)
        return 0;
 }
 
-/**
- * dock_create_acpi_device - add new devices to acpi
- * @handle - handle of the device to add
- *
- *  This function will create a new acpi_device for the given
- *  handle if one does not exist already.  This should cause
- *  acpi to scan for drivers for the given devices, and call
- *  matching driver's add routine.
- */
-static void dock_create_acpi_device(acpi_handle handle)
-{
-       struct acpi_device *device = NULL;
-       int ret;
-
-       acpi_bus_get_device(handle, &device);
-       if (!acpi_device_enumerated(device)) {
-               ret = acpi_bus_scan(handle);
-               if (ret)
-                       pr_debug("error adding bus, %x\n", -ret);
-       }
-}
-
-/**
- * dock_remove_acpi_device - remove the acpi_device struct from acpi
- * @handle - the handle of the device to remove
- *
- *  Tell acpi to remove the acpi_device.  This should cause any loaded
- *  driver to have it's remove routine called.
- */
-static void dock_remove_acpi_device(acpi_handle handle)
-{
-       struct acpi_device *device;
-
-       if (!acpi_bus_get_device(handle, &device))
-               acpi_bus_trim(device);
-}
-
 /**
  * hot_remove_dock_devices - Remove dock station devices.
  * @ds: Dock station.
@@ -366,7 +264,7 @@ static void hot_remove_dock_devices(struct dock_station *ds)
                dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
 
        list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
-               dock_remove_acpi_device(dd->handle);
+               acpi_bus_trim(dd->adev);
 }
 
 /**
@@ -392,12 +290,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
                dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
 
        /*
-        * Now make sure that an acpi_device is created for each dependent
-        * device.  That will cause scan handlers to be attached to device
-        * objects or acpi_drivers to be stopped/started if they are present.
+        * Check if all devices have been enumerated already.  If not, run
+        * acpi_bus_scan() for them and that will cause scan handlers to be
+        * attached to device objects or acpi_drivers to be stopped/started if
+        * they are present.
         */
-       list_for_each_entry(dd, &ds->dependent_devices, list)
-               dock_create_acpi_device(dd->handle);
+       list_for_each_entry(dd, &ds->dependent_devices, list) {
+               struct acpi_device *adev = dd->adev;
+
+               if (!acpi_device_enumerated(adev)) {
+                       int ret = acpi_bus_scan(adev->handle);
+                       if (ret)
+                               dev_dbg(&adev->dev, "scan error %d\n", -ret);
+               }
+       }
 }
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -500,71 +406,6 @@ static int dock_in_progress(struct dock_station *ds)
        return 0;
 }
 
-/**
- * register_hotplug_dock_device - register a hotplug function
- * @handle: the handle of the device
- * @ops: handlers to call after docking
- * @context: device specific data
- * @init: Optional initialization routine to run after registration
- * @release: Optional release routine to run on unregistration
- *
- * If a driver would like to perform a hotplug operation after a dock
- * event, they can register an acpi_notifiy_handler to be called by
- * the dock driver after _DCK is executed.
- */
-int register_hotplug_dock_device(acpi_handle handle,
-                                const struct acpi_dock_ops *ops, void *context,
-                                void (*init)(void *), void (*release)(void *))
-{
-       struct dock_dependent_device *dd;
-       struct dock_station *dock_station;
-       int ret = -EINVAL;
-
-       if (WARN_ON(!context))
-               return -EINVAL;
-
-       if (!dock_station_count)
-               return -ENODEV;
-
-       /*
-        * make sure this handle is for a device dependent on the dock,
-        * this would include the dock station itself
-        */
-       list_for_each_entry(dock_station, &dock_stations, sibling) {
-               /*
-                * An ATA bay can be in a dock and itself can be ejected
-                * separately, so there are two 'dock stations' which need the
-                * ops
-                */
-               dd = find_dock_dependent_device(dock_station, handle);
-               if (dd && !dock_init_hotplug(dd, ops, context, init, release))
-                       ret = 0;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
-
-/**
- * unregister_hotplug_dock_device - remove yourself from the hotplug list
- * @handle: the acpi handle of the device
- */
-void unregister_hotplug_dock_device(acpi_handle handle)
-{
-       struct dock_dependent_device *dd;
-       struct dock_station *dock_station;
-
-       if (!dock_station_count)
-               return;
-
-       list_for_each_entry(dock_station, &dock_stations, sibling) {
-               dd = find_dock_dependent_device(dock_station, handle);
-               if (dd)
-                       dock_release_hotplug(dd);
-       }
-}
-EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
-
 /**
  * handle_eject_request - handle an undock request checking for error conditions
  *
@@ -598,20 +439,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
 }
 
 /**
- * dock_notify - act upon an acpi dock notification
- * @ds: dock station
- * @event: the acpi event
+ * dock_notify - Handle ACPI dock notification.
+ * @adev: Dock station's ACPI device object.
+ * @event: Event code.
  *
  * If we are notified to dock, then check to see if the dock is
  * present and then dock.  Notify all drivers of the dock event,
  * and then hotplug and devices that may need hotplugging.
  */
-static void dock_notify(struct dock_station *ds, u32 event)
+int dock_notify(struct acpi_device *adev, u32 event)
 {
-       acpi_handle handle = ds->handle;
-       struct acpi_device *adev = NULL;
+       acpi_handle handle = adev->handle;
+       struct dock_station *ds = find_dock_station(handle);
        int surprise_removal = 0;
 
+       if (!ds)
+               return -ENODEV;
+
        /*
         * According to acpi spec 3.0a, if a DEVICE_CHECK notification
         * is sent and _DCK is present, it is assumed to mean an undock
@@ -632,7 +476,6 @@ static void dock_notify(struct dock_station *ds, u32 event)
        switch (event) {
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
-               acpi_bus_get_device(handle, &adev);
                if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
                        begin_dock(ds);
                        dock(ds);
@@ -662,49 +505,8 @@ static void dock_notify(struct dock_station *ds, u32 event)
                else
                        dock_event(ds, event, UNDOCK_EVENT);
                break;
-       default:
-               acpi_handle_err(handle, "Unknown dock event %d\n", event);
        }
-}
-
-static void acpi_dock_deferred_cb(void *data, u32 event)
-{
-       acpi_scan_lock_acquire();
-       dock_notify(data, event);
-       acpi_scan_lock_release();
-}
-
-static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
-{
-       if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
-          && event != ACPI_NOTIFY_EJECT_REQUEST)
-               return;
-
-       acpi_hotplug_execute(acpi_dock_deferred_cb, data, event);
-}
-
-/**
- * find_dock_devices - find devices on the dock station
- * @handle: the handle of the device we are examining
- * @lvl: unused
- * @context: the dock station private data
- * @rv: unused
- *
- * This function is called by acpi_walk_namespace.  It will
- * check to see if an object has an _EJD method.  If it does, then it
- * will see if it is dependent on the dock station.
- */
-static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
-                                           void *context, void **rv)
-{
-       struct dock_station *ds = context;
-       acpi_handle ejd = NULL;
-
-       acpi_bus_get_ejd(handle, &ejd);
-       if (ejd == ds->handle)
-               add_dock_dependent_device(ds, handle);
-
-       return AE_OK;
+       return 0;
 }
 
 /*
@@ -803,23 +605,28 @@ static struct attribute_group dock_attribute_group = {
 };
 
 /**
- * dock_add - add a new dock station
- * @handle: the dock station handle
+ * acpi_dock_add - Add a new dock station
+ * @adev: Dock station ACPI device object.
  *
- * allocated and initialize a new dock station device.  Find all devices
- * that are on the dock station, and register for dock event notifications.
+ * allocated and initialize a new dock station device.
  */
-static int __init dock_add(acpi_handle handle)
+void acpi_dock_add(struct acpi_device *adev)
 {
        struct dock_station *dock_station, ds = { NULL, };
+       struct platform_device_info pdevinfo;
+       acpi_handle handle = adev->handle;
        struct platform_device *dd;
-       acpi_status status;
        int ret;
 
-       dd = platform_device_register_data(NULL, "dock", dock_station_count,
-                                          &ds, sizeof(ds));
+       memset(&pdevinfo, 0, sizeof(pdevinfo));
+       pdevinfo.name = "dock";
+       pdevinfo.id = dock_station_count;
+       pdevinfo.acpi_node.companion = adev;
+       pdevinfo.data = &ds;
+       pdevinfo.size_data = sizeof(ds);
+       dd = platform_device_register_full(&pdevinfo);
        if (IS_ERR(dd))
-               return PTR_ERR(dd);
+               return;
 
        dock_station = dd->dev.platform_data;
 
@@ -837,72 +644,29 @@ static int __init dock_add(acpi_handle handle)
                dock_station->flags |= DOCK_IS_DOCK;
        if (acpi_ata_match(handle))
                dock_station->flags |= DOCK_IS_ATA;
-       if (is_battery(handle))
+       if (acpi_device_is_battery(adev))
                dock_station->flags |= DOCK_IS_BAT;
 
        ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
        if (ret)
                goto err_unregister;
 
-       /* Find dependent devices */
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-                           ACPI_UINT32_MAX, find_dock_devices, NULL,
-                           dock_station, NULL);
-
        /* add the dock station as a device dependent on itself */
-       ret = add_dock_dependent_device(dock_station, handle);
+       ret = add_dock_dependent_device(dock_station, adev);
        if (ret)
                goto err_rmgroup;
 
-       status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-                                            dock_notify_handler, dock_station);
-       if (ACPI_FAILURE(status)) {
-               ret = -ENODEV;
-               goto err_rmgroup;
-       }
-
        dock_station_count++;
        list_add(&dock_station->sibling, &dock_stations);
-       return 0;
+       adev->flags.is_dock_station = true;
+       dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
+                dock_station_count);
+       return;
 
 err_rmgroup:
-       remove_dock_dependent_devices(dock_station);
        sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
+
 err_unregister:
        platform_device_unregister(dd);
        acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
-       return ret;
-}
-
-/**
- * find_dock_and_bay - look for dock stations and bays
- * @handle: acpi handle of a device
- * @lvl: unused
- * @context: unused
- * @rv: unused
- *
- * This is called by acpi_walk_namespace to look for dock stations and bays.
- */
-static acpi_status __init
-find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       if (acpi_dock_match(handle) || is_ejectable_bay(handle))
-               dock_add(handle);
-
-       return AE_OK;
-}
-
-void __init acpi_dock_init(void)
-{
-       /* look for dock stations and bays */
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-               ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);
-
-       if (!dock_station_count) {
-               pr_info(PREFIX "No dock devices found.\n");
-               return;
-       }
-
-       pr_info(PREFIX "%s: %d docks/bays found\n",
-               ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
 }
index 959d41acc108a847308773f754fdb4fff3b1fd26..d7d32c28829b17834507bf8683f2c2a5c77d0a0d 100644 (file)
@@ -67,6 +67,8 @@ enum ec_command {
 #define ACPI_EC_DELAY          500     /* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
 #define ACPI_EC_MSI_UDELAY     550     /* Wait 550us for MSI EC */
+#define ACPI_EC_CLEAR_MAX      100     /* Maximum number of events to query
+                                        * when trying to clear the EC */
 
 enum {
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
 static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)
 
 EXPORT_SYMBOL(ec_get_handle);
 
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
+
+/*
+ * Clears stale _Q events that might have accumulated in the EC.
+ * Run with locked ec mutex.
+ */
+static void acpi_ec_clear(struct acpi_ec *ec)
+{
+       int i, status;
+       u8 value = 0;
+
+       for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
+               status = acpi_ec_query_unlocked(ec, &value);
+               if (status || !value)
+                       break;
+       }
+
+       if (unlikely(i == ACPI_EC_CLEAR_MAX))
+               pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
+       else
+               pr_info("%d stale EC events cleared\n", i);
+}
+
 void acpi_ec_block_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
        mutex_lock(&ec->mutex);
        /* Allow transactions to be carried out again */
        clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+
+       if (EC_FLAGS_CLEAR_ON_RESUME)
+               acpi_ec_clear(ec);
+
        mutex_unlock(&ec->mutex);
 }
 
@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)
 
        /* EC is fully operational, allow queries */
        clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+
+       /* Clear stale _Q events if hardware might require that */
+       if (EC_FLAGS_CLEAR_ON_RESUME) {
+               mutex_lock(&ec->mutex);
+               acpi_ec_clear(ec);
+               mutex_unlock(&ec->mutex);
+       }
        return ret;
 }
 
@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
        return 0;
 }
 
+/*
+ * On some hardware it is necessary to clear events accumulated by the EC during
+ * sleep. These ECs stop reporting GPEs until they are manually polled, if too
+ * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=44161
+ *
+ * Ideally, the EC should also be instructed NOT to accumulate events during
+ * sleep (which Windows seems to do somehow), but the interface to control this
+ * behaviour is not known at this time.
+ *
+ * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
+ * however it is very likely that other Samsung models are affected.
+ *
+ * On systems which don't accumulate _Q events during sleep, this extra check
+ * should be harmless.
+ */
+static int ec_clear_on_resume(const struct dmi_system_id *id)
+{
+       pr_debug("Detected system needing EC poll on resume.\n");
+       EC_FLAGS_CLEAR_ON_RESUME = 1;
+       return 0;
+}
+
 static struct dmi_system_id ec_dmi_table[] __initdata = {
        {
        ec_skip_dsdt_scan, "Compal JFL92", {
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
        DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
+       {
+       ec_clear_on_resume, "Samsung hardware", {
+       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
        {},
 };
 
index 09e423f3d8ad30fbd16d2d2b2e2766e69e64de82..8acf53e6296605a013a6359299c3e9cf29bcbf67 100644 (file)
@@ -55,11 +55,16 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
 #ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev);
 static int acpi_fan_resume(struct device *dev);
+static struct dev_pm_ops acpi_fan_pm = {
+       .resume = acpi_fan_resume,
+       .freeze = acpi_fan_suspend,
+       .thaw = acpi_fan_resume,
+       .restore = acpi_fan_resume,
+};
+#define FAN_PM_OPS_PTR (&acpi_fan_pm)
 #else
-#define acpi_fan_suspend NULL
-#define acpi_fan_resume NULL
+#define FAN_PM_OPS_PTR NULL
 #endif
-static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
 
 static struct acpi_driver acpi_fan_driver = {
        .name = "fan",
@@ -69,7 +74,7 @@ static struct acpi_driver acpi_fan_driver = {
                .add = acpi_fan_add,
                .remove = acpi_fan_remove,
                },
-       .drv.pm = &acpi_fan_pm,
+       .drv.pm = FAN_PM_OPS_PTR,
 };
 
 /* thermal cooling device callbacks */
index 0c789224d40d4da34aa3c7f1a9314bb12ba7b459..f774c65ecb8bb03065ba406e658710aead5d02c0 100644 (file)
@@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one);
 static int acpi_platform_notify(struct device *dev)
 {
        struct acpi_bus_type *type = acpi_get_bus_type(dev);
+       struct acpi_device *adev;
        int ret;
 
        ret = acpi_bind_one(dev, NULL);
@@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev)
                if (ret)
                        goto out;
        }
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               goto out;
 
        if (type && type->setup)
                type->setup(dev);
+       else if (adev->handler && adev->handler->bind)
+               adev->handler->bind(dev);
 
  out:
 #if ACPI_GLUE_DEBUG
@@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev)
 
 static int acpi_platform_notify_remove(struct device *dev)
 {
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_bus_type *type;
 
+       if (!adev)
+               return 0;
+
        type = acpi_get_bus_type(dev);
        if (type && type->cleanup)
                type->cleanup(dev);
+       else if (adev->handler && adev->handler->unbind)
+               adev->handler->unbind(dev);
 
        acpi_unbind_one(dev);
        return 0;
index dedbb2d802f1a87bd5a3c288067124514cad9824..957391306cbf32953457b1e8a540a66b32bd253b 100644 (file)
@@ -37,9 +37,15 @@ void acpi_container_init(void);
 static inline void acpi_container_init(void) {}
 #endif
 #ifdef CONFIG_ACPI_DOCK
-void acpi_dock_init(void);
+void register_dock_dependent_device(struct acpi_device *adev,
+                                   acpi_handle dshandle);
+int dock_notify(struct acpi_device *adev, u32 event);
+void acpi_dock_add(struct acpi_device *adev);
 #else
-static inline void acpi_dock_init(void) {}
+static inline void register_dock_dependent_device(struct acpi_device *adev,
+                                                 acpi_handle dshandle) {}
+static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
+static inline void acpi_dock_add(struct acpi_device *adev) {}
 #endif
 #ifdef CONFIG_ACPI_HOTPLUG_MEMORY
 void acpi_memory_hotplug_init(void);
@@ -72,7 +78,9 @@ void acpi_lpss_init(void);
 static inline void acpi_lpss_init(void) {}
 #endif
 
+acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
 bool acpi_queue_hotplug_work(struct work_struct *work);
+void acpi_device_hotplug(struct acpi_device *adev, u32 src);
 bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
 
 /* --------------------------------------------------------------------------
@@ -90,6 +98,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
 int acpi_bind_one(struct device *dev, struct acpi_device *adev);
 int acpi_unbind_one(struct device *dev);
 bool acpi_device_is_present(struct acpi_device *adev);
+bool acpi_device_is_battery(struct acpi_device *adev);
 
 /* --------------------------------------------------------------------------
                                   Power Resource
index 9e6816ef280ab7a5def6586cfabd3f60b7cd0ccb..24b5476449a110ad8c16ef6a246169be06e41b65 100644 (file)
@@ -60,7 +60,7 @@ int node_to_pxm(int node)
        return node_to_pxm_map[node];
 }
 
-void __acpi_map_pxm_to_node(int pxm, int node)
+static void __acpi_map_pxm_to_node(int pxm, int node)
 {
        if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
                pxm_to_node_map[pxm] = node;
@@ -193,7 +193,7 @@ static int __init acpi_parse_slit(struct acpi_table_header *table)
        return 0;
 }
 
-void __init __attribute__ ((weak))
+void __init __weak
 acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
 {
        printk(KERN_WARNING PREFIX
@@ -314,7 +314,7 @@ int __init acpi_numa_init(void)
        return 0;
 }
 
-int acpi_get_pxm(acpi_handle h)
+static int acpi_get_pxm(acpi_handle h)
 {
        unsigned long long pxm;
        acpi_status status;
@@ -331,14 +331,14 @@ int acpi_get_pxm(acpi_handle h)
        return -1;
 }
 
-int acpi_get_node(acpi_handle *handle)
+int acpi_get_node(acpi_handle handle)
 {
-       int pxm, node = NUMA_NO_NODE;
+       int pxm;
 
        pxm = acpi_get_pxm(handle);
-       if (pxm >= 0 && pxm < MAX_PXM_DOMAINS)
-               node = acpi_map_pxm_to_node(pxm);
+       if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+               return NUMA_NO_NODE;
 
-       return node;
+       return acpi_map_pxm_to_node(pxm);
 }
 EXPORT_SYMBOL(acpi_get_node);
index fc1aa7909690c3ef148930a4a96080d2bcaaa155..27f84af4e337df87540e3c4e1e84f358eef7cb3c 100644 (file)
@@ -52,7 +52,7 @@
 
 #define _COMPONENT             ACPI_OS_SERVICES
 ACPI_MODULE_NAME("osl");
-#define PREFIX         "ACPI: "
+
 struct acpi_os_dpc {
        acpi_osd_exec_callback function;
        void *context;
@@ -1168,8 +1168,7 @@ void acpi_os_wait_events_complete(void)
 
 struct acpi_hp_work {
        struct work_struct work;
-       acpi_hp_callback func;
-       void *data;
+       struct acpi_device *adev;
        u32 src;
 };
 
@@ -1178,25 +1177,24 @@ static void acpi_hotplug_work_fn(struct work_struct *work)
        struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work);
 
        acpi_os_wait_events_complete();
-       hpw->func(hpw->data, hpw->src);
+       acpi_device_hotplug(hpw->adev, hpw->src);
        kfree(hpw);
 }
 
-acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
+acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src)
 {
        struct acpi_hp_work *hpw;
 
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                 "Scheduling function [%p(%p, %u)] for deferred execution.\n",
-                 func, data, src));
+                 "Scheduling hotplug event (%p, %u) for deferred execution.\n",
+                 adev, src));
 
        hpw = kmalloc(sizeof(*hpw), GFP_KERNEL);
        if (!hpw)
                return AE_NO_MEMORY;
 
        INIT_WORK(&hpw->work, acpi_hotplug_work_fn);
-       hpw->func = func;
-       hpw->data = data;
+       hpw->adev = adev;
        hpw->src = src;
        /*
         * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because
@@ -1780,6 +1778,17 @@ static int __init acpi_no_auto_ssdt_setup(char *s)
 
 __setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
 
+static int __init acpi_disable_return_repair(char *s)
+{
+       printk(KERN_NOTICE PREFIX
+              "ACPI: Predefined validation mechanism disabled\n");
+       acpi_gbl_disable_auto_repair = TRUE;
+
+       return 1;
+}
+
+__setup("acpica_no_return_repair", acpi_disable_return_repair);
+
 acpi_status __init acpi_os_initialize(void)
 {
        acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
index 361b40c10c3f522e28e2b334dd5f8976109bc772..9c62340c2360b5960bdde09dc5172ca763506473 100644 (file)
@@ -370,6 +370,30 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
        return NULL;
 }
 
+#if IS_ENABLED(CONFIG_ISA) || IS_ENABLED(CONFIG_EISA)
+static int acpi_isa_register_gsi(struct pci_dev *dev)
+{
+       u32 dev_gsi;
+
+       /* Interrupt Line values above 0xF are forbidden */
+       if (dev->irq > 0 && (dev->irq <= 0xF) &&
+           (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
+               dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
+                        pin_name(dev->pin), dev->irq);
+               acpi_register_gsi(&dev->dev, dev_gsi,
+                                 ACPI_LEVEL_SENSITIVE,
+                                 ACPI_ACTIVE_LOW);
+               return 0;
+       }
+       return -EINVAL;
+}
+#else
+static inline int acpi_isa_register_gsi(struct pci_dev *dev)
+{
+       return -ENODEV;
+}
+#endif
+
 int acpi_pci_irq_enable(struct pci_dev *dev)
 {
        struct acpi_prt_entry *entry;
@@ -416,19 +440,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
         * driver reported one, then use it. Exit in any case.
         */
        if (gsi < 0) {
-               u32 dev_gsi;
-               /* Interrupt Line values above 0xF are forbidden */
-               if (dev->irq > 0 && (dev->irq <= 0xF) &&
-                   (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
-                       dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
-                                pin_name(pin), dev->irq);
-                       acpi_register_gsi(&dev->dev, dev_gsi,
-                                         ACPI_LEVEL_SENSITIVE,
-                                         ACPI_ACTIVE_LOW);
-               } else {
+               if (acpi_isa_register_gsi(dev))
                        dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
                                 pin_name(pin));
-               }
 
                kfree(entry);
                return 0;
index 9418c7a1f78665b32c980f815e789f152e973cb5..cfd7581cc19fa24c37d1a3fb7cb370e33a63c760 100644 (file)
@@ -43,8 +43,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define _COMPONENT                     ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME("pci_link");
 #define ACPI_PCI_LINK_CLASS            "pci_irq_routing"
index c1c4102e647898717fb8e3c7acc440561d608d8a..d388f13d48b43634acaaddaf526f037051db78c0 100644 (file)
@@ -39,8 +39,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define _COMPONENT             ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME("pci_root");
 #define ACPI_PCI_ROOT_CLASS            "pci_bridge"
@@ -51,7 +49,7 @@ static void acpi_pci_root_remove(struct acpi_device *device);
 
 static int acpi_pci_root_scan_dependent(struct acpi_device *adev)
 {
-       acpiphp_check_host_bridge(adev->handle);
+       acpiphp_check_host_bridge(adev);
        return 0;
 }
 
index ad7da686e6e6f8d9745a4edf866e174b99b08538..e0bcfb642b52654f1dfb2f8948c1cac62ff96c68 100644 (file)
@@ -46,8 +46,6 @@
 #include "sleep.h"
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define _COMPONENT                     ACPI_POWER_COMPONENT
 ACPI_MODULE_NAME("power");
 #define ACPI_POWER_CLASS               "power_resource"
index a4eea9a508d3efd977fe97563b967b776a49a084..86d73d5d503f7708f52444e6a10bb4da285e3036 100644 (file)
 
 #include "internal.h"
 
-#define PREFIX                 "ACPI: "
 #define _COMPONENT             ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_core");
 
-static int __init set_no_mwait(const struct dmi_system_id *id)
-{
-       printk(KERN_NOTICE PREFIX "%s detected - "
-               "disabling mwait for CPU C-states\n", id->ident);
-       boot_option_idle_override = IDLE_NOMWAIT;
-       return 0;
-}
-
-static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
-       {
-       set_no_mwait, "Extensa 5220", {
-       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
-       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-       DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
-       DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
-       {},
-};
-
 static int map_lapic_id(struct acpi_subtable_header *entry,
                 u32 acpi_id, int *apic_id)
 {
@@ -89,6 +70,28 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
        return 0;
 }
 
+static int map_gic_id(struct acpi_subtable_header *entry,
+               int device_declaration, u32 acpi_id, int *apic_id)
+{
+       struct acpi_madt_generic_interrupt *gic =
+               (struct acpi_madt_generic_interrupt *)entry;
+
+       if (!(gic->flags & ACPI_MADT_ENABLED))
+               return -ENODEV;
+
+       /*
+        * In the GIC interrupt model, logical processors are
+        * required to have a Processor Device object in the DSDT,
+        * so we should check device_declaration here
+        */
+       if (device_declaration && (gic->uid == acpi_id)) {
+               *apic_id = gic->gic_id;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 static int map_madt_entry(int type, u32 acpi_id)
 {
        unsigned long madt_end, entry;
@@ -124,6 +127,9 @@ static int map_madt_entry(int type, u32 acpi_id)
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
                        if (!map_lsapic_id(header, type, acpi_id, &apic_id))
                                break;
+               } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+                       if (!map_gic_id(header, type, acpi_id, &apic_id))
+                               break;
                }
                entry += header->length;
        }
@@ -154,6 +160,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
                map_lapic_id(header, acpi_id, &apic_id);
        } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
                map_lsapic_id(header, type, acpi_id, &apic_id);
+       } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+               map_gic_id(header, type, acpi_id, &apic_id);
        }
 
 exit:
@@ -323,7 +331,7 @@ static struct acpi_object_list *acpi_processor_alloc_pdc(void)
  * _PDC is required for a BIOS-OS handshake for most of the newer
  * ACPI processor features.
  */
-static int
+static acpi_status
 acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
 {
        acpi_status status = AE_OK;
@@ -379,16 +387,43 @@ early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-void __init acpi_early_processor_set_pdc(void)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+static int __init set_no_mwait(const struct dmi_system_id *id)
+{
+       pr_notice(PREFIX "%s detected - disabling mwait for CPU C-states\n",
+                 id->ident);
+       boot_option_idle_override = IDLE_NOMWAIT;
+       return 0;
+}
+
+static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
+       {
+       set_no_mwait, "Extensa 5220", {
+       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+       DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+       DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
+       {},
+};
+
+static void __init processor_dmi_check(void)
 {
        /*
         * Check whether the system is DMI table. If yes, OSPM
         * should not use mwait for CPU-states.
         */
        dmi_check_system(processor_idle_dmi_table);
+}
+#else
+static inline void processor_dmi_check(void) {}
+#endif
+
+void __init acpi_early_processor_set_pdc(void)
+{
+       processor_dmi_check();
 
        acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
                            ACPI_UINT32_MAX,
                            early_init_pdc, NULL, NULL, NULL);
-       acpi_get_devices("ACPI0007", early_init_pdc, NULL, NULL);
+       acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL);
 }
index c1c35623550fd723e74a63d5abfaea1ef724e3ab..7f70f3182d506ffc41ce61f370e047d514c34db3 100644 (file)
@@ -41,8 +41,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
 #define ACPI_PROCESSOR_NOTIFY_POWER    0x81
 #define ACPI_PROCESSOR_NOTIFY_THROTTLING       0x82
index ff90054f04fdb88e15e1279b23b43d78884596f9..cfc8aba72f86d02eb0c9ae53576382b6ef76f287 100644 (file)
@@ -156,17 +156,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
  */
 static void acpi_processor_ppc_ost(acpi_handle handle, int status)
 {
-       union acpi_object params[2] = {
-               {.type = ACPI_TYPE_INTEGER,},
-               {.type = ACPI_TYPE_INTEGER,},
-       };
-       struct acpi_object_list arg_list = {2, params};
-
-       if (acpi_has_method(handle, "_OST")) {
-               params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
-               params[1].integer.value =  status;
-               acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-       }
+       if (acpi_has_method(handle, "_OST"))
+               acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE,
+                                 status, NULL);
 }
 
 int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
index b7201fc6f1e19c06c798889900c1e9c689494c8d..0bdacc5e26a3b9411b82a5fe4772c2c9f9b7d490 100644 (file)
@@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
        switch (ares->type) {
        case ACPI_RESOURCE_TYPE_MEMORY24:
                memory24 = &ares->data.memory24;
+               if (!memory24->address_length)
+                       return false;
                acpi_dev_get_memresource(res, memory24->minimum,
                                         memory24->address_length,
                                         memory24->write_protect);
                break;
        case ACPI_RESOURCE_TYPE_MEMORY32:
                memory32 = &ares->data.memory32;
+               if (!memory32->address_length)
+                       return false;
                acpi_dev_get_memresource(res, memory32->minimum,
                                         memory32->address_length,
                                         memory32->write_protect);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
                fixed_memory32 = &ares->data.fixed_memory32;
+               if (!fixed_memory32->address_length)
+                       return false;
                acpi_dev_get_memresource(res, fixed_memory32->address,
                                         fixed_memory32->address_length,
                                         fixed_memory32->write_protect);
@@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
        switch (ares->type) {
        case ACPI_RESOURCE_TYPE_IO:
                io = &ares->data.io;
+               if (!io->address_length)
+                       return false;
                acpi_dev_get_ioresource(res, io->minimum,
                                        io->address_length,
                                        io->io_decode);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_IO:
                fixed_io = &ares->data.fixed_io;
+               if (!fixed_io->address_length)
+                       return false;
                acpi_dev_get_ioresource(res, fixed_io->address,
                                        fixed_io->address_length,
                                        ACPI_DECODE_10);
index dbd48498b93863a1fa37ab0b23706f2dae89345d..366ca40a6f703433efc1016a658eaac9e28c5c48 100644 (file)
 #include <linux/power_supply.h>
 
 #include "sbshc.h"
+#include "battery.h"
 
 #define PREFIX "ACPI: "
 
 #define ACPI_SBS_CLASS                 "sbs"
 #define ACPI_AC_CLASS                  "ac_adapter"
-#define ACPI_BATTERY_CLASS             "battery"
 #define ACPI_SBS_DEVICE_NAME           "Smart Battery System"
 #define ACPI_SBS_FILE_INFO             "info"
 #define ACPI_SBS_FILE_STATE            "state"
index 57b053f424d13e23ef2dd4b43a191c0d9dda09da..7efe546a8c42704137f3cbae8a3159485f3473b9 100644 (file)
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock);
 static LIST_HEAD(acpi_scan_handlers_list);
 DEFINE_MUTEX(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
+static DEFINE_MUTEX(acpi_hp_context_lock);
 
 struct acpi_device_bus_id{
        char bus_id[15];
@@ -60,6 +61,27 @@ void acpi_scan_lock_release(void)
 }
 EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
 
+void acpi_lock_hp_context(void)
+{
+       mutex_lock(&acpi_hp_context_lock);
+}
+
+void acpi_unlock_hp_context(void)
+{
+       mutex_unlock(&acpi_hp_context_lock);
+}
+
+void acpi_initialize_hp_context(struct acpi_device *adev,
+                               struct acpi_hotplug_context *hp,
+                               int (*notify)(struct acpi_device *, u32),
+                               void (*uevent)(struct acpi_device *, u32))
+{
+       acpi_lock_hp_context();
+       acpi_set_hp_context(adev, hp, notify, uevent, NULL);
+       acpi_unlock_hp_context();
+}
+EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
+
 int acpi_scan_add_handler(struct acpi_scan_handler *handler)
 {
        if (!handler || !handler->attach)
@@ -439,90 +461,75 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
        return 0;
 }
 
-static void acpi_device_hotplug(void *data, u32 src)
+static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
 {
-       u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-       struct acpi_device *adev = data;
-       int error;
-
-       lock_device_hotplug();
-       mutex_lock(&acpi_scan_lock);
-
-       /*
-        * The device object's ACPI handle cannot become invalid as long as we
-        * are holding acpi_scan_lock, but it may have become invalid before
-        * that lock was acquired.
-        */
-       if (adev->handle == INVALID_ACPI_HANDLE)
-               goto out;
-
-       switch (src) {
+       switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
-               error = acpi_scan_bus_check(adev);
-               break;
+               return acpi_scan_bus_check(adev);
        case ACPI_NOTIFY_DEVICE_CHECK:
-               error = acpi_scan_device_check(adev);
-               break;
+               return acpi_scan_device_check(adev);
        case ACPI_NOTIFY_EJECT_REQUEST:
        case ACPI_OST_EC_OSPM_EJECT:
-               error = acpi_scan_hot_remove(adev);
-               break;
-       default:
-               error = -EINVAL;
-               break;
+               if (adev->handler && !adev->handler->hotplug.enabled) {
+                       dev_info(&adev->dev, "Eject disabled\n");
+                       return -EPERM;
+               }
+               acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST,
+                                 ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+               return acpi_scan_hot_remove(adev);
        }
-       if (!error)
-               ost_code = ACPI_OST_SC_SUCCESS;
-
- out:
-       acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
-       put_device(&adev->dev);
-       mutex_unlock(&acpi_scan_lock);
-       unlock_device_hotplug();
+       return -EINVAL;
 }
 
-static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
+void acpi_device_hotplug(struct acpi_device *adev, u32 src)
 {
        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-       struct acpi_device *adev;
-       acpi_status status;
+       int error = -ENODEV;
 
-       if (acpi_bus_get_device(handle, &adev))
-               goto err_out;
+       lock_device_hotplug();
+       mutex_lock(&acpi_scan_lock);
 
-       switch (type) {
-       case ACPI_NOTIFY_BUS_CHECK:
-               acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
-               break;
-       case ACPI_NOTIFY_DEVICE_CHECK:
-               acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
-               break;
-       case ACPI_NOTIFY_EJECT_REQUEST:
-               acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
-               if (!adev->handler)
-                       goto err_out;
+       /*
+        * The device object's ACPI handle cannot become invalid as long as we
+        * are holding acpi_scan_lock, but it might have become invalid before
+        * that lock was acquired.
+        */
+       if (adev->handle == INVALID_ACPI_HANDLE)
+               goto err_out;
 
-               if (!adev->handler->hotplug.enabled) {
-                       acpi_handle_err(handle, "Eject disabled\n");
+       if (adev->flags.is_dock_station) {
+               error = dock_notify(adev, src);
+       } else if (adev->flags.hotplug_notify) {
+               error = acpi_generic_hotplug_event(adev, src);
+               if (error == -EPERM) {
                        ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
                        goto err_out;
                }
-               acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
-                                         ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
-               break;
-       default:
-               /* non-hotplug event; possibly handled by other handler */
-               return;
-       }
-       get_device(&adev->dev);
-       status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
-       if (ACPI_SUCCESS(status))
-               return;
+       } else {
+               int (*notify)(struct acpi_device *, u32);
 
-       put_device(&adev->dev);
+               acpi_lock_hp_context();
+               notify = adev->hp ? adev->hp->notify : NULL;
+               acpi_unlock_hp_context();
+               /*
+                * There may be additional notify handlers for device objects
+                * without the .event() callback, so ignore them here.
+                */
+               if (notify)
+                       error = notify(adev, src);
+               else
+                       goto out;
+       }
+       if (!error)
+               ost_code = ACPI_OST_SC_SUCCESS;
 
  err_out:
-       acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+       acpi_evaluate_ost(adev->handle, src, ost_code, NULL);
+
+ out:
+       acpi_bus_put_acpi_device(adev);
+       mutex_unlock(&acpi_scan_lock);
+       unlock_device_hotplug();
 }
 
 static ssize_t real_power_state_show(struct device *dev,
@@ -570,17 +577,14 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
        if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
                return -ENODEV;
 
-       acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
-                                 ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
        get_device(&acpi_device->dev);
-       status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
-                                     ACPI_OST_EC_OSPM_EJECT);
+       status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
        if (ACPI_SUCCESS(status))
                return count;
 
        put_device(&acpi_device->dev);
-       acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
-                                 ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+       acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
+                         ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
        return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
 }
 
@@ -1114,14 +1118,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context)
        mutex_unlock(&acpi_device_del_lock);
 }
 
-int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
+                               void (*callback)(void *))
 {
        acpi_status status;
 
        if (!device)
                return -EINVAL;
 
-       status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
+       status = acpi_get_data_full(handle, acpi_scan_drop_device,
+                                   (void **)device, callback);
        if (ACPI_FAILURE(status) || !*device) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
                                  handle));
@@ -1129,8 +1135,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
        }
        return 0;
 }
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+       return acpi_get_device_data(handle, device, NULL);
+}
 EXPORT_SYMBOL(acpi_bus_get_device);
 
+static void get_acpi_device(void *dev)
+{
+       if (dev)
+               get_device(&((struct acpi_device *)dev)->dev);
+}
+
+struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
+{
+       struct acpi_device *adev = NULL;
+
+       acpi_get_device_data(handle, &adev, get_acpi_device);
+       return adev;
+}
+
+void acpi_bus_put_acpi_device(struct acpi_device *adev)
+{
+       put_device(&adev->dev);
+}
+
 int acpi_device_add(struct acpi_device *device,
                    void (*release)(struct device *))
 {
@@ -1641,6 +1671,27 @@ bool acpi_bay_match(acpi_handle handle)
        return acpi_ata_match(phandle);
 }
 
+bool acpi_device_is_battery(struct acpi_device *adev)
+{
+       struct acpi_hardware_id *hwid;
+
+       list_for_each_entry(hwid, &adev->pnp.ids, list)
+               if (!strcmp("PNP0C0A", hwid->id))
+                       return true;
+
+       return false;
+}
+
+static bool is_ejectable_bay(struct acpi_device *adev)
+{
+       acpi_handle handle = adev->handle;
+
+       if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev))
+               return true;
+
+       return acpi_bay_match(handle);
+}
+
 /*
  * acpi_dock_match - see if an acpi object has a _DCK method
  */
@@ -1706,6 +1757,20 @@ static bool acpi_ibm_smbus_match(acpi_handle handle)
        return false;
 }
 
+static bool acpi_object_is_system_bus(acpi_handle handle)
+{
+       acpi_handle tmp;
+
+       if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) &&
+           tmp == handle)
+               return true;
+       if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) &&
+           tmp == handle)
+               return true;
+
+       return false;
+}
+
 static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                                int device_type)
 {
@@ -1757,8 +1822,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                        acpi_add_id(pnp, ACPI_DOCK_HID);
                else if (acpi_ibm_smbus_match(handle))
                        acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
-               else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
-                       acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
+               else if (list_empty(&pnp->ids) &&
+                        acpi_object_is_system_bus(handle)) {
+                       /* \_SB, \_TZ, LNXSYBUS */
+                       acpi_add_id(pnp, ACPI_BUS_HID);
                        strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
                        strcpy(pnp->device_class, ACPI_BUS_CLASS);
                }
@@ -1941,33 +2008,23 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
        mutex_unlock(&acpi_scan_lock);
 }
 
-static void acpi_scan_init_hotplug(acpi_handle handle, int type)
+static void acpi_scan_init_hotplug(struct acpi_device *adev)
 {
-       struct acpi_device_pnp pnp = {};
        struct acpi_hardware_id *hwid;
-       struct acpi_scan_handler *handler;
 
-       INIT_LIST_HEAD(&pnp.ids);
-       acpi_set_pnp_ids(handle, &pnp, type);
-
-       if (!pnp.type.hardware_id)
-               goto out;
+       if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) {
+               acpi_dock_add(adev);
+               return;
+       }
+       list_for_each_entry(hwid, &adev->pnp.ids, list) {
+               struct acpi_scan_handler *handler;
 
-       /*
-        * This relies on the fact that acpi_install_notify_handler() will not
-        * install the same notify handler routine twice for the same handle.
-        */
-       list_for_each_entry(hwid, &pnp.ids, list) {
                handler = acpi_scan_match_handler(hwid->id, NULL);
                if (handler) {
-                       acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-                                       acpi_hotplug_notify_cb, handler);
+                       adev->flags.hotplug_notify = true;
                        break;
                }
        }
-
-out:
-       acpi_free_pnp_ids(&pnp);
 }
 
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
@@ -1991,12 +2048,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
                return AE_OK;
        }
 
-       acpi_scan_init_hotplug(handle, type);
-
        acpi_add_single_object(&device, handle, type, sta);
        if (!device)
                return AE_CTRL_DEPTH;
 
+       acpi_scan_init_hotplug(device);
+
  out:
        if (!*return_value)
                *return_value = device;
@@ -2015,13 +2072,14 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
 
                handler = acpi_scan_match_handler(hwid->id, &devid);
                if (handler) {
+                       device->handler = handler;
                        ret = handler->attach(device, devid);
-                       if (ret > 0) {
-                               device->handler = handler;
+                       if (ret > 0)
                                break;
-                       } else if (ret < 0) {
+
+                       device->handler = NULL;
+                       if (ret < 0)
                                break;
-                       }
                }
        }
        return ret;
@@ -2030,8 +2088,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
 static void acpi_bus_attach(struct acpi_device *device)
 {
        struct acpi_device *child;
+       acpi_handle ejd;
        int ret;
 
+       if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
+               register_dock_dependent_device(device, ejd);
+
        acpi_bus_get_status(device);
        /* Skip devices that are not present. */
        if (!acpi_device_is_present(device)) {
@@ -2184,7 +2246,6 @@ int __init acpi_scan_init(void)
        acpi_cmos_rtc_init();
        acpi_container_init();
        acpi_memory_hotplug_init();
-       acpi_dock_init();
 
        mutex_lock(&acpi_scan_lock);
        /*
index b718806657cdac29d9ccb3a1cad3fe6528865176..c40fb2e81bbc5d4ce9266174c0c2d7614755c644 100644 (file)
@@ -71,6 +71,17 @@ static int acpi_sleep_prepare(u32 acpi_state)
        return 0;
 }
 
+static bool acpi_sleep_state_supported(u8 sleep_state)
+{
+       acpi_status status;
+       u8 type_a, type_b;
+
+       status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
+       return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
+               || (acpi_gbl_FADT.sleep_control.address
+                       && acpi_gbl_FADT.sleep_status.address));
+}
+
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
 
@@ -604,15 +615,9 @@ static void acpi_sleep_suspend_setup(void)
 {
        int i;
 
-       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
-               acpi_status status;
-               u8 type_a, type_b;
-
-               status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-               if (ACPI_SUCCESS(status)) {
+       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
+               if (acpi_sleep_state_supported(i))
                        sleep_states[i] = 1;
-               }
-       }
 
        suspend_set_ops(old_suspend_ordering ?
                &acpi_suspend_ops_old : &acpi_suspend_ops);
@@ -740,11 +745,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
 
 static void acpi_sleep_hibernate_setup(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
-
-       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-       if (ACPI_FAILURE(status))
+       if (!acpi_sleep_state_supported(ACPI_STATE_S4))
                return;
 
        hibernation_set_ops(old_suspend_ordering ?
@@ -793,8 +794,6 @@ static void acpi_power_off(void)
 
 int __init acpi_sleep_init(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
        char supported[ACPI_S_STATE_COUNT * 3 + 1];
        char *pos = supported;
        int i;
@@ -806,8 +805,7 @@ int __init acpi_sleep_init(void)
        acpi_sleep_suspend_setup();
        acpi_sleep_hibernate_setup();
 
-       status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
                sleep_states[ACPI_STATE_S5] = 1;
                pm_power_off_prepare = acpi_power_off_prepare;
                pm_power_off = acpi_power_off;
index 91a32cefb11f6098fbea62d9744ed61ed864c4a9..38cb9782d4b871f54c646fc360f922bac03a68fd 100644 (file)
@@ -12,8 +12,6 @@
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("sysfs");
 
-#define PREFIX "ACPI: "
-
 #ifdef CONFIG_ACPI_DEBUG
 /*
  * ACPI debug sysfs I/F, including:
index 5837f857ac2e82aff69a5d9bf7e619ace323d946..21782290df41f3383140667edffbdddbb2ec1ae7 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#define pr_fmt(fmt) "ACPI: " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
@@ -33,8 +35,6 @@
 #include <linux/acpi.h>
 #include <linux/bootmem.h>
 
-#define PREFIX                 "ACPI: "
-
 #define ACPI_MAX_TABLES                128
 
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
@@ -55,10 +55,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_local_apic *p =
                            (struct acpi_madt_local_apic *)header;
-                       printk(KERN_INFO PREFIX
-                              "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
-                              p->processor_id, p->id,
-                              (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+                       pr_info("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
+                               p->processor_id, p->id,
+                               (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
                }
                break;
 
@@ -66,11 +65,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_local_x2apic *p =
                            (struct acpi_madt_local_x2apic *)header;
-                       printk(KERN_INFO PREFIX
-                              "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
-                              p->local_apic_id, p->uid,
-                              (p->lapic_flags & ACPI_MADT_ENABLED) ?
-                              "enabled" : "disabled");
+                       pr_info("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
+                               p->local_apic_id, p->uid,
+                               (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
                }
                break;
 
@@ -78,9 +75,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_io_apic *p =
                            (struct acpi_madt_io_apic *)header;
-                       printk(KERN_INFO PREFIX
-                              "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
-                              p->id, p->address, p->global_irq_base);
+                       pr_info("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
+                               p->id, p->address, p->global_irq_base);
                }
                break;
 
@@ -88,18 +84,15 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_interrupt_override *p =
                            (struct acpi_madt_interrupt_override *)header;
-                       printk(KERN_INFO PREFIX
-                              "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
-                              p->bus, p->source_irq, p->global_irq,
-                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
-                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+                       pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
+                               p->bus, p->source_irq, p->global_irq,
+                               mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+                               mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
                        if (p->inti_flags  &
                            ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
-                               printk(KERN_INFO PREFIX
-                                      "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
-                                      p->inti_flags  &
+                               pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n",
+                                       p->inti_flags  &
                                        ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
-
                }
                break;
 
@@ -107,11 +100,10 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_nmi_source *p =
                            (struct acpi_madt_nmi_source *)header;
-                       printk(KERN_INFO PREFIX
-                              "NMI_SRC (%s %s global_irq %d)\n",
-                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
-                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
-                              p->global_irq);
+                       pr_info("NMI_SRC (%s %s global_irq %d)\n",
+                               mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+                               mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+                               p->global_irq);
                }
                break;
 
@@ -119,12 +111,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_local_apic_nmi *p =
                            (struct acpi_madt_local_apic_nmi *)header;
-                       printk(KERN_INFO PREFIX
-                              "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
-                              p->processor_id,
-                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK  ],
-                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
-                              p->lint);
+                       pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
+                               p->processor_id,
+                               mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
+                               mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+                               p->lint);
                }
                break;
 
@@ -137,12 +128,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                        polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
                        trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
 
-                       printk(KERN_INFO PREFIX
-                              "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
-                              p->uid,
-                              mps_inti_flags_polarity[polarity],
-                              mps_inti_flags_trigger[trigger],
-                              p->lint);
+                       pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
+                               p->uid,
+                               mps_inti_flags_polarity[polarity],
+                               mps_inti_flags_trigger[trigger],
+                               p->lint);
                }
                break;
 
@@ -150,9 +140,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_local_apic_override *p =
                            (struct acpi_madt_local_apic_override *)header;
-                       printk(KERN_INFO PREFIX
-                              "LAPIC_ADDR_OVR (address[%p])\n",
-                              (void *)(unsigned long)p->address);
+                       pr_info("LAPIC_ADDR_OVR (address[%p])\n",
+                               (void *)(unsigned long)p->address);
                }
                break;
 
@@ -160,10 +149,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_io_sapic *p =
                            (struct acpi_madt_io_sapic *)header;
-                       printk(KERN_INFO PREFIX
-                              "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
-                              p->id, (void *)(unsigned long)p->address,
-                              p->global_irq_base);
+                       pr_info("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+                               p->id, (void *)(unsigned long)p->address,
+                               p->global_irq_base);
                }
                break;
 
@@ -171,10 +159,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_local_sapic *p =
                            (struct acpi_madt_local_sapic *)header;
-                       printk(KERN_INFO PREFIX
-                              "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
-                              p->processor_id, p->id, p->eid,
-                              (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+                       pr_info("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
+                               p->processor_id, p->id, p->eid,
+                               (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
                }
                break;
 
@@ -182,19 +169,17 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                {
                        struct acpi_madt_interrupt_source *p =
                            (struct acpi_madt_interrupt_source *)header;
-                       printk(KERN_INFO PREFIX
-                              "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
-                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
-                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
-                              p->type, p->id, p->eid, p->io_sapic_vector,
-                              p->global_irq);
+                       pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
+                               mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+                               mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+                               p->type, p->id, p->eid, p->io_sapic_vector,
+                               p->global_irq);
                }
                break;
 
        default:
-               printk(KERN_WARNING PREFIX
-                      "Found unsupported MADT entry (type = 0x%x)\n",
-                      header->type);
+               pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
+                       header->type);
                break;
        }
 }
@@ -225,7 +210,7 @@ acpi_table_parse_entries(char *id,
                acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
 
        if (!table_header) {
-               printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
+               pr_warn("%4.4s not present\n", id);
                return -ENODEV;
        }
 
@@ -248,7 +233,7 @@ acpi_table_parse_entries(char *id,
                 * infinite loop.
                 */
                if (entry->length == 0) {
-                       pr_err(PREFIX "[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
+                       pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
                        goto err;
                }
 
@@ -256,8 +241,8 @@ acpi_table_parse_entries(char *id,
                    ((unsigned long)entry + entry->length);
        }
        if (max_entries && count > max_entries) {
-               printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
-                      "%i found\n", id, entry_id, count - max_entries, count);
+               pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
+                       id, entry_id, count - max_entries, count);
        }
 
        early_acpi_os_unmap_memory((char *)table_header, tbl_size);
@@ -322,13 +307,11 @@ static void __init check_multiple_madt(void)
 
        acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size);
        if (table) {
-               printk(KERN_WARNING PREFIX
-                      "BIOS bug: multiple APIC/MADT found,"
-                      " using %d\n", acpi_apic_instance);
-               printk(KERN_WARNING PREFIX
-                      "If \"acpi_apic_instance=%d\" works better, "
-                      "notify linux-acpi@vger.kernel.org\n",
-                      acpi_apic_instance ? 0 : 2);
+               pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
+                       acpi_apic_instance);
+               pr_warn("If \"acpi_apic_instance=%d\" works better, "
+                       "notify linux-acpi@vger.kernel.org\n",
+                       acpi_apic_instance ? 0 : 2);
                early_acpi_os_unmap_memory(table, tbl_size);
 
        } else
@@ -365,8 +348,7 @@ static int __init acpi_parse_apic_instance(char *str)
 
        acpi_apic_instance = simple_strtoul(str, NULL, 0);
 
-       printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n",
-              acpi_apic_instance);
+       pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance);
 
        return 0;
 }
index 08626c851be7eef72c5a639522b708586736adc5..9640685533345340bbff00bc67abeecac4e9c7d1 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/device.h>
 #include <linux/thermal.h>
 #include <linux/acpi.h>
+#include <linux/workqueue.h>
 #include <asm/uaccess.h>
 
 #define PREFIX "ACPI: "
@@ -90,6 +91,8 @@ static int psv;
 module_param(psv, int, 0644);
 MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
 
+static struct workqueue_struct *acpi_thermal_pm_queue;
+
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device);
 static void acpi_thermal_notify(struct acpi_device *device, u32 event);
@@ -101,11 +104,13 @@ static const struct acpi_device_id  thermal_device_ids[] = {
 MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 
 #ifdef CONFIG_PM_SLEEP
+static int acpi_thermal_suspend(struct device *dev);
 static int acpi_thermal_resume(struct device *dev);
 #else
+#define acpi_thermal_suspend NULL
 #define acpi_thermal_resume NULL
 #endif
-static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
+static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
 
 static struct acpi_driver acpi_thermal_driver = {
        .name = "thermal",
@@ -186,6 +191,7 @@ struct acpi_thermal {
        struct thermal_zone_device *thermal_zone;
        int tz_enabled;
        int kelvin_offset;
+       struct work_struct thermal_check_work;
 };
 
 /* --------------------------------------------------------------------------
@@ -1064,6 +1070,13 @@ static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
                tz->kelvin_offset = 2732;
 }
 
+static void acpi_thermal_check_fn(struct work_struct *work)
+{
+       struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
+                                              thermal_check_work);
+       acpi_thermal_check(tz);
+}
+
 static int acpi_thermal_add(struct acpi_device *device)
 {
        int result = 0;
@@ -1093,6 +1106,8 @@ static int acpi_thermal_add(struct acpi_device *device)
        if (result)
                goto free_memory;
 
+       INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
+
        pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
                acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature));
        goto end;
@@ -1110,6 +1125,7 @@ static int acpi_thermal_remove(struct acpi_device *device)
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
 
+       flush_workqueue(acpi_thermal_pm_queue);
        tz = acpi_driver_data(device);
 
        acpi_thermal_unregister_thermal_zone(tz);
@@ -1118,6 +1134,13 @@ static int acpi_thermal_remove(struct acpi_device *device)
 }
 
 #ifdef CONFIG_PM_SLEEP
+static int acpi_thermal_suspend(struct device *dev)
+{
+       /* Make sure the previously queued thermal check work has been done */
+       flush_workqueue(acpi_thermal_pm_queue);
+       return 0;
+}
+
 static int acpi_thermal_resume(struct device *dev)
 {
        struct acpi_thermal *tz;
@@ -1148,7 +1171,7 @@ static int acpi_thermal_resume(struct device *dev)
                tz->state.active |= tz->trips.active[i].flags.enabled;
        }
 
-       acpi_thermal_check(tz);
+       queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
 
        return AE_OK;
 }
@@ -1240,16 +1263,22 @@ static int __init acpi_thermal_init(void)
                return -ENODEV;
        }
 
+       acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm");
+       if (!acpi_thermal_pm_queue)
+               return -ENODEV;
+
        result = acpi_bus_register_driver(&acpi_thermal_driver);
-       if (result < 0)
+       if (result < 0) {
+               destroy_workqueue(acpi_thermal_pm_queue);
                return -ENODEV;
+       }
 
        return 0;
 }
 
 static void __exit acpi_thermal_exit(void)
 {
-
+       destroy_workqueue(acpi_thermal_pm_queue);
        acpi_bus_unregister_driver(&acpi_thermal_driver);
 
        return;
index 85e3b612bdc0d49f7df07d056b0d9c14f8aca89e..0f5f78fa6545cf4d30da8f56b426033ac7f7132e 100644 (file)
@@ -422,7 +422,7 @@ out:
 EXPORT_SYMBOL(acpi_get_physical_device_location);
 
 /**
- * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations
+ * acpi_evaluate_ost: Evaluate _OST for hotplug operations
  * @handle: ACPI device handle
  * @source_event: source event code
  * @status_code: status code
@@ -433,17 +433,15 @@ EXPORT_SYMBOL(acpi_get_physical_device_location);
  * When the platform does not support _OST, this function has no effect.
  */
 acpi_status
-acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
-               u32 status_code, struct acpi_buffer *status_buf)
+acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
+                 struct acpi_buffer *status_buf)
 {
-#ifdef ACPI_HOTPLUG_OST
        union acpi_object params[3] = {
                {.type = ACPI_TYPE_INTEGER,},
                {.type = ACPI_TYPE_INTEGER,},
                {.type = ACPI_TYPE_BUFFER,}
        };
        struct acpi_object_list arg_list = {3, params};
-       acpi_status status;
 
        params[0].integer.value = source_event;
        params[1].integer.value = status_code;
@@ -455,13 +453,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
                params[2].buffer.length = 0;
        }
 
-       status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-       return status;
-#else
-       return AE_OK;
-#endif
+       return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
 }
-EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
+EXPORT_SYMBOL(acpi_evaluate_ost);
 
 /**
  * acpi_handle_printk: Print message with ACPI prefix and object path
index b6ba88ed31aeeb1854e48bb73b95fc59a4d58706..48c7e8af9c96cba545731cb0ab464cb4097dc44b 100644 (file)
@@ -45,8 +45,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 #define ACPI_VIDEO_BUS_NAME            "Video Bus"
 #define ACPI_VIDEO_DEVICE_NAME         "Video Device"
 #define ACPI_VIDEO_NOTIFY_SWITCH       0x80
index 19080c8e2f2a9c6d5df7f5475d581f5348ed9e8e..33e3db548a2918a6ee0fc71d7daf9c678c9a141f 100644 (file)
@@ -40,8 +40,6 @@
 
 #include "internal.h"
 
-#define PREFIX "ACPI: "
-
 ACPI_MODULE_NAME("video");
 #define _COMPONENT             ACPI_VIDEO_COMPONENT
 
index 868429a47be41a2c50ff146389df25dfcb8f5b30..20e03a7eb8b431f692e534f6a3d895a2c2cd9476 100644 (file)
@@ -11,13 +11,13 @@ config HAVE_PATA_PLATFORM
          to update the PATA_PLATFORM entry.
 
 menuconfig ATA
-       tristate "Serial ATA and Parallel ATA drivers"
+       tristate "Serial ATA and Parallel ATA drivers (libata)"
        depends on HAS_IOMEM
        depends on BLOCK
        depends on !(M32R || M68K || S390) || BROKEN
        select SCSI
        ---help---
-         If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+         If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or
          any other ATA device under Linux, say Y and make sure that you know
          the name of your ATA host adapter (the card inside your computer
          that "speaks" the ATA protocol, also called ATA controller),
@@ -60,7 +60,7 @@ config ATA_ACPI
 
 config SATA_ZPODD
        bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
-       depends on ATA_ACPI
+       depends on ATA_ACPI && PM_RUNTIME
        default n
        help
          This option adds support for SATA Zero Power Optical Disc
@@ -97,15 +97,48 @@ config SATA_AHCI_PLATFORM
 
          If unsure, say N.
 
+config AHCI_DA850
+       tristate "DaVinci DA850 AHCI SATA support"
+       depends on ARCH_DAVINCI_DA850
+       help
+         This option enables support for the DaVinci DA850 SoC's
+         onboard AHCI SATA.
+
+         If unsure, say N.
+
+config AHCI_ST
+       tristate "ST AHCI SATA support"
+       depends on ARCH_STI
+       help
+         This option enables support for ST AHCI SATA controller.
+
+         If unsure, say N.
+
 config AHCI_IMX
        tristate "Freescale i.MX AHCI SATA support"
-       depends on SATA_AHCI_PLATFORM && MFD_SYSCON
+       depends on MFD_SYSCON
        help
          This option enables support for the Freescale i.MX SoC's
          onboard AHCI SATA.
 
          If unsure, say N.
 
+config AHCI_SUNXI
+       tristate "Allwinner sunxi AHCI SATA support"
+       depends on ARCH_SUNXI
+       help
+         This option enables support for the Allwinner sunxi SoC's
+         onboard AHCI SATA.
+
+         If unsure, say N.
+
+config AHCI_XGENE
+       tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
+       depends on ARM64 || COMPILE_TEST
+       select PHY_XGENE
+       help
+        This option enables support for APM X-Gene SoC SATA host controller.
+
 config SATA_FSL
        tristate "Freescale 3.0Gbps SATA support"
        depends on FSL_SOC
@@ -239,6 +272,7 @@ config SATA_DWC_VDEBUG
 
 config SATA_HIGHBANK
        tristate "Calxeda Highbank SATA support"
+       depends on ARCH_HIGHBANK || COMPILE_TEST
        help
          This option enables support for the Calxeda Highbank SoC's
          onboard SATA.
@@ -247,6 +281,8 @@ config SATA_HIGHBANK
 
 config SATA_MV
        tristate "Marvell SATA support"
+       depends on PCI || ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
+                  ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
        select GENERIC_PHY
        help
          This option enables support for the Marvell Serial ATA family.
@@ -273,6 +309,7 @@ config SATA_PROMISE
 
 config SATA_RCAR
        tristate "Renesas R-Car SATA support"
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        help
          This option enables support for Renesas R-Car Serial ATA.
 
@@ -352,6 +389,7 @@ config PATA_AMD
 
 config PATA_ARASAN_CF
        tristate "ARASAN CompactFlash PATA Controller Support"
+       depends on ARCH_SPEAR13XX || COMPILE_TEST
        depends on DMADEVICES
        select DMA_ENGINE
        help
@@ -403,7 +441,7 @@ config PATA_CMD64X
 
 config PATA_CS5520
        tristate "CS5510/5520 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the Cyrix 5510/5520
          companion chip used with the MediaGX/Geode processor family.
@@ -412,7 +450,7 @@ config PATA_CS5520
 
 config PATA_CS5530
        tristate "CS5530 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the Cyrix/NatSemi/AMD CS5530
          companion chip used with the MediaGX/Geode processor family.
@@ -421,7 +459,7 @@ config PATA_CS5530
 
 config PATA_CS5535
        tristate "CS5535 PATA support (Experimental)"
-       depends on PCI && X86 && !X86_64
+       depends on PCI && X86_32
        help
          This option enables support for the NatSemi/AMD CS5535
          companion chip used with the Geode processor family.
@@ -430,7 +468,7 @@ config PATA_CS5535
 
 config PATA_CS5536
        tristate "CS5536 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
        help
          This option enables support for the AMD CS5536
          companion chip used with the Geode LX processor family.
@@ -666,7 +704,7 @@ config PATA_RDC
 
 config PATA_SC1200
        tristate "SC1200 PATA support"
-       depends on PCI
+       depends on PCI && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the NatSemi/AMD SC1200 SoC
          companion chip used with the Geode processor family.
index 46518c622460942cdf8e2971dd95f3b069961ada..44c8016e565c9b8771924fbc7f7b5a00d9c078c7 100644 (file)
@@ -4,13 +4,17 @@ obj-$(CONFIG_ATA)             += libata.o
 # non-SFF interface
 obj-$(CONFIG_SATA_AHCI)                += ahci.o libahci.o
 obj-$(CONFIG_SATA_ACARD_AHCI)  += acard-ahci.o libahci.o
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
 obj-$(CONFIG_SATA_FSL)         += sata_fsl.o
 obj-$(CONFIG_SATA_INIC162X)    += sata_inic162x.o
 obj-$(CONFIG_SATA_SIL24)       += sata_sil24.o
 obj-$(CONFIG_SATA_DWC)         += sata_dwc_460ex.o
 obj-$(CONFIG_SATA_HIGHBANK)    += sata_highbank.o libahci.o
-obj-$(CONFIG_AHCI_IMX)         += ahci_imx.o
+obj-$(CONFIG_AHCI_DA850)       += ahci_da850.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_IMX)         += ahci_imx.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_SUNXI)       += ahci_sunxi.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_ST)          += ahci_st.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_XGENE)       += ahci_xgene.o libahci.o libahci_platform.o
 
 # SFF w/ custom DMA
 obj-$(CONFIG_PDC_ADMA)         += pdc_adma.o
index fd665d919df2e59a4b44c334bd9c96d14fd946b5..b51605ac597418f7aa352789dc9aeeb1b8ca015b 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index c81d809c111b238e72f65d185add59f5bef4fade..5a0bf8ed649b8cf9266530ef309aec89a54f99ef 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -578,6 +577,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
                                 unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        bool online;
        int rc;
 
@@ -588,7 +588,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
                                 deadline, &online, NULL);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 
@@ -603,6 +603,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
 {
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
        bool online;
@@ -618,7 +619,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
                                 deadline, &online, NULL);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        /* The pseudo configuration device on SIMG4726 attached to
         * ASUS P5W-DH Deluxe doesn't send signature FIS after
@@ -1165,13 +1166,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
 static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
                         struct ahci_host_priv *hpriv)
 {
-       int rc, nvec;
+       int nvec;
 
        if (hpriv->flags & AHCI_HFLAG_NO_MSI)
                goto intx;
 
-       rc = pci_msi_vec_count(pdev);
-       if (rc < 0)
+       nvec = pci_msi_vec_count(pdev);
+       if (nvec < 0)
                goto intx;
 
        /*
@@ -1179,21 +1180,19 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
         * Message mode could be enforced. In this case assume that advantage
         * of multipe MSIs is negated and use single MSI mode instead.
         */
-       if (rc < n_ports)
+       if (nvec < n_ports)
                goto single_msi;
 
-       nvec = rc;
-       rc = pci_enable_msi_block(pdev, nvec);
-       if (rc < 0)
-               goto intx;
-       else if (rc > 0)
+       nvec = pci_enable_msi_range(pdev, nvec, nvec);
+       if (nvec == -ENOSPC)
                goto single_msi;
+       else if (nvec < 0)
+               goto intx;
 
        return nvec;
 
 single_msi:
-       rc = pci_enable_msi(pdev);
-       if (rc)
+       if (pci_enable_msi(pdev))
                goto intx;
        return 1;
 
index 2289efdf82030e388ce977957eeb5b26f26f19d2..51af275b3388541baad3f7bf021a098de9da9bf0 100644 (file)
@@ -37,6 +37,8 @@
 
 #include <linux/clk.h>
 #include <linux/libata.h>
+#include <linux/phy/phy.h>
+#include <linux/regulator/consumer.h>
 
 /* Enclosure Management Control */
 #define EM_CTRL_MSG_TYPE              0x000f0000
@@ -51,6 +53,7 @@
 
 enum {
        AHCI_MAX_PORTS          = 32,
+       AHCI_MAX_CLKS           = 3,
        AHCI_MAX_SG             = 168, /* hardware max is 64K */
        AHCI_DMA_BOUNDARY       = 0xffffffff,
        AHCI_MAX_CMDS           = 32,
@@ -321,8 +324,17 @@ struct ahci_host_priv {
        u32                     em_loc; /* enclosure management location */
        u32                     em_buf_sz;      /* EM buffer size in byte */
        u32                     em_msg_type;    /* EM message type */
-       struct clk              *clk;           /* Only for platforms supporting clk */
+       bool                    got_runtime_pm; /* Did we do pm_runtime_get? */
+       struct clk              *clks[AHCI_MAX_CLKS]; /* Optional */
+       struct regulator        *target_pwr;    /* Optional */
+       struct phy              *phy;           /* If platform uses phy */
        void                    *plat_data;     /* Other platform data */
+       /*
+        * Optional ahci_start_engine override, if not set this gets set to the
+        * default ahci_start_engine during ahci_save_initial_config, this can
+        * be overridden anytime before the host is activated.
+        */
+       void                    (*start_engine)(struct ata_port *ap);
 };
 
 extern int ahci_ignore_sss;
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
new file mode 100644 (file)
index 0000000..2c83613
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * DaVinci DA850 AHCI SATA platform driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/* SATA PHY Control Register offset from AHCI base */
+#define SATA_P0PHYCR_REG       0x178
+
+#define SATA_PHY_MPY(x)                ((x) << 0)
+#define SATA_PHY_LOS(x)                ((x) << 6)
+#define SATA_PHY_RXCDR(x)      ((x) << 10)
+#define SATA_PHY_RXEQ(x)       ((x) << 13)
+#define SATA_PHY_TXSWING(x)    ((x) << 19)
+#define SATA_PHY_ENPLL(x)      ((x) << 31)
+
+/*
+ * The multiplier needed for 1.5GHz PLL output.
+ *
+ * NOTE: This is currently hardcoded to be suitable for 100MHz crystal
+ * frequency (which is used by DA850 EVM board) and may need to be changed
+ * if you would like to use this driver on some other board.
+ */
+#define DA850_SATA_CLK_MULTIPLIER      7
+
+static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
+                           void __iomem *ahci_base)
+{
+       unsigned int val;
+
+       /* Enable SATA clock receiver */
+       val = readl(pwrdn_reg);
+       val &= ~BIT(0);
+       writel(val, pwrdn_reg);
+
+       val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
+             SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
+             SATA_PHY_ENPLL(1);
+
+       writel(val, ahci_base + SATA_P0PHYCR_REG);
+}
+
+static const struct ata_port_info ahci_da850_port_info = {
+       .flags          = AHCI_FLAG_COMMON,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &ahci_platform_ops,
+};
+
+static int ahci_da850_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct resource *res;
+       void __iomem *pwrdn_reg;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res)
+               goto disable_resources;
+
+       pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
+       if (!pwrdn_reg)
+               goto disable_resources;
+
+       da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
+
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
+                        ahci_platform_resume);
+
+static struct platform_driver ahci_da850_driver = {
+       .probe = ahci_da850_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "ahci_da850",
+               .owner = THIS_MODULE,
+               .pm = &ahci_da850_pm_ops,
+       },
+};
+module_platform_driver(ahci_da850_driver);
+
+MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
+MODULE_LICENSE("GPL");
index dd4d6f74d7bd5067a62840019a53c016b74efd6e..497c7abe1c7df5ef79ccd246828b68a1251c5201 100644 (file)
@@ -42,13 +42,7 @@ enum ahci_imx_type {
 struct imx_ahci_priv {
        struct platform_device *ahci_pdev;
        enum ahci_imx_type type;
-
-       /* i.MX53 clock */
-       struct clk *sata_gate_clk;
-       /* Common clock */
-       struct clk *sata_ref_clk;
        struct clk *ahb_clk;
-
        struct regmap *gpr;
        bool no_device;
        bool first_time;
@@ -58,28 +52,52 @@ static int ahci_imx_hotplug;
 module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
 MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
 
-static int imx_sata_clock_enable(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
 {
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
        int ret;
 
-       if (imxpriv->type == AHCI_IMX53) {
-               ret = clk_prepare_enable(imxpriv->sata_gate_clk);
-               if (ret < 0) {
-                       dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
-                               ret);
+       if (imxpriv->no_device)
+               return 0;
+
+       if (hpriv->target_pwr) {
+               ret = regulator_enable(hpriv->target_pwr);
+               if (ret)
                        return ret;
-               }
        }
 
-       ret = clk_prepare_enable(imxpriv->sata_ref_clk);
-       if (ret < 0) {
-               dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
-                       ret);
-               goto clk_err;
-       }
+       ret = ahci_platform_enable_clks(hpriv);
+       if (ret < 0)
+               goto disable_regulator;
 
        if (imxpriv->type == AHCI_IMX6Q) {
+               /*
+                * set PHY Paremeters, two steps to configure the GPR13,
+                * one write for rest of parameters, mask of first write
+                * is 0x07ffffff, and the other one write for setting
+                * the mpll_clk_en.
+                */
+               regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+                                  IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
+                                  IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+                                  IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+                                  IMX6Q_GPR13_SATA_TX_LVL_MASK |
+                                  IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+                                  IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+                                  IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
+                                  IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+                                  IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+                                  IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN,
                                   IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev)
 
        return 0;
 
-clk_err:
-       if (imxpriv->type == AHCI_IMX53)
-               clk_disable_unprepare(imxpriv->sata_gate_clk);
+disable_regulator:
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+
        return ret;
 }
 
-static void imx_sata_clock_disable(struct device *dev)
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
 {
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+       if (imxpriv->no_device)
+               return;
 
        if (imxpriv->type == AHCI_IMX6Q) {
                regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
@@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev)
                                   !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
        }
 
-       clk_disable_unprepare(imxpriv->sata_ref_clk);
+       ahci_platform_disable_clks(hpriv);
 
-       if (imxpriv->type == AHCI_IMX53)
-               clk_disable_unprepare(imxpriv->sata_gate_clk);
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
 }
 
 static void ahci_imx_error_handler(struct ata_port *ap)
@@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
        struct ata_host *host = dev_get_drvdata(ap->dev);
        struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = hpriv->mmio;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
 
        ahci_error_handler(ap);
 
@@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
         */
        reg_val = readl(mmio + PORT_PHY_CTL);
        writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
-       imx_sata_clock_disable(ap->dev);
+       imx_sata_disable(hpriv);
        imxpriv->no_device = true;
 }
 
@@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
                       unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+       struct ata_host *host = dev_get_drvdata(ap->dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct imx_ahci_priv *imxpriv = hpriv->plat_data;
        int ret = -EIO;
 
        if (imxpriv->type == AHCI_IMX53)
@@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
 }
 
 static struct ata_port_operations ahci_imx_ops = {
-       .inherits       = &ahci_platform_ops,
+       .inherits       = &ahci_ops,
+       .host_stop      = ahci_imx_host_stop,
        .error_handler  = ahci_imx_error_handler,
        .softreset      = ahci_imx_softreset,
 };
@@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = {
        .port_ops       = &ahci_imx_ops,
 };
 
-static int imx_sata_init(struct device *dev, void __iomem *mmio)
-{
-       int ret = 0;
-       unsigned int reg_val;
-       struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
-       ret = imx_sata_clock_enable(dev);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
-        * and IP vendor specific register HOST_TIMER1MS.
-        * Configure CAP_SSS (support stagered spin up).
-        * Implement the port0.
-        * Get the ahb clock rate, and configure the TIMER1MS register.
-        */
-       reg_val = readl(mmio + HOST_CAP);
-       if (!(reg_val & HOST_CAP_SSS)) {
-               reg_val |= HOST_CAP_SSS;
-               writel(reg_val, mmio + HOST_CAP);
-       }
-       reg_val = readl(mmio + HOST_PORTS_IMPL);
-       if (!(reg_val & 0x1)) {
-               reg_val |= 0x1;
-               writel(reg_val, mmio + HOST_PORTS_IMPL);
-       }
-
-       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
-       writel(reg_val, mmio + HOST_TIMER1MS);
-
-       return 0;
-}
-
-static void imx_sata_exit(struct device *dev)
-{
-       imx_sata_clock_disable(dev);
-}
-
-static int imx_ahci_suspend(struct device *dev)
-{
-       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
-
-       /*
-        * If no_device is set, The CLKs had been gated off in the
-        * initialization so don't do it again here.
-        */
-       if (!imxpriv->no_device)
-               imx_sata_clock_disable(dev);
-
-       return 0;
-}
-
-static int imx_ahci_resume(struct device *dev)
-{
-       struct imx_ahci_priv *imxpriv =  dev_get_drvdata(dev->parent);
-       int ret = 0;
-
-       if (!imxpriv->no_device)
-               ret = imx_sata_clock_enable(dev);
-
-       return ret;
-}
-
-static struct ahci_platform_data imx_sata_pdata = {
-       .init           = imx_sata_init,
-       .exit           = imx_sata_exit,
-       .ata_port_info  = &ahci_imx_port_info,
-       .suspend        = imx_ahci_suspend,
-       .resume         = imx_ahci_resume,
-
-};
-
 static const struct of_device_id imx_ahci_of_match[] = {
        { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
        { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
@@ -251,151 +203,124 @@ MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
 static int imx_ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct resource *mem, *irq, res[2];
        const struct of_device_id *of_id;
-       enum ahci_imx_type type;
-       const struct ahci_platform_data *pdata = NULL;
+       struct ahci_host_priv *hpriv;
        struct imx_ahci_priv *imxpriv;
-       struct device *ahci_dev;
-       struct platform_device *ahci_pdev;
+       unsigned int reg_val;
        int ret;
 
        of_id = of_match_device(imx_ahci_of_match, dev);
        if (!of_id)
                return -EINVAL;
 
-       type = (enum ahci_imx_type)of_id->data;
-       pdata = &imx_sata_pdata;
-
        imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
-       if (!imxpriv) {
-               dev_err(dev, "can't alloc ahci_host_priv\n");
+       if (!imxpriv)
                return -ENOMEM;
-       }
-
-       ahci_pdev = platform_device_alloc("ahci", -1);
-       if (!ahci_pdev)
-               return -ENODEV;
-
-       ahci_dev = &ahci_pdev->dev;
-       ahci_dev->parent = dev;
 
        imxpriv->no_device = false;
        imxpriv->first_time = true;
-       imxpriv->type = type;
-
+       imxpriv->type = (enum ahci_imx_type)of_id->data;
        imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
        if (IS_ERR(imxpriv->ahb_clk)) {
                dev_err(dev, "can't get ahb clock.\n");
-               ret = PTR_ERR(imxpriv->ahb_clk);
-               goto err_out;
+               return PTR_ERR(imxpriv->ahb_clk);
        }
 
-       if (type == AHCI_IMX53) {
-               imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
-               if (IS_ERR(imxpriv->sata_gate_clk)) {
-                       dev_err(dev, "can't get sata_gate clock.\n");
-                       ret = PTR_ERR(imxpriv->sata_gate_clk);
-                       goto err_out;
+       if (imxpriv->type == AHCI_IMX6Q) {
+               imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+                                                       "fsl,imx6q-iomuxc-gpr");
+               if (IS_ERR(imxpriv->gpr)) {
+                       dev_err(dev,
+                               "failed to find fsl,imx6q-iomux-gpr regmap\n");
+                       return PTR_ERR(imxpriv->gpr);
                }
        }
 
-       imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
-       if (IS_ERR(imxpriv->sata_ref_clk)) {
-               dev_err(dev, "can't get sata_ref clock.\n");
-               ret = PTR_ERR(imxpriv->sata_ref_clk);
-               goto err_out;
-       }
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       hpriv->plat_data = imxpriv;
 
-       imxpriv->ahci_pdev = ahci_pdev;
-       platform_set_drvdata(pdev, imxpriv);
+       ret = imx_sata_enable(hpriv);
+       if (ret)
+               return ret;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!mem || !irq) {
-               dev_err(dev, "no mmio/irq resource\n");
-               ret = -ENOMEM;
-               goto err_out;
+       /*
+        * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+        * and IP vendor specific register HOST_TIMER1MS.
+        * Configure CAP_SSS (support stagered spin up).
+        * Implement the port0.
+        * Get the ahb clock rate, and configure the TIMER1MS register.
+        */
+       reg_val = readl(hpriv->mmio + HOST_CAP);
+       if (!(reg_val & HOST_CAP_SSS)) {
+               reg_val |= HOST_CAP_SSS;
+               writel(reg_val, hpriv->mmio + HOST_CAP);
+       }
+       reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+       if (!(reg_val & 0x1)) {
+               reg_val |= 0x1;
+               writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
        }
 
-       res[0] = *mem;
-       res[1] = *irq;
+       reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+       writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
 
-       ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
-       ahci_dev->of_node = dev->of_node;
+       ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+       if (ret)
+               imx_sata_disable(hpriv);
 
-       if (type == AHCI_IMX6Q) {
-               imxpriv->gpr = syscon_regmap_lookup_by_compatible(
-                                                       "fsl,imx6q-iomuxc-gpr");
-               if (IS_ERR(imxpriv->gpr)) {
-                       dev_err(dev,
-                               "failed to find fsl,imx6q-iomux-gpr regmap\n");
-                       ret = PTR_ERR(imxpriv->gpr);
-                       goto err_out;
-               }
+       return ret;
+}
 
-               /*
-                * Set PHY Paremeters, two steps to configure the GPR13,
-                * one write for rest of parameters, mask of first write
-                * is 0x07fffffe, and the other one write for setting
-                * the mpll_clk_en happens in imx_sata_clock_enable().
-                */
-               regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
-                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
-                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
-                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
-                                  IMX6Q_GPR13_SATA_SPD_MODE_MASK |
-                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
-                                  IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
-                                  IMX6Q_GPR13_SATA_TX_BOOST_MASK |
-                                  IMX6Q_GPR13_SATA_TX_LVL_MASK |
-                                  IMX6Q_GPR13_SATA_MPLL_CLK_EN |
-                                  IMX6Q_GPR13_SATA_TX_EDGE_RATE,
-                                  IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
-                                  IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
-                                  IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
-                                  IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
-                                  IMX6Q_GPR13_SATA_MPLL_SS_EN |
-                                  IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
-                                  IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
-                                  IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
-       }
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
 
-       ret = platform_device_add_resources(ahci_pdev, res, 2);
-       if (ret)
-               goto err_out;
+       imx_sata_disable(hpriv);
+}
 
-       ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
-       if (ret)
-               goto err_out;
+#ifdef CONFIG_PM_SLEEP
+static int imx_ahci_suspend(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int ret;
 
-       ret = platform_device_add(ahci_pdev);
-       if (ret) {
-err_out:
-               platform_device_put(ahci_pdev);
+       ret = ahci_platform_suspend_host(dev);
+       if (ret)
                return ret;
-       }
+
+       imx_sata_disable(hpriv);
 
        return 0;
 }
 
-static int imx_ahci_remove(struct platform_device *pdev)
+static int imx_ahci_resume(struct device *dev)
 {
-       struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
-       struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int ret;
 
-       platform_device_unregister(ahci_pdev);
-       return 0;
+       ret = imx_sata_enable(hpriv);
+       if (ret)
+               return ret;
+
+       return ahci_platform_resume_host(dev);
 }
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
 
 static struct platform_driver imx_ahci_driver = {
        .probe = imx_ahci_probe,
-       .remove = imx_ahci_remove,
+       .remove = ata_platform_remove_one,
        .driver = {
                .name = "ahci-imx",
                .owner = THIS_MODULE,
                .of_match_table = imx_ahci_of_match,
+               .pm = &ahci_imx_pm_ops,
        },
 };
 module_platform_driver(imx_ahci_driver);
index 4b231baceb0995557c2cae40e501f6d3449dc365..ef67e79944f9962e3e32382dd43794404d866b01 100644 (file)
  * any later version.
  */
 
-#include <linux/clk.h>
 #include <linux/kernel.h>
-#include <linux/gfp.h>
 #include <linux/module.h>
 #include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/libata.h>
 #include <linux/ahci_platform.h>
 #include "ahci.h"
 
-static void ahci_host_stop(struct ata_host *host);
-
-enum ahci_type {
-       AHCI,           /* standard platform ahci */
-       IMX53_AHCI,     /* ahci on i.mx53 */
-       STRICT_AHCI,    /* delayed DMA engine start */
-};
-
-static struct platform_device_id ahci_devtype[] = {
-       {
-               .name = "ahci",
-               .driver_data = AHCI,
-       }, {
-               .name = "imx53-ahci",
-               .driver_data = IMX53_AHCI,
-       }, {
-               .name = "strict-ahci",
-               .driver_data = STRICT_AHCI,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(platform, ahci_devtype);
-
-struct ata_port_operations ahci_platform_ops = {
-       .inherits       = &ahci_ops,
-       .host_stop      = ahci_host_stop,
-};
-EXPORT_SYMBOL_GPL(ahci_platform_ops);
-
-static struct ata_port_operations ahci_platform_retry_srst_ops = {
-       .inherits       = &ahci_pmp_retry_srst_ops,
-       .host_stop      = ahci_host_stop,
-};
-
-static const struct ata_port_info ahci_port_info[] = {
-       /* by features */
-       [AHCI] = {
-               .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = ATA_PIO4,
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_platform_ops,
-       },
-       [IMX53_AHCI] = {
-               .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = ATA_PIO4,
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_platform_retry_srst_ops,
-       },
-       [STRICT_AHCI] = {
-               AHCI_HFLAGS     (AHCI_HFLAG_DELAY_ENGINE),
-               .flags          = AHCI_FLAG_COMMON,
-               .pio_mask       = ATA_PIO4,
-               .udma_mask      = ATA_UDMA6,
-               .port_ops       = &ahci_platform_ops,
-       },
-};
-
-static struct scsi_host_template ahci_platform_sht = {
-       AHCI_SHT("ahci_platform"),
+static const struct ata_port_info ahci_port_info = {
+       .flags          = AHCI_FLAG_COMMON,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &ahci_platform_ops,
 };
 
 static int ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       const struct platform_device_id *id = platform_get_device_id(pdev);
-       struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
-       const struct ata_port_info *ppi[] = { &pi, NULL };
        struct ahci_host_priv *hpriv;
-       struct ata_host *host;
-       struct resource *mem;
-       int irq;
-       int n_ports;
-       int i;
        int rc;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(dev, "no mmio space\n");
-               return -EINVAL;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(dev, "no irq\n");
-               return -EINVAL;
-       }
-
-       if (pdata && pdata->ata_port_info)
-               pi = *pdata->ata_port_info;
-
-       hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-       if (!hpriv) {
-               dev_err(dev, "can't alloc ahci_host_priv\n");
-               return -ENOMEM;
-       }
-
-       hpriv->flags |= (unsigned long)pi.private_data;
-
-       hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
-       if (!hpriv->mmio) {
-               dev_err(dev, "can't map %pR\n", mem);
-               return -ENOMEM;
-       }
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
 
-       hpriv->clk = clk_get(dev, NULL);
-       if (IS_ERR(hpriv->clk)) {
-               dev_err(dev, "can't get clock\n");
-       } else {
-               rc = clk_prepare_enable(hpriv->clk);
-               if (rc) {
-                       dev_err(dev, "clock prepare enable failed");
-                       goto free_clk;
-               }
-       }
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
 
        /*
         * Some platforms might need to prepare for mmio region access,
@@ -151,69 +52,10 @@ static int ahci_probe(struct platform_device *pdev)
        if (pdata && pdata->init) {
                rc = pdata->init(dev, hpriv->mmio);
                if (rc)
-                       goto disable_unprepare_clk;
-       }
-
-       ahci_save_initial_config(dev, hpriv,
-               pdata ? pdata->force_port_map : 0,
-               pdata ? pdata->mask_port_map  : 0);
-
-       /* prepare host */
-       if (hpriv->cap & HOST_CAP_NCQ)
-               pi.flags |= ATA_FLAG_NCQ;
-
-       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
-        * both CAP.NP and port_map.
-        */
-       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
-       host = ata_host_alloc_pinfo(dev, ppi, n_ports);
-       if (!host) {
-               rc = -ENOMEM;
-               goto pdata_exit;
-       }
-
-       host->private_data = hpriv;
-
-       if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
-               host->flags |= ATA_HOST_PARALLEL_SCAN;
-       else
-               dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
-
-       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];
-
-               ata_port_desc(ap, "mmio %pR", mem);
-               ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
-               /* set enclosure management message type */
-               if (ap->flags & ATA_FLAG_EM)
-                       ap->em_message_type = hpriv->em_msg_type;
-
-               /* disabled/not-implemented port */
-               if (!(hpriv->port_map & (1 << i)))
-                       ap->ops = &ata_dummy_port_ops;
+                       goto disable_resources;
        }
 
-       rc = ahci_reset_controller(host);
-       if (rc)
-               goto pdata_exit;
-
-       ahci_init_controller(host);
-       ahci_print_info(host, "platform");
-
-       rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
-                              &ahci_platform_sht);
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, 0, 0);
        if (rc)
                goto pdata_exit;
 
@@ -221,115 +63,19 @@ static int ahci_probe(struct platform_device *pdev)
 pdata_exit:
        if (pdata && pdata->exit)
                pdata->exit(dev);
-disable_unprepare_clk:
-       if (!IS_ERR(hpriv->clk))
-               clk_disable_unprepare(hpriv->clk);
-free_clk:
-       if (!IS_ERR(hpriv->clk))
-               clk_put(hpriv->clk);
-       return rc;
-}
-
-static void ahci_host_stop(struct ata_host *host)
-{
-       struct device *dev = host->dev;
-       struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-
-       if (pdata && pdata->exit)
-               pdata->exit(dev);
-
-       if (!IS_ERR(hpriv->clk)) {
-               clk_disable_unprepare(hpriv->clk);
-               clk_put(hpriv->clk);
-       }
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_suspend(struct device *dev)
-{
-       struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       struct ata_host *host = dev_get_drvdata(dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-       void __iomem *mmio = hpriv->mmio;
-       u32 ctl;
-       int rc;
-
-       if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
-               dev_err(dev, "firmware update required for suspend/resume\n");
-               return -EIO;
-       }
-
-       /*
-        * AHCI spec rev1.1 section 8.3.3:
-        * Software must disable interrupts prior to requesting a
-        * transition of the HBA to D3 state.
-        */
-       ctl = readl(mmio + HOST_CTL);
-       ctl &= ~HOST_IRQ_EN;
-       writel(ctl, mmio + HOST_CTL);
-       readl(mmio + HOST_CTL); /* flush */
-
-       rc = ata_host_suspend(host, PMSG_SUSPEND);
-       if (rc)
-               return rc;
-
-       if (pdata && pdata->suspend)
-               return pdata->suspend(dev);
-
-       if (!IS_ERR(hpriv->clk))
-               clk_disable_unprepare(hpriv->clk);
-
-       return 0;
-}
-
-static int ahci_resume(struct device *dev)
-{
-       struct ahci_platform_data *pdata = dev_get_platdata(dev);
-       struct ata_host *host = dev_get_drvdata(dev);
-       struct ahci_host_priv *hpriv = host->private_data;
-       int rc;
-
-       if (!IS_ERR(hpriv->clk)) {
-               rc = clk_prepare_enable(hpriv->clk);
-               if (rc) {
-                       dev_err(dev, "clock prepare enable failed");
-                       return rc;
-               }
-       }
-
-       if (pdata && pdata->resume) {
-               rc = pdata->resume(dev);
-               if (rc)
-                       goto disable_unprepare_clk;
-       }
-
-       if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
-               rc = ahci_reset_controller(host);
-               if (rc)
-                       goto disable_unprepare_clk;
-
-               ahci_init_controller(host);
-       }
-
-       ata_host_resume(host);
-
-       return 0;
-
-disable_unprepare_clk:
-       if (!IS_ERR(hpriv->clk))
-               clk_disable_unprepare(hpriv->clk);
-
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
        return rc;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
+                        ahci_platform_resume);
 
 static const struct of_device_id ahci_of_match[] = {
        { .compatible = "snps,spear-ahci", },
        { .compatible = "snps,exynos5440-ahci", },
        { .compatible = "ibm,476gtr-ahci", },
+       { .compatible = "snps,dwc-ahci", },
        {},
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
@@ -343,7 +89,6 @@ static struct platform_driver ahci_driver = {
                .of_match_table = ahci_of_match,
                .pm = &ahci_pm_ops,
        },
-       .id_table       = ahci_devtype,
 };
 module_platform_driver(ahci_driver);
 
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
new file mode 100644 (file)
index 0000000..6332222
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited
+ *
+ * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
+ *         Alexandre Torgue <alexandre.torgue@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/export.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/ahci_platform.h>
+#include <linux/libata.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include "ahci.h"
+
+#define ST_AHCI_OOBR                   0xbc
+#define ST_AHCI_OOBR_WE                        BIT(31)
+#define ST_AHCI_OOBR_CWMIN_SHIFT       24
+#define ST_AHCI_OOBR_CWMAX_SHIFT       16
+#define ST_AHCI_OOBR_CIMIN_SHIFT       8
+#define ST_AHCI_OOBR_CIMAX_SHIFT       0
+
+struct st_ahci_drv_data {
+       struct platform_device *ahci;
+       struct reset_control *pwr;
+       struct reset_control *sw_rst;
+       struct reset_control *pwr_rst;
+       struct ahci_host_priv *hpriv;
+};
+
+static void st_ahci_configure_oob(void __iomem *mmio)
+{
+       unsigned long old_val, new_val;
+
+       new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
+                 (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
+                 (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
+                 (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
+
+       old_val = readl(mmio + ST_AHCI_OOBR);
+       writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+       writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+       writel(new_val, mmio + ST_AHCI_OOBR);
+}
+
+static int st_ahci_deassert_resets(struct device *dev)
+{
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       int err;
+
+       if (drv_data->pwr) {
+               err = reset_control_deassert(drv_data->pwr);
+               if (err) {
+                       dev_err(dev, "unable to bring out of pwrdwn\n");
+                       return err;
+               }
+       }
+
+       st_ahci_configure_oob(drv_data->hpriv->mmio);
+
+       if (drv_data->sw_rst) {
+               err = reset_control_deassert(drv_data->sw_rst);
+               if (err) {
+                       dev_err(dev, "unable to bring out of sw-rst\n");
+                       return err;
+               }
+       }
+
+       if (drv_data->pwr_rst) {
+               err = reset_control_deassert(drv_data->pwr_rst);
+               if (err) {
+                       dev_err(dev, "unable to bring out of pwr-rst\n");
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static void st_ahci_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
+       struct device *dev = host->dev;
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       int err;
+
+       if (drv_data->pwr) {
+               err = reset_control_assert(drv_data->pwr);
+               if (err)
+                       dev_err(dev, "unable to pwrdwn\n");
+       }
+
+       ahci_platform_disable_resources(hpriv);
+}
+
+static int st_ahci_probe_resets(struct platform_device *pdev)
+{
+       struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+
+       drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+       if (IS_ERR(drv_data->pwr)) {
+               dev_info(&pdev->dev, "power reset control not defined\n");
+               drv_data->pwr = NULL;
+       }
+
+       drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+       if (IS_ERR(drv_data->sw_rst)) {
+               dev_info(&pdev->dev, "soft reset control not defined\n");
+               drv_data->sw_rst = NULL;
+       }
+
+       drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+       if (IS_ERR(drv_data->pwr_rst)) {
+               dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+               drv_data->pwr_rst = NULL;
+       }
+
+       return st_ahci_deassert_resets(&pdev->dev);
+}
+
+static struct ata_port_operations st_ahci_port_ops = {
+       .inherits       = &ahci_platform_ops,
+       .host_stop      = st_ahci_host_stop,
+};
+
+static const struct ata_port_info st_ahci_port_info = {
+       .flags          = AHCI_FLAG_COMMON,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &st_ahci_port_ops,
+};
+
+static int st_ahci_probe(struct platform_device *pdev)
+{
+       struct st_ahci_drv_data *drv_data;
+       struct ahci_host_priv *hpriv;
+       int err;
+
+       drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, drv_data);
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       drv_data->hpriv = hpriv;
+
+       err = st_ahci_probe_resets(pdev);
+       if (err)
+               return err;
+
+       err = ahci_platform_enable_resources(hpriv);
+       if (err)
+               return err;
+
+       err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0);
+       if (err) {
+               ahci_platform_disable_resources(hpriv);
+               return err;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int st_ahci_suspend(struct device *dev)
+{
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = drv_data->hpriv;
+       int err;
+
+       err = ahci_platform_suspend_host(dev);
+       if (err)
+               return err;
+
+       if (drv_data->pwr) {
+               err = reset_control_assert(drv_data->pwr);
+               if (err) {
+                       dev_err(dev, "unable to pwrdwn");
+                       return err;
+               }
+       }
+
+       ahci_platform_disable_resources(hpriv);
+
+       return 0;
+}
+
+static int st_ahci_resume(struct device *dev)
+{
+       struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = drv_data->hpriv;
+       int err;
+
+       err = ahci_platform_enable_resources(hpriv);
+       if (err)
+               return err;
+
+       err = st_ahci_deassert_resets(dev);
+       if (err) {
+               ahci_platform_disable_resources(hpriv);
+               return err;
+       }
+
+       return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
+
+static struct of_device_id st_ahci_match[] = {
+       { .compatible = "st,ahci", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, st_ahci_match);
+
+static struct platform_driver st_ahci_driver = {
+       .driver = {
+               .name = "st_ahci",
+               .owner = THIS_MODULE,
+               .pm = &st_ahci_pm_ops,
+               .of_match_table = of_match_ptr(st_ahci_match),
+       },
+       .probe = st_ahci_probe,
+       .remove = ata_platform_remove_one,
+};
+module_platform_driver(st_ahci_driver);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
+MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644 (file)
index 0000000..42d3f64
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
+ * Daniel Wang <danielwang@allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "ahci.h"
+
+#define AHCI_BISTAFR   0x00a0
+#define AHCI_BISTCR    0x00a4
+#define AHCI_BISTFCTR  0x00a8
+#define AHCI_BISTSR    0x00ac
+#define AHCI_BISTDECR  0x00b0
+#define AHCI_DIAGNR0   0x00b4
+#define AHCI_DIAGNR1   0x00b8
+#define AHCI_OOBR      0x00bc
+#define AHCI_PHYCS0R   0x00c0
+#define AHCI_PHYCS1R   0x00c4
+#define AHCI_PHYCS2R   0x00c8
+#define AHCI_TIMER1MS  0x00e0
+#define AHCI_GPARAM1R  0x00e8
+#define AHCI_GPARAM2R  0x00ec
+#define AHCI_PPARAMR   0x00f0
+#define AHCI_TESTR     0x00f4
+#define AHCI_VERSIONR  0x00f8
+#define AHCI_IDR       0x00fc
+#define AHCI_RWCR      0x00fc
+#define AHCI_P0DMACR   0x0170
+#define AHCI_P0PHYCR   0x0178
+#define AHCI_P0PHYSR   0x017c
+
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
+{
+       u32 reg_val;
+
+       reg_val = readl(reg);
+       reg_val &= ~(clr_val);
+       writel(reg_val, reg);
+}
+
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
+{
+       u32 reg_val;
+
+       reg_val = readl(reg);
+       reg_val |= set_val;
+       writel(reg_val, reg);
+}
+
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
+{
+       u32 reg_val;
+
+       reg_val = readl(reg);
+       reg_val &= ~(clr_val);
+       reg_val |= set_val;
+       writel(reg_val, reg);
+}
+
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
+{
+       return (readl(reg) >> shift) & mask;
+}
+
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+{
+       u32 reg_val;
+       int timeout;
+
+       /* This magic is from the original code */
+       writel(0, reg_base + AHCI_RWCR);
+       msleep(5);
+
+       sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+                        (0x7 << 24),
+                        (0x5 << 24) | BIT(23) | BIT(18));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
+                        (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+                        (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+       sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
+       sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+                        (0x7 << 20), (0x3 << 20));
+       sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+                        (0x1f << 5), (0x19 << 5));
+       msleep(5);
+
+       sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+       timeout = 250; /* Power up takes aprox 50 us */
+       do {
+               reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
+               if (reg_val == 0x02)
+                       break;
+
+               if (--timeout == 0) {
+                       dev_err(dev, "PHY power up failed.\n");
+                       return -EIO;
+               }
+               udelay(1);
+       } while (1);
+
+       sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+       timeout = 100; /* Calibration takes aprox 10 us */
+       do {
+               reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
+               if (reg_val == 0x00)
+                       break;
+
+               if (--timeout == 0) {
+                       dev_err(dev, "PHY calibration failed.\n");
+                       return -EIO;
+               }
+               udelay(1);
+       } while (1);
+
+       msleep(15);
+
+       writel(0x7, reg_base + AHCI_RWCR);
+
+       return 0;
+}
+
+static void ahci_sunxi_start_engine(struct ata_port *ap)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+
+       /* Setup DMA before DMA start */
+       sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+
+       /* Start DMA */
+       sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
+}
+
+static const struct ata_port_info ahci_sunxi_port_info = {
+       AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
+                         AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+       .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .pio_mask       = ATA_PIO4,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &ahci_platform_ops,
+};
+
+static int ahci_sunxi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       hpriv->start_engine = ahci_sunxi_start_engine;
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+       if (rc)
+               goto disable_resources;
+
+       rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ahci_sunxi_resume(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int rc;
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+       if (rc)
+               goto disable_resources;
+
+       rc = ahci_platform_resume_host(dev);
+       if (rc)
+               goto disable_resources;
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
+                        ahci_sunxi_resume);
+
+static const struct of_device_id ahci_sunxi_of_match[] = {
+       { .compatible = "allwinner,sun4i-a10-ahci", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
+
+static struct platform_driver ahci_sunxi_driver = {
+       .probe = ahci_sunxi_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "ahci-sunxi",
+               .owner = THIS_MODULE,
+               .of_match_table = ahci_sunxi_of_match,
+               .pm = &ahci_sunxi_pm_ops,
+       },
+};
+module_platform_driver(ahci_sunxi_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
new file mode 100644 (file)
index 0000000..77c89bf
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * AppliedMicro X-Gene SoC SATA Host Controller Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ *         Tuan Phan <tphan@apm.com>
+ *         Suman Tripathi <stripathi@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * NOTE: PM support is not currently available.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
+#include "ahci.h"
+
+/* Max # of disk per a controller */
+#define MAX_AHCI_CHN_PERCTR            2
+
+/* MUX CSR */
+#define SATA_ENET_CONFIG_REG           0x00000000
+#define  CFG_SATA_ENET_SELECT_MASK     0x00000001
+
+/* SATA core host controller CSR */
+#define SLVRDERRATTRIBUTES             0x00000000
+#define SLVWRERRATTRIBUTES             0x00000004
+#define MSTRDERRATTRIBUTES             0x00000008
+#define MSTWRERRATTRIBUTES             0x0000000c
+#define BUSCTLREG                      0x00000014
+#define IOFMSTRWAUX                    0x00000018
+#define INTSTATUSMASK                  0x0000002c
+#define ERRINTSTATUS                   0x00000030
+#define ERRINTSTATUSMASK               0x00000034
+
+/* SATA host AHCI CSR */
+#define PORTCFG                                0x000000a4
+#define  PORTADDR_SET(dst, src) \
+               (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
+#define PORTPHY1CFG            0x000000a8
+#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
+               (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
+#define PORTPHY2CFG                    0x000000ac
+#define PORTPHY3CFG                    0x000000b0
+#define PORTPHY4CFG                    0x000000b4
+#define PORTPHY5CFG                    0x000000b8
+#define SCTL0                          0x0000012C
+#define PORTPHY5CFG_RTCHG_SET(dst, src) \
+               (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
+#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
+               (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
+#define PORTAXICFG                     0x000000bc
+#define PORTAXICFG_OUTTRANS_SET(dst, src) \
+               (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
+
+/* SATA host controller AXI CSR */
+#define INT_SLV_TMOMASK                        0x00000010
+
+/* SATA diagnostic CSR */
+#define CFG_MEM_RAM_SHUTDOWN           0x00000070
+#define BLOCK_MEM_RDY                  0x00000074
+
+struct xgene_ahci_context {
+       struct ahci_host_priv *hpriv;
+       struct device *dev;
+       void __iomem *csr_core;         /* Core CSR address of IP */
+       void __iomem *csr_diag;         /* Diag CSR address of IP */
+       void __iomem *csr_axi;          /* AXI CSR address of IP */
+       void __iomem *csr_mux;          /* MUX CSR address of IP */
+};
+
+static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
+{
+       dev_dbg(ctx->dev, "Release memory from shutdown\n");
+       writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN);
+       readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
+       msleep(1);      /* reset may take up to 1ms */
+       if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) {
+               dev_err(ctx->dev, "failed to release memory from shutdown\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/**
+ * xgene_ahci_read_id - Read ID data from the specified device
+ * @dev: device
+ * @tf: proposed taskfile
+ * @id: data buffer
+ *
+ * This custom read ID function is required due to the fact that the HW
+ * does not support DEVSLP and the controller state machine may get stuck
+ * after processing the ID query command.
+ */
+static unsigned int xgene_ahci_read_id(struct ata_device *dev,
+                                      struct ata_taskfile *tf, u16 *id)
+{
+       u32 err_mask;
+       void __iomem *port_mmio = ahci_port_base(dev->link->ap);
+
+       err_mask = ata_do_dev_read_id(dev, tf, id);
+       if (err_mask)
+               return err_mask;
+
+       /*
+        * Mask reserved area. Word78 spec of Link Power Management
+        * bit15-8: reserved
+        * bit7: NCQ autosence
+        * bit6: Software settings preservation supported
+        * bit5: reserved
+        * bit4: In-order sata delivery supported
+        * bit3: DIPM requests supported
+        * bit2: DMA Setup FIS Auto-Activate optimization supported
+        * bit1: DMA Setup FIX non-Zero buffer offsets supported
+        * bit0: Reserved
+        *
+        * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
+        */
+       id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
+
+       /*
+        * Due to HW errata, restart the port if no other command active.
+        * Otherwise the controller may get stuck.
+        */
+       if (!readl(port_mmio + PORT_CMD_ISSUE)) {
+               writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD);    /* Force a barrier */
+               writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD);    /* Force a barrier */
+       }
+       return 0;
+}
+
+static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
+{
+       void __iomem *mmio = ctx->hpriv->mmio;
+       u32 val;
+
+       dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
+               mmio, channel);
+       val = readl(mmio + PORTCFG);
+       val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+       writel(val, mmio + PORTCFG);
+       readl(mmio + PORTCFG);  /* Force a barrier */
+       /* Disable fix rate */
+       writel(0x0001fffe, mmio + PORTPHY1CFG);
+       readl(mmio + PORTPHY1CFG); /* Force a barrier */
+       writel(0x5018461c, mmio + PORTPHY2CFG);
+       readl(mmio + PORTPHY2CFG); /* Force a barrier */
+       writel(0x1c081907, mmio + PORTPHY3CFG);
+       readl(mmio + PORTPHY3CFG); /* Force a barrier */
+       writel(0x1c080815, mmio + PORTPHY4CFG);
+       readl(mmio + PORTPHY4CFG); /* Force a barrier */
+       /* Set window negotiation */
+       val = readl(mmio + PORTPHY5CFG);
+       val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
+       writel(val, mmio + PORTPHY5CFG);
+       readl(mmio + PORTPHY5CFG); /* Force a barrier */
+       val = readl(mmio + PORTAXICFG);
+       val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
+       val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
+       writel(val, mmio + PORTAXICFG);
+       readl(mmio + PORTAXICFG); /* Force a barrier */
+}
+
+/**
+ * xgene_ahci_do_hardreset - Issue the actual COMRESET
+ * @link: link to reset
+ * @deadline: deadline jiffies for the operation
+ * @online: Return value to indicate if device online
+ *
+ * Due to the limitation of the hardware PHY, a difference set of setting is
+ * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps),
+ * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
+ * report disparity error and etc. In addition, during COMRESET, there can
+ * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
+ * algorithm is followed to proper configure the hardware PHY during COMRESET:
+ *
+ * Alg Part 1:
+ * 1. Start the PHY at Gen3 speed (default setting)
+ * 2. Issue the COMRESET
+ * 3. If no link, go to Alg Part 3
+ * 4. If link up, determine if the negotiated speed matches the PHY
+ *    configured speed
+ * 5. If they matched, go to Alg Part 2
+ * 6. If they do not matched and first time, configure the PHY for the linked
+ *    up disk speed and repeat step 2
+ * 7. Go to Alg Part 2
+ *
+ * Alg Part 2:
+ * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
+ *    reported in the register PORT_SCR_ERR, then reset the PHY receiver line
+ * 2. Go to Alg Part 3
+ *
+ * Alg Part 3:
+ * 1. Clear any pending from register PORT_SCR_ERR.
+ *
+ * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
+ *       and until the underlying PHY supports an method to reset the receiver
+ *       line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors,
+ *       an warning message will be printed.
+ */
+static int xgene_ahci_do_hardreset(struct ata_link *link,
+                                  unsigned long deadline, bool *online)
+{
+       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       struct ata_port *ap = link->ap;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+       struct xgene_ahci_context *ctx = hpriv->plat_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ata_taskfile tf;
+       int rc;
+       u32 val;
+
+       /* clear D2H reception area to properly wait for D2H FIS */
+       ata_tf_init(link->device, &tf);
+       tf.command = ATA_BUSY;
+       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+       rc = sata_link_hardreset(link, timing, deadline, online,
+                                ahci_check_ready);
+
+       val = readl(port_mmio + PORT_SCR_ERR);
+       if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
+               dev_warn(ctx->dev, "link has error\n");
+
+       /* clear all errors if any pending */
+       val = readl(port_mmio + PORT_SCR_ERR);
+       writel(val, port_mmio + PORT_SCR_ERR);
+
+       return rc;
+}
+
+static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
+                               unsigned long deadline)
+{
+       struct ata_port *ap = link->ap;
+        struct ahci_host_priv *hpriv = ap->host->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       bool online;
+       int rc;
+       u32 portcmd_saved;
+       u32 portclb_saved;
+       u32 portclbhi_saved;
+       u32 portrxfis_saved;
+       u32 portrxfishi_saved;
+
+       /* As hardreset resets these CSR, save it to restore later */
+       portcmd_saved = readl(port_mmio + PORT_CMD);
+       portclb_saved = readl(port_mmio + PORT_LST_ADDR);
+       portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
+       portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
+       portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
+
+       ahci_stop_engine(ap);
+
+       rc = xgene_ahci_do_hardreset(link, deadline, &online);
+
+       /* As controller hardreset clears them, restore them */
+       writel(portcmd_saved, port_mmio + PORT_CMD);
+       writel(portclb_saved, port_mmio + PORT_LST_ADDR);
+       writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
+       writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
+       writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
+
+       hpriv->start_engine(ap);
+
+       if (online)
+               *class = ahci_dev_classify(ap);
+
+       return rc;
+}
+
+static void xgene_ahci_host_stop(struct ata_host *host)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
+
+       ahci_platform_disable_resources(hpriv);
+}
+
+static struct ata_port_operations xgene_ahci_ops = {
+       .inherits = &ahci_ops,
+       .host_stop = xgene_ahci_host_stop,
+       .hardreset = xgene_ahci_hardreset,
+       .read_id = xgene_ahci_read_id,
+};
+
+static const struct ata_port_info xgene_ahci_port_info = {
+       AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+       .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .pio_mask = ATA_PIO4,
+       .udma_mask = ATA_UDMA6,
+       .port_ops = &xgene_ahci_ops,
+};
+
+static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
+{
+       struct xgene_ahci_context *ctx = hpriv->plat_data;
+       int i;
+       int rc;
+       u32 val;
+
+       /* Remove IP RAM out of shutdown */
+       rc = xgene_ahci_init_memram(ctx);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
+               xgene_ahci_set_phy_cfg(ctx, i);
+
+       /* AXI disable Mask */
+       writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
+       readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
+       writel(0, ctx->csr_core + INTSTATUSMASK);
+       val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */
+       dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
+               INTSTATUSMASK, val);
+
+       writel(0x0, ctx->csr_core + ERRINTSTATUSMASK);
+       readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */
+       writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK);
+       readl(ctx->csr_axi + INT_SLV_TMOMASK);
+
+       /* Enable AXI Interrupt */
+       writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES);
+       writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES);
+       writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES);
+       writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES);
+
+       /* Enable coherency */
+       val = readl(ctx->csr_core + BUSCTLREG);
+       val &= ~0x00000002;     /* Enable write coherency */
+       val &= ~0x00000001;     /* Enable read coherency */
+       writel(val, ctx->csr_core + BUSCTLREG);
+
+       val = readl(ctx->csr_core + IOFMSTRWAUX);
+       val |= (1 << 3);        /* Enable read coherency */
+       val |= (1 << 9);        /* Enable write coherency */
+       writel(val, ctx->csr_core + IOFMSTRWAUX);
+       val = readl(ctx->csr_core + IOFMSTRWAUX);
+       dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
+               IOFMSTRWAUX, val);
+
+       return rc;
+}
+
+static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
+{
+       u32 val;
+
+       /* Check for optional MUX resource */
+       if (IS_ERR(ctx->csr_mux))
+               return 0;
+
+       val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+       val &= ~CFG_SATA_ENET_SELECT_MASK;
+       writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG);
+       val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+       return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static int xgene_ahci_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct xgene_ahci_context *ctx;
+       struct resource *res;
+       int rc;
+
+       hpriv = ahci_platform_get_resources(pdev);
+       if (IS_ERR(hpriv))
+               return PTR_ERR(hpriv);
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       hpriv->plat_data = ctx;
+       ctx->hpriv = hpriv;
+       ctx->dev = dev;
+
+       /* Retrieve the IP core resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       ctx->csr_core = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->csr_core))
+               return PTR_ERR(ctx->csr_core);
+
+       /* Retrieve the IP diagnostic resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       ctx->csr_diag = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->csr_diag))
+               return PTR_ERR(ctx->csr_diag);
+
+       /* Retrieve the IP AXI resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+       ctx->csr_axi = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ctx->csr_axi))
+               return PTR_ERR(ctx->csr_axi);
+
+       /* Retrieve the optional IP mux resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+       ctx->csr_mux = devm_ioremap_resource(dev, res);
+
+       dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
+               hpriv->mmio);
+
+       /* Select ATA */
+       if ((rc = xgene_ahci_mux_select(ctx))) {
+               dev_err(dev, "SATA mux selection failed error %d\n", rc);
+               return -ENODEV;
+       }
+
+       /* Due to errata, HW requires full toggle transition */
+       rc = ahci_platform_enable_clks(hpriv);
+       if (rc)
+               goto disable_resources;
+       ahci_platform_disable_clks(hpriv);
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               goto disable_resources;
+
+       /* Configure the host controller */
+       xgene_ahci_hw_init(hpriv);
+
+       /*
+        * Setup DMA mask. This is preliminary until the DMA range is sorted
+        * out.
+        */
+       rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+       if (rc) {
+               dev_err(dev, "Unable to set dma mask\n");
+               goto disable_resources;
+       }
+
+       rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0);
+       if (rc)
+               goto disable_resources;
+
+       dev_dbg(dev, "X-Gene SATA host controller initialized\n");
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+       return rc;
+}
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+       {.compatible = "apm,xgene-ahci"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
+static struct platform_driver xgene_ahci_driver = {
+       .probe = xgene_ahci_probe,
+       .remove = ata_platform_remove_one,
+       .driver = {
+               .name = "xgene-ahci",
+               .owner = THIS_MODULE,
+               .of_match_table = xgene_ahci_of_match,
+       },
+};
+
+module_platform_driver(xgene_ahci_driver);
+
+MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
index 7d196656adb5581533517a6ed0ec49d8c2966b58..9498a7d3846fef6e2c88bdd8596d3f2080e0349e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 36605abe5a6786dd8282bceb798c10663e3b16f6..6bd4f660b4e15966ca2c351b4501c0521491de32 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -394,6 +393,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
  *
  *     If inconsistent, config values are fixed up by this function.
  *
+ *     If it is not set already this function sets hpriv->start_engine to
+ *     ahci_start_engine.
+ *
  *     LOCKING:
  *     None.
  */
@@ -500,6 +502,9 @@ void ahci_save_initial_config(struct device *dev,
        hpriv->cap = cap;
        hpriv->cap2 = cap2;
        hpriv->port_map = port_map;
+
+       if (!hpriv->start_engine)
+               hpriv->start_engine = ahci_start_engine;
 }
 EXPORT_SYMBOL_GPL(ahci_save_initial_config);
 
@@ -766,7 +771,7 @@ static void ahci_start_port(struct ata_port *ap)
 
        /* enable DMA */
        if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
-               ahci_start_engine(ap);
+               hpriv->start_engine(ap);
 
        /* turn on LEDs */
        if (ap->flags & ATA_FLAG_EM) {
@@ -1032,12 +1037,13 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
 static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
                                size_t size)
 {
-       int state;
+       unsigned int state;
        int pmp;
        struct ahci_port_priv *pp = ap->private_data;
        struct ahci_em_priv *emp;
 
-       state = simple_strtoul(buf, NULL, 0);
+       if (kstrtouint(buf, 0, &state) < 0)
+               return -EINVAL;
 
        /* get the slot number from the message */
        pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
 
        /* restart engine */
  out_restart:
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
        return rc;
 }
 EXPORT_SYMBOL_GPL(ahci_kick_engine);
@@ -1387,8 +1393,8 @@ static int ahci_bad_pmp_check_ready(struct ata_link *link)
        return ata_check_ready(status);
 }
 
-int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
-                               unsigned long deadline)
+static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
+                                   unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
        void __iomem *port_mmio = ahci_port_base(ap);
@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
        const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
        bool online;
@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, timing, deadline, &online,
                                 ahci_check_ready);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        if (online)
                *class = ahci_dev_classify(ap);
@@ -1629,7 +1636,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        }
 
        if (irq_stat & PORT_IRQ_UNK_FIS) {
-               u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+               u32 *unk = pp->rx_fis + RX_FIS_UNK;
 
                active_ehi->err_mask |= AC_ERR_HSM;
                active_ehi->action |= ATA_EH_RESET;
@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
 
 void ahci_error_handler(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
+
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
                ahci_stop_engine(ap);
-               ahci_start_engine(ap);
+               hpriv->start_engine(ap);
        }
 
        sata_pmp_error_handler(ap);
@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 
 static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_device *dev = ap->link.device;
        u32 devslp, dm, dito, mdat, deto;
@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
                   PORT_DEVSLP_ADSE);
        writel(devslp, port_mmio + PORT_DEVSLP);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        /* enable device sleep feature for the drive */
        err_mask = ata_dev_set_feature(dev,
@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 
 static void ahci_enable_fbs(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 fbs;
@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
        } else
                dev_err(ap->host->dev, "Failed to enable FBS\n");
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 }
 
 static void ahci_disable_fbs(struct ata_port *ap)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        u32 fbs;
@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
                pp->fbs_enabled = false;
        }
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 }
 
 static void ahci_pmp_attach(struct ata_port *ap)
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
new file mode 100644 (file)
index 0000000..7cb3a85
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * AHCI SATA platform library
+ *
+ * Copyright 2004-2005  Red Hat, Inc.
+ *   Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2010  MontaVista Software, LLC.
+ *   Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
+#include "ahci.h"
+
+static void ahci_host_stop(struct ata_host *host);
+
+struct ata_port_operations ahci_platform_ops = {
+       .inherits       = &ahci_ops,
+       .host_stop      = ahci_host_stop,
+};
+EXPORT_SYMBOL_GPL(ahci_platform_ops);
+
+static struct scsi_host_template ahci_platform_sht = {
+       AHCI_SHT("ahci_platform"),
+};
+
+/**
+ * ahci_platform_enable_clks - Enable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all the clks found in hpriv->clks, starting at
+ * index 0. If any clk fails to enable it disables all the clks already
+ * enabled in reverse order, and then returns an error.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+       int c, rc;
+
+       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+               rc = clk_prepare_enable(hpriv->clks[c]);
+               if (rc)
+                       goto disable_unprepare_clk;
+       }
+       return 0;
+
+disable_unprepare_clk:
+       while (--c >= 0)
+               clk_disable_unprepare(hpriv->clks[c]);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+/**
+ * ahci_platform_disable_clks - Disable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all the clks found in hpriv->clks, in reverse
+ * order of ahci_platform_enable_clks (starting at the end of the array).
+ */
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+       int c;
+
+       for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+               if (hpriv->clks[c])
+                       clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+/**
+ * ahci_platform_enable_resources - Enable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all ahci_platform managed resources in the
+ * following order:
+ * 1) Regulator
+ * 2) Clocks (through ahci_platform_enable_clks)
+ * 3) Phy
+ *
+ * If resource enabling fails at any point the previous enabled resources
+ * are disabled in reverse order.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+       int rc;
+
+       if (hpriv->target_pwr) {
+               rc = regulator_enable(hpriv->target_pwr);
+               if (rc)
+                       return rc;
+       }
+
+       rc = ahci_platform_enable_clks(hpriv);
+       if (rc)
+               goto disable_regulator;
+
+       if (hpriv->phy) {
+               rc = phy_init(hpriv->phy);
+               if (rc)
+                       goto disable_clks;
+
+               rc = phy_power_on(hpriv->phy);
+               if (rc) {
+                       phy_exit(hpriv->phy);
+                       goto disable_clks;
+               }
+       }
+
+       return 0;
+
+disable_clks:
+       ahci_platform_disable_clks(hpriv);
+
+disable_regulator:
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+/**
+ * ahci_platform_disable_resources - Disable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all ahci_platform managed resources in the
+ * following order:
+ * 1) Phy
+ * 2) Clocks (through ahci_platform_disable_clks)
+ * 3) Regulator
+ */
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+       if (hpriv->phy) {
+               phy_power_off(hpriv->phy);
+               phy_exit(hpriv->phy);
+       }
+
+       ahci_platform_disable_clks(hpriv);
+
+       if (hpriv->target_pwr)
+               regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+static void ahci_platform_put_resources(struct device *dev, void *res)
+{
+       struct ahci_host_priv *hpriv = res;
+       int c;
+
+       if (hpriv->got_runtime_pm) {
+               pm_runtime_put_sync(dev);
+               pm_runtime_disable(dev);
+       }
+
+       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+               clk_put(hpriv->clks[c]);
+}
+
+/**
+ * ahci_platform_get_resources - Get platform resources
+ * @pdev: platform device to get resources for
+ *
+ * This function allocates an ahci_host_priv struct, and gets the following
+ * resources, storing a reference to them inside the returned struct:
+ *
+ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
+ * 2) regulator for controlling the targets power (optional)
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
+ *    or for non devicetree enabled platforms a single clock
+ *     4) phy (optional)
+ *
+ * RETURNS:
+ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
+ */
+struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ahci_host_priv *hpriv;
+       struct clk *clk;
+       int i, rc = -ENOMEM;
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return ERR_PTR(-ENOMEM);
+
+       hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
+                            GFP_KERNEL);
+       if (!hpriv)
+               goto err_out;
+
+       devres_add(dev, hpriv);
+
+       hpriv->mmio = devm_ioremap_resource(dev,
+                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
+       if (IS_ERR(hpriv->mmio)) {
+               dev_err(dev, "no mmio space\n");
+               rc = PTR_ERR(hpriv->mmio);
+               goto err_out;
+       }
+
+       hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+       if (IS_ERR(hpriv->target_pwr)) {
+               rc = PTR_ERR(hpriv->target_pwr);
+               if (rc == -EPROBE_DEFER)
+                       goto err_out;
+               hpriv->target_pwr = NULL;
+       }
+
+       for (i = 0; i < AHCI_MAX_CLKS; i++) {
+               /*
+                * For now we must use clk_get(dev, NULL) for the first clock,
+                * because some platforms (da850, spear13xx) are not yet
+                * converted to use devicetree for clocks.  For new platforms
+                * this is equivalent to of_clk_get(dev->of_node, 0).
+                */
+               if (i == 0)
+                       clk = clk_get(dev, NULL);
+               else
+                       clk = of_clk_get(dev->of_node, i);
+
+               if (IS_ERR(clk)) {
+                       rc = PTR_ERR(clk);
+                       if (rc == -EPROBE_DEFER)
+                               goto err_out;
+                       break;
+               }
+               hpriv->clks[i] = clk;
+       }
+
+       hpriv->phy = devm_phy_get(dev, "sata-phy");
+       if (IS_ERR(hpriv->phy)) {
+               rc = PTR_ERR(hpriv->phy);
+               switch (rc) {
+               case -ENODEV:
+               case -ENOSYS:
+                       /* continue normally */
+                       hpriv->phy = NULL;
+                       break;
+
+               case -EPROBE_DEFER:
+                       goto err_out;
+
+               default:
+                       dev_err(dev, "couldn't get sata-phy\n");
+                       goto err_out;
+               }
+       }
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       hpriv->got_runtime_pm = true;
+
+       devres_remove_group(dev, NULL);
+       return hpriv;
+
+err_out:
+       devres_release_group(dev, NULL);
+       return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+/**
+ * ahci_platform_init_host - Bring up an ahci-platform host
+ * @pdev: platform device pointer for the host
+ * @hpriv: ahci-host private data for the host
+ * @pi_template: template for the ata_port_info to use
+ * @force_port_map: param passed to ahci_save_initial_config
+ * @mask_port_map: param passed to ahci_save_initial_config
+ *
+ * This function does all the usual steps needed to bring up an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_init_host(struct platform_device *pdev,
+                           struct ahci_host_priv *hpriv,
+                           const struct ata_port_info *pi_template,
+                           unsigned int force_port_map,
+                           unsigned int mask_port_map)
+{
+       struct device *dev = &pdev->dev;
+       struct ata_port_info pi = *pi_template;
+       const struct ata_port_info *ppi[] = { &pi, NULL };
+       struct ata_host *host;
+       int i, irq, n_ports, rc;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(dev, "no irq\n");
+               return -EINVAL;
+       }
+
+       /* prepare host */
+       hpriv->flags |= (unsigned long)pi.private_data;
+
+       ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
+
+       if (hpriv->cap & HOST_CAP_NCQ)
+               pi.flags |= ATA_FLAG_NCQ;
+
+       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
+        * both CAP.NP and port_map.
+        */
+       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+       host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+       if (!host)
+               return -ENOMEM;
+
+       host->private_data = hpriv;
+
+       if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+               host->flags |= ATA_HOST_PARALLEL_SCAN;
+       else
+               dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
+
+       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];
+
+               ata_port_desc(ap, "mmio %pR",
+                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
+               ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+               /* set enclosure management message type */
+               if (ap->flags & ATA_FLAG_EM)
+                       ap->em_message_type = hpriv->em_msg_type;
+
+               /* disabled/not-implemented port */
+               if (!(hpriv->port_map & (1 << i)))
+                       ap->ops = &ata_dummy_port_ops;
+       }
+
+       rc = ahci_reset_controller(host);
+       if (rc)
+               return rc;
+
+       ahci_init_controller(host);
+       ahci_print_info(host, "platform");
+
+       return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+                                &ahci_platform_sht);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
+
+static void ahci_host_stop(struct ata_host *host)
+{
+       struct device *dev = host->dev;
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+
+       if (pdata && pdata->exit)
+               pdata->exit(dev);
+
+       ahci_platform_disable_resources(hpriv);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * ahci_platform_suspend_host - Suspend an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to suspend an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be disabled after calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend_host(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->mmio;
+       u32 ctl;
+
+       if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+               dev_err(dev, "firmware update required for suspend/resume\n");
+               return -EIO;
+       }
+
+       /*
+        * AHCI spec rev1.1 section 8.3.3:
+        * Software must disable interrupts prior to requesting a
+        * transition of the HBA to D3 state.
+        */
+       ctl = readl(mmio + HOST_CTL);
+       ctl &= ~HOST_IRQ_EN;
+       writel(ctl, mmio + HOST_CTL);
+       readl(mmio + HOST_CTL); /* flush */
+
+       return ata_host_suspend(host, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
+
+/**
+ * ahci_platform_resume_host - Resume an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to resume an ahci-platform
+ * host, note any necessary resources (ie clks, phy, etc.)  must be
+ * initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume_host(struct device *dev)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       int rc;
+
+       if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+               rc = ahci_reset_controller(host);
+               if (rc)
+                       return rc;
+
+               ahci_init_controller(host);
+       }
+
+       ata_host_resume(host);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
+
+/**
+ * ahci_platform_suspend - Suspend an ahci-platform device
+ * @dev: the platform device to suspend
+ *
+ * This function suspends the host associated with the device, followed by
+ * disabling all the resources of the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend(struct device *dev)
+{
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int rc;
+
+       rc = ahci_platform_suspend_host(dev);
+       if (rc)
+               return rc;
+
+       if (pdata && pdata->suspend) {
+               rc = pdata->suspend(dev);
+               if (rc)
+                       goto resume_host;
+       }
+
+       ahci_platform_disable_resources(hpriv);
+
+       return 0;
+
+resume_host:
+       ahci_platform_resume_host(dev);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
+
+/**
+ * ahci_platform_resume - Resume an ahci-platform device
+ * @dev: the platform device to resume
+ *
+ * This function enables all the resources of the device followed by
+ * resuming the host associated with the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume(struct device *dev)
+{
+       struct ahci_platform_data *pdata = dev_get_platdata(dev);
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+       int rc;
+
+       rc = ahci_platform_enable_resources(hpriv);
+       if (rc)
+               return rc;
+
+       if (pdata && pdata->resume) {
+               rc = pdata->resume(dev);
+               if (rc)
+                       goto disable_resources;
+       }
+
+       rc = ahci_platform_resume_host(dev);
+       if (rc)
+               goto disable_resources;
+
+       /* We resumed so update PM runtime state */
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+
+disable_resources:
+       ahci_platform_disable_resources(hpriv);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
+#endif
+
+MODULE_DESCRIPTION("AHCI SATA platform library");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
index 9e69a5308693de59abd5c596244033af43f7b3a8..97a14fe47de1b357f34081379f96454a3b6e49dc 100644 (file)
@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev)
        dev->gtf_cache = NULL;
 }
 
+struct ata_acpi_hotplug_context {
+       struct acpi_hotplug_context hp;
+       union {
+               struct ata_port *ap;
+               struct ata_device *dev;
+       } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
 /**
  * ata_dev_acpi_handle - provide the acpi_handle for an ata_device
  * @dev: the acpi_handle returned will correspond to this device
@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
                ata_port_wait_eh(ap);
 }
 
-static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
 {
-       struct ata_device *dev = data;
-
+       struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
        ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+       return 0;
 }
 
-static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
 {
-       struct ata_port *ap = data;
-
-       ata_acpi_handle_hotplug(ap, NULL, event);
+       ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+       return 0;
 }
 
 static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
        }
 }
 
-static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
 {
-       ata_acpi_uevent(data, NULL, event);
+       ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
 }
 
-static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
 {
-       struct ata_device *dev = data;
+       struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
        ata_acpi_uevent(dev->link->ap, dev, event);
 }
 
-static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
-       .handler = ata_acpi_dev_notify_dock,
-       .uevent = ata_acpi_dev_uevent,
-};
-
-static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
-       .handler = ata_acpi_ap_notify_dock,
-       .uevent = ata_acpi_ap_uevent,
-};
-
 /* bind acpi handle to pata port */
 void ata_acpi_bind_port(struct ata_port *ap)
 {
        struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+       struct acpi_device *adev;
+       struct ata_acpi_hotplug_context *context;
 
        if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
                return;
@@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap)
        if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
                ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
 
-       /* we might be on a docking station */
-       register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
-                                    &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+       adev = ACPI_COMPANION(&ap->tdev);
+       if (!adev || adev->hp)
+               return;
+
+       context = kzalloc(sizeof(*context), GFP_KERNEL);
+       if (!context)
+               return;
+
+       context->data.ap = ap;
+       acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+                                  ata_acpi_ap_uevent);
 }
 
 void ata_acpi_bind_dev(struct ata_device *dev)
@@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev)
        struct ata_port *ap = dev->link->ap;
        struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
        struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
-       struct acpi_device *parent;
+       struct acpi_device *parent, *adev;
+       struct ata_acpi_hotplug_context *context;
        u64 adr;
 
        /*
@@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev)
        }
 
        acpi_preset_companion(&dev->tdev, parent, adr);
+       adev = ACPI_COMPANION(&dev->tdev);
+       if (!adev || adev->hp)
+               return;
+
+       context = kzalloc(sizeof(*context), GFP_KERNEL);
+       if (!context)
+               return;
 
-       register_hotplug_dock_device(ata_dev_acpi_handle(dev),
-                                    &ata_acpi_dev_dock_ops, dev, NULL, NULL);
+       context->data.dev = dev;
+       acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+                                  ata_acpi_dev_uevent);
 }
 
 /**
@@ -835,6 +853,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
                ata_for_each_dev(dev, &ap->link, ALL) {
                        ata_acpi_clear_gtf(dev);
                        if (ata_dev_enabled(dev) &&
+                           ata_dev_acpi_handle(dev) &&
                            ata_dev_get_GTF(dev, NULL) >= 0)
                                dev->flags |= ATA_DFLAG_ACPI_PENDING;
                }
index 1a3dbd1b196ecb121b1ee9d34388ecd00c307b71..34406f7fdd7a1274da79601489a30e6df774290c 100644 (file)
@@ -4175,6 +4175,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
        { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+       { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
 
        /* Blacklist entries taken from Silicon Image 3124/3132
           Windows driver .inf file - also several Linux problem reports */
@@ -4224,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* devices that don't properly handle queued TRIM commands */
        { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT???M500SSD1",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Crucial_CT???M500SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * Some WD SATA-I drives spin up and down erratically when the link
@@ -5351,22 +5352,17 @@ bool ata_link_offline(struct ata_link *link)
 }
 
 #ifdef CONFIG_PM
-static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
-                              unsigned int action, unsigned int ehi_flags,
-                              int *async)
+static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
+                               unsigned int action, unsigned int ehi_flags,
+                               bool async)
 {
        struct ata_link *link;
        unsigned long flags;
-       int rc = 0;
 
        /* Previous resume operation might still be in
         * progress.  Wait for PM_PENDING to clear.
         */
        if (ap->pflags & ATA_PFLAG_PM_PENDING) {
-               if (async) {
-                       *async = -EAGAIN;
-                       return 0;
-               }
                ata_port_wait_eh(ap);
                WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
        }
@@ -5375,11 +5371,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        spin_lock_irqsave(ap->lock, flags);
 
        ap->pm_mesg = mesg;
-       if (async)
-               ap->pm_result = async;
-       else
-               ap->pm_result = &rc;
-
        ap->pflags |= ATA_PFLAG_PM_PENDING;
        ata_for_each_link(link, ap, HOST_FIRST) {
                link->eh_info.action |= action;
@@ -5390,87 +5381,81 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       /* wait and check result */
        if (!async) {
                ata_port_wait_eh(ap);
                WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
        }
-
-       return rc;
 }
 
-static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
+/*
+ * On some hardware, device fails to respond after spun down for suspend.  As
+ * the device won't be used before being resumed, we don't need to touch the
+ * device.  Ask EH to skip the usual stuff and proceed directly to suspend.
+ *
+ * http://thread.gmane.org/gmane.linux.ide/46764
+ */
+static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET
+                                                | ATA_EHI_NO_AUTOPSY
+                                                | ATA_EHI_NO_RECOVERY;
+
+static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg)
 {
-       /*
-        * On some hardware, device fails to respond after spun down
-        * for suspend.  As the device won't be used before being
-        * resumed, we don't need to touch the device.  Ask EH to skip
-        * the usual stuff and proceed directly to suspend.
-        *
-        * http://thread.gmane.org/gmane.linux.ide/46764
-        */
-       unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY |
-                                ATA_EHI_NO_RECOVERY;
-       return ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
+       ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false);
 }
 
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg)
 {
-       struct ata_port *ap = to_ata_port(dev);
-
-       return __ata_port_suspend_common(ap, mesg, NULL);
+       ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
 }
 
-static int ata_port_suspend(struct device *dev)
+static int ata_port_pm_suspend(struct device *dev)
 {
+       struct ata_port *ap = to_ata_port(dev);
+
        if (pm_runtime_suspended(dev))
                return 0;
 
-       return ata_port_suspend_common(dev, PMSG_SUSPEND);
+       ata_port_suspend(ap, PMSG_SUSPEND);
+       return 0;
 }
 
-static int ata_port_do_freeze(struct device *dev)
+static int ata_port_pm_freeze(struct device *dev)
 {
+       struct ata_port *ap = to_ata_port(dev);
+
        if (pm_runtime_suspended(dev))
                return 0;
 
-       return ata_port_suspend_common(dev, PMSG_FREEZE);
+       ata_port_suspend(ap, PMSG_FREEZE);
+       return 0;
 }
 
-static int ata_port_poweroff(struct device *dev)
+static int ata_port_pm_poweroff(struct device *dev)
 {
-       return ata_port_suspend_common(dev, PMSG_HIBERNATE);
+       ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE);
+       return 0;
 }
 
-static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
-                                   int *async)
-{
-       int rc;
+static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY
+                                               | ATA_EHI_QUIET;
 
-       rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
-               ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
-       return rc;
+static void ata_port_resume(struct ata_port *ap, pm_message_t mesg)
+{
+       ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false);
 }
 
-static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
+static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg)
 {
-       struct ata_port *ap = to_ata_port(dev);
-
-       return __ata_port_resume_common(ap, mesg, NULL);
+       ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true);
 }
 
-static int ata_port_resume(struct device *dev)
+static int ata_port_pm_resume(struct device *dev)
 {
-       int rc;
-
-       rc = ata_port_resume_common(dev, PMSG_RESUME);
-       if (!rc) {
-               pm_runtime_disable(dev);
-               pm_runtime_set_active(dev);
-               pm_runtime_enable(dev);
-       }
-
-       return rc;
+       ata_port_resume_async(to_ata_port(dev), PMSG_RESUME);
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       return 0;
 }
 
 /*
@@ -5499,21 +5484,23 @@ static int ata_port_runtime_idle(struct device *dev)
 
 static int ata_port_runtime_suspend(struct device *dev)
 {
-       return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+       ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND);
+       return 0;
 }
 
 static int ata_port_runtime_resume(struct device *dev)
 {
-       return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+       ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME);
+       return 0;
 }
 
 static const struct dev_pm_ops ata_port_pm_ops = {
-       .suspend = ata_port_suspend,
-       .resume = ata_port_resume,
-       .freeze = ata_port_do_freeze,
-       .thaw = ata_port_resume,
-       .poweroff = ata_port_poweroff,
-       .restore = ata_port_resume,
+       .suspend = ata_port_pm_suspend,
+       .resume = ata_port_pm_resume,
+       .freeze = ata_port_pm_freeze,
+       .thaw = ata_port_pm_resume,
+       .poweroff = ata_port_pm_poweroff,
+       .restore = ata_port_pm_resume,
 
        .runtime_suspend = ata_port_runtime_suspend,
        .runtime_resume = ata_port_runtime_resume,
@@ -5525,18 +5512,17 @@ static const struct dev_pm_ops ata_port_pm_ops = {
  * level. sas suspend/resume is async to allow parallel port recovery
  * since sas has multiple ata_port instances per Scsi_Host.
  */
-int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+void ata_sas_port_suspend(struct ata_port *ap)
 {
-       return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+       ata_port_suspend_async(ap, PMSG_SUSPEND);
 }
-EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+EXPORT_SYMBOL_GPL(ata_sas_port_suspend);
 
-int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+void ata_sas_port_resume(struct ata_port *ap)
 {
-       return __ata_port_resume_common(ap, PMSG_RESUME, async);
+       ata_port_resume_async(ap, PMSG_RESUME);
 }
-EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
-
+EXPORT_SYMBOL_GPL(ata_sas_port_resume);
 
 /**
  *     ata_host_suspend - suspend host
index 6d87570083187bbbe749fe566195f854707a641c..6760fc4e85b8c809e39655fd92adc83871e75fce 100644 (file)
@@ -95,12 +95,13 @@ enum {
  * represents timeout for that try.  The first try can be soft or
  * hardreset.  All others are hardreset if available.  In most cases
  * the first reset w/ 10sec timeout should succeed.  Following entries
- * are mostly for error handling, hotplug and retarded devices.
+ * are mostly for error handling, hotplug and those outlier devices that
+ * take an exceptionally long time to recover from reset.
  */
 static const unsigned long ata_eh_reset_timeouts[] = {
        10000,  /* most drives spin up by 10sec */
        10000,  /* > 99% working drives spin up before 20sec */
-       35000,  /* give > 30 secs of idleness for retarded devices */
+       35000,  /* give > 30 secs of idleness for outlier devices */
         5000,  /* and sweet one last chance */
        ULONG_MAX, /* > 1 min has elapsed, give up */
 };
@@ -4069,7 +4070,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
 
        ata_acpi_set_state(ap, ap->pm_mesg);
  out:
-       /* report result */
+       /* update the flags */
        spin_lock_irqsave(ap->lock, flags);
 
        ap->pflags &= ~ATA_PFLAG_PM_PENDING;
@@ -4078,11 +4079,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
        else if (ap->pflags & ATA_PFLAG_FROZEN)
                ata_port_schedule_eh(ap);
 
-       if (ap->pm_result) {
-               *ap->pm_result = rc;
-               ap->pm_result = NULL;
-       }
-
        spin_unlock_irqrestore(ap->lock, flags);
 
        return;
@@ -4134,13 +4130,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
        /* tell ACPI that we're resuming */
        ata_acpi_on_resume(ap);
 
-       /* report result */
+       /* update the flags */
        spin_lock_irqsave(ap->lock, flags);
        ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
-       if (ap->pm_result) {
-               *ap->pm_result = rc;
-               ap->pm_result = NULL;
-       }
        spin_unlock_irqrestore(ap->lock, flags);
 }
 #endif /* CONFIG_PM */
index 88949c6d55ddd43b32b07accdb892256028d5e25..f3a65a3140d3c7e51bef6dce19f676de768abfdf 100644 (file)
@@ -85,21 +85,6 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
                return ODD_MECH_TYPE_UNSUPPORTED;
 }
 
-static bool odd_can_poweroff(struct ata_device *ata_dev)
-{
-       acpi_handle handle;
-       struct acpi_device *acpi_dev;
-
-       handle = ata_dev_acpi_handle(ata_dev);
-       if (!handle)
-               return false;
-
-       if (acpi_bus_get_device(handle, &acpi_dev))
-               return false;
-
-       return acpi_device_can_poweroff(acpi_dev);
-}
-
 /* Test if ODD is zero power ready by sense code */
 static bool zpready(struct ata_device *dev)
 {
@@ -267,13 +252,11 @@ static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
 
 void zpodd_init(struct ata_device *dev)
 {
+       struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
        enum odd_mech_type mech_type;
        struct zpodd *zpodd;
 
-       if (dev->zpodd)
-               return;
-
-       if (!odd_can_poweroff(dev))
+       if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
                return;
 
        mech_type = zpodd_get_mech_type(dev);
index 62c9ac80c6e96ed1f0a4421fb22b7ee3629ae2e9..5108b8744dce4c70d37d913fbf5b916984b36f6c 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d23e2b3ca0b68a6c7109eef8e53b2e3e68048281..1206fa6b62cae199a00302729565915ed931509a 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 73492dd4a4bce8aade1f79a7dbdfd3926c7f6f6b..6fac524c2f500381ac8d76b2a94bf4d88314f1e7 100644 (file)
@@ -356,7 +356,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
 
 static void dma_callback(void *dev)
 {
-       struct arasan_cf_dev *acdev = (struct arasan_cf_dev *) dev;
+       struct arasan_cf_dev *acdev = dev;
 
        complete(&acdev->dma_completion);
 }
index 1581dee2967a80368976303fc9e7865b1e69cef2..3aa4e655e3c64cb5a81f3759f5638e2eb003c5df 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d63ee8f41a4f29e9c0bc9209236c97ca47259ab5..e9c87274a781551d4496ac81b213855dd766ae41 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/gfp.h>
 #include <scsi/scsi_host.h>
index 24e51056ac26a857c1db028b9eb71450a0608d45..30fa4ca4cef65607493a1e8fd1e5fe6bf13b5bbb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 2ca5026f2c150f9e83b37e48e8227e944a18253f..7e73a0f1e3237698b2b7afcd70207655e53dc2d3 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 8fb69e5ca1b7f08be8ef7a635acdf8122765f577..57f1be64dbf239e8c631687ea5b5c28f1c1b5577 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
index 1275a8d4dedc06940cbce5660d24136d27aea0ef..6bca3505b9e9d5431d537e2fdf2fbcae917e76c6 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index f10baabbf5db5ae2f266aed4f7559d258962f267..bcde4b786807079126aed18744edbbf972a86d3c 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index f07f2296acdcf5c986a0c33bd423736268f42c33..8afe854a5a50c24abeb2c9f96966264d09c0f8bc 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 997e16a3a63f6154373d33854fed1c1532ee657f..2c0986fa4bb2ccd8efc1d2ead606c05e6d734ae1 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 0448860a2077526cea30354fc60b6c6c3cacada9..32ddcae5a360a387b010db88cf951287ab219bd6 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/libata.h>
index 810bc9964ddec6a12a72ca50206b7b67039c1183..3435bd6a5cc918984ba7aee85cfc8e4435e7106c 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 3c12fd7acd4126c256a3c87822b744c77af4a43b..f440892225f4d220603759f196cd2b5ca155a87f 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 980b88e109fcf5109e164d155dfca86de735c2c2..cad9d45749c419e51dbdf852fe67ee998796938b 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <linux/ata.h>
index 35b521348d311fbb7b2921618e348661a57edfb6..8e76f79689d371bd96fbd2f276d53ab265edc026 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index a9d74eff5fc4b159367b1f8f03d7aa842e331dba..3ba843f5cdc0f91a789e536b876a0b4bb292e645 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 4be0398c153d36b448cc5f23199514a48c8cc35b..b93c0f0729e7676e9e4b78d9611d3547ed8350b9 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 85cf2861e0b7d217eaabd6ffa446a6446de84c72..255c5aaff3a81e8c3ddce32dca7ba49a6dd0cf1d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index b0b18ec5465ffe32bae62d11f97d1b0cba8c313c..e0872db913d65d1f120a753ac2f313162add41dd 100644 (file)
@@ -15,7 +15,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <linux/ata.h>
@@ -100,13 +99,9 @@ static int pata_imx_probe(struct platform_device *pdev)
        struct resource *io_res;
        int ret;
 
-       io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (io_res == NULL)
-               return -EINVAL;
-
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0)
-               return -EINVAL;
+       if (irq < 0)
+               return irq;
 
        priv = devm_kzalloc(&pdev->dev,
                                sizeof(struct pata_imx_priv), GFP_KERNEL);
@@ -136,11 +131,10 @@ static int pata_imx_probe(struct platform_device *pdev)
        ap->pio_mask = ATA_PIO0;
        ap->flags |= ATA_FLAG_SLAVE_POSS;
 
-       priv->host_regs = devm_ioremap(&pdev->dev, io_res->start,
-               resource_size(io_res));
-       if (!priv->host_regs) {
-               dev_err(&pdev->dev, "failed to map IO/CTL base\n");
-               ret = -EBUSY;
+       io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res);
+       if (IS_ERR(priv->host_regs)) {
+               ret = PTR_ERR(priv->host_regs);
                goto err;
        }
 
index 2a8dd9527eccd4d435b65f7532091520cd5de40b..81369d187a5cb8f9e8e7d40158741533486d19a5 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 581e04d80367a9690c22513aaba376bf7dff643f..dc3d7877f29d7898a11780595e27cabb01d53a7e 100644 (file)
@@ -72,7 +72,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
index 76e739b031b6a3a15c036b082bcb8ba8d4f1ad06..b1cfa0258fd38017337e345b5095677a50567133 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index be816428b430fbb73135ef1591bbde2219097221..bce2a8ca4678ace5375b6a0f90699481b8ff9659 100644 (file)
@@ -916,7 +916,6 @@ static __init int probe_chip_type(struct legacy_probe *probe)
                        local_irq_restore(flags);
                        return BIOS;
                }
-               local_irq_restore(flags);
        }
 
        if (ht6560a & mask)
index a4f5e781c8c237dd794588b0bc0c050216763ce0..6bad3df3a13c7741095ac7e88c80d7d7e75d98c4 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 1f5f28bb0bb8082c5cb66dcb714af3fec6bed5e2..f39a5379e8165a0adf8e59f3fa34412822724289 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index ad1a0febd6207dc08521c245a8e650f30e149dff..e3b97093ef9a3cc60aa5a904bc39e7c31f2546b7 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 9513e071040da8f148dc63a6b2aca8f7d7018a83..56201a69af127322e0070b3f4b18c8a0d0355cec 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 0c424dae56e7e13a686bdf062baadcbb422d8fe6..6154c3ee11a5b32d94fd065e0b5abbf8c0109c79 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 16dc3a63a23d5f763b28c92d7fcc9170d0e2320e..d44df7ccfe43930fa51354ce4dab57545bb381f9 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d77b2e1054efc25cf8207ec6b963ce853427255f..319b64491b7b504fd1fb67350d16e8374fd6cecf 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 4ea70cd22aee8fc70a75f9bfb5696122fee2bd32..fb042e0519d00f780d4a642e4b8a3e27bdec0d11 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 78ede3fd187559360d246cb8f52439fdbd2364ad..bb71ea214b9902ee63258acefaefc795bf18bbc8 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 40254f4df584f781100476dbd391941148042fc8..bcc4b968c0497cb74ec005c433a993054fe42273 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
index 9d874c85d64d7f5eb7f5d4c44fe785e8aa1c555a..1151f23177bb803df56a20fbc30be6032e382598 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index c34fc50070a6382fc48f9c428557c9f9bca5ee9b..defa050e17843d26db5ef685e8c4263fc64eb23b 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 2beb6b5045f8fd224e1f535c20254caa99aa9540..0b46be11705169b0cb8150d2a3792be72caae3c2 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 02794885de10be8329003300d19c2f8084ff9032..a5579b55e3329ee395cfbddd30eb034711e0aab1 100644 (file)
@@ -13,7 +13,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <linux/ata.h>
index a6f05acad61ed01d68b0ec201698a8abc406cf44..73259bfda1e364e5e99b89aec1a6ae99400f6297 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/ata.h>
 #include <linux/libata.h>
index f582ba180a7d6e3c799a788f86c477ed43f36660..be3f10240dca4961f80d34437acaac78298dbea1 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 79a970f05a2e2bb54d60fcfa92211596f41791ec..521b2137ea3e39ccccb35cb78810316bebc26b72 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 040b093617a4ada5ffa76c61c2d20615644d5b35..caedc90855b2fdb931f39018b31f3d9f7b0effff 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index ce2f828c17b30f4ff5fa831c933d3174c6136d5d..96a232fffae6089ddfa77b8981e04115700e872a 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index f35f15f4d83e30288abf6506e9802c66f969ace7..f1f5b5ae33826356230f2689996c34065afb3f7a 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index d3830c45a369cd611ba99ff78bac235c5fc4e258..5a1cde0ea3601818456b44b51c0cc059ece726e0 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 96c6a79ef6066af0171b74864134f34a05ebb611..e27f31fe1b67b93a3c6c326be0d434a26d8d056a 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index c4b0b073ba8e8c7d13512a2c6930b987ba1a4745..73fe362d97161dffcb75a514c41b65fb9a5baf0b 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 1e8363640bf5e7bd16a065ce0222c161b745e459..78d913aa93c812f8eae1ccd572ad1c7ea1dfd22a 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 6816911ac4229ba8e7dc46829cd2da9461015ef5..900f0e4a1faf61462b20f37b8b29176d194a17e0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index 94473da68c02d9664906f8c5c82a0f395d881d63..7bc78e264f9eda5cd4cd7eabc4a2acf6dae9bb7e 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <scsi/scsi_host.h>
index c3ab9a6c3965b1c8df7045da6f6a1a10f414ca9b..f6c9632bdff6a11c6fbdcc18d7ff703d1c4b20cc 100644 (file)
@@ -55,7 +55,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
index 8ea6e6afd041db7736e6a69c88641253fa4b4078..f10631beffa87cd258950bb4c85778ce166205e0 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 523524b68022d3710f342d96f54926014de551ae..0bb2cabd2197bba01c0b4dd175f662a353eba076 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -462,8 +461,7 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
        int chan;
        u32 tfr_reg, err_reg;
        unsigned long flags;
-       struct sata_dwc_device *hsdev =
-               (struct sata_dwc_device *)hsdev_instance;
+       struct sata_dwc_device *hsdev = hsdev_instance;
        struct ata_host *host = (struct ata_host *)hsdev->host;
        struct ata_port *ap;
        struct sata_dwc_device_port *hsdevp;
index 870b11eadc6d793d3abcebdcc6bb72c4cc326f45..65965cf5af06ba94c8c77ebfcf01ca584f81d0be 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -142,7 +141,7 @@ 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 ecx_plat_data *pdata = hpriv->plat_data;
        struct ahci_port_priv *pp = ap->private_data;
        unsigned long flags;
        int pmp, i;
@@ -403,6 +402,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
        static const unsigned long timing[] = { 5, 100, 500};
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
        bool online;
@@ -431,7 +431,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
                        break;
        } while (!online && retry--);
 
-       ahci_start_engine(ap);
+       hpriv->start_engine(ap);
 
        if (online)
                *class = ahci_dev_classify(ap);
index d74def823d3ed865be0841d771fb7141ac1c1a07..ba5f27120332fe5b2e15d553cb7a7bc25aaa7a44 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 97f4acb54ad626795972ffb8e35572101d05d08d..3638887476f610a933d57b29cae7f84c4d6f229f 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 3b0dd57984e18370f5a659907c1c3326aed6fb49..9a6bd4cd29a0661cefd71f686e7c4bbc778911ed 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index b7695e804635b87c0d7c787be1d900facaa68963..3062f8605b2955956bff191d6034530ce7fbd636 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 1ad2f62d34b98fd0b41be9a239827e1634327c54..b513428171b3592a4033e597ec593a7e4189ab21 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index dc4f70179e7d37470dc358b02c96b328d8bbeeae..c630fa81262439939c3ad770f3538e48c0862522 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 9947010afc0f7973e2af77664f6ef39e53840358..39b5de60a1f96a93a80193b5a7ce8ec6e0ecea43 100644 (file)
@@ -82,7 +82,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -1021,8 +1020,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
        idx++;
        dist = ((long) (window_size - (offset + size))) >= 0 ? size :
                (long) (window_size - offset);
-       memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
-                     dist);
+       memcpy_fromio(psource, dimm_mmio + offset / 4, dist);
 
        psource += dist;
        size -= dist;
@@ -1031,8 +1029,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
                readl(mmio + PDC_GENERAL_CTLR);
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_fromio((char *) psource, (char *) (dimm_mmio),
-                             window_size / 4);
+               memcpy_fromio(psource, dimm_mmio, window_size / 4);
                psource += window_size;
                size -= window_size;
                idx++;
@@ -1043,8 +1040,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
                readl(mmio + PDC_GENERAL_CTLR);
                writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
                readl(mmio + PDC_DIMM_WINDOW_CTLR);
-               memcpy_fromio((char *) psource, (char *) (dimm_mmio),
-                             size / 4);
+               memcpy_fromio(psource, dimm_mmio, size / 4);
        }
 }
 #endif
index 6d6489118873fe50bd4f04a0cc3320e5eae5747c..08f98c3ed5c8e28f89d45ec467f3dec69f28d204 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 87f056e54a9d7566504925ca812347baf6b3e62f..f72e84228c5c10e05db80755df5a64efd5606b38 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 44f304b3de63c6ee45fa87f88793e900359ac1be..29e847aac34be5ea88871ff03c99856b20c4492e 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 545c4de412c3e0ba5a2680d9143e059a9c475dbd..db4e264eecb60c88fb089b77878d644da4801a8f 100644 (file)
@@ -790,6 +790,32 @@ void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
 }
 EXPORT_SYMBOL_GPL(devm_kmalloc);
 
+/**
+ * devm_kstrdup - Allocate resource managed space and
+ *                copy an existing string into that.
+ * @dev: Device to allocate memory for
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the devm_kmalloc() call when
+ *       allocating memory
+ * RETURNS:
+ * Pointer to allocated string on success, NULL on failure.
+ */
+char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
+{
+       size_t size;
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       size = strlen(s) + 1;
+       buf = devm_kmalloc(dev, size, gfp);
+       if (buf)
+               memcpy(buf, s, size);
+       return buf;
+}
+EXPORT_SYMBOL_GPL(devm_kstrdup);
+
 /**
  * devm_kfree - Resource-managed kfree
  * @dev: Device this memory belongs to
index 2e58ebb1f6c0ab63467656afc2e64f9ef333b6c4..1cb8544598d5584ac8f69ece8d6e9a113a734942 100644 (file)
@@ -1,6 +1,5 @@
-obj-$(CONFIG_PM)       += sysfs.o generic_ops.o common.o qos.o
+obj-$(CONFIG_PM)       += sysfs.o generic_ops.o common.o qos.o runtime.o
 obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
-obj-$(CONFIG_PM_RUNTIME)       += runtime.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
 obj-$(CONFIG_PM_OPP)   += opp.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS)       +=  domain.o domain_governor.o
index 921b19234a4dbb81ea1506cf5596b70303cb461c..6f54962aae1dd1a6160b777238b37f639f03f80f 100644 (file)
@@ -41,7 +41,7 @@
        struct gpd_timing_data *__td = &dev_gpd_data(dev)->td;                  \
        if (!__retval && __elapsed > __td->field) {                             \
                __td->field = __elapsed;                                        \
-               dev_warn(dev, name " latency exceeded, new value %lld ns\n",    \
+               dev_dbg(dev, name " latency exceeded, new value %lld ns\n",     \
                        __elapsed);                                             \
                genpd->max_off_time_changed = true;                             \
                __td->constraint_changed = true;                                \
index 1b41fca3d65a54545c6c124e0df696998c29a1af..86d5e4fb5b98314d10504f0c91ea5c2765038ddd 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/async.h>
 #include <linux/suspend.h>
 #include <trace/events/power.h>
+#include <linux/cpufreq.h>
 #include <linux/cpuidle.h>
 #include <linux/timer.h>
 
@@ -91,6 +92,8 @@ void device_pm_sleep_init(struct device *dev)
 {
        dev->power.is_prepared = false;
        dev->power.is_suspended = false;
+       dev->power.is_noirq_suspended = false;
+       dev->power.is_late_suspended = false;
        init_completion(&dev->power.completion);
        complete_all(&dev->power.completion);
        dev->power.wakeup = NULL;
@@ -467,7 +470,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
  * The driver of @dev will not receive interrupts while this function is being
  * executed.
  */
-static int device_resume_noirq(struct device *dev, pm_message_t state)
+static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
 {
        pm_callback_t callback = NULL;
        char *info = NULL;
@@ -479,6 +482,11 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
        if (dev->power.syscore)
                goto Out;
 
+       if (!dev->power.is_noirq_suspended)
+               goto Out;
+
+       dpm_wait(dev->parent, async);
+
        if (dev->pm_domain) {
                info = "noirq power domain ";
                callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -499,12 +507,32 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
        }
 
        error = dpm_run_callback(callback, dev, state, info);
+       dev->power.is_noirq_suspended = false;
 
  Out:
+       complete_all(&dev->power.completion);
        TRACE_RESUME(error);
        return error;
 }
 
+static bool is_async(struct device *dev)
+{
+       return dev->power.async_suspend && pm_async_enabled
+               && !pm_trace_is_enabled();
+}
+
+static void async_resume_noirq(void *data, async_cookie_t cookie)
+{
+       struct device *dev = (struct device *)data;
+       int error;
+
+       error = device_resume_noirq(dev, pm_transition, true);
+       if (error)
+               pm_dev_err(dev, pm_transition, " async", error);
+
+       put_device(dev);
+}
+
 /**
  * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices.
  * @state: PM transition of the system being carried out.
@@ -514,29 +542,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
  */
 static void dpm_resume_noirq(pm_message_t state)
 {
+       struct device *dev;
        ktime_t starttime = ktime_get();
 
        mutex_lock(&dpm_list_mtx);
-       while (!list_empty(&dpm_noirq_list)) {
-               struct device *dev = to_device(dpm_noirq_list.next);
-               int error;
+       pm_transition = state;
 
+       /*
+        * Advanced the async threads upfront,
+        * in case the starting of async threads is
+        * delayed by non-async resuming devices.
+        */
+       list_for_each_entry(dev, &dpm_noirq_list, power.entry) {
+               reinit_completion(&dev->power.completion);
+               if (is_async(dev)) {
+                       get_device(dev);
+                       async_schedule(async_resume_noirq, dev);
+               }
+       }
+
+       while (!list_empty(&dpm_noirq_list)) {
+               dev = to_device(dpm_noirq_list.next);
                get_device(dev);
                list_move_tail(&dev->power.entry, &dpm_late_early_list);
                mutex_unlock(&dpm_list_mtx);
 
-               error = device_resume_noirq(dev, state);
-               if (error) {
-                       suspend_stats.failed_resume_noirq++;
-                       dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
-                       dpm_save_failed_dev(dev_name(dev));
-                       pm_dev_err(dev, state, " noirq", error);
+               if (!is_async(dev)) {
+                       int error;
+
+                       error = device_resume_noirq(dev, state, false);
+                       if (error) {
+                               suspend_stats.failed_resume_noirq++;
+                               dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+                               dpm_save_failed_dev(dev_name(dev));
+                               pm_dev_err(dev, state, " noirq", error);
+                       }
                }
 
                mutex_lock(&dpm_list_mtx);
                put_device(dev);
        }
        mutex_unlock(&dpm_list_mtx);
+       async_synchronize_full();
        dpm_show_time(starttime, state, "noirq");
        resume_device_irqs();
        cpuidle_resume();
@@ -549,7 +596,7 @@ static void dpm_resume_noirq(pm_message_t state)
  *
  * Runtime PM is disabled for @dev while this function is being executed.
  */
-static int device_resume_early(struct device *dev, pm_message_t state)
+static int device_resume_early(struct device *dev, pm_message_t state, bool async)
 {
        pm_callback_t callback = NULL;
        char *info = NULL;
@@ -561,6 +608,11 @@ static int device_resume_early(struct device *dev, pm_message_t state)
        if (dev->power.syscore)
                goto Out;
 
+       if (!dev->power.is_late_suspended)
+               goto Out;
+
+       dpm_wait(dev->parent, async);
+
        if (dev->pm_domain) {
                info = "early power domain ";
                callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -581,43 +633,75 @@ static int device_resume_early(struct device *dev, pm_message_t state)
        }
 
        error = dpm_run_callback(callback, dev, state, info);
+       dev->power.is_late_suspended = false;
 
  Out:
        TRACE_RESUME(error);
 
        pm_runtime_enable(dev);
+       complete_all(&dev->power.completion);
        return error;
 }
 
+static void async_resume_early(void *data, async_cookie_t cookie)
+{
+       struct device *dev = (struct device *)data;
+       int error;
+
+       error = device_resume_early(dev, pm_transition, true);
+       if (error)
+               pm_dev_err(dev, pm_transition, " async", error);
+
+       put_device(dev);
+}
+
 /**
  * dpm_resume_early - Execute "early resume" callbacks for all devices.
  * @state: PM transition of the system being carried out.
  */
 static void dpm_resume_early(pm_message_t state)
 {
+       struct device *dev;
        ktime_t starttime = ktime_get();
 
        mutex_lock(&dpm_list_mtx);
-       while (!list_empty(&dpm_late_early_list)) {
-               struct device *dev = to_device(dpm_late_early_list.next);
-               int error;
+       pm_transition = state;
 
+       /*
+        * Advanced the async threads upfront,
+        * in case the starting of async threads is
+        * delayed by non-async resuming devices.
+        */
+       list_for_each_entry(dev, &dpm_late_early_list, power.entry) {
+               reinit_completion(&dev->power.completion);
+               if (is_async(dev)) {
+                       get_device(dev);
+                       async_schedule(async_resume_early, dev);
+               }
+       }
+
+       while (!list_empty(&dpm_late_early_list)) {
+               dev = to_device(dpm_late_early_list.next);
                get_device(dev);
                list_move_tail(&dev->power.entry, &dpm_suspended_list);
                mutex_unlock(&dpm_list_mtx);
 
-               error = device_resume_early(dev, state);
-               if (error) {
-                       suspend_stats.failed_resume_early++;
-                       dpm_save_failed_step(SUSPEND_RESUME_EARLY);
-                       dpm_save_failed_dev(dev_name(dev));
-                       pm_dev_err(dev, state, " early", error);
-               }
+               if (!is_async(dev)) {
+                       int error;
 
+                       error = device_resume_early(dev, state, false);
+                       if (error) {
+                               suspend_stats.failed_resume_early++;
+                               dpm_save_failed_step(SUSPEND_RESUME_EARLY);
+                               dpm_save_failed_dev(dev_name(dev));
+                               pm_dev_err(dev, state, " early", error);
+                       }
+               }
                mutex_lock(&dpm_list_mtx);
                put_device(dev);
        }
        mutex_unlock(&dpm_list_mtx);
+       async_synchronize_full();
        dpm_show_time(starttime, state, "early");
 }
 
@@ -732,12 +816,6 @@ static void async_resume(void *data, async_cookie_t cookie)
        put_device(dev);
 }
 
-static bool is_async(struct device *dev)
-{
-       return dev->power.async_suspend && pm_async_enabled
-               && !pm_trace_is_enabled();
-}
-
 /**
  * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
  * @state: PM transition of the system being carried out.
@@ -789,6 +867,8 @@ void dpm_resume(pm_message_t state)
        mutex_unlock(&dpm_list_mtx);
        async_synchronize_full();
        dpm_show_time(starttime, state, NULL);
+
+       cpufreq_resume();
 }
 
 /**
@@ -913,13 +993,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
  * The driver of @dev will not receive interrupts while this function is being
  * executed.
  */
-static int device_suspend_noirq(struct device *dev, pm_message_t state)
+static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
 {
        pm_callback_t callback = NULL;
        char *info = NULL;
+       int error = 0;
+
+       if (async_error)
+               goto Complete;
+
+       if (pm_wakeup_pending()) {
+               async_error = -EBUSY;
+               goto Complete;
+       }
 
        if (dev->power.syscore)
-               return 0;
+               goto Complete;
+
+       dpm_wait_for_children(dev, async);
 
        if (dev->pm_domain) {
                info = "noirq power domain ";
@@ -940,7 +1031,41 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
                callback = pm_noirq_op(dev->driver->pm, state);
        }
 
-       return dpm_run_callback(callback, dev, state, info);
+       error = dpm_run_callback(callback, dev, state, info);
+       if (!error)
+               dev->power.is_noirq_suspended = true;
+       else
+               async_error = error;
+
+Complete:
+       complete_all(&dev->power.completion);
+       return error;
+}
+
+static void async_suspend_noirq(void *data, async_cookie_t cookie)
+{
+       struct device *dev = (struct device *)data;
+       int error;
+
+       error = __device_suspend_noirq(dev, pm_transition, true);
+       if (error) {
+               dpm_save_failed_dev(dev_name(dev));
+               pm_dev_err(dev, pm_transition, " async", error);
+       }
+
+       put_device(dev);
+}
+
+static int device_suspend_noirq(struct device *dev)
+{
+       reinit_completion(&dev->power.completion);
+
+       if (pm_async_enabled && dev->power.async_suspend) {
+               get_device(dev);
+               async_schedule(async_suspend_noirq, dev);
+               return 0;
+       }
+       return __device_suspend_noirq(dev, pm_transition, false);
 }
 
 /**
@@ -958,19 +1083,20 @@ static int dpm_suspend_noirq(pm_message_t state)
        cpuidle_pause();
        suspend_device_irqs();
        mutex_lock(&dpm_list_mtx);
+       pm_transition = state;
+       async_error = 0;
+
        while (!list_empty(&dpm_late_early_list)) {
                struct device *dev = to_device(dpm_late_early_list.prev);
 
                get_device(dev);
                mutex_unlock(&dpm_list_mtx);
 
-               error = device_suspend_noirq(dev, state);
+               error = device_suspend_noirq(dev);
 
                mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, " noirq", error);
-                       suspend_stats.failed_suspend_noirq++;
-                       dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
                        dpm_save_failed_dev(dev_name(dev));
                        put_device(dev);
                        break;
@@ -979,16 +1105,21 @@ static int dpm_suspend_noirq(pm_message_t state)
                        list_move(&dev->power.entry, &dpm_noirq_list);
                put_device(dev);
 
-               if (pm_wakeup_pending()) {
-                       error = -EBUSY;
+               if (async_error)
                        break;
-               }
        }
        mutex_unlock(&dpm_list_mtx);
-       if (error)
+       async_synchronize_full();
+       if (!error)
+               error = async_error;
+
+       if (error) {
+               suspend_stats.failed_suspend_noirq++;
+               dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
                dpm_resume_noirq(resume_event(state));
-       else
+       } else {
                dpm_show_time(starttime, state, "noirq");
+       }
        return error;
 }
 
@@ -999,15 +1130,26 @@ static int dpm_suspend_noirq(pm_message_t state)
  *
  * Runtime PM is disabled for @dev while this function is being executed.
  */
-static int device_suspend_late(struct device *dev, pm_message_t state)
+static int __device_suspend_late(struct device *dev, pm_message_t state, bool async)
 {
        pm_callback_t callback = NULL;
        char *info = NULL;
+       int error = 0;
 
        __pm_runtime_disable(dev, false);
 
+       if (async_error)
+               goto Complete;
+
+       if (pm_wakeup_pending()) {
+               async_error = -EBUSY;
+               goto Complete;
+       }
+
        if (dev->power.syscore)
-               return 0;
+               goto Complete;
+
+       dpm_wait_for_children(dev, async);
 
        if (dev->pm_domain) {
                info = "late power domain ";
@@ -1028,7 +1170,41 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
                callback = pm_late_early_op(dev->driver->pm, state);
        }
 
-       return dpm_run_callback(callback, dev, state, info);
+       error = dpm_run_callback(callback, dev, state, info);
+       if (!error)
+               dev->power.is_late_suspended = true;
+       else
+               async_error = error;
+
+Complete:
+       complete_all(&dev->power.completion);
+       return error;
+}
+
+static void async_suspend_late(void *data, async_cookie_t cookie)
+{
+       struct device *dev = (struct device *)data;
+       int error;
+
+       error = __device_suspend_late(dev, pm_transition, true);
+       if (error) {
+               dpm_save_failed_dev(dev_name(dev));
+               pm_dev_err(dev, pm_transition, " async", error);
+       }
+       put_device(dev);
+}
+
+static int device_suspend_late(struct device *dev)
+{
+       reinit_completion(&dev->power.completion);
+
+       if (pm_async_enabled && dev->power.async_suspend) {
+               get_device(dev);
+               async_schedule(async_suspend_late, dev);
+               return 0;
+       }
+
+       return __device_suspend_late(dev, pm_transition, false);
 }
 
 /**
@@ -1041,19 +1217,20 @@ static int dpm_suspend_late(pm_message_t state)
        int error = 0;
 
        mutex_lock(&dpm_list_mtx);
+       pm_transition = state;
+       async_error = 0;
+
        while (!list_empty(&dpm_suspended_list)) {
                struct device *dev = to_device(dpm_suspended_list.prev);
 
                get_device(dev);
                mutex_unlock(&dpm_list_mtx);
 
-               error = device_suspend_late(dev, state);
+               error = device_suspend_late(dev);
 
                mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, " late", error);
-                       suspend_stats.failed_suspend_late++;
-                       dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
                        dpm_save_failed_dev(dev_name(dev));
                        put_device(dev);
                        break;
@@ -1062,17 +1239,18 @@ static int dpm_suspend_late(pm_message_t state)
                        list_move(&dev->power.entry, &dpm_late_early_list);
                put_device(dev);
 
-               if (pm_wakeup_pending()) {
-                       error = -EBUSY;
+               if (async_error)
                        break;
-               }
        }
        mutex_unlock(&dpm_list_mtx);
-       if (error)
+       async_synchronize_full();
+       if (error) {
+               suspend_stats.failed_suspend_late++;
+               dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
                dpm_resume_early(resume_event(state));
-       else
+       } else {
                dpm_show_time(starttime, state, "late");
-
+       }
        return error;
 }
 
@@ -1259,6 +1437,8 @@ int dpm_suspend(pm_message_t state)
 
        might_sleep();
 
+       cpufreq_suspend();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
index cfc3226ec4928dee99ff95540eed87af1058d5af..a21223d95926fe2d5207ae445f61fe6c79d86e78 100644 (file)
@@ -89,8 +89,8 @@ extern void dpm_sysfs_remove(struct device *dev);
 extern void rpm_sysfs_remove(struct device *dev);
 extern int wakeup_sysfs_add(struct device *dev);
 extern void wakeup_sysfs_remove(struct device *dev);
-extern int pm_qos_sysfs_add_latency(struct device *dev);
-extern void pm_qos_sysfs_remove_latency(struct device *dev);
+extern int pm_qos_sysfs_add_resume_latency(struct device *dev);
+extern void pm_qos_sysfs_remove_resume_latency(struct device *dev);
 extern int pm_qos_sysfs_add_flags(struct device *dev);
 extern void pm_qos_sysfs_remove_flags(struct device *dev);
 
index 5c1361a9e5dd58049c3835d414f42607cdb46411..36b9eb4862cb96e2561321500982730e4ff1587f 100644 (file)
@@ -105,7 +105,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
 s32 __dev_pm_qos_read_value(struct device *dev)
 {
        return IS_ERR_OR_NULL(dev->power.qos) ?
-               0 : pm_qos_read_value(&dev->power.qos->latency);
+               0 : pm_qos_read_value(&dev->power.qos->resume_latency);
 }
 
 /**
@@ -141,16 +141,24 @@ static int apply_constraint(struct dev_pm_qos_request *req,
        int ret;
 
        switch(req->type) {
-       case DEV_PM_QOS_LATENCY:
-               ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
-                                          action, value);
+       case DEV_PM_QOS_RESUME_LATENCY:
+               ret = pm_qos_update_target(&qos->resume_latency,
+                                          &req->data.pnode, action, value);
                if (ret) {
-                       value = pm_qos_read_value(&qos->latency);
+                       value = pm_qos_read_value(&qos->resume_latency);
                        blocking_notifier_call_chain(&dev_pm_notifiers,
                                                     (unsigned long)value,
                                                     req);
                }
                break;
+       case DEV_PM_QOS_LATENCY_TOLERANCE:
+               ret = pm_qos_update_target(&qos->latency_tolerance,
+                                          &req->data.pnode, action, value);
+               if (ret) {
+                       value = pm_qos_read_value(&qos->latency_tolerance);
+                       req->dev->power.set_latency_tolerance(req->dev, value);
+               }
+               break;
        case DEV_PM_QOS_FLAGS:
                ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
                                          action, value);
@@ -186,13 +194,21 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        }
        BLOCKING_INIT_NOTIFIER_HEAD(n);
 
-       c = &qos->latency;
+       c = &qos->resume_latency;
        plist_head_init(&c->list);
-       c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
-       c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+       c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+       c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+       c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
        c->type = PM_QOS_MIN;
        c->notifiers = n;
 
+       c = &qos->latency_tolerance;
+       plist_head_init(&c->list);
+       c->target_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
+       c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
+       c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
+       c->type = PM_QOS_MIN;
+
        INIT_LIST_HEAD(&qos->flags.list);
 
        spin_lock_irq(&dev->power.lock);
@@ -224,7 +240,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
         * If the device's PM QoS resume latency limit or PM QoS flags have been
         * exposed to user space, they have to be hidden at this point.
         */
-       pm_qos_sysfs_remove_latency(dev);
+       pm_qos_sysfs_remove_resume_latency(dev);
        pm_qos_sysfs_remove_flags(dev);
 
        mutex_lock(&dev_pm_qos_mtx);
@@ -237,7 +253,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
                goto out;
 
        /* Flush the constraints lists for the device. */
-       c = &qos->latency;
+       c = &qos->resume_latency;
        plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
                /*
                 * Update constraints list and call the notification
@@ -246,6 +262,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
                memset(req, 0, sizeof(*req));
        }
+       c = &qos->latency_tolerance;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
        f = &qos->flags;
        list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -265,6 +286,40 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
        mutex_unlock(&dev_pm_qos_sysfs_mtx);
 }
 
+static bool dev_pm_qos_invalid_request(struct device *dev,
+                                      struct dev_pm_qos_request *req)
+{
+       return !req || (req->type == DEV_PM_QOS_LATENCY_TOLERANCE
+                       && !dev->power.set_latency_tolerance);
+}
+
+static int __dev_pm_qos_add_request(struct device *dev,
+                                   struct dev_pm_qos_request *req,
+                                   enum dev_pm_qos_req_type type, s32 value)
+{
+       int ret = 0;
+
+       if (!dev || dev_pm_qos_invalid_request(dev, req))
+               return -EINVAL;
+
+       if (WARN(dev_pm_qos_request_active(req),
+                "%s() called for already added request\n", __func__))
+               return -EINVAL;
+
+       if (IS_ERR(dev->power.qos))
+               ret = -ENODEV;
+       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;
+               ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
+       }
+       return ret;
+}
+
 /**
  * dev_pm_qos_add_request - inserts new qos request into the list
  * @dev: target device for the constraint
@@ -290,31 +345,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
 int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
                           enum dev_pm_qos_req_type type, s32 value)
 {
-       int ret = 0;
-
-       if (!dev || !req) /*guard against callers passing in null */
-               return -EINVAL;
-
-       if (WARN(dev_pm_qos_request_active(req),
-                "%s() called for already added request\n", __func__))
-               return -EINVAL;
+       int ret;
 
        mutex_lock(&dev_pm_qos_mtx);
-
-       if (IS_ERR(dev->power.qos))
-               ret = -ENODEV;
-       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;
-               ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
-       }
-
+       ret = __dev_pm_qos_add_request(dev, req, type, value);
        mutex_unlock(&dev_pm_qos_mtx);
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
@@ -341,7 +376,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
                return -ENODEV;
 
        switch(req->type) {
-       case DEV_PM_QOS_LATENCY:
+       case DEV_PM_QOS_RESUME_LATENCY:
+       case DEV_PM_QOS_LATENCY_TOLERANCE:
                curr_value = req->data.pnode.prio;
                break;
        case DEV_PM_QOS_FLAGS:
@@ -460,8 +496,8 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
                ret = dev_pm_qos_constraints_allocate(dev);
 
        if (!ret)
-               ret = blocking_notifier_chain_register(
-                               dev->power.qos->latency.notifiers, notifier);
+               ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
+                                                      notifier);
 
        mutex_unlock(&dev_pm_qos_mtx);
        return ret;
@@ -487,9 +523,8 @@ int dev_pm_qos_remove_notifier(struct device *dev,
 
        /* Silently return if the constraints object is not present. */
        if (!IS_ERR_OR_NULL(dev->power.qos))
-               retval = blocking_notifier_chain_unregister(
-                               dev->power.qos->latency.notifiers,
-                               notifier);
+               retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
+                                                           notifier);
 
        mutex_unlock(&dev_pm_qos_mtx);
        return retval;
@@ -530,20 +565,32 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
  * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
  * @dev: Device whose ancestor to add the request for.
  * @req: Pointer to the preallocated handle.
+ * @type: Type of the request.
  * @value: Constraint latency value.
  */
 int dev_pm_qos_add_ancestor_request(struct device *dev,
-                                   struct dev_pm_qos_request *req, s32 value)
+                                   struct dev_pm_qos_request *req,
+                                   enum dev_pm_qos_req_type type, s32 value)
 {
        struct device *ancestor = dev->parent;
        int ret = -ENODEV;
 
-       while (ancestor && !ancestor->power.ignore_children)
-               ancestor = ancestor->parent;
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
+               while (ancestor && !ancestor->power.ignore_children)
+                       ancestor = ancestor->parent;
 
+               break;
+       case DEV_PM_QOS_LATENCY_TOLERANCE:
+               while (ancestor && !ancestor->power.set_latency_tolerance)
+                       ancestor = ancestor->parent;
+
+               break;
+       default:
+               ancestor = NULL;
+       }
        if (ancestor)
-               ret = dev_pm_qos_add_request(ancestor, req,
-                                            DEV_PM_QOS_LATENCY, value);
+               ret = dev_pm_qos_add_request(ancestor, req, type, value);
 
        if (ret < 0)
                req->dev = NULL;
@@ -559,9 +606,13 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
        struct dev_pm_qos_request *req = NULL;
 
        switch(type) {
-       case DEV_PM_QOS_LATENCY:
-               req = dev->power.qos->latency_req;
-               dev->power.qos->latency_req = NULL;
+       case DEV_PM_QOS_RESUME_LATENCY:
+               req = dev->power.qos->resume_latency_req;
+               dev->power.qos->resume_latency_req = NULL;
+               break;
+       case DEV_PM_QOS_LATENCY_TOLERANCE:
+               req = dev->power.qos->latency_tolerance_req;
+               dev->power.qos->latency_tolerance_req = NULL;
                break;
        case DEV_PM_QOS_FLAGS:
                req = dev->power.qos->flags_req;
@@ -597,7 +648,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
        if (!req)
                return -ENOMEM;
 
-       ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
+       ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_RESUME_LATENCY, value);
        if (ret < 0) {
                kfree(req);
                return ret;
@@ -609,7 +660,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
 
        if (IS_ERR_OR_NULL(dev->power.qos))
                ret = -ENODEV;
-       else if (dev->power.qos->latency_req)
+       else if (dev->power.qos->resume_latency_req)
                ret = -EEXIST;
 
        if (ret < 0) {
@@ -618,13 +669,13 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
                mutex_unlock(&dev_pm_qos_mtx);
                goto out;
        }
-       dev->power.qos->latency_req = req;
+       dev->power.qos->resume_latency_req = req;
 
        mutex_unlock(&dev_pm_qos_mtx);
 
-       ret = pm_qos_sysfs_add_latency(dev);
+       ret = pm_qos_sysfs_add_resume_latency(dev);
        if (ret)
-               dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+               dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
 
  out:
        mutex_unlock(&dev_pm_qos_sysfs_mtx);
@@ -634,8 +685,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
 
 static void __dev_pm_qos_hide_latency_limit(struct device *dev)
 {
-       if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
-               __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+       if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->resume_latency_req)
+               __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
 }
 
 /**
@@ -646,7 +697,7 @@ void dev_pm_qos_hide_latency_limit(struct device *dev)
 {
        mutex_lock(&dev_pm_qos_sysfs_mtx);
 
-       pm_qos_sysfs_remove_latency(dev);
+       pm_qos_sysfs_remove_resume_latency(dev);
 
        mutex_lock(&dev_pm_qos_mtx);
        __dev_pm_qos_hide_latency_limit(dev);
@@ -768,6 +819,67 @@ int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
        pm_runtime_put(dev);
        return ret;
 }
+
+/**
+ * dev_pm_qos_get_user_latency_tolerance - Get user space latency tolerance.
+ * @dev: Device to obtain the user space latency tolerance for.
+ */
+s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
+{
+       s32 ret;
+
+       mutex_lock(&dev_pm_qos_mtx);
+       ret = IS_ERR_OR_NULL(dev->power.qos)
+               || !dev->power.qos->latency_tolerance_req ?
+                       PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
+                       dev->power.qos->latency_tolerance_req->data.pnode.prio;
+       mutex_unlock(&dev_pm_qos_mtx);
+       return ret;
+}
+
+/**
+ * dev_pm_qos_update_user_latency_tolerance - Update user space latency tolerance.
+ * @dev: Device to update the user space latency tolerance for.
+ * @val: New user space latency tolerance for @dev (negative values disable).
+ */
+int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
+{
+       int ret;
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       if (IS_ERR_OR_NULL(dev->power.qos)
+           || !dev->power.qos->latency_tolerance_req) {
+               struct dev_pm_qos_request *req;
+
+               if (val < 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               req = kzalloc(sizeof(*req), GFP_KERNEL);
+               if (!req) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               ret = __dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY_TOLERANCE, val);
+               if (ret < 0) {
+                       kfree(req);
+                       goto out;
+               }
+               dev->power.qos->latency_tolerance_req = req;
+       } else {
+               if (val < 0) {
+                       __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY_TOLERANCE);
+                       ret = 0;
+               } else {
+                       ret = __dev_pm_qos_update_request(dev->power.qos->latency_tolerance_req, val);
+               }
+       }
+
+ out:
+       mutex_unlock(&dev_pm_qos_mtx);
+       return ret;
+}
 #else /* !CONFIG_PM_RUNTIME */
 static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
 static void __dev_pm_qos_hide_flags(struct device *dev) {}
index 72e00e66ecc5d3f84c6d2cce5f6d387c3d4ee260..67c7938e430bbd87d706fb03688de83a2641cb7f 100644 (file)
 #include <trace/events/rpm.h>
 #include "power.h"
 
+#define RPM_GET_CALLBACK(dev, cb)                              \
+({                                                             \
+       int (*__rpm_cb)(struct device *__d);                    \
+                                                               \
+       if (dev->pm_domain)                                     \
+               __rpm_cb = dev->pm_domain->ops.cb;              \
+       else if (dev->type && dev->type->pm)                    \
+               __rpm_cb = dev->type->pm->cb;                   \
+       else if (dev->class && dev->class->pm)                  \
+               __rpm_cb = dev->class->pm->cb;                  \
+       else if (dev->bus && dev->bus->pm)                      \
+               __rpm_cb = dev->bus->pm->cb;                    \
+       else                                                    \
+               __rpm_cb = NULL;                                \
+                                                               \
+       if (!__rpm_cb && dev->driver && dev->driver->pm)        \
+               __rpm_cb = dev->driver->pm->cb;                 \
+                                                               \
+       __rpm_cb;                                               \
+})
+
+static int (*rpm_get_suspend_cb(struct device *dev))(struct device *)
+{
+       return RPM_GET_CALLBACK(dev, runtime_suspend);
+}
+
+static int (*rpm_get_resume_cb(struct device *dev))(struct device *)
+{
+       return RPM_GET_CALLBACK(dev, runtime_resume);
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int (*rpm_get_idle_cb(struct device *dev))(struct device *)
+{
+       return RPM_GET_CALLBACK(dev, runtime_idle);
+}
+
 static int rpm_resume(struct device *dev, int rpmflags);
 static int rpm_suspend(struct device *dev, int rpmflags);
 
@@ -310,19 +347,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
 
        dev->power.idle_notification = true;
 
-       if (dev->pm_domain)
-               callback = dev->pm_domain->ops.runtime_idle;
-       else if (dev->type && dev->type->pm)
-               callback = dev->type->pm->runtime_idle;
-       else if (dev->class && dev->class->pm)
-               callback = dev->class->pm->runtime_idle;
-       else if (dev->bus && dev->bus->pm)
-               callback = dev->bus->pm->runtime_idle;
-       else
-               callback = NULL;
-
-       if (!callback && dev->driver && dev->driver->pm)
-               callback = dev->driver->pm->runtime_idle;
+       callback = rpm_get_idle_cb(dev);
 
        if (callback)
                retval = __rpm_callback(callback, dev);
@@ -492,19 +517,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
 
        __update_runtime_status(dev, RPM_SUSPENDING);
 
-       if (dev->pm_domain)
-               callback = dev->pm_domain->ops.runtime_suspend;
-       else if (dev->type && dev->type->pm)
-               callback = dev->type->pm->runtime_suspend;
-       else if (dev->class && dev->class->pm)
-               callback = dev->class->pm->runtime_suspend;
-       else if (dev->bus && dev->bus->pm)
-               callback = dev->bus->pm->runtime_suspend;
-       else
-               callback = NULL;
-
-       if (!callback && dev->driver && dev->driver->pm)
-               callback = dev->driver->pm->runtime_suspend;
+       callback = rpm_get_suspend_cb(dev);
 
        retval = rpm_callback(callback, dev);
        if (retval)
@@ -724,19 +737,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
 
        __update_runtime_status(dev, RPM_RESUMING);
 
-       if (dev->pm_domain)
-               callback = dev->pm_domain->ops.runtime_resume;
-       else if (dev->type && dev->type->pm)
-               callback = dev->type->pm->runtime_resume;
-       else if (dev->class && dev->class->pm)
-               callback = dev->class->pm->runtime_resume;
-       else if (dev->bus && dev->bus->pm)
-               callback = dev->bus->pm->runtime_resume;
-       else
-               callback = NULL;
-
-       if (!callback && dev->driver && dev->driver->pm)
-               callback = dev->driver->pm->runtime_resume;
+       callback = rpm_get_resume_cb(dev);
 
        retval = rpm_callback(callback, dev);
        if (retval) {
@@ -1130,7 +1131,7 @@ EXPORT_SYMBOL_GPL(pm_runtime_barrier);
  * @dev: Device to handle.
  * @check_resume: If set, check if there's a resume request for the device.
  *
- * Increment power.disable_depth for the device and if was zero previously,
+ * Increment power.disable_depth for the device and if it was zero previously,
  * cancel all pending runtime PM requests for the device and wait for all
  * operations in progress to complete.  The device can be either active or
  * suspended after its runtime PM has been disabled.
@@ -1401,3 +1402,86 @@ void pm_runtime_remove(struct device *dev)
        if (dev->power.irq_safe && dev->parent)
                pm_runtime_put(dev->parent);
 }
+#endif
+
+/**
+ * pm_runtime_force_suspend - Force a device into suspend state if needed.
+ * @dev: Device to suspend.
+ *
+ * Disable runtime PM so we safely can check the device's runtime PM status and
+ * if it is active, invoke it's .runtime_suspend callback to bring it into
+ * suspend state. Keep runtime PM disabled to preserve the state unless we
+ * encounter errors.
+ *
+ * Typically this function may be invoked from a system suspend callback to make
+ * sure the device is put into low power state.
+ */
+int pm_runtime_force_suspend(struct device *dev)
+{
+       int (*callback)(struct device *);
+       int ret = 0;
+
+       pm_runtime_disable(dev);
+
+       /*
+        * Note that pm_runtime_status_suspended() returns false while
+        * !CONFIG_PM_RUNTIME, which means the device will be put into low
+        * power state.
+        */
+       if (pm_runtime_status_suspended(dev))
+               return 0;
+
+       callback = rpm_get_suspend_cb(dev);
+
+       if (!callback) {
+               ret = -ENOSYS;
+               goto err;
+       }
+
+       ret = callback(dev);
+       if (ret)
+               goto err;
+
+       pm_runtime_set_suspended(dev);
+       return 0;
+err:
+       pm_runtime_enable(dev);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
+
+/**
+ * pm_runtime_force_resume - Force a device into resume state.
+ * @dev: Device to resume.
+ *
+ * Prior invoking this function we expect the user to have brought the device
+ * into low power state by a call to pm_runtime_force_suspend(). Here we reverse
+ * those actions and brings the device into full power. We update the runtime PM
+ * status and re-enables runtime PM.
+ *
+ * Typically this function may be invoked from a system resume callback to make
+ * sure the device is put into full power state.
+ */
+int pm_runtime_force_resume(struct device *dev)
+{
+       int (*callback)(struct device *);
+       int ret = 0;
+
+       callback = rpm_get_resume_cb(dev);
+
+       if (!callback) {
+               ret = -ENOSYS;
+               goto out;
+       }
+
+       ret = callback(dev);
+       if (ret)
+               goto out;
+
+       pm_runtime_set_active(dev);
+       pm_runtime_mark_last_busy(dev);
+out:
+       pm_runtime_enable(dev);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
index 03e089ade5cef214227b54cd889dedcf08217a1a..95b181d1ca6df76d1b3a355e6a7bffca3aa26854 100644 (file)
@@ -218,15 +218,16 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
 static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
                autosuspend_delay_ms_store);
 
-static ssize_t pm_qos_latency_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t pm_qos_resume_latency_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
 {
-       return sprintf(buf, "%d\n", dev_pm_qos_requested_latency(dev));
+       return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
 }
 
-static ssize_t pm_qos_latency_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t n)
+static ssize_t pm_qos_resume_latency_store(struct device *dev,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t n)
 {
        s32 value;
        int ret;
@@ -237,12 +238,47 @@ static ssize_t pm_qos_latency_store(struct device *dev,
        if (value < 0)
                return -EINVAL;
 
-       ret = dev_pm_qos_update_request(dev->power.qos->latency_req, value);
+       ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
+                                       value);
        return ret < 0 ? ret : n;
 }
 
 static DEVICE_ATTR(pm_qos_resume_latency_us, 0644,
-                  pm_qos_latency_show, pm_qos_latency_store);
+                  pm_qos_resume_latency_show, pm_qos_resume_latency_store);
+
+static ssize_t pm_qos_latency_tolerance_show(struct device *dev,
+                                            struct device_attribute *attr,
+                                            char *buf)
+{
+       s32 value = dev_pm_qos_get_user_latency_tolerance(dev);
+
+       if (value < 0)
+               return sprintf(buf, "auto\n");
+       else if (value == PM_QOS_LATENCY_ANY)
+               return sprintf(buf, "any\n");
+
+       return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t pm_qos_latency_tolerance_store(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t n)
+{
+       s32 value;
+       int ret;
+
+       if (kstrtos32(buf, 0, &value)) {
+               if (!strcmp(buf, "auto") || !strcmp(buf, "auto\n"))
+                       value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
+               else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
+                       value = PM_QOS_LATENCY_ANY;
+       }
+       ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
+       return ret < 0 ? ret : n;
+}
+
+static DEVICE_ATTR(pm_qos_latency_tolerance_us, 0644,
+                  pm_qos_latency_tolerance_show, pm_qos_latency_tolerance_store);
 
 static ssize_t pm_qos_no_power_off_show(struct device *dev,
                                        struct device_attribute *attr,
@@ -618,15 +654,26 @@ static struct attribute_group pm_runtime_attr_group = {
        .attrs  = runtime_attrs,
 };
 
-static struct attribute *pm_qos_latency_attrs[] = {
+static struct attribute *pm_qos_resume_latency_attrs[] = {
 #ifdef CONFIG_PM_RUNTIME
        &dev_attr_pm_qos_resume_latency_us.attr,
 #endif /* CONFIG_PM_RUNTIME */
        NULL,
 };
-static struct attribute_group pm_qos_latency_attr_group = {
+static struct attribute_group pm_qos_resume_latency_attr_group = {
+       .name   = power_group_name,
+       .attrs  = pm_qos_resume_latency_attrs,
+};
+
+static struct attribute *pm_qos_latency_tolerance_attrs[] = {
+#ifdef CONFIG_PM_RUNTIME
+       &dev_attr_pm_qos_latency_tolerance_us.attr,
+#endif /* CONFIG_PM_RUNTIME */
+       NULL,
+};
+static struct attribute_group pm_qos_latency_tolerance_attr_group = {
        .name   = power_group_name,
-       .attrs  = pm_qos_latency_attrs,
+       .attrs  = pm_qos_latency_tolerance_attrs,
 };
 
 static struct attribute *pm_qos_flags_attrs[] = {
@@ -654,18 +701,23 @@ int dpm_sysfs_add(struct device *dev)
                if (rc)
                        goto err_out;
        }
-
        if (device_can_wakeup(dev)) {
                rc = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
-               if (rc) {
-                       if (pm_runtime_callbacks_present(dev))
-                               sysfs_unmerge_group(&dev->kobj,
-                                                   &pm_runtime_attr_group);
-                       goto err_out;
-               }
+               if (rc)
+                       goto err_runtime;
+       }
+       if (dev->power.set_latency_tolerance) {
+               rc = sysfs_merge_group(&dev->kobj,
+                                      &pm_qos_latency_tolerance_attr_group);
+               if (rc)
+                       goto err_wakeup;
        }
        return 0;
 
+ err_wakeup:
+       sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
+ err_runtime:
+       sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
  err_out:
        sysfs_remove_group(&dev->kobj, &pm_attr_group);
        return rc;
@@ -681,14 +733,14 @@ void wakeup_sysfs_remove(struct device *dev)
        sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
 }
 
-int pm_qos_sysfs_add_latency(struct device *dev)
+int pm_qos_sysfs_add_resume_latency(struct device *dev)
 {
-       return sysfs_merge_group(&dev->kobj, &pm_qos_latency_attr_group);
+       return sysfs_merge_group(&dev->kobj, &pm_qos_resume_latency_attr_group);
 }
 
-void pm_qos_sysfs_remove_latency(struct device *dev)
+void pm_qos_sysfs_remove_resume_latency(struct device *dev)
 {
-       sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_attr_group);
+       sysfs_unmerge_group(&dev->kobj, &pm_qos_resume_latency_attr_group);
 }
 
 int pm_qos_sysfs_add_flags(struct device *dev)
@@ -708,6 +760,7 @@ void rpm_sysfs_remove(struct device *dev)
 
 void dpm_sysfs_remove(struct device *dev)
 {
+       sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
        dev_pm_qos_constraints_destroy(dev);
        rpm_sysfs_remove(dev);
        sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
index 33414b1de2013b8e3fc68f31a70f8a56f2900cbe..7d1326985bee8b4d3e9dcb326bf795622901bf49 100644 (file)
@@ -134,6 +134,8 @@ struct regmap {
 
        /* if set, converts bulk rw to single rw */
        bool use_single_rw;
+       /* if set, the device supports multi write mode */
+       bool can_multi_write;
 
        struct rb_root range_tree;
        void *selector_work_buf;        /* Scratch buffer used for selector */
index d4dd77134814bac1a8ba2bc91a817c1cc2002454..29b4128da0b08ce6b8eda048557ed9093b07efa0 100644 (file)
@@ -249,11 +249,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
 {
        unsigned int reg;
 
-       for (reg = min; reg <= max; reg++) {
+       for (reg = min; reg <= max; reg += map->reg_stride) {
                unsigned int val;
                int ret;
 
-               if (regmap_volatile(map, reg))
+               if (regmap_volatile(map, reg) ||
+                   !regmap_writeable(map, reg))
                        continue;
 
                ret = regcache_read(map, reg, &val);
@@ -312,10 +313,6 @@ int regcache_sync(struct regmap *map)
        /* Apply any patch first */
        map->cache_bypass = 1;
        for (i = 0; i < map->patch_regs; i++) {
-               if (map->patch[i].reg % map->reg_stride) {
-                       ret = -EINVAL;
-                       goto out;
-               }
                ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
                if (ret != 0) {
                        dev_err(map->dev, "Failed to write %x = %x: %d\n",
@@ -636,10 +633,10 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
        if (*data == NULL)
                return 0;
 
-       count = cur - base;
+       count = (cur - base) / map->reg_stride;
 
        dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n",
-               count * val_bytes, count, base, cur - 1);
+               count * val_bytes, count, base, cur - map->reg_stride);
 
        map->cache_bypass = 1;
 
index c5471cd6ebb7bc78f1e8e63e0d4330e37835e5ca..45d812c0ea7751868d3d14d7691da6f74493b54a 100644 (file)
@@ -511,7 +511,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
        debugfs_create_file("range", 0400, map->debugfs,
                            map, &regmap_reg_ranges_fops);
 
-       if (map->max_register) {
+       if (map->max_register || regmap_readable(map, 0)) {
                debugfs_create_file("registers", 0400, map->debugfs,
                                    map, &regmap_map_fops);
                debugfs_create_file("access", 0400, map->debugfs,
index 82692068d3cbe8dfa4cc5fdb6b544b74168255ea..edf88f20cbce8df434058b18f772393e781b4547 100644 (file)
@@ -368,8 +368,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        if (!d)
                return -ENOMEM;
 
-       *data = d;
-
        d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
                                GFP_KERNEL);
        if (!d->status_buf)
@@ -506,6 +504,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                goto err_domain;
        }
 
+       *data = d;
+
        return 0;
 
 err_domain:
@@ -533,7 +533,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
                return;
 
        free_irq(irq, d);
-       /* We should unmap the domain but... */
+       irq_domain_remove(d->domain);
        kfree(d->wake_buf);
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
index 4410cb2d7d8206bf7eada6e69d4f8994b9a5026e..1e03e7f8bacb220a47d0edf29700f6a1814fc21e 100644 (file)
 
 struct regmap_mmio_context {
        void __iomem *regs;
+       unsigned reg_bytes;
        unsigned val_bytes;
+       unsigned pad_bytes;
        struct clk *clk;
 };
 
+static inline void regmap_mmio_regsize_check(size_t reg_size)
+{
+       switch (reg_size) {
+       case 1:
+       case 2:
+       case 4:
+#ifdef CONFIG_64BIT
+       case 8:
+#endif
+               break;
+       default:
+               BUG();
+       }
+}
+
+static int regmap_mmio_regbits_check(size_t reg_bits)
+{
+       switch (reg_bits) {
+       case 8:
+       case 16:
+       case 32:
+#ifdef CONFIG_64BIT
+       case 64:
+#endif
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static inline void regmap_mmio_count_check(size_t count)
+{
+       BUG_ON(count % 2 != 0);
+}
+
 static int regmap_mmio_gather_write(void *context,
                                    const void *reg, size_t reg_size,
                                    const void *val, size_t val_size)
@@ -37,7 +74,7 @@ static int regmap_mmio_gather_write(void *context,
        u32 offset;
        int ret;
 
-       BUG_ON(reg_size != 4);
+       regmap_mmio_regsize_check(reg_size);
 
        if (!IS_ERR(ctx->clk)) {
                ret = clk_enable(ctx->clk);
@@ -80,9 +117,13 @@ static int regmap_mmio_gather_write(void *context,
 
 static int regmap_mmio_write(void *context, const void *data, size_t count)
 {
-       BUG_ON(count < 4);
+       struct regmap_mmio_context *ctx = context;
+       u32 offset = ctx->reg_bytes + ctx->pad_bytes;
+
+       regmap_mmio_count_check(count);
 
-       return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
+       return regmap_mmio_gather_write(context, data, ctx->reg_bytes,
+                                       data + offset, count - offset);
 }
 
 static int regmap_mmio_read(void *context,
@@ -93,7 +134,7 @@ static int regmap_mmio_read(void *context,
        u32 offset;
        int ret;
 
-       BUG_ON(reg_size != 4);
+       regmap_mmio_regsize_check(reg_size);
 
        if (!IS_ERR(ctx->clk)) {
                ret = clk_enable(ctx->clk);
@@ -164,8 +205,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
        int min_stride;
        int ret;
 
-       if (config->reg_bits != 32)
-               return ERR_PTR(-EINVAL);
+       ret = regmap_mmio_regbits_check(config->reg_bits);
+       if (ret)
+               return ERR_PTR(ret);
 
        if (config->pad_bits)
                return ERR_PTR(-EINVAL);
@@ -208,6 +250,8 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
 
        ctx->regs = regs;
        ctx->val_bytes = config->val_bits / 8;
+       ctx->reg_bytes = config->reg_bits / 8;
+       ctx->pad_bytes = config->pad_bits / 8;
        ctx->clk = ERR_PTR(-ENODEV);
 
        if (clk_id == NULL)
index ac2391013db16f96fd76497c8743f69401c712f0..d7026dc33388aada6003886d14d8d73f264b56a9 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 
-static int regmap_spmi_read(void *context,
-                           const void *reg, size_t reg_size,
-                           void *val, size_t val_size)
+static int regmap_spmi_base_read(void *context,
+                                const void *reg, size_t reg_size,
+                                void *val, size_t val_size)
 {
+       u8 addr = *(u8 *)reg;
+       int err = 0;
+
+       BUG_ON(reg_size != 1);
+
+       while (val_size-- && !err)
+               err = spmi_register_read(context, addr++, val++);
+
+       return err;
+}
+
+static int regmap_spmi_base_gather_write(void *context,
+                                        const void *reg, size_t reg_size,
+                                        const void *val, size_t val_size)
+{
+       const u8 *data = val;
+       u8 addr = *(u8 *)reg;
+       int err = 0;
+
+       BUG_ON(reg_size != 1);
+
+       /*
+        * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
+        * use it when possible.
+        */
+       if (addr == 0 && val_size) {
+               err = spmi_register_zero_write(context, *data);
+               if (err)
+                       goto err_out;
+
+               data++;
+               addr++;
+               val_size--;
+       }
+
+       while (val_size) {
+               err = spmi_register_write(context, addr, *data);
+               if (err)
+                       goto err_out;
+
+               data++;
+               addr++;
+               val_size--;
+       }
+
+err_out:
+       return err;
+}
+
+static int regmap_spmi_base_write(void *context, const void *data,
+                                 size_t count)
+{
+       BUG_ON(count < 1);
+       return regmap_spmi_base_gather_write(context, data, 1, data + 1,
+                                            count - 1);
+}
+
+static struct regmap_bus regmap_spmi_base = {
+       .read                           = regmap_spmi_base_read,
+       .write                          = regmap_spmi_base_write,
+       .gather_write                   = regmap_spmi_base_gather_write,
+       .reg_format_endian_default      = REGMAP_ENDIAN_NATIVE,
+       .val_format_endian_default      = REGMAP_ENDIAN_NATIVE,
+};
+
+/**
+ * regmap_init_spmi_base(): Create regmap for the Base register space
+ * @sdev:      SPMI device that will be interacted with
+ * @config:    Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_spmi_base(struct spmi_device *sdev,
+                                    const struct regmap_config *config)
+{
+       return regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_spmi_base);
+
+/**
+ * devm_regmap_init_spmi_base(): Create managed regmap for Base register space
+ * @sdev:      SPMI device that will be interacted with
+ * @config:    Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev,
+                                         const struct regmap_config *config)
+{
+       return devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base);
+
+static int regmap_spmi_ext_read(void *context,
+                               const void *reg, size_t reg_size,
+                               void *val, size_t val_size)
+{
+       int err = 0;
+       size_t len;
+       u16 addr;
+
        BUG_ON(reg_size != 2);
-       return spmi_ext_register_readl(context, *(u16 *)reg,
-                                      val, val_size);
+
+       addr = *(u16 *)reg;
+
+       /*
+        * Split accesses into two to take advantage of the more
+        * bandwidth-efficient 'Extended Register Read' command when possible
+        */
+       while (addr <= 0xFF && val_size) {
+               len = min_t(size_t, val_size, 16);
+
+               err = spmi_ext_register_read(context, addr, val, len);
+               if (err)
+                       goto err_out;
+
+               addr += len;
+               val += len;
+               val_size -= len;
+       }
+
+       while (val_size) {
+               len = min_t(size_t, val_size, 8);
+
+               err = spmi_ext_register_readl(context, addr, val, val_size);
+               if (err)
+                       goto err_out;
+
+               addr += len;
+               val += len;
+               val_size -= len;
+       }
+
+err_out:
+       return err;
 }
 
-static int regmap_spmi_gather_write(void *context,
-                                   const void *reg, size_t reg_size,
-                                   const void *val, size_t val_size)
+static int regmap_spmi_ext_gather_write(void *context,
+                                       const void *reg, size_t reg_size,
+                                       const void *val, size_t val_size)
 {
+       int err = 0;
+       size_t len;
+       u16 addr;
+
        BUG_ON(reg_size != 2);
-       return spmi_ext_register_writel(context, *(u16 *)reg, val, val_size);
+
+       addr = *(u16 *)reg;
+
+       while (addr <= 0xFF && val_size) {
+               len = min_t(size_t, val_size, 16);
+
+               err = spmi_ext_register_write(context, addr, val, len);
+               if (err)
+                       goto err_out;
+
+               addr += len;
+               val += len;
+               val_size -= len;
+       }
+
+       while (val_size) {
+               len = min_t(size_t, val_size, 8);
+
+               err = spmi_ext_register_writel(context, addr, val, len);
+               if (err)
+                       goto err_out;
+
+               addr += len;
+               val += len;
+               val_size -= len;
+       }
+
+err_out:
+       return err;
 }
 
-static int regmap_spmi_write(void *context, const void *data,
-                            size_t count)
+static int regmap_spmi_ext_write(void *context, const void *data,
+                                size_t count)
 {
        BUG_ON(count < 2);
-       return regmap_spmi_gather_write(context, data, 2, data + 2, count - 2);
+       return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
+                                           count - 2);
 }
 
-static struct regmap_bus regmap_spmi = {
-       .read                           = regmap_spmi_read,
-       .write                          = regmap_spmi_write,
-       .gather_write                   = regmap_spmi_gather_write,
+static struct regmap_bus regmap_spmi_ext = {
+       .read                           = regmap_spmi_ext_read,
+       .write                          = regmap_spmi_ext_write,
+       .gather_write                   = regmap_spmi_ext_gather_write,
        .reg_format_endian_default      = REGMAP_ENDIAN_NATIVE,
        .val_format_endian_default      = REGMAP_ENDIAN_NATIVE,
 };
 
 /**
- * regmap_init_spmi(): Initialize register map
- *
- * @sdev: Device that will be interacted with
- * @config: Configuration for register map
+ * regmap_init_spmi_ext(): Create regmap for Ext register space
+ * @sdev:      Device that will be interacted with
+ * @config:    Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer to
  * a struct regmap.
  */
-struct regmap *regmap_init_spmi(struct spmi_device *sdev,
-                               const struct regmap_config *config)
+struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev,
+                                   const struct regmap_config *config)
 {
-       return regmap_init(&sdev->dev, &regmap_spmi, sdev, config);
+       return regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
 }
-EXPORT_SYMBOL_GPL(regmap_init_spmi);
+EXPORT_SYMBOL_GPL(regmap_init_spmi_ext);
 
 /**
- * devm_regmap_init_spmi(): Initialise managed register map
- *
- * @sdev: Device that will be interacted with
- * @config: Configuration for register map
+ * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space
+ * @sdev:      SPMI device that will be interacted with
+ * @config:    Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer
  * to a struct regmap.  The regmap will be automatically freed by the
  * device management code.
  */
-struct regmap *devm_regmap_init_spmi(struct spmi_device *sdev,
+struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev,
                                     const struct regmap_config *config)
 {
-       return devm_regmap_init(&sdev->dev, &regmap_spmi, sdev, config);
+       return devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
 }
-EXPORT_SYMBOL_GPL(devm_regmap_init_spmi);
+EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext);
 
 MODULE_LICENSE("GPL");
index 6a19515f8a458b3719fce7325f265a60a4d147a4..d0a072463a04ff1c4d3f83cbd66de587be4c5e44 100644 (file)
@@ -380,6 +380,28 @@ static void regmap_range_exit(struct regmap *map)
        kfree(map->selector_work_buf);
 }
 
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+                     const struct regmap_config *config)
+{
+       struct regmap **m;
+
+       map->dev = dev;
+
+       regmap_debugfs_init(map, config->name);
+
+       /* Add a devres resource for dev_get_regmap() */
+       m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+       if (!m) {
+               regmap_debugfs_exit(map);
+               return -ENOMEM;
+       }
+       *m = map;
+       devres_add(dev, m);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_attach_dev);
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -397,7 +419,7 @@ struct regmap *regmap_init(struct device *dev,
                           void *bus_context,
                           const struct regmap_config *config)
 {
-       struct regmap *map, **m;
+       struct regmap *map;
        int ret = -EINVAL;
        enum regmap_endian reg_endian, val_endian;
        int i, j;
@@ -439,6 +461,7 @@ struct regmap *regmap_init(struct device *dev,
        else
                map->reg_stride = 1;
        map->use_single_rw = config->use_single_rw;
+       map->can_multi_write = config->can_multi_write;
        map->dev = dev;
        map->bus = bus;
        map->bus_context = bus_context;
@@ -718,7 +741,7 @@ skip_format_initialization:
                new->window_start = range_cfg->window_start;
                new->window_len = range_cfg->window_len;
 
-               if (_regmap_range_add(map, new) == false) {
+               if (!_regmap_range_add(map, new)) {
                        dev_err(map->dev, "Failed to add range %d\n", i);
                        kfree(new);
                        goto err_range;
@@ -734,25 +757,18 @@ skip_format_initialization:
                }
        }
 
-       regmap_debugfs_init(map, config->name);
-
        ret = regcache_init(map, config);
        if (ret != 0)
                goto err_range;
 
-       /* Add a devres resource for dev_get_regmap() */
-       m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
-       if (!m) {
-               ret = -ENOMEM;
-               goto err_debugfs;
-       }
-       *m = map;
-       devres_add(dev, m);
+       if (dev)
+               ret = regmap_attach_dev(dev, map, config);
+               if (ret != 0)
+                       goto err_regcache;
 
        return map;
 
-err_debugfs:
-       regmap_debugfs_exit(map);
+err_regcache:
        regcache_exit(map);
 err_range:
        regmap_range_exit(map);
@@ -1520,12 +1536,12 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
        if (reg % map->reg_stride)
                return -EINVAL;
 
-       map->lock(map->lock_arg);
        /*
         * Some devices don't support bulk write, for
         * them we have a series of single write operations.
         */
        if (!map->bus || map->use_single_rw) {
+               map->lock(map->lock_arg);
                for (i = 0; i < val_count; i++) {
                        unsigned int ival;
 
@@ -1554,31 +1570,239 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
                        if (ret != 0)
                                goto out;
                }
+out:
+               map->unlock(map->lock_arg);
        } else {
                void *wval;
 
                wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
                if (!wval) {
-                       ret = -ENOMEM;
                        dev_err(map->dev, "Error in memory allocation\n");
-                       goto out;
+                       return -ENOMEM;
                }
                for (i = 0; i < val_count * val_bytes; i += val_bytes)
                        map->format.parse_inplace(wval + i);
 
+               map->lock(map->lock_arg);
                ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+               map->unlock(map->lock_arg);
 
                kfree(wval);
        }
-out:
-       map->unlock(map->lock_arg);
        return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_write);
 
+/*
+ * _regmap_raw_multi_reg_write()
+ *
+ * the (register,newvalue) pairs in regs have not been formatted, but
+ * they are all in the same page and have been changed to being page
+ * relative. The page register has been written if that was neccessary.
+ */
+static int _regmap_raw_multi_reg_write(struct regmap *map,
+                                      const struct reg_default *regs,
+                                      size_t num_regs)
+{
+       int ret;
+       void *buf;
+       int i;
+       u8 *u8;
+       size_t val_bytes = map->format.val_bytes;
+       size_t reg_bytes = map->format.reg_bytes;
+       size_t pad_bytes = map->format.pad_bytes;
+       size_t pair_size = reg_bytes + pad_bytes + val_bytes;
+       size_t len = pair_size * num_regs;
+
+       buf = kzalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /* We have to linearise by hand. */
+
+       u8 = buf;
+
+       for (i = 0; i < num_regs; i++) {
+               int reg = regs[i].reg;
+               int val = regs[i].def;
+               trace_regmap_hw_write_start(map->dev, reg, 1);
+               map->format.format_reg(u8, reg, map->reg_shift);
+               u8 += reg_bytes + pad_bytes;
+               map->format.format_val(u8, val, 0);
+               u8 += val_bytes;
+       }
+       u8 = buf;
+       *u8 |= map->write_flag_mask;
+
+       ret = map->bus->write(map->bus_context, buf, len);
+
+       kfree(buf);
+
+       for (i = 0; i < num_regs; i++) {
+               int reg = regs[i].reg;
+               trace_regmap_hw_write_done(map->dev, reg, 1);
+       }
+       return ret;
+}
+
+static unsigned int _regmap_register_page(struct regmap *map,
+                                         unsigned int reg,
+                                         struct regmap_range_node *range)
+{
+       unsigned int win_page = (reg - range->range_min) / range->window_len;
+
+       return win_page;
+}
+
+static int _regmap_range_multi_paged_reg_write(struct regmap *map,
+                                              struct reg_default *regs,
+                                              size_t num_regs)
+{
+       int ret;
+       int i, n;
+       struct reg_default *base;
+       unsigned int this_page;
+       /*
+        * the set of registers are not neccessarily in order, but
+        * since the order of write must be preserved this algorithm
+        * chops the set each time the page changes
+        */
+       base = regs;
+       for (i = 0, n = 0; i < num_regs; i++, n++) {
+               unsigned int reg = regs[i].reg;
+               struct regmap_range_node *range;
+
+               range = _regmap_range_lookup(map, reg);
+               if (range) {
+                       unsigned int win_page = _regmap_register_page(map, reg,
+                                                                     range);
+
+                       if (i == 0)
+                               this_page = win_page;
+                       if (win_page != this_page) {
+                               this_page = win_page;
+                               ret = _regmap_raw_multi_reg_write(map, base, n);
+                               if (ret != 0)
+                                       return ret;
+                               base += n;
+                               n = 0;
+                       }
+                       ret = _regmap_select_page(map, &base[n].reg, range, 1);
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+       if (n > 0)
+               return _regmap_raw_multi_reg_write(map, base, n);
+       return 0;
+}
+
+static int _regmap_multi_reg_write(struct regmap *map,
+                                  const struct reg_default *regs,
+                                  size_t num_regs)
+{
+       int i;
+       int ret;
+
+       if (!map->can_multi_write) {
+               for (i = 0; i < num_regs; i++) {
+                       ret = _regmap_write(map, regs[i].reg, regs[i].def);
+                       if (ret != 0)
+                               return ret;
+               }
+               return 0;
+       }
+
+       if (!map->format.parse_inplace)
+               return -EINVAL;
+
+       if (map->writeable_reg)
+               for (i = 0; i < num_regs; i++) {
+                       int reg = regs[i].reg;
+                       if (!map->writeable_reg(map->dev, reg))
+                               return -EINVAL;
+                       if (reg % map->reg_stride)
+                               return -EINVAL;
+               }
+
+       if (!map->cache_bypass) {
+               for (i = 0; i < num_regs; i++) {
+                       unsigned int val = regs[i].def;
+                       unsigned int reg = regs[i].reg;
+                       ret = regcache_write(map, reg, val);
+                       if (ret) {
+                               dev_err(map->dev,
+                               "Error in caching of register: %x ret: %d\n",
+                                                               reg, ret);
+                               return ret;
+                       }
+               }
+               if (map->cache_only) {
+                       map->cache_dirty = true;
+                       return 0;
+               }
+       }
+
+       WARN_ON(!map->bus);
+
+       for (i = 0; i < num_regs; i++) {
+               unsigned int reg = regs[i].reg;
+               struct regmap_range_node *range;
+               range = _regmap_range_lookup(map, reg);
+               if (range) {
+                       size_t len = sizeof(struct reg_default)*num_regs;
+                       struct reg_default *base = kmemdup(regs, len,
+                                                          GFP_KERNEL);
+                       if (!base)
+                               return -ENOMEM;
+                       ret = _regmap_range_multi_paged_reg_write(map, base,
+                                                                 num_regs);
+                       kfree(base);
+
+                       return ret;
+               }
+       }
+       return _regmap_raw_multi_reg_write(map, regs, num_regs);
+}
+
 /*
  * regmap_multi_reg_write(): Write multiple registers to the device
  *
+ * where the set of register,value pairs are supplied in any order,
+ * possibly not all in a single range.
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register,value to be written
+ * @num_regs: Number of registers to write
+ *
+ * The 'normal' block write mode will send ultimately send data on the
+ * target bus as R,V1,V2,V3,..,Vn where successively higer registers are
+ * addressed. However, this alternative block multi write mode will send
+ * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device
+ * must of course support the mode.
+ *
+ * A value of zero will be returned on success, a negative errno will be
+ * returned in error cases.
+ */
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+                          int num_regs)
+{
+       int ret;
+
+       map->lock(map->lock_arg);
+
+       ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+       map->unlock(map->lock_arg);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+
+/*
+ * regmap_multi_reg_write_bypassed(): Write multiple registers to the
+ *                                    device but not the cache
+ *
  * where the set of register are supplied in any order
  *
  * @map: Register map to write to
@@ -1592,30 +1816,27 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
  * A value of zero will be returned on success, a negative errno will
  * be returned in error cases.
  */
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
-                               int num_regs)
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+                                   const struct reg_default *regs,
+                                   int num_regs)
 {
-       int ret = 0, i;
-
-       for (i = 0; i < num_regs; i++) {
-               int reg = regs[i].reg;
-               if (reg % map->reg_stride)
-                       return -EINVAL;
-       }
+       int ret;
+       bool bypass;
 
        map->lock(map->lock_arg);
 
-       for (i = 0; i < num_regs; i++) {
-               ret = _regmap_write(map, regs[i].reg, regs[i].def);
-               if (ret != 0)
-                       goto out;
-       }
-out:
+       bypass = map->cache_bypass;
+       map->cache_bypass = true;
+
+       ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+       map->cache_bypass = bypass;
+
        map->unlock(map->lock_arg);
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
 
 /**
  * regmap_raw_write_async(): Write raw values to one or more registers
@@ -1736,6 +1957,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
        if (map->cache_only)
                return -EBUSY;
 
+       if (!regmap_readable(map, reg))
+               return -EIO;
+
        ret = map->reg_read(context, reg, val);
        if (ret == 0) {
 #ifdef LOG_DEVICE
@@ -1966,9 +2190,11 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 
        if (tmp != orig) {
                ret = _regmap_write(map, reg, tmp);
-               *change = true;
+               if (change)
+                       *change = true;
        } else {
-               *change = false;
+               if (change)
+                       *change = false;
        }
 
        return ret;
@@ -1987,11 +2213,10 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 int regmap_update_bits(struct regmap *map, unsigned int reg,
                       unsigned int mask, unsigned int val)
 {
-       bool change;
        int ret;
 
        map->lock(map->lock_arg);
-       ret = _regmap_update_bits(map, reg, mask, val, &change);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL);
        map->unlock(map->lock_arg);
 
        return ret;
@@ -2016,14 +2241,13 @@ EXPORT_SYMBOL_GPL(regmap_update_bits);
 int regmap_update_bits_async(struct regmap *map, unsigned int reg,
                             unsigned int mask, unsigned int val)
 {
-       bool change;
        int ret;
 
        map->lock(map->lock_arg);
 
        map->async = true;
 
-       ret = _regmap_update_bits(map, reg, mask, val, &change);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL);
 
        map->async = false;
 
@@ -2173,35 +2397,21 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
  * apply them immediately.  Typically this is used to apply
  * corrections to be applied to the device defaults on startup, such
  * as the updates some vendors provide to undocumented registers.
+ *
+ * The caller must ensure that this function cannot be called
+ * concurrently with either itself or regcache_sync().
  */
 int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                          int num_regs)
 {
        struct reg_default *p;
-       int i, ret;
+       int ret;
        bool bypass;
 
        if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n",
            num_regs))
                return 0;
 
-       map->lock(map->lock_arg);
-
-       bypass = map->cache_bypass;
-
-       map->cache_bypass = true;
-       map->async = true;
-
-       /* Write out first; it's useful to apply even if we fail later. */
-       for (i = 0; i < num_regs; i++) {
-               ret = _regmap_write(map, regs[i].reg, regs[i].def);
-               if (ret != 0) {
-                       dev_err(map->dev, "Failed to write %x = %x: %d\n",
-                               regs[i].reg, regs[i].def, ret);
-                       goto out;
-               }
-       }
-
        p = krealloc(map->patch,
                     sizeof(struct reg_default) * (map->patch_regs + num_regs),
                     GFP_KERNEL);
@@ -2210,9 +2420,20 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                map->patch = p;
                map->patch_regs += num_regs;
        } else {
-               ret = -ENOMEM;
+               return -ENOMEM;
        }
 
+       map->lock(map->lock_arg);
+
+       bypass = map->cache_bypass;
+
+       map->cache_bypass = true;
+       map->async = true;
+
+       ret = _regmap_multi_reg_write(map, regs, num_regs);
+       if (ret != 0)
+               goto out;
+
 out:
        map->async = false;
        map->cache_bypass = bypass;
@@ -2240,6 +2461,18 @@ int regmap_get_val_bytes(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 
+int regmap_parse_val(struct regmap *map, const void *buf,
+                       unsigned int *val)
+{
+       if (!map->format.parse_val)
+               return -EINVAL;
+
+       *val = map->format.parse_val(buf);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_parse_val);
+
 static int __init regmap_initcall(void)
 {
        regmap_debugfs_initcall();
index 8184451b57c04999bd23c286080e14ca7f069031..422b7d84f686b90147f97565210687d343a3d9eb 100644 (file)
@@ -874,7 +874,7 @@ bio_pageinc(struct bio *bio)
                /* Non-zero page count for non-head members of
                 * compound pages is no longer allowed by the kernel.
                 */
-               page = compound_trans_head(bv.bv_page);
+               page = compound_head(bv.bv_page);
                atomic_inc(&page->_count);
        }
 }
@@ -887,7 +887,7 @@ bio_pagedec(struct bio *bio)
        struct bvec_iter iter;
 
        bio_for_each_segment(bv, bio, iter) {
-               page = compound_trans_head(bv.bv_page);
+               page = compound_head(bv.bv_page);
                atomic_dec(&page->_count);
        }
 }
index 2023043ce7c0e94b0e3c3618eb0787a9ad5ddb73..8f5565bf34cda31504e526ccc3d79d4e7fe20fd2 100644 (file)
@@ -961,17 +961,31 @@ static void empty(void)
 {
 }
 
-static DECLARE_WORK(floppy_work, NULL);
+static void (*floppy_work_fn)(void);
+
+static void floppy_work_workfn(struct work_struct *work)
+{
+       floppy_work_fn();
+}
+
+static DECLARE_WORK(floppy_work, floppy_work_workfn);
 
 static void schedule_bh(void (*handler)(void))
 {
        WARN_ON(work_pending(&floppy_work));
 
-       PREPARE_WORK(&floppy_work, (work_func_t)handler);
+       floppy_work_fn = handler;
        queue_work(floppy_wq, &floppy_work);
 }
 
-static DECLARE_DELAYED_WORK(fd_timer, NULL);
+static void (*fd_timer_fn)(void) = NULL;
+
+static void fd_timer_workfn(struct work_struct *work)
+{
+       fd_timer_fn();
+}
+
+static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
 
 static void cancel_activity(void)
 {
@@ -982,7 +996,7 @@ static void cancel_activity(void)
 
 /* this function makes sure that the disk stays in the drive during the
  * transfer */
-static void fd_watchdog(struct work_struct *arg)
+static void fd_watchdog(void)
 {
        debug_dcl(DP->flags, "calling disk change from watchdog\n");
 
@@ -993,7 +1007,7 @@ static void fd_watchdog(struct work_struct *arg)
                reset_fdc();
        } else {
                cancel_delayed_work(&fd_timer);
-               PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog);
+               fd_timer_fn = fd_watchdog;
                queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
        }
 }
@@ -1005,7 +1019,8 @@ static void main_command_interrupt(void)
 }
 
 /* waits for a delay (spinup or select) to pass */
-static int fd_wait_for_completion(unsigned long expires, work_func_t function)
+static int fd_wait_for_completion(unsigned long expires,
+                                 void (*function)(void))
 {
        if (FDCS->reset) {
                reset_fdc();    /* do the reset during sleep to win time
@@ -1016,7 +1031,7 @@ static int fd_wait_for_completion(unsigned long expires, work_func_t function)
 
        if (time_before(jiffies, expires)) {
                cancel_delayed_work(&fd_timer);
-               PREPARE_DELAYED_WORK(&fd_timer, function);
+               fd_timer_fn = function;
                queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
                return 1;
        }
@@ -1334,8 +1349,7 @@ static int fdc_dtr(void)
         * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
         */
        FDCS->dtr = raw_cmd->rate & 3;
-       return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
-                                     (work_func_t)floppy_ready);
+       return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
 }                              /* fdc_dtr */
 
 static void tell_sector(void)
@@ -1440,7 +1454,7 @@ static void setup_rw_floppy(void)
        int flags;
        int dflags;
        unsigned long ready_date;
-       work_func_t function;
+       void (*function)(void);
 
        flags = raw_cmd->flags;
        if (flags & (FD_RAW_READ | FD_RAW_WRITE))
@@ -1454,9 +1468,9 @@ static void setup_rw_floppy(void)
                 */
                if (time_after(ready_date, jiffies + DP->select_delay)) {
                        ready_date -= DP->select_delay;
-                       function = (work_func_t)floppy_start;
+                       function = floppy_start;
                } else
-                       function = (work_func_t)setup_rw_floppy;
+                       function = setup_rw_floppy;
 
                /* wait until the floppy is spinning fast enough */
                if (fd_wait_for_completion(ready_date, function))
@@ -1486,7 +1500,7 @@ static void setup_rw_floppy(void)
                inr = result();
                cont->interrupt();
        } else if (flags & FD_RAW_NEED_DISK)
-               fd_watchdog(NULL);
+               fd_watchdog();
 }
 
 static int blind_seek;
@@ -1863,7 +1877,7 @@ static int start_motor(void (*function)(void))
 
        /* wait_for_completion also schedules reset if needed. */
        return fd_wait_for_completion(DRS->select_date + DP->select_delay,
-                                     (work_func_t)function);
+                                     function);
 }
 
 static void floppy_ready(void)
index 516026954be62d325a9e9d7c5541e5fbf51c7569..d777bb7cea93fd4338149fd9b91335305cce055b 100644 (file)
@@ -4498,7 +4498,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        }
        dev_info(&pdev->dev, "NUMA node %d (closest: %d,%d, probe on %d:%d)\n",
                my_node, pcibus_to_node(pdev->bus), dev_to_node(&pdev->dev),
-               cpu_to_node(smp_processor_id()), smp_processor_id());
+               cpu_to_node(raw_smp_processor_id()), raw_smp_processor_id());
 
        dd = kzalloc_node(sizeof(struct driver_data), GFP_KERNEL, my_node);
        if (dd == NULL) {
index b52e9a6d6aad6d602bf3a9d6f73c9b4c277c7e17..54174cb32febe10a45eddd8e837d8267bfe594a1 100644 (file)
@@ -53,7 +53,7 @@
 #define MTIP_FTL_REBUILD_TIMEOUT_MS    2400000
 
 /* unaligned IO handling */
-#define MTIP_MAX_UNALIGNED_SLOTS       8
+#define MTIP_MAX_UNALIGNED_SLOTS       2
 
 /* Macro to extract the tag bit number from a tag value. */
 #define MTIP_TAG_BIT(tag)      (tag & 0x1F)
index 51824d1f23ea53df5d49cd6d4e10e07b6b45b1fb..8459e4e7c71940462134eb6a7ad68c86f03ebb7a 100644 (file)
@@ -993,7 +993,7 @@ static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq)
                dev_warn(&dev->pci_dev->dev,
                        "I/O %d QID %d timeout, reset controller\n", cmdid,
                                                                nvmeq->qid);
-               PREPARE_WORK(&dev->reset_work, nvme_reset_failed_dev);
+               dev->reset_workfn = nvme_reset_failed_dev;
                queue_work(nvme_workq, &dev->reset_work);
                return;
        }
@@ -1696,8 +1696,7 @@ static int nvme_kthread(void *data)
                                list_del_init(&dev->node);
                                dev_warn(&dev->pci_dev->dev,
                                        "Failed status, reset controller\n");
-                               PREPARE_WORK(&dev->reset_work,
-                                                       nvme_reset_failed_dev);
+                               dev->reset_workfn = nvme_reset_failed_dev;
                                queue_work(nvme_workq, &dev->reset_work);
                                continue;
                        }
@@ -2406,7 +2405,7 @@ static int nvme_dev_resume(struct nvme_dev *dev)
                return ret;
        if (ret == -EBUSY) {
                spin_lock(&dev_list_lock);
-               PREPARE_WORK(&dev->reset_work, nvme_remove_disks);
+               dev->reset_workfn = nvme_remove_disks;
                queue_work(nvme_workq, &dev->reset_work);
                spin_unlock(&dev_list_lock);
        }
@@ -2435,6 +2434,12 @@ static void nvme_reset_failed_dev(struct work_struct *ws)
        nvme_dev_reset(dev);
 }
 
+static void nvme_reset_workfn(struct work_struct *work)
+{
+       struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
+       dev->reset_workfn(work);
+}
+
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int result = -ENOMEM;
@@ -2453,7 +2458,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto free;
 
        INIT_LIST_HEAD(&dev->namespaces);
-       INIT_WORK(&dev->reset_work, nvme_reset_failed_dev);
+       dev->reset_workfn = nvme_reset_failed_dev;
+       INIT_WORK(&dev->reset_work, nvme_reset_workfn);
        dev->pci_dev = pdev;
        pci_set_drvdata(pdev, dev);
        result = nvme_set_instance(dev);
@@ -2553,7 +2559,7 @@ static int nvme_resume(struct device *dev)
        struct nvme_dev *ndev = pci_get_drvdata(pdev);
 
        if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) {
-               PREPARE_WORK(&ndev->reset_work, nvme_reset_failed_dev);
+               ndev->reset_workfn = nvme_reset_failed_dev;
                queue_work(nvme_workq, &ndev->reset_work);
        }
        return 0;
index b365e0dfccb66f7c256a9d07d7fd976fba17ae95..34898d53395b10eae386e06fef3d12b9635fe93a 100644 (file)
@@ -2109,7 +2109,6 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
        rbd_assert(img_request->obj_request_count > 0);
        rbd_assert(which != BAD_WHICH);
        rbd_assert(which < img_request->obj_request_count);
-       rbd_assert(which >= img_request->next_completion);
 
        spin_lock_irq(&img_request->completion_lock);
        if (which != img_request->next_completion)
index 011e55d820b1811a3379a65a4ef754fcc785f3ef..51c557cfd92b37cf6b7aecdfa50d212fdacc05ee 100644 (file)
@@ -612,6 +612,8 @@ static ssize_t disksize_store(struct device *dev,
 
        disksize = PAGE_ALIGN(disksize);
        meta = zram_meta_alloc(disksize);
+       if (!meta)
+               return -ENOMEM;
        down_write(&zram->init_lock);
        if (zram->init_done) {
                up_write(&zram->init_lock);
index 725c46162bbd1cb0ad05624502ad16030e5991ca..2ac754e18bcf1af6a285c5de9f6df867f4e83298 100644 (file)
@@ -870,14 +870,14 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
        ret = of_property_read_u32_array(np, "pcie-mem-aperture", reg, ARRAY_SIZE(reg));
        if (!ret) {
                mem->start = reg[0];
-               mem->end = mem->start + reg[1];
+               mem->end = mem->start + reg[1] - 1;
                mem->flags = IORESOURCE_MEM;
        }
 
        ret = of_property_read_u32_array(np, "pcie-io-aperture", reg, ARRAY_SIZE(reg));
        if (!ret) {
                io->start = reg[0];
-               io->end = io->start + reg[1];
+               io->end = io->start + reg[1] - 1;
                io->flags = IORESOURCE_IO;
        }
 }
index 1b192395a90c840d48362fdf81a139a75243e08f..8121b4c70edec77114e20295e195fa1d5f2cc797 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/module.h>
 #include <linux/mman.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/agp_backend.h>
 #include <linux/agpgart.h>
index f39437addb58ce2dde481f2ecdc0008024e35df4..0fbccce1cee92920106de28ff3dc2accd97d76b3 100644 (file)
@@ -29,7 +29,6 @@
  */
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/miscdevice.h>
 #include <linux/pm.h>
index 5c85350f4c3d065e9c9bdf9ba762667604b7c0f3..9a024f899dd40a040ccede1571e1e2919e61bea9 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/agp_backend.h>
index 05b8d0241bdefe2df440bf7637f37efe7ee367df..3051c73bc3838a0ccdbc0784d7a5bac76d356cd2 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/agp_backend.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/io.h>
index 43577ca780e304e7c6d25d919da70927bb8ffeb5..8c3b255e629a8253f040175c968905f10a064716 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/hw_random.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index a0f7724852eb84d2ccb20eebc8e4309ea48a085c..b9495a8c05c6d7e9b192c8a2b403b7fb2ac90fdc 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
index 402ccfb625c516739b440f9a5fba76ff2c98e4d0..9f8277cc44b49639332f76b4f2c47da6db85fdd8 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/hw_random.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
index f9beed54d0c87fe2908b7c7d84bba111ee580f0b..432232eefe057da718751d9b6721ca9a0e657aaf 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/preempt.h>
index 232b87fb5fc911d8697b4fbddd04063614dffd07..00e9d2d466343784a46abae1bbdbb5623d6d5037 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/amba/bus.h>
 #include <linux/hw_random.h>
index f2885dbe1849e03d0691a7cc51a6e85e646a7c0f..b5cc3420c659442a7ff77d748b23e5cbf0d814df 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/device.h>
 #include <linux/hw_random.h>
index 03f41896d09050ff391ad55ef263faa1430de19a..b7efd3c1a882525431da787f1679e33729243f82 100644 (file)
@@ -61,7 +61,6 @@
 #include <linux/ipmi_smi.h>
 #include <asm/io.h>
 #include "ipmi_si_sm.h"
-#include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
index 92c5937f80c33acac907dccb2377b6157721b33c..917403fe10da3eb62c0548bb29a2f0d898c8400a 100644 (file)
@@ -99,6 +99,9 @@ static ssize_t read_mem(struct file *file, char __user *buf,
        ssize_t read, sz;
        char *ptr;
 
+       if (p != *ppos)
+               return 0;
+
        if (!valid_phys_addr_range(p, count))
                return -EFAULT;
        read = 0;
@@ -157,6 +160,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
        unsigned long copied;
        void *ptr;
 
+       if (p != *ppos)
+               return -EFBIG;
+
        if (!valid_phys_addr_range(p, count))
                return -EFAULT;
 
index 881c9e59593912261bd68a39b0c08cfbcd4b793d..28740046bc83752ffbe3ba47b3ec1a540a8bb648 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/sched.h>       /* cond_resched() */
 
index 0e506bad19866d78f1952bc26666eabc7725a046..bd377472dcfb33277f20fdc382a9a717dad92823 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
 #include <linux/kernel.h>      /* printk() */
 #include <linux/slab.h>                /* kmalloc() */
 #include <linux/fs.h>          /* everything... */
index 52b9b2b2f30045d94be453785df66e54b0cc6e0b..472af4bb1b6128d3f7a0176fcb51720115f11aec 100644 (file)
@@ -21,7 +21,6 @@
  *
  *
  */
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/wait.h>
index 5b0dd8ef74c0eb896cba51c275eff71d797ad888..3b7bf216289858ece2f8aff141b9d77ed023fde2 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/miscdevice.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
index bd313f7816a8d9461deba6889b99415b87010467..c1af80bcdf2082c8d0d7b32e28eb9122c59ac53f 100644 (file)
@@ -242,7 +242,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
 
        irq = irq_of_parse_and_map(np, 0);
        if (!irq)
-               return;
+               goto out_free_characteristics;
 
        clk = at91_clk_register_master(pmc, irq, name, num_parents,
                                       parent_names, layout,
index 6a934a5296bd4ca2867146dc06272ea1003e238e..05e04ce0f1488f7301ad5153f687860bf872f8bc 100644 (file)
@@ -494,6 +494,9 @@ static const struct file_operations nomadik_src_clk_debugfs_ops = {
 
 static int __init nomadik_src_clk_init_debugfs(void)
 {
+       /* Vital for multiplatform */
+       if (!src_base)
+               return -ENODEV;
        src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
        src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
        debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
index 5517944495d893cc3c8dd60569b58e67e9289765..c42e608af6bbe0980717a74e69a143cdc742f1b1 100644 (file)
@@ -2226,24 +2226,25 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
  */
 int __clk_get(struct clk *clk)
 {
-       if (clk && !try_module_get(clk->owner))
-               return 0;
+       if (clk) {
+               if (!try_module_get(clk->owner))
+                       return 0;
 
-       kref_get(&clk->ref);
+               kref_get(&clk->ref);
+       }
        return 1;
 }
 
 void __clk_put(struct clk *clk)
 {
-       if (WARN_ON_ONCE(IS_ERR(clk)))
+       if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
                return;
 
        clk_prepare_lock();
        kref_put(&clk->ref, __clk_release);
        clk_prepare_unlock();
 
-       if (clk)
-               module_put(clk->owner);
+       module_put(clk->owner);
 }
 
 /***        clk rate change notifiers        ***/
index 17a598398a53df461e110ca5c16d29e7bc92e6f5..86f1e362eafb8e29c02fae393620d39d32278529 100644 (file)
@@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev,
 
        init.name = name;
        init.ops = &clk_psc_ops;
+       init.flags = 0;
        init.parent_names = (parent_name ? &parent_name : NULL);
        init.num_parents = (parent_name ? 1 : 0);
 
index 81a202d12a7ad89ab56909fce6782baa7fb94ec2..bef198a83863aaa79e21ca1c4e1401238cae31b7 100644 (file)
@@ -141,13 +141,6 @@ static const struct coreclk_soc_desc a370_coreclks = {
        .num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
 };
 
-static void __init a370_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &a370_coreclks);
-}
-CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock",
-              a370_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
        { }
 };
 
-static void __init a370_clk_gating_init(struct device_node *np)
+static void __init a370_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, a370_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
+
+       mvebu_coreclk_setup(np, &a370_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, a370_gating_desc);
 }
-CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock",
-              a370_clk_gating_init);
+CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
+
index 9922c4475aa8b3f7d01c2881c8a757b94f9027af..b3094315a3c0faa89926dcf7442d5034f39b4f15 100644 (file)
@@ -158,13 +158,6 @@ static const struct coreclk_soc_desc axp_coreclks = {
        .num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
 };
 
-static void __init axp_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &axp_coreclks);
-}
-CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock",
-              axp_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
        { }
 };
 
-static void __init axp_clk_gating_init(struct device_node *np)
+static void __init axp_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, axp_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock");
+
+       mvebu_coreclk_setup(np, &axp_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, axp_gating_desc);
 }
-CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock",
-              axp_clk_gating_init);
+CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
index 38aee1e3f242b237079aaeb775aa2fd8dae89453..b8c2424ac9261dea5c36553b09f5262bba359299 100644 (file)
@@ -154,12 +154,6 @@ static const struct coreclk_soc_desc dove_coreclks = {
        .num_ratios = ARRAY_SIZE(dove_coreclk_ratios),
 };
 
-static void __init dove_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &dove_coreclks);
-}
-CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = {
        { }
 };
 
-static void __init dove_clk_gating_init(struct device_node *np)
+static void __init dove_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, dove_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+
+       mvebu_coreclk_setup(np, &dove_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, dove_gating_desc);
 }
-CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock",
-              dove_clk_gating_init);
+CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init);
index 2636a55f29f9403df92aec0c11e5a504fc7f9deb..ddb666a86500964201db0ad6d3a3724511302b59 100644 (file)
@@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
-static void __init kirkwood_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &kirkwood_coreclks);
-}
-CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock",
-              kirkwood_coreclk_init);
-
 static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .get_tclk_freq = kirkwood_get_tclk_freq,
        .get_cpu_freq = mv88f6180_get_cpu_freq,
@@ -208,13 +201,6 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
-static void __init mv88f6180_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &mv88f6180_coreclks);
-}
-CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock",
-              mv88f6180_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
        { }
 };
 
-static void __init kirkwood_clk_gating_init(struct device_node *np)
+static void __init kirkwood_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, kirkwood_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
+
+
+       if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
+               mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+       else
+               mvebu_coreclk_setup(np, &kirkwood_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
 }
-CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock",
-              kirkwood_clk_gating_init);
+CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
+              kirkwood_clk_init);
+CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
+              kirkwood_clk_init);
index a59ec217a12437785ea1c689b28744bfcd19ac3d..99c27b1c625b8e3eaf514895a0a13ebf8b94fdef 100644 (file)
@@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
        void __iomem *reg;
 };
 
+#define CPG_FRQCRB                     0x00000004
+#define CPG_FRQCRB_KICK                        BIT(31)
 #define CPG_SDCKCR                     0x00000074
 #define CPG_PLL0CR                     0x000000d8
 #define CPG_FRQCRC                     0x000000e0
@@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
 struct cpg_z_clk {
        struct clk_hw hw;
        void __iomem *reg;
+       void __iomem *kick_reg;
 };
 
 #define to_z_clk(_hw)  container_of(_hw, struct cpg_z_clk, hw)
@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct cpg_z_clk *zclk = to_z_clk(hw);
        unsigned int mult;
-       u32 val;
+       u32 val, kick;
+       unsigned int i;
 
        mult = div_u64((u64)rate * 32, parent_rate);
        mult = clamp(mult, 1U, 32U);
 
+       if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
+               return -EBUSY;
+
        val = clk_readl(zclk->reg);
        val &= ~CPG_FRQCRC_ZFC_MASK;
        val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
        clk_writel(val, zclk->reg);
 
-       return 0;
+       /*
+        * Set KICK bit in FRQCRB to update hardware setting and wait for
+        * clock change completion.
+        */
+       kick = clk_readl(zclk->kick_reg);
+       kick |= CPG_FRQCRB_KICK;
+       clk_writel(kick, zclk->kick_reg);
+
+       /*
+        * Note: There is no HW information about the worst case latency.
+        *
+        * Using experimental measurements, it seems that no more than
+        * ~10 iterations are needed, independently of the CPU rate.
+        * Since this value might be dependant of external xtal rate, pll1
+        * rate or even the other emulation clocks rate, use 1000 as a
+        * "super" safe value.
+        */
+       for (i = 1000; i; i--) {
+               if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
+                       return 0;
+
+               cpu_relax();
+       }
+
+       return -ETIMEDOUT;
 }
 
 static const struct clk_ops cpg_z_clk_ops = {
@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
        init.num_parents = 1;
 
        zclk->reg = cpg->reg + CPG_FRQCRC;
+       zclk->kick_reg = cpg->reg + CPG_FRQCRB;
        zclk->hw.init = &init;
 
        clk = clk_register(NULL, &zclk->hw);
@@ -186,7 +218,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                             const char *name)
 {
        const struct clk_div_table *table = NULL;
-       const char *parent_name = "main";
+       const char *parent_name;
        unsigned int shift;
        unsigned int mult = 1;
        unsigned int div = 1;
@@ -201,23 +233,31 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                 * the multiplier value.
                 */
                u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+               parent_name = "main";
                mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
        } else if (!strcmp(name, "pll1")) {
+               parent_name = "main";
                mult = config->pll1_mult / 2;
        } else if (!strcmp(name, "pll3")) {
+               parent_name = "main";
                mult = config->pll3_mult;
        } else if (!strcmp(name, "lb")) {
+               parent_name = "pll1_div2";
                div = cpg_mode & BIT(18) ? 36 : 24;
        } else if (!strcmp(name, "qspi")) {
+               parent_name = "pll1_div2";
                div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
-                   ? 16 : 20;
+                   ? 8 : 10;
        } else if (!strcmp(name, "sdh")) {
+               parent_name = "pll1_div2";
                table = cpg_sdh_div_table;
                shift = 8;
        } else if (!strcmp(name, "sd0")) {
+               parent_name = "pll1_div2";
                table = cpg_sd01_div_table;
                shift = 4;
        } else if (!strcmp(name, "sd1")) {
+               parent_name = "pll1_div2";
                table = cpg_sd01_div_table;
                shift = 0;
        } else if (!strcmp(name, "z")) {
index 4d75b1f37e3a4b74ee4606ce33d54b8a771beb6a..290f9c1a37498ccf16ae0b09804ca15e722a2da2 100644 (file)
@@ -59,7 +59,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
                return 0;
 
        if (divider_ux1 > get_max_div(divider))
-               return -EINVAL;
+               return get_max_div(divider);
 
        return divider_ux1;
 }
index cf0c323f2c36ec453deed1c5374fbbce4df543b2..c39613c519af85aa5faf14cc02857219cde56a3b 100644 (file)
@@ -180,9 +180,13 @@ enum clk_id {
        tegra_clk_sbc6_8,
        tegra_clk_sclk,
        tegra_clk_sdmmc1,
+       tegra_clk_sdmmc1_8,
        tegra_clk_sdmmc2,
+       tegra_clk_sdmmc2_8,
        tegra_clk_sdmmc3,
+       tegra_clk_sdmmc3_8,
        tegra_clk_sdmmc4,
+       tegra_clk_sdmmc4_8,
        tegra_clk_se,
        tegra_clk_soc_therm,
        tegra_clk_sor0,
index 5c35885f4a7cee9a4ecb9309f93c345befe28a2e..1fa5c3f33b2033a5e4a32716706d2221d548adf1 100644 (file)
@@ -371,9 +371,7 @@ static const char *mux_pllp3_pllc_clkm[] = {
 static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = {
        "pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m"
 };
-static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = {
-       [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
-};
+#define mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx NULL
 
 static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = {
        "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4",
@@ -465,6 +463,10 @@ static struct tegra_periph_init_data periph_clks[] = {
        MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
        MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
        MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+       MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
+       MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
+       MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
+       MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
        MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
        MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
        MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -492,7 +494,7 @@ static struct tegra_periph_init_data periph_clks[] = {
        UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
        UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
        UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
-       UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte),
+       UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
        XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
        XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
        XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
index 05dce4aa2c11e2a0d3e73cb84f4dc6231537b08d..feb3201c85ce5df6d8786eaf2e4a0408e5890ec0 100644 (file)
@@ -120,7 +120,7 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
                                        ARRAY_SIZE(cclk_lp_parents),
                                        CLK_SET_RATE_PARENT,
                                        clk_base + CCLKLP_BURST_POLICY,
-                                       0, 4, 8, 9, NULL);
+                                       TEGRA_DIVIDER_2, 4, 8, 9, NULL);
                *dt_clk = clk;
        }
 
index 90d9d25f2228195308f328a9d7c05c1a5bbe5a40..80431f0fb2688f84557383b20ea39513ed2ffcc4 100644 (file)
@@ -682,12 +682,12 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
        [tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true },
        [tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true },
        [tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true },
-       [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
+       [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
        [tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true },
        [tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true },
        [tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true },
-       [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
-       [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
+       [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
+       [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
        [tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true },
        [tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true },
        [tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true },
@@ -723,7 +723,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
        [tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true },
        [tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true },
        [tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true },
-       [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
+       [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
        [tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true },
        [tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true },
        [tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true },
index aff86b5bc7455c190fbf5ebaf2be08c204262e26..166e02f16c8a25f28f4441584dc6e8babc448f3b 100644 (file)
@@ -516,11 +516,11 @@ static struct div_nmp pllp_nmp = {
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-       {12000000, 216000000, 432, 12, 1, 8},
-       {13000000, 216000000, 432, 13, 1, 8},
-       {16800000, 216000000, 360, 14, 1, 8},
-       {19200000, 216000000, 360, 16, 1, 8},
-       {26000000, 216000000, 432, 26, 1, 8},
+       {12000000, 408000000, 408, 12, 0, 8},
+       {13000000, 408000000, 408, 13, 0, 8},
+       {16800000, 408000000, 340, 14, 0, 8},
+       {19200000, 408000000, 340, 16, 0, 8},
+       {26000000, 408000000, 408, 26, 0, 8},
        {0, 0, 0, 0, 0, 0},
 };
 
@@ -570,6 +570,15 @@ static struct tegra_clk_pll_params pll_a_params = {
        .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
 };
 
+static struct div_nmp plld_nmp = {
+       .divm_shift = 0,
+       .divm_width = 5,
+       .divn_shift = 8,
+       .divn_width = 11,
+       .divp_shift = 20,
+       .divp_width = 3,
+};
+
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
        {12000000, 216000000, 864, 12, 4, 12},
        {13000000, 216000000, 864, 13, 4, 12},
@@ -603,19 +612,18 @@ 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,
+       .div_nmp = &plld_nmp,
        .freq_table = pll_d_freq_table,
        .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
                 TEGRA_PLL_USE_LOCK,
 };
 
 static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
-       { 12000000, 148500000,  99, 1, 8},
-       { 12000000, 594000000,  99, 1, 1},
-       { 13000000, 594000000,  91, 1, 1},      /* actual: 591.5 MHz */
-       { 16800000, 594000000,  71, 1, 1},      /* actual: 596.4 MHz */
-       { 19200000, 594000000,  62, 1, 1},      /* actual: 595.2 MHz */
-       { 26000000, 594000000,  91, 2, 1},      /* actual: 591.5 MHz */
+       { 12000000, 594000000,  99, 1, 2},
+       { 13000000, 594000000,  91, 1, 2},      /* actual: 591.5 MHz */
+       { 16800000, 594000000,  71, 1, 2},      /* actual: 596.4 MHz */
+       { 19200000, 594000000,  62, 1, 2},      /* actual: 595.2 MHz */
+       { 26000000, 594000000,  91, 2, 2},      /* actual: 591.5 MHz */
        { 0, 0, 0, 0, 0, 0 },
 };
 
@@ -753,21 +761,19 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true },
        [tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true },
        [tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true },
-       [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
+       [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
        [tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true },
        [tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true },
        [tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true },
-       [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
-       [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
+       [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
+       [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
        [tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true },
        [tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true },
-       [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true },
        [tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true },
        [tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true },
-       [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true },
        [tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true },
        [tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true },
-       [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
+       [tegra_clk_host1x_8] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
        [tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true },
        [tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true },
        [tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true },
@@ -794,7 +800,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true },
        [tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true },
        [tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true },
-       [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
+       [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
        [tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true },
        [tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true },
        [tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true },
@@ -1286,9 +1292,9 @@ static void __init tegra124_pll_init(void __iomem *clk_base,
        clk_register_clkdev(clk, "pll_d2", NULL);
        clks[TEGRA124_CLK_PLL_D2] = clk;
 
-       /* PLLD2_OUT0 ?? */
+       /* PLLD2_OUT0 */
        clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
-                                       CLK_SET_RATE_PARENT, 1, 2);
+                                       CLK_SET_RATE_PARENT, 1, 1);
        clk_register_clkdev(clk, "pll_d2_out0", NULL);
        clks[TEGRA124_CLK_PLL_D2_OUT0] = clk;
 
index dbace152b2faa9e4f1699b8369d935683900df89..dace2b1b5ae66dafab4fe4639e6291872491119d 100644 (file)
@@ -574,6 +574,8 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
        [tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true },
        [tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true },
        [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true },
+       [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true },
+       [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true },
 };
 
 static unsigned long tegra20_clk_measure_input_freq(void)
index cd6950fd8caf063417f6717db581f39d69100ed4..52e9329e3c51c05419a2d811ad3ed8fd271baa66 100644 (file)
@@ -140,3 +140,51 @@ config VF_PIT_TIMER
        bool
        help
          Support for Period Interrupt Timer on Freescale Vybrid Family SoCs.
+
+config SYS_SUPPORTS_SH_CMT
+        bool
+
+config SYS_SUPPORTS_SH_MTU2
+        bool
+
+config SYS_SUPPORTS_SH_TMU
+        bool
+
+config SYS_SUPPORTS_EM_STI
+        bool
+
+config SH_TIMER_CMT
+       bool "Renesas CMT timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       default SYS_SUPPORTS_SH_CMT
+       help
+         This enables build of a clocksource and clockevent driver for
+         the Compare Match Timer (CMT) hardware available in 16/32/48-bit
+         variants on a wide range of Mobile and Automotive SoCs from Renesas.
+
+config SH_TIMER_MTU2
+       bool "Renesas MTU2 timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       default SYS_SUPPORTS_SH_MTU2
+       help
+         This enables build of a clockevent driver for the Multi-Function
+         Timer Pulse Unit 2 (TMU2) hardware available on SoCs from Renesas.
+         This hardware comes with 16 bit-timer registers.
+
+config SH_TIMER_TMU
+       bool "Renesas TMU timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       default SYS_SUPPORTS_SH_TMU
+       help
+         This enables build of a clocksource and clockevent driver for
+         the 32-bit Timer Unit (TMU) hardware available on a wide range
+         SoCs from Renesas.
+
+config EM_TIMER_STI
+       bool "Renesas STI timer driver" if COMPILE_TEST
+       depends on GENERIC_CLOCKEVENTS
+       default SYS_SUPPORTS_EM_STI
+       help
+         This enables build of a clocksource and clockevent driver for
+         the 48-bit System Timer (STI) hardware available on a SoCs
+         such as EMEV2 from former NEC Electronics.
index c7ca50a9c232bdcc246fbce2508f71ff6dbcab97..aed3488d942656f087fbc639dce87b48ad76c277 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_ARCH_MARCO)      += timer-marco.o
 obj-$(CONFIG_ARCH_MOXART)      += moxart_timer.o
 obj-$(CONFIG_ARCH_MXS)         += mxs_timer.o
 obj-$(CONFIG_ARCH_PRIMA2)      += timer-prima2.o
+obj-$(CONFIG_ARCH_U300)                += timer-u300.o
 obj-$(CONFIG_SUN4I_TIMER)      += sun4i_timer.o
 obj-$(CONFIG_SUN5I_HSTIMER)    += timer-sun5i.o
 obj-$(CONFIG_ARCH_TEGRA)       += tegra20_timer.o
@@ -37,3 +38,4 @@ obj-$(CONFIG_ARM_ARCH_TIMER)          += arm_arch_timer.o
 obj-$(CONFIG_ARM_GLOBAL_TIMER)         += arm_global_timer.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)     += metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)  += dummy_timer.o
+obj-$(CONFIG_ARCH_KEYSTONE)            += timer-keystone.o
index 95fb944e15ee0579a6f437f8440ba93fe8443524..57e823c44d2ad326eeaaa788fbb67d80ba620c7d 100644 (file)
@@ -277,6 +277,7 @@ static void __arch_timer_setup(unsigned type,
                        clk->set_next_event = arch_timer_set_next_event_phys;
                }
        } else {
+               clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
                clk->name = "arch_mem_timer";
                clk->rating = 400;
                clk->cpumask = cpu_all_mask;
index 63f176de0d0228c63ba58f606d21afd98cdc5e9e..49fbe2847c8474cfd9398ee70e5bba713fe381c4 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
 #include <linux/of_address.h>
@@ -52,6 +53,8 @@
 #define TTC_CNT_CNTRL_DISABLE_MASK     0x1
 
 #define TTC_CLK_CNTRL_CSRC_MASK                (1 << 5)        /* clock source */
+#define TTC_CLK_CNTRL_PSV_MASK         0x1e
+#define TTC_CLK_CNTRL_PSV_SHIFT                1
 
 /*
  * Setup the timers to use pre-scaling, using a fixed value for now that will
@@ -63,6 +66,8 @@
 #define CLK_CNTRL_PRESCALE_EN  1
 #define CNT_CNTRL_RESET                (1 << 4)
 
+#define MAX_F_ERR 50
+
 /**
  * struct ttc_timer - This definition defines local timer structure
  *
@@ -82,6 +87,8 @@ struct ttc_timer {
                container_of(x, struct ttc_timer, clk_rate_change_nb)
 
 struct ttc_timer_clocksource {
+       u32                     scale_clk_ctrl_reg_old;
+       u32                     scale_clk_ctrl_reg_new;
        struct ttc_timer        ttc;
        struct clocksource      cs;
 };
@@ -229,32 +236,89 @@ static int ttc_rate_change_clocksource_cb(struct notifier_block *nb,
                        struct ttc_timer_clocksource, ttc);
 
        switch (event) {
-       case POST_RATE_CHANGE:
+       case PRE_RATE_CHANGE:
+       {
+               u32 psv;
+               unsigned long factor, rate_low, rate_high;
+
+               if (ndata->new_rate > ndata->old_rate) {
+                       factor = DIV_ROUND_CLOSEST(ndata->new_rate,
+                                       ndata->old_rate);
+                       rate_low = ndata->old_rate;
+                       rate_high = ndata->new_rate;
+               } else {
+                       factor = DIV_ROUND_CLOSEST(ndata->old_rate,
+                                       ndata->new_rate);
+                       rate_low = ndata->new_rate;
+                       rate_high = ndata->old_rate;
+               }
+
+               if (!is_power_of_2(factor))
+                               return NOTIFY_BAD;
+
+               if (abs(rate_high - (factor * rate_low)) > MAX_F_ERR)
+                       return NOTIFY_BAD;
+
+               factor = __ilog2_u32(factor);
+
                /*
-                * Do whatever is necessary to maintain a proper time base
-                *
-                * I cannot find a way to adjust the currently used clocksource
-                * to the new frequency. __clocksource_updatefreq_hz() sounds
-                * good, but does not work. Not sure what's that missing.
-                *
-                * This approach works, but triggers two clocksource switches.
-                * The first after unregister to clocksource jiffies. And
-                * another one after the register to the newly registered timer.
-                *
-                * Alternatively we could 'waste' another HW timer to ping pong
-                * between clock sources. That would also use one register and
-                * one unregister call, but only trigger one clocksource switch
-                * for the cost of another HW timer used by the OS.
+                * store timer clock ctrl register so we can restore it in case
+                * of an abort.
                 */
-               clocksource_unregister(&ttccs->cs);
-               clocksource_register_hz(&ttccs->cs,
-                               ndata->new_rate / PRESCALE);
-               /* fall through */
-       case PRE_RATE_CHANGE:
+               ttccs->scale_clk_ctrl_reg_old =
+                       __raw_readl(ttccs->ttc.base_addr +
+                                       TTC_CLK_CNTRL_OFFSET);
+
+               psv = (ttccs->scale_clk_ctrl_reg_old &
+                               TTC_CLK_CNTRL_PSV_MASK) >>
+                               TTC_CLK_CNTRL_PSV_SHIFT;
+               if (ndata->new_rate < ndata->old_rate)
+                       psv -= factor;
+               else
+                       psv += factor;
+
+               /* prescaler within legal range? */
+               if (psv & ~(TTC_CLK_CNTRL_PSV_MASK >> TTC_CLK_CNTRL_PSV_SHIFT))
+                       return NOTIFY_BAD;
+
+               ttccs->scale_clk_ctrl_reg_new = ttccs->scale_clk_ctrl_reg_old &
+                       ~TTC_CLK_CNTRL_PSV_MASK;
+               ttccs->scale_clk_ctrl_reg_new |= psv << TTC_CLK_CNTRL_PSV_SHIFT;
+
+
+               /* scale down: adjust divider in post-change notification */
+               if (ndata->new_rate < ndata->old_rate)
+                       return NOTIFY_DONE;
+
+               /* scale up: adjust divider now - before frequency change */
+               __raw_writel(ttccs->scale_clk_ctrl_reg_new,
+                               ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+               break;
+       }
+       case POST_RATE_CHANGE:
+               /* scale up: pre-change notification did the adjustment */
+               if (ndata->new_rate > ndata->old_rate)
+                       return NOTIFY_OK;
+
+               /* scale down: adjust divider now - after frequency change */
+               __raw_writel(ttccs->scale_clk_ctrl_reg_new,
+                               ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+               break;
+
        case ABORT_RATE_CHANGE:
+               /* we have to undo the adjustment in case we scale up */
+               if (ndata->new_rate < ndata->old_rate)
+                       return NOTIFY_OK;
+
+               /* restore original register value */
+               __raw_writel(ttccs->scale_clk_ctrl_reg_old,
+                               ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+               /* fall through */
        default:
                return NOTIFY_DONE;
        }
+
+       return NOTIFY_DONE;
 }
 
 static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base)
@@ -321,25 +385,12 @@ static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
 
        switch (event) {
        case POST_RATE_CHANGE:
-       {
-               unsigned long flags;
-
-               /*
-                * clockevents_update_freq should be called with IRQ disabled on
-                * the CPU the timer provides events for. The timer we use is
-                * common to both CPUs, not sure if we need to run on both
-                * cores.
-                */
-               local_irq_save(flags);
-               clockevents_update_freq(&ttcce->ce,
-                               ndata->new_rate / PRESCALE);
-               local_irq_restore(flags);
-
                /* update cached frequency */
                ttc->freq = ndata->new_rate;
 
+               clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE);
+
                /* fall through */
-       }
        case PRE_RATE_CHANGE:
        case ABORT_RATE_CHANGE:
        default:
index 48f76bc05da0d8fb5b5515cd6c919a9cf3c373f6..c2e390efbdca6fc2b71a3e39356ddb9c2156200a 100644 (file)
@@ -410,7 +410,7 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
        mevt = container_of(evt, struct mct_clock_event_device, evt);
 
        mevt->base = EXYNOS4_MCT_L_BASE(cpu);
-       sprintf(mevt->name, "mct_tick%d", cpu);
+       snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
 
        evt->name = mevt->name;
        evt->cpumask = cpumask_of(cpu);
index bf497afba9ad1ef0c6c8ec57c9761f05d3acf799..efb17c3ee120e5ee28fa05099c4c3c7ce09f0ac1 100644 (file)
@@ -196,5 +196,5 @@ static void __init sun4i_timer_init(struct device_node *node)
        clockevents_config_and_register(&sun4i_clockevent, rate,
                                        TIMER_SYNC_TICKS, 0xffffffff);
 }
-CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
+CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
                       sun4i_timer_init);
index ee8691b89944e3fcbc3dbf7eeaadf00ec38ffd93..0451e62fac7a8e31fd2bc370a83b4fdc4083bf01 100644 (file)
@@ -85,12 +85,6 @@ static u32 ticks_per_jiffy;
 
 static struct clock_event_device __percpu *armada_370_xp_evt;
 
-static void timer_ctrl_clrset(u32 clr, u32 set)
-{
-       writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
-               timer_base + TIMER_CTRL_OFF);
-}
-
 static void local_timer_ctrl_clrset(u32 clr, u32 set)
 {
        writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
@@ -245,7 +239,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
                clr = TIMER0_25MHZ;
                enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT);
        }
-       timer_ctrl_clrset(clr, set);
+       atomic_io_modify(timer_base + TIMER_CTRL_OFF, clr | set, set);
        local_timer_ctrl_clrset(clr, set);
 
        /*
@@ -263,7 +257,9 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
        writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
        writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
 
-       timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
+       atomic_io_modify(timer_base + TIMER_CTRL_OFF,
+               TIMER0_RELOAD_EN | enable_mask,
+               TIMER0_RELOAD_EN | enable_mask);
 
        /*
         * Set scale and timer for sched_clock.
index 20066222f3f29cdb052c2282eafd1dadb8519d8b..0b3ce0399c519e354117a7a5c06a754f63453da6 100644 (file)
 #define ORION_ONESHOT_MAX      0xfffffffe
 
 static void __iomem *timer_base;
-static DEFINE_SPINLOCK(timer_ctrl_lock);
-
-/*
- * Thread-safe access to TIMER_CTRL register
- * (shared with watchdog timer)
- */
-void orion_timer_ctrl_clrset(u32 clr, u32 set)
-{
-       spin_lock(&timer_ctrl_lock);
-       writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
-               timer_base + TIMER_CTRL);
-       spin_unlock(&timer_ctrl_lock);
-}
-EXPORT_SYMBOL(orion_timer_ctrl_clrset);
 
 /*
  * Free-running clocksource handling.
@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta,
 {
        /* setup and enable one-shot timer */
        writel(delta, timer_base + TIMER1_VAL);
-       orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+       atomic_io_modify(timer_base + TIMER_CTRL,
+               TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN);
 
        return 0;
 }
@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,
                /* setup and enable periodic timer at 1/HZ intervals */
                writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
                writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
-               orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+               atomic_io_modify(timer_base + TIMER_CTRL,
+                       TIMER1_RELOAD_EN | TIMER1_EN,
+                       TIMER1_RELOAD_EN | TIMER1_EN);
        } else {
                /* disable timer */
-               orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+               atomic_io_modify(timer_base + TIMER_CTRL,
+                       TIMER1_RELOAD_EN | TIMER1_EN, 0);
        }
 }
 
@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)
        /* setup timer0 as free-running clocksource */
        writel(~0, timer_base + TIMER0_VAL);
        writel(~0, timer_base + TIMER0_RELOAD);
-       orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+       atomic_io_modify(timer_base + TIMER_CTRL,
+               TIMER0_RELOAD_EN | TIMER0_EN,
+               TIMER0_RELOAD_EN | TIMER0_EN);
        clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
                              clk_get_rate(clk), 300, 32,
                              clocksource_mmio_readl_down);
diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c
new file mode 100644 (file)
index 0000000..0250354
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Keystone broadcast clock-event
+ *
+ * Copyright 2013 Texas Instruments, Inc.
+ *
+ * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TIMER_NAME                     "timer-keystone"
+
+/* Timer register offsets */
+#define TIM12                          0x10
+#define TIM34                          0x14
+#define PRD12                          0x18
+#define PRD34                          0x1c
+#define TCR                            0x20
+#define TGCR                           0x24
+#define INTCTLSTAT                     0x44
+
+/* Timer register bitfields */
+#define TCR_ENAMODE_MASK               0xC0
+#define TCR_ENAMODE_ONESHOT_MASK       0x40
+#define TCR_ENAMODE_PERIODIC_MASK      0x80
+
+#define TGCR_TIM_UNRESET_MASK          0x03
+#define INTCTLSTAT_ENINT_MASK          0x01
+
+/**
+ * struct keystone_timer: holds timer's data
+ * @base: timer memory base address
+ * @hz_period: cycles per HZ period
+ * @event_dev: event device based on timer
+ */
+static struct keystone_timer {
+       void __iomem *base;
+       unsigned long hz_period;
+       struct clock_event_device event_dev;
+} timer;
+
+static inline u32 keystone_timer_readl(unsigned long rg)
+{
+       return readl_relaxed(timer.base + rg);
+}
+
+static inline void keystone_timer_writel(u32 val, unsigned long rg)
+{
+       writel_relaxed(val, timer.base + rg);
+}
+
+/**
+ * keystone_timer_barrier: write memory barrier
+ * use explicit barrier to avoid using readl/writel non relaxed function
+ * variants, because in our case non relaxed variants hide the true places
+ * where barrier is needed.
+ */
+static inline void keystone_timer_barrier(void)
+{
+       __iowmb();
+}
+
+/**
+ * keystone_timer_config: configures timer to work in oneshot/periodic modes.
+ * @ mode: mode to configure
+ * @ period: cycles number to configure for
+ */
+static int keystone_timer_config(u64 period, enum clock_event_mode mode)
+{
+       u32 tcr;
+       u32 off;
+
+       tcr = keystone_timer_readl(TCR);
+       off = tcr & ~(TCR_ENAMODE_MASK);
+
+       /* set enable mode */
+       switch (mode) {
+       case CLOCK_EVT_MODE_ONESHOT:
+               tcr |= TCR_ENAMODE_ONESHOT_MASK;
+               break;
+       case CLOCK_EVT_MODE_PERIODIC:
+               tcr |= TCR_ENAMODE_PERIODIC_MASK;
+               break;
+       default:
+               return -1;
+       }
+
+       /* disable timer */
+       keystone_timer_writel(off, TCR);
+       /* here we have to be sure the timer has been disabled */
+       keystone_timer_barrier();
+
+       /* reset counter to zero, set new period */
+       keystone_timer_writel(0, TIM12);
+       keystone_timer_writel(0, TIM34);
+       keystone_timer_writel(period & 0xffffffff, PRD12);
+       keystone_timer_writel(period >> 32, PRD34);
+
+       /*
+        * enable timer
+        * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers
+        * have been written.
+        */
+       keystone_timer_barrier();
+       keystone_timer_writel(tcr, TCR);
+       return 0;
+}
+
+static void keystone_timer_disable(void)
+{
+       u32 tcr;
+
+       tcr = keystone_timer_readl(TCR);
+
+       /* disable timer */
+       tcr &= ~(TCR_ENAMODE_MASK);
+       keystone_timer_writel(tcr, TCR);
+}
+
+static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = dev_id;
+
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+static int keystone_set_next_event(unsigned long cycles,
+                                 struct clock_event_device *evt)
+{
+       return keystone_timer_config(cycles, evt->mode);
+}
+
+static void keystone_set_mode(enum clock_event_mode mode,
+                            struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_ONESHOT:
+               keystone_timer_disable();
+               break;
+       default:
+               break;
+       }
+}
+
+static void __init keystone_timer_init(struct device_node *np)
+{
+       struct clock_event_device *event_dev = &timer.event_dev;
+       unsigned long rate;
+       struct clk *clk;
+       int irq, error;
+
+       irq  = irq_of_parse_and_map(np, 0);
+       if (irq == NO_IRQ) {
+               pr_err("%s: failed to map interrupts\n", __func__);
+               return;
+       }
+
+       timer.base = of_iomap(np, 0);
+       if (!timer.base) {
+               pr_err("%s: failed to map registers\n", __func__);
+               return;
+       }
+
+       clk = of_clk_get(np, 0);
+       if (IS_ERR(clk)) {
+               pr_err("%s: failed to get clock\n", __func__);
+               iounmap(timer.base);
+               return;
+       }
+
+       error = clk_prepare_enable(clk);
+       if (error) {
+               pr_err("%s: failed to enable clock\n", __func__);
+               goto err;
+       }
+
+       rate = clk_get_rate(clk);
+
+       /* disable, use internal clock source */
+       keystone_timer_writel(0, TCR);
+       /* here we have to be sure the timer has been disabled */
+       keystone_timer_barrier();
+
+       /* reset timer as 64-bit, no pre-scaler, plus features are disabled */
+       keystone_timer_writel(0, TGCR);
+
+       /* unreset timer */
+       keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR);
+
+       /* init counter to zero */
+       keystone_timer_writel(0, TIM12);
+       keystone_timer_writel(0, TIM34);
+
+       timer.hz_period = DIV_ROUND_UP(rate, HZ);
+
+       /* enable timer interrupts */
+       keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT);
+
+       error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER,
+                           TIMER_NAME, event_dev);
+       if (error) {
+               pr_err("%s: failed to setup irq\n", __func__);
+               goto err;
+       }
+
+       /* setup clockevent */
+       event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       event_dev->set_next_event = keystone_set_next_event;
+       event_dev->set_mode = keystone_set_mode;
+       event_dev->cpumask = cpu_all_mask;
+       event_dev->owner = THIS_MODULE;
+       event_dev->name = TIMER_NAME;
+       event_dev->irq = irq;
+
+       clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX);
+
+       pr_info("keystone timer clock @%lu Hz\n", rate);
+       return;
+err:
+       clk_put(clk);
+       iounmap(timer.base);
+}
+
+CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer",
+                                       keystone_timer_init);
diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c
new file mode 100644 (file)
index 0000000..e63d469
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Timer COH 901 328, runs the OS timer interrupt.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+
+/* Generic stuff */
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+/*
+ * APP side special timer registers
+ * This timer contains four timers which can fire an interrupt each.
+ * OS (operating system) timer @ 32768 Hz
+ * DD (device driver) timer @ 1 kHz
+ * GP1 (general purpose 1) timer @ 1MHz
+ * GP2 (general purpose 2) timer @ 1MHz
+ */
+
+/* Reset OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_ROST                                    (0x0000)
+#define U300_TIMER_APP_ROST_TIMER_RESET                                (0x00000000)
+/* Enable OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_EOST                                    (0x0004)
+#define U300_TIMER_APP_EOST_TIMER_ENABLE                       (0x00000000)
+/* Disable OS Timer 32bit (-/W) */
+#define U300_TIMER_APP_DOST                                    (0x0008)
+#define U300_TIMER_APP_DOST_TIMER_DISABLE                      (0x00000000)
+/* OS Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SOSTM                                   (0x000c)
+#define U300_TIMER_APP_SOSTM_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_SOSTM_MODE_ONE_SHOT                     (0x00000001)
+/* OS Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_OSTS                                    (0x0010)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_MASK                   (0x0000000F)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_IDLE                   (0x00000001)
+#define U300_TIMER_APP_OSTS_TIMER_STATE_ACTIVE                 (0x00000002)
+#define U300_TIMER_APP_OSTS_ENABLE_IND                         (0x00000010)
+#define U300_TIMER_APP_OSTS_MODE_MASK                          (0x00000020)
+#define U300_TIMER_APP_OSTS_MODE_CONTINUOUS                    (0x00000000)
+#define U300_TIMER_APP_OSTS_MODE_ONE_SHOT                      (0x00000020)
+#define U300_TIMER_APP_OSTS_IRQ_ENABLED_IND                    (0x00000040)
+#define U300_TIMER_APP_OSTS_IRQ_PENDING_IND                    (0x00000080)
+/* OS Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_OSTCC                                   (0x0014)
+/* OS Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_OSTTC                                   (0x0018)
+/* OS Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_OSTIE                                   (0x001c)
+#define U300_TIMER_APP_OSTIE_IRQ_DISABLE                       (0x00000000)
+#define U300_TIMER_APP_OSTIE_IRQ_ENABLE                                (0x00000001)
+/* OS Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_OSTIA                                   (0x0020)
+#define U300_TIMER_APP_OSTIA_IRQ_ACK                           (0x00000080)
+
+/* Reset DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_RDDT                                    (0x0040)
+#define U300_TIMER_APP_RDDT_TIMER_RESET                                (0x00000000)
+/* Enable DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_EDDT                                    (0x0044)
+#define U300_TIMER_APP_EDDT_TIMER_ENABLE                       (0x00000000)
+/* Disable DD Timer 32bit (-/W) */
+#define U300_TIMER_APP_DDDT                                    (0x0048)
+#define U300_TIMER_APP_DDDT_TIMER_DISABLE                      (0x00000000)
+/* DD Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SDDTM                                   (0x004c)
+#define U300_TIMER_APP_SDDTM_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_SDDTM_MODE_ONE_SHOT                     (0x00000001)
+/* DD Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_DDTS                                    (0x0050)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_MASK                   (0x0000000F)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_IDLE                   (0x00000001)
+#define U300_TIMER_APP_DDTS_TIMER_STATE_ACTIVE                 (0x00000002)
+#define U300_TIMER_APP_DDTS_ENABLE_IND                         (0x00000010)
+#define U300_TIMER_APP_DDTS_MODE_MASK                          (0x00000020)
+#define U300_TIMER_APP_DDTS_MODE_CONTINUOUS                    (0x00000000)
+#define U300_TIMER_APP_DDTS_MODE_ONE_SHOT                      (0x00000020)
+#define U300_TIMER_APP_DDTS_IRQ_ENABLED_IND                    (0x00000040)
+#define U300_TIMER_APP_DDTS_IRQ_PENDING_IND                    (0x00000080)
+/* DD Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_DDTCC                                   (0x0054)
+/* DD Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_DDTTC                                   (0x0058)
+/* DD Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_DDTIE                                   (0x005c)
+#define U300_TIMER_APP_DDTIE_IRQ_DISABLE                       (0x00000000)
+#define U300_TIMER_APP_DDTIE_IRQ_ENABLE                                (0x00000001)
+/* DD Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_DDTIA                                   (0x0060)
+#define U300_TIMER_APP_DDTIA_IRQ_ACK                           (0x00000080)
+
+/* Reset GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_RGPT1                                   (0x0080)
+#define U300_TIMER_APP_RGPT1_TIMER_RESET                       (0x00000000)
+/* Enable GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_EGPT1                                   (0x0084)
+#define U300_TIMER_APP_EGPT1_TIMER_ENABLE                      (0x00000000)
+/* Disable GP1 Timer 32bit (-/W) */
+#define U300_TIMER_APP_DGPT1                                   (0x0088)
+#define U300_TIMER_APP_DGPT1_TIMER_DISABLE                     (0x00000000)
+/* GP1 Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SGPT1M                                  (0x008c)
+#define U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS                  (0x00000000)
+#define U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT                    (0x00000001)
+/* GP1 Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT1S                                   (0x0090)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_MASK                  (0x0000000F)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_IDLE                  (0x00000001)
+#define U300_TIMER_APP_GPT1S_TIMER_STATE_ACTIVE                        (0x00000002)
+#define U300_TIMER_APP_GPT1S_ENABLE_IND                                (0x00000010)
+#define U300_TIMER_APP_GPT1S_MODE_MASK                         (0x00000020)
+#define U300_TIMER_APP_GPT1S_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_GPT1S_MODE_ONE_SHOT                     (0x00000020)
+#define U300_TIMER_APP_GPT1S_IRQ_ENABLED_IND                   (0x00000040)
+#define U300_TIMER_APP_GPT1S_IRQ_PENDING_IND                   (0x00000080)
+/* GP1 Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT1CC                                  (0x0094)
+/* GP1 Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_GPT1TC                                  (0x0098)
+/* GP1 Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT1IE                                  (0x009c)
+#define U300_TIMER_APP_GPT1IE_IRQ_DISABLE                      (0x00000000)
+#define U300_TIMER_APP_GPT1IE_IRQ_ENABLE                       (0x00000001)
+/* GP1 Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT1IA                                  (0x00a0)
+#define U300_TIMER_APP_GPT1IA_IRQ_ACK                          (0x00000080)
+
+/* Reset GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_RGPT2                                   (0x00c0)
+#define U300_TIMER_APP_RGPT2_TIMER_RESET                       (0x00000000)
+/* Enable GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_EGPT2                                   (0x00c4)
+#define U300_TIMER_APP_EGPT2_TIMER_ENABLE                      (0x00000000)
+/* Disable GP2 Timer 32bit (-/W) */
+#define U300_TIMER_APP_DGPT2                                   (0x00c8)
+#define U300_TIMER_APP_DGPT2_TIMER_DISABLE                     (0x00000000)
+/* GP2 Timer Mode Register 32bit (-/W) */
+#define U300_TIMER_APP_SGPT2M                                  (0x00cc)
+#define U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS                  (0x00000000)
+#define U300_TIMER_APP_SGPT2M_MODE_ONE_SHOT                    (0x00000001)
+/* GP2 Timer Status Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT2S                                   (0x00d0)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_MASK                  (0x0000000F)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_IDLE                  (0x00000001)
+#define U300_TIMER_APP_GPT2S_TIMER_STATE_ACTIVE                        (0x00000002)
+#define U300_TIMER_APP_GPT2S_ENABLE_IND                                (0x00000010)
+#define U300_TIMER_APP_GPT2S_MODE_MASK                         (0x00000020)
+#define U300_TIMER_APP_GPT2S_MODE_CONTINUOUS                   (0x00000000)
+#define U300_TIMER_APP_GPT2S_MODE_ONE_SHOT                     (0x00000020)
+#define U300_TIMER_APP_GPT2S_IRQ_ENABLED_IND                   (0x00000040)
+#define U300_TIMER_APP_GPT2S_IRQ_PENDING_IND                   (0x00000080)
+/* GP2 Timer Current Count Register 32bit (R/-) */
+#define U300_TIMER_APP_GPT2CC                                  (0x00d4)
+/* GP2 Timer Terminal Count Register 32bit (R/W) */
+#define U300_TIMER_APP_GPT2TC                                  (0x00d8)
+/* GP2 Timer Interrupt Enable Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT2IE                                  (0x00dc)
+#define U300_TIMER_APP_GPT2IE_IRQ_DISABLE                      (0x00000000)
+#define U300_TIMER_APP_GPT2IE_IRQ_ENABLE                       (0x00000001)
+/* GP2 Timer Interrupt Acknowledge Register 32bit (-/W) */
+#define U300_TIMER_APP_GPT2IA                                  (0x00e0)
+#define U300_TIMER_APP_GPT2IA_IRQ_ACK                          (0x00000080)
+
+/* Clock request control register - all four timers */
+#define U300_TIMER_APP_CRC                                     (0x100)
+#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE                        (0x00000001)
+
+static void __iomem *u300_timer_base;
+
+struct u300_clockevent_data {
+       struct clock_event_device cevd;
+       unsigned ticks_per_jiffy;
+};
+
+/*
+ * The u300_set_mode() function is always called first, if we
+ * have oneshot timer active, the oneshot scheduling function
+ * u300_set_next_event() is called immediately after.
+ */
+static void u300_set_mode(enum clock_event_mode mode,
+                         struct clock_event_device *evt)
+{
+       struct u300_clockevent_data *cevdata =
+               container_of(evt, struct u300_clockevent_data, cevd);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* Disable interrupts on GPT1 */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+                      u300_timer_base + U300_TIMER_APP_GPT1IE);
+               /* Disable GP1 while we're reprogramming it. */
+               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+                      u300_timer_base + U300_TIMER_APP_DGPT1);
+               /*
+                * Set the periodic mode to a certain number of ticks per
+                * jiffy.
+                */
+               writel(cevdata->ticks_per_jiffy,
+                      u300_timer_base + U300_TIMER_APP_GPT1TC);
+               /*
+                * Set continuous mode, so the timer keeps triggering
+                * interrupts.
+                */
+               writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
+                      u300_timer_base + U300_TIMER_APP_SGPT1M);
+               /* Enable timer interrupts */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+                      u300_timer_base + U300_TIMER_APP_GPT1IE);
+               /* Then enable the OS timer again */
+               writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+                      u300_timer_base + U300_TIMER_APP_EGPT1);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* Just break; here? */
+               /*
+                * The actual event will be programmed by the next event hook,
+                * so we just set a dummy value somewhere at the end of the
+                * universe here.
+                */
+               /* Disable interrupts on GPT1 */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+                      u300_timer_base + U300_TIMER_APP_GPT1IE);
+               /* Disable GP1 while we're reprogramming it. */
+               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+                      u300_timer_base + U300_TIMER_APP_DGPT1);
+               /*
+                * Expire far in the future, u300_set_next_event() will be
+                * called soon...
+                */
+               writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC);
+               /* We run one shot per tick here! */
+               writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
+                      u300_timer_base + U300_TIMER_APP_SGPT1M);
+               /* Enable interrupts for this timer */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+                      u300_timer_base + U300_TIMER_APP_GPT1IE);
+               /* Enable timer */
+               writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+                      u300_timer_base + U300_TIMER_APP_EGPT1);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /* Disable interrupts on GP1 */
+               writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+                      u300_timer_base + U300_TIMER_APP_GPT1IE);
+               /* Disable GP1 */
+               writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+                      u300_timer_base + U300_TIMER_APP_DGPT1);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               /* Ignore this call */
+               break;
+       }
+}
+
+/*
+ * The app timer in one shot mode obviously has to be reprogrammed
+ * in EXACTLY this sequence to work properly. Do NOT try to e.g. replace
+ * the interrupt disable + timer disable commands with a reset command,
+ * it will fail miserably. Apparently (and I found this the hard way)
+ * the timer is very sensitive to the instruction order, though you don't
+ * get that impression from the data sheet.
+ */
+static int u300_set_next_event(unsigned long cycles,
+                              struct clock_event_device *evt)
+
+{
+       /* Disable interrupts on GPT1 */
+       writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
+              u300_timer_base + U300_TIMER_APP_GPT1IE);
+       /* Disable GP1 while we're reprogramming it. */
+       writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
+              u300_timer_base + U300_TIMER_APP_DGPT1);
+       /* Reset the General Purpose timer 1. */
+       writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
+              u300_timer_base + U300_TIMER_APP_RGPT1);
+       /* IRQ in n * cycles */
+       writel(cycles, u300_timer_base + U300_TIMER_APP_GPT1TC);
+       /*
+        * We run one shot per tick here! (This is necessary to reconfigure,
+        * the timer will tilt if you don't!)
+        */
+       writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
+              u300_timer_base + U300_TIMER_APP_SGPT1M);
+       /* Enable timer interrupts */
+       writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
+              u300_timer_base + U300_TIMER_APP_GPT1IE);
+       /* Then enable the OS timer again */
+       writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
+              u300_timer_base + U300_TIMER_APP_EGPT1);
+       return 0;
+}
+
+static struct u300_clockevent_data u300_clockevent_data = {
+       /* Use general purpose timer 1 as clock event */
+       .cevd = {
+               .name           = "GPT1",
+               /* Reasonably fast and accurate clock event */
+               .rating         = 300,
+               .features       = CLOCK_EVT_FEAT_PERIODIC |
+                       CLOCK_EVT_FEAT_ONESHOT,
+               .set_next_event = u300_set_next_event,
+               .set_mode       = u300_set_mode,
+       },
+};
+
+/* Clock event timer interrupt handler */
+static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &u300_clockevent_data.cevd;
+       /* ACK/Clear timer IRQ for the APP GPT1 Timer */
+
+       writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
+               u300_timer_base + U300_TIMER_APP_GPT1IA);
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction u300_timer_irq = {
+       .name           = "U300 Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = u300_timer_interrupt,
+};
+
+/*
+ * Override the global weak sched_clock symbol with this
+ * local implementation which uses the clocksource to get some
+ * better resolution when scheduling the kernel. We accept that
+ * this wraps around for now, since it is just a relative time
+ * stamp. (Inspired by OMAP implementation.)
+ */
+
+static u64 notrace u300_read_sched_clock(void)
+{
+       return readl(u300_timer_base + U300_TIMER_APP_GPT2CC);
+}
+
+static unsigned long u300_read_current_timer(void)
+{
+       return readl(u300_timer_base + U300_TIMER_APP_GPT2CC);
+}
+
+static struct delay_timer u300_delay_timer;
+
+/*
+ * This sets up the system timers, clock source and clock event.
+ */
+static void __init u300_timer_init_of(struct device_node *np)
+{
+       unsigned int irq;
+       struct clk *clk;
+       unsigned long rate;
+
+       u300_timer_base = of_iomap(np, 0);
+       if (!u300_timer_base)
+               panic("could not ioremap system timer\n");
+
+       /* Get the IRQ for the GP1 timer */
+       irq = irq_of_parse_and_map(np, 2);
+       if (!irq)
+               panic("no IRQ for system timer\n");
+
+       pr_info("U300 GP1 timer @ base: %p, IRQ: %u\n", u300_timer_base, irq);
+
+       /* Clock the interrupt controller */
+       clk = of_clk_get(np, 0);
+       BUG_ON(IS_ERR(clk));
+       clk_prepare_enable(clk);
+       rate = clk_get_rate(clk);
+
+       u300_clockevent_data.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
+
+       sched_clock_register(u300_read_sched_clock, 32, rate);
+
+       u300_delay_timer.read_current_timer = &u300_read_current_timer;
+       u300_delay_timer.freq = rate;
+       register_current_timer_delay(&u300_delay_timer);
+
+       /*
+        * Disable the "OS" and "DD" timers - these are designed for Symbian!
+        * Example usage in cnh1601578 cpu subsystem pd_timer_app.c
+        */
+       writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE,
+               u300_timer_base + U300_TIMER_APP_CRC);
+       writel(U300_TIMER_APP_ROST_TIMER_RESET,
+               u300_timer_base + U300_TIMER_APP_ROST);
+       writel(U300_TIMER_APP_DOST_TIMER_DISABLE,
+               u300_timer_base + U300_TIMER_APP_DOST);
+       writel(U300_TIMER_APP_RDDT_TIMER_RESET,
+               u300_timer_base + U300_TIMER_APP_RDDT);
+       writel(U300_TIMER_APP_DDDT_TIMER_DISABLE,
+               u300_timer_base + U300_TIMER_APP_DDDT);
+
+       /* Reset the General Purpose timer 1. */
+       writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
+               u300_timer_base + U300_TIMER_APP_RGPT1);
+
+       /* Set up the IRQ handler */
+       setup_irq(irq, &u300_timer_irq);
+
+       /* Reset the General Purpose timer 2 */
+       writel(U300_TIMER_APP_RGPT2_TIMER_RESET,
+               u300_timer_base + U300_TIMER_APP_RGPT2);
+       /* Set this timer to run around forever */
+       writel(0xFFFFFFFFU, u300_timer_base + U300_TIMER_APP_GPT2TC);
+       /* Set continuous mode so it wraps around */
+       writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS,
+              u300_timer_base + U300_TIMER_APP_SGPT2M);
+       /* Disable timer interrupts */
+       writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE,
+               u300_timer_base + U300_TIMER_APP_GPT2IE);
+       /* Then enable the GP2 timer to use as a free running us counter */
+       writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
+               u300_timer_base + U300_TIMER_APP_EGPT2);
+
+       /* Use general purpose timer 2 as clock source */
+       if (clocksource_mmio_init(u300_timer_base + U300_TIMER_APP_GPT2CC,
+                       "GPT2", rate, 300, 32, clocksource_mmio_readl_up))
+               pr_err("timer: failed to initialize U300 clock source\n");
+
+       /* Configure and register the clockevent */
+       clockevents_config_and_register(&u300_clockevent_data.cevd, rate,
+                                       1, 0xffffffff);
+
+       /*
+        * TODO: init and register the rest of the timers too, they can be
+        * used by hrtimers!
+        */
+}
+
+CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer",
+                      u300_timer_init_of);
index 02821b06a39e33be4cb403b202286deb530ff399..a918bc481c52c46a83f2e1ff1a50a96dc4180082 100644 (file)
@@ -54,7 +54,7 @@ static inline void pit_irq_acknowledge(void)
 
 static u64 pit_read_sched_clock(void)
 {
-       return __raw_readl(clksrc_base + PITCVAL);
+       return ~__raw_readl(clksrc_base + PITCVAL);
 }
 
 static int __init pit_clocksource_init(unsigned long rate)
index 18c5b9b16645dfa49a218d4b12253240f97310b7..148d707a1d439375ef36bf2ac8e6655fe2a61042 100644 (file)
@@ -95,7 +95,7 @@ void proc_fork_connector(struct task_struct *task)
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
        /*  If cn_netlink_send() failed, the data is not sent */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_exec_connector(struct task_struct *task)
@@ -122,7 +122,7 @@ void proc_exec_connector(struct task_struct *task)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_id_connector(struct task_struct *task, int which_id)
@@ -163,7 +163,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_sid_connector(struct task_struct *task)
@@ -190,7 +190,7 @@ void proc_sid_connector(struct task_struct *task)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
@@ -225,7 +225,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_comm_connector(struct task_struct *task)
@@ -253,7 +253,7 @@ void proc_comm_connector(struct task_struct *task)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_coredump_connector(struct task_struct *task)
@@ -280,7 +280,7 @@ void proc_coredump_connector(struct task_struct *task)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 void proc_exit_connector(struct task_struct *task)
@@ -309,7 +309,7 @@ void proc_exit_connector(struct task_struct *task)
        msg->ack = 0; /* not used */
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 /*
@@ -343,7 +343,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
        msg->ack = rcvd_ack + 1;
        msg->len = sizeof(*ev);
        msg->flags = 0; /* not used */
-       cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+       cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
 }
 
 /**
index a36749f1e44a869418e1bcab6481334948618391..77afe7487d34e4f94b40dd7727571827069b2236 100644 (file)
@@ -50,7 +50,7 @@ static int cn_already_initialized;
  *
  * Sequence number is incremented with each message to be sent.
  *
- * If we expect reply to our message then the sequence number in
+ * If we expect reply to our message then the sequence number in
  * received message MUST be the same as in original message, and
  * acknowledge number MUST be the same + 1.
  *
@@ -62,8 +62,11 @@ static int cn_already_initialized;
  * the acknowledgement number in the original message + 1, then it is
  * a new message.
  *
+ * The message is sent to, the portid if given, the group if given, both if
+ * both, or if both are zero then the group is looked up and sent there.
  */
-int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
+int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group,
+       gfp_t gfp_mask)
 {
        struct cn_callback_entry *__cbq;
        unsigned int size;
@@ -74,7 +77,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
        u32 group = 0;
        int found = 0;
 
-       if (!__group) {
+       if (portid || __group) {
+               group = __group;
+       } else {
                spin_lock_bh(&dev->cbdev->queue_lock);
                list_for_each_entry(__cbq, &dev->cbdev->queue_list,
                                    callback_entry) {
@@ -88,11 +93,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
 
                if (!found)
                        return -ENODEV;
-       } else {
-               group = __group;
        }
 
-       if (!netlink_has_listeners(dev->nls, group))
+       if (!portid && !netlink_has_listeners(dev->nls, group))
                return -ESRCH;
 
        size = sizeof(*msg) + msg->len;
@@ -113,7 +116,10 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
 
        NETLINK_CB(skb).dst_group = group;
 
-       return netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
+       if (group)
+               return netlink_broadcast(dev->nls, skb, portid, group,
+                                        gfp_mask);
+       return netlink_unicast(dev->nls, skb, portid, !(gfp_mask&__GFP_WAIT));
 }
 EXPORT_SYMBOL_GPL(cn_netlink_send);
 
index 4b029c0944af5ef55b9bdb02a266cbcb3ecd2d23..1fbe11f2a14603e499042974e7fc8064414978a4 100644 (file)
@@ -200,7 +200,7 @@ source "drivers/cpufreq/Kconfig.x86"
 endmenu
 
 menu "ARM CPU frequency scaling drivers"
-depends on ARM
+depends on ARM || ARM64
 source "drivers/cpufreq/Kconfig.arm"
 endmenu
 
index 31297499a60ad94d8f7636271bb64e1832b4209a..9fb627046e17ad33c5f1c2cc1078a27e1df1245b 100644 (file)
@@ -2,6 +2,7 @@
 # ARM CPU Frequency scaling drivers
 #
 
+# big LITTLE core layer and glue drivers
 config ARM_BIG_LITTLE_CPUFREQ
        tristate "Generic ARM big LITTLE CPUfreq driver"
        depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
@@ -16,6 +17,14 @@ config ARM_DT_BL_CPUFREQ
          This enables probing via DT for Generic CPUfreq driver for ARM
          big.LITTLE platform. This gets frequency tables from DT.
 
+config ARM_VEXPRESS_SPC_CPUFREQ
+        tristate "Versatile Express SPC based CPUfreq driver"
+       depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC
+        help
+          This add the CPUfreq driver support for Versatile Express
+         big.LITTLE platforms using SPC for power management.
+
+
 config ARM_EXYNOS_CPUFREQ
        bool
 
@@ -241,11 +250,3 @@ config ARM_TEGRA_CPUFREQ
        default y
        help
          This adds the CPUFreq driver support for TEGRA SOCs.
-
-config ARM_VEXPRESS_SPC_CPUFREQ
-        tristate "Versatile Express SPC based CPUfreq driver"
-        select ARM_BIG_LITTLE_CPUFREQ
-        depends on ARCH_VEXPRESS_SPC
-        help
-          This add the CPUfreq driver support for Versatile Express
-         big.LITTLE platforms using SPC for power management.
index 18448a7e9f8654e1560d2ec7eb354dd85ba094f4..822ca03a87f796ae321cb9c2bd54ffe7380b5581 100644 (file)
@@ -855,7 +855,6 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
        pr_debug("acpi_cpufreq_cpu_exit\n");
 
        if (data) {
-               cpufreq_frequency_table_put_attr(policy->cpu);
                per_cpu(acfreq_data, policy->cpu) = NULL;
                acpi_processor_unregister_performance(data->acpi_data,
                                                      policy->cpu);
index 72f87e9317e31057525b0785b36d78467890a34c..bad2ed317ba294462212bc00cc3cc94132e0aeb2 100644 (file)
@@ -446,9 +446,12 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
        }
 
        if (cur_cluster < MAX_CLUSTERS) {
+               int cpu;
+
                cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
 
-               per_cpu(physical_cluster, policy->cpu) = cur_cluster;
+               for_each_cpu(cpu, policy->cpus)
+                       per_cpu(physical_cluster, cpu) = cur_cluster;
        } else {
                /* Assumption: during init, we are always running on A15 */
                per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
@@ -478,7 +481,6 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
                return -ENODEV;
        }
 
-       cpufreq_frequency_table_put_attr(policy->cpu);
        put_cluster_clk_and_freq_table(cpu_dev);
        dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
 
index e9e63fc9c2c9d09b7710f61d3c8769ac77584bcc..a9f8e5bd0716f508858627d33c381437153fc3a3 100644 (file)
@@ -195,7 +195,6 @@ static struct cpufreq_driver bfin_driver = {
        .target_index = bfin_target,
        .get = bfin_getfreq_khz,
        .init = __bfin_cpu_init,
-       .exit = cpufreq_generic_exit,
        .name = "bfin cpufreq",
        .attr = cpufreq_generic_attr,
 };
index 0c12ffc0ebcbf2a5daad62e4a47674fdcedadf75..1bf6bbac3e03ae1bd9ffc4f001a71f7a0d0befcb 100644 (file)
@@ -109,7 +109,6 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
        .target_index = cpu0_set_target,
        .get = cpufreq_generic_get,
        .init = cpu0_cpufreq_init,
-       .exit = cpufreq_generic_exit,
        .name = "generic_cpu0",
        .attr = cpufreq_generic_attr,
 };
index cb003a6b72c86f10f31afd0d7b3c156308f95acc..3aa7a7a226b3f23f2977975651fc0fc2869ffd7b 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/syscore_ops.h>
+#include <linux/suspend.h>
 #include <linux/tick.h>
 #include <trace/events/power.h>
 
@@ -42,10 +42,11 @@ static DEFINE_RWLOCK(cpufreq_driver_lock);
 DEFINE_MUTEX(cpufreq_governor_lock);
 static LIST_HEAD(cpufreq_policy_list);
 
-#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
+
+/* Flag to suspend/resume CPUFreq governors */
+static bool cpufreq_suspended;
 
 static inline bool has_target(void)
 {
@@ -181,8 +182,8 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
        struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
 
        if (!policy || IS_ERR(policy->clk)) {
-               pr_err("%s: No %s associated to cpu: %d\n", __func__,
-                               policy ? "clk" : "policy", cpu);
+               pr_err("%s: No %s associated to cpu: %d\n",
+                      __func__, policy ? "clk" : "policy", cpu);
                return 0;
        }
 
@@ -190,6 +191,12 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
 }
 EXPORT_SYMBOL_GPL(cpufreq_generic_get);
 
+/* Only for cpufreq core internal use */
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
+{
+       return per_cpu(cpufreq_cpu_data, cpu);
+}
+
 struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 {
        struct cpufreq_policy *policy = NULL;
@@ -254,15 +261,14 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
        if (!l_p_j_ref_freq) {
                l_p_j_ref = loops_per_jiffy;
                l_p_j_ref_freq = ci->old;
-               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);
+               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) ||
-           (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+       if (val == CPUFREQ_POSTCHANGE && ci->old != ci->new) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
-               pr_debug("scaling loops_per_jiffy to %lu "
-                       "for frequency %u kHz\n", loops_per_jiffy, ci->new);
+               pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
+                        loops_per_jiffy, ci->new);
        }
 }
 #else
@@ -282,7 +288,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
 
        freqs->flags = cpufreq_driver->flags;
        pr_debug("notification %u of frequency transition to %u kHz\n",
-               state, freqs->new);
+                state, freqs->new);
 
        switch (state) {
 
@@ -294,9 +300,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
                        if ((policy) && (policy->cpu == freqs->cpu) &&
                            (policy->cur) && (policy->cur != freqs->old)) {
-                               pr_debug("Warning: CPU frequency is"
-                                       " %u, cpufreq assumed %u kHz.\n",
-                                       freqs->old, policy->cur);
+                               pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
+                                        freqs->old, policy->cur);
                                freqs->old = policy->cur;
                        }
                }
@@ -307,8 +312,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
 
        case CPUFREQ_POSTCHANGE:
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
-               pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
-                       (unsigned long)freqs->cpu);
+               pr_debug("FREQ: %lu - CPU: %lu\n",
+                        (unsigned long)freqs->new, (unsigned long)freqs->cpu);
                trace_cpu_frequency(freqs->new, freqs->cpu);
                srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
                                CPUFREQ_POSTCHANGE, freqs);
@@ -352,7 +357,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
 /*********************************************************************
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
-ssize_t show_boost(struct kobject *kobj,
+static ssize_t show_boost(struct kobject *kobj,
                                 struct attribute *attr, char *buf)
 {
        return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
@@ -368,13 +373,13 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
                return -EINVAL;
 
        if (cpufreq_boost_trigger_state(enable)) {
-               pr_err("%s: Cannot %s BOOST!\n", __func__,
-                      enable ? "enable" : "disable");
+               pr_err("%s: Cannot %s BOOST!\n",
+                      __func__, enable ? "enable" : "disable");
                return -EINVAL;
        }
 
-       pr_debug("%s: cpufreq BOOST %s\n", __func__,
-                enable ? "enabled" : "disabled");
+       pr_debug("%s: cpufreq BOOST %s\n",
+                __func__, enable ? "enabled" : "disabled");
 
        return count;
 }
@@ -879,18 +884,25 @@ err_out_kobj_put:
 
 static void cpufreq_init_policy(struct cpufreq_policy *policy)
 {
+       struct cpufreq_governor *gov = NULL;
        struct cpufreq_policy new_policy;
        int ret = 0;
 
        memcpy(&new_policy, policy, sizeof(*policy));
 
+       /* Update governor of new_policy to the governor used before hotplug */
+       gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
+       if (gov)
+               pr_debug("Restoring governor %s for cpu %d\n",
+                               policy->governor->name, policy->cpu);
+       else
+               gov = CPUFREQ_DEFAULT_GOVERNOR;
+
+       new_policy.governor = gov;
+
        /* Use the default policy if its valid. */
        if (cpufreq_driver->setpolicy)
-               cpufreq_parse_governor(policy->governor->name,
-                                       &new_policy.policy, NULL);
-
-       /* assure that the starting sequence is run in cpufreq_set_policy */
-       policy->governor = NULL;
+               cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
 
        /* set default policy */
        ret = cpufreq_set_policy(policy, &new_policy);
@@ -927,8 +939,11 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
        up_write(&policy->rwsem);
 
        if (has_target()) {
-               if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
-                       (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+               ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+               if (!ret)
+                       ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+               if (ret) {
                        pr_err("%s: Failed to start governor\n", __func__);
                        return ret;
                }
@@ -949,6 +964,8 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
 
        read_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
+       policy->governor = NULL;
+
        return policy;
 }
 
@@ -1022,21 +1039,19 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
 
        up_write(&policy->rwsem);
 
-       cpufreq_frequency_table_update_policy_cpu(policy);
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                        CPUFREQ_UPDATE_POLICY_CPU, policy);
 }
 
-static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
-                            bool frozen)
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int j, cpu = dev->id;
        int ret = -ENOMEM;
        struct cpufreq_policy *policy;
        unsigned long flags;
+       bool recover_policy = cpufreq_suspended;
 #ifdef CONFIG_HOTPLUG_CPU
        struct cpufreq_policy *tpolicy;
-       struct cpufreq_governor *gov;
 #endif
 
        if (cpu_is_offline(cpu))
@@ -1075,9 +1090,9 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
         * Restore the saved policy when doing light-weight init and fall back
         * to the full init if that fails.
         */
-       policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
+       policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;
        if (!policy) {
-               frozen = false;
+               recover_policy = false;
                policy = cpufreq_policy_alloc();
                if (!policy)
                        goto nomem_out;
@@ -1089,12 +1104,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
         * the creation of a brand new one. So we need to perform this update
         * by invoking update_policy_cpu().
         */
-       if (frozen && cpu != policy->cpu)
+       if (recover_policy && cpu != policy->cpu)
                update_policy_cpu(policy, cpu);
        else
                policy->cpu = cpu;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        cpumask_copy(policy->cpus, cpumask_of(cpu));
 
        init_completion(&policy->kobj_unregister);
@@ -1109,12 +1123,27 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                goto err_set_policy_cpu;
        }
 
+       /* related cpus should atleast have policy->cpus */
+       cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+       /*
+        * affected cpus must always be the one, which are online. We aren't
+        * managing offline cpus here.
+        */
+       cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
+       if (!recover_policy) {
+               policy->user_policy.min = policy->min;
+               policy->user_policy.max = policy->max;
+       }
+
+       down_write(&policy->rwsem);
        write_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu(j, policy->cpus)
                per_cpu(cpufreq_cpu_data, j) = policy;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       if (cpufreq_driver->get) {
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
                policy->cur = cpufreq_driver->get(policy->cpu);
                if (!policy->cur) {
                        pr_err("%s: ->get() failed\n", __func__);
@@ -1162,33 +1191,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                }
        }
 
-       /* related cpus should atleast have policy->cpus */
-       cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
-
-       /*
-        * affected cpus must always be the one, which are online. We aren't
-        * managing offline cpus here.
-        */
-       cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
-
-       if (!frozen) {
-               policy->user_policy.min = policy->min;
-               policy->user_policy.max = policy->max;
-       }
-
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                                     CPUFREQ_START, policy);
 
-#ifdef CONFIG_HOTPLUG_CPU
-       gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
-       if (gov) {
-               policy->governor = gov;
-               pr_debug("Restoring governor %s for cpu %d\n",
-                      policy->governor->name, cpu);
-       }
-#endif
-
-       if (!frozen) {
+       if (!recover_policy) {
                ret = cpufreq_add_dev_interface(policy, dev);
                if (ret)
                        goto err_out_unregister;
@@ -1202,10 +1208,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
 
        cpufreq_init_policy(policy);
 
-       if (!frozen) {
+       if (!recover_policy) {
                policy->user_policy.policy = policy->policy;
                policy->user_policy.governor = policy->governor;
        }
+       up_write(&policy->rwsem);
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        up_read(&cpufreq_rwsem);
@@ -1224,7 +1231,7 @@ err_get_freq:
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
 err_set_policy_cpu:
-       if (frozen) {
+       if (recover_policy) {
                /* Do not leave stale fallback data behind. */
                per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
                cpufreq_policy_put_kobj(policy);
@@ -1248,7 +1255,7 @@ nomem_out:
  */
 static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 {
-       return __cpufreq_add_dev(dev, sif, false);
+       return __cpufreq_add_dev(dev, sif);
 }
 
 static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
@@ -1263,7 +1270,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
        sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
        ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
        if (ret) {
-               pr_err("%s: Failed to move kobj: %d", __func__, ret);
+               pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
 
                down_write(&policy->rwsem);
                cpumask_set_cpu(old_cpu, policy->cpus);
@@ -1279,8 +1286,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
 }
 
 static int __cpufreq_remove_dev_prepare(struct device *dev,
-                                       struct subsys_interface *sif,
-                                       bool frozen)
+                                       struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id, cpus;
        int new_cpu, ret;
@@ -1294,7 +1300,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
        policy = per_cpu(cpufreq_cpu_data, cpu);
 
        /* Save the policy somewhere when doing a light-weight tear-down */
-       if (frozen)
+       if (cpufreq_suspended)
                per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
 
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -1312,11 +1318,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
                }
        }
 
-#ifdef CONFIG_HOTPLUG_CPU
        if (!cpufreq_driver->setpolicy)
                strncpy(per_cpu(cpufreq_cpu_governor, cpu),
                        policy->governor->name, CPUFREQ_NAME_LEN);
-#endif
 
        down_read(&policy->rwsem);
        cpus = cpumask_weight(policy->cpus);
@@ -1329,19 +1333,19 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
                if (new_cpu >= 0) {
                        update_policy_cpu(policy, new_cpu);
 
-                       if (!frozen) {
+                       if (!cpufreq_suspended)
                                pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
-                                               __func__, new_cpu, cpu);
-                       }
+                                        __func__, new_cpu, cpu);
                }
+       } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
+               cpufreq_driver->stop_cpu(policy);
        }
 
        return 0;
 }
 
 static int __cpufreq_remove_dev_finish(struct device *dev,
-                                      struct subsys_interface *sif,
-                                      bool frozen)
+                                      struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id, cpus;
        int ret;
@@ -1371,12 +1375,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
                                        CPUFREQ_GOV_POLICY_EXIT);
                        if (ret) {
                                pr_err("%s: Failed to exit governor\n",
-                                               __func__);
+                                      __func__);
                                return ret;
                        }
                }
 
-               if (!frozen)
+               if (!cpufreq_suspended)
                        cpufreq_policy_put_kobj(policy);
 
                /*
@@ -1392,16 +1396,16 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
                list_del(&policy->policy_list);
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-               if (!frozen)
+               if (!cpufreq_suspended)
                        cpufreq_policy_free(policy);
-       } else {
-               if (has_target()) {
-                       if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
-                                       (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
-                               pr_err("%s: Failed to start governor\n",
-                                               __func__);
-                               return ret;
-                       }
+       } else if (has_target()) {
+               ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+               if (!ret)
+                       ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+               if (ret) {
+                       pr_err("%s: Failed to start governor\n", __func__);
+                       return ret;
                }
        }
 
@@ -1422,10 +1426,10 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        if (cpu_is_offline(cpu))
                return 0;
 
-       ret = __cpufreq_remove_dev_prepare(dev, sif, false);
+       ret = __cpufreq_remove_dev_prepare(dev, sif);
 
        if (!ret)
-               ret = __cpufreq_remove_dev_finish(dev, sif, false);
+               ret = __cpufreq_remove_dev_finish(dev, sif);
 
        return ret;
 }
@@ -1456,8 +1460,8 @@ 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);
+       pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
+                old_freq, new_freq);
 
        freqs.old = old_freq;
        freqs.new = new_freq;
@@ -1546,23 +1550,16 @@ static unsigned int __cpufreq_get(unsigned int cpu)
  */
 unsigned int cpufreq_get(unsigned int cpu)
 {
-       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
        unsigned int ret_freq = 0;
 
-       if (cpufreq_disabled() || !cpufreq_driver)
-               return -ENOENT;
-
-       BUG_ON(!policy);
-
-       if (!down_read_trylock(&cpufreq_rwsem))
-               return 0;
-
-       down_read(&policy->rwsem);
-
-       ret_freq = __cpufreq_get(cpu);
+       if (policy) {
+               down_read(&policy->rwsem);
+               ret_freq = __cpufreq_get(cpu);
+               up_read(&policy->rwsem);
 
-       up_read(&policy->rwsem);
-       up_read(&cpufreq_rwsem);
+               cpufreq_cpu_put(policy);
+       }
 
        return ret_freq;
 }
@@ -1575,83 +1572,104 @@ static struct subsys_interface cpufreq_interface = {
        .remove_dev     = cpufreq_remove_dev,
 };
 
+/*
+ * In case platform wants some specific frequency to be configured
+ * during suspend..
+ */
+int cpufreq_generic_suspend(struct cpufreq_policy *policy)
+{
+       int ret;
+
+       if (!policy->suspend_freq) {
+               pr_err("%s: suspend_freq can't be zero\n", __func__);
+               return -EINVAL;
+       }
+
+       pr_debug("%s: Setting suspend-freq: %u\n", __func__,
+                       policy->suspend_freq);
+
+       ret = __cpufreq_driver_target(policy, policy->suspend_freq,
+                       CPUFREQ_RELATION_H);
+       if (ret)
+               pr_err("%s: unable to set suspend-freq: %u. err: %d\n",
+                               __func__, policy->suspend_freq, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(cpufreq_generic_suspend);
+
 /**
- * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
+ * cpufreq_suspend() - Suspend CPUFreq governors
  *
- * This function is only executed for the boot processor.  The other CPUs
- * have been put offline by means of CPU hotplug.
+ * Called during system wide Suspend/Hibernate cycles for suspending governors
+ * as some platforms can't change frequency after this point in suspend cycle.
+ * Because some of the devices (like: i2c, regulators, etc) they use for
+ * changing frequency are suspended quickly after this point.
  */
-static int cpufreq_bp_suspend(void)
+void cpufreq_suspend(void)
 {
-       int ret = 0;
-
-       int cpu = smp_processor_id();
        struct cpufreq_policy *policy;
 
-       pr_debug("suspending cpu %u\n", cpu);
+       if (!cpufreq_driver)
+               return;
 
-       /* If there's no policy for the boot CPU, we have nothing to do. */
-       policy = cpufreq_cpu_get(cpu);
-       if (!policy)
-               return 0;
+       if (!has_target())
+               return;
 
-       if (cpufreq_driver->suspend) {
-               ret = cpufreq_driver->suspend(policy);
-               if (ret)
-                       printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
-                                       "step on CPU %u\n", policy->cpu);
+       pr_debug("%s: Suspending Governors\n", __func__);
+
+       list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+               if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
+                       pr_err("%s: Failed to stop governor for policy: %p\n",
+                               __func__, policy);
+               else if (cpufreq_driver->suspend
+                   && cpufreq_driver->suspend(policy))
+                       pr_err("%s: Failed to suspend driver: %p\n", __func__,
+                               policy);
        }
 
-       cpufreq_cpu_put(policy);
-       return ret;
+       cpufreq_suspended = true;
 }
 
 /**
- * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
- *
- *     1.) resume CPUfreq hardware support (cpufreq_driver->resume())
- *     2.) schedule call cpufreq_update_policy() ASAP as interrupts are
- *         restored. It will verify that the current freq is in sync with
- *         what we believe it to be. This is a bit later than when it
- *         should be, but nonethteless it's better than calling
- *         cpufreq_driver->get() here which might re-enable interrupts...
+ * cpufreq_resume() - Resume CPUFreq governors
  *
- * This function is only executed for the boot CPU.  The other CPUs have not
- * been turned on yet.
+ * Called during system wide Suspend/Hibernate cycle for resuming governors that
+ * are suspended with cpufreq_suspend().
  */
-static void cpufreq_bp_resume(void)
+void cpufreq_resume(void)
 {
-       int ret = 0;
-
-       int cpu = smp_processor_id();
        struct cpufreq_policy *policy;
 
-       pr_debug("resuming cpu %u\n", cpu);
+       if (!cpufreq_driver)
+               return;
 
-       /* If there's no policy for the boot CPU, we have nothing to do. */
-       policy = cpufreq_cpu_get(cpu);
-       if (!policy)
+       if (!has_target())
                return;
 
-       if (cpufreq_driver->resume) {
-               ret = cpufreq_driver->resume(policy);
-               if (ret) {
-                       printk(KERN_ERR "cpufreq: resume failed in ->resume "
-                                       "step on CPU %u\n", policy->cpu);
-                       goto fail;
-               }
-       }
+       pr_debug("%s: Resuming Governors\n", __func__);
 
-       schedule_work(&policy->update);
+       cpufreq_suspended = false;
 
-fail:
-       cpufreq_cpu_put(policy);
-}
+       list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+               if (__cpufreq_governor(policy, CPUFREQ_GOV_START)
+                   || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))
+                       pr_err("%s: Failed to start governor for policy: %p\n",
+                               __func__, policy);
+               else if (cpufreq_driver->resume
+                   && cpufreq_driver->resume(policy))
+                       pr_err("%s: Failed to resume driver: %p\n", __func__,
+                               policy);
 
-static struct syscore_ops cpufreq_syscore_ops = {
-       .suspend        = cpufreq_bp_suspend,
-       .resume         = cpufreq_bp_resume,
-};
+               /*
+                * schedule call cpufreq_update_policy() for boot CPU, i.e. last
+                * policy in list. It will verify that the current freq is in
+                * sync with what we believe it to be.
+                */
+               if (list_is_last(&policy->policy_list, &cpufreq_policy_list))
+                       schedule_work(&policy->update);
+       }
+}
 
 /**
  *     cpufreq_get_current_driver - return current driver's name
@@ -1767,7 +1785,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
                target_freq = policy->min;
 
        pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
-                       policy->cpu, target_freq, relation, old_target_freq);
+                policy->cpu, target_freq, relation, old_target_freq);
 
        /*
         * This might look like a redundant call as we are checking it again
@@ -1812,8 +1830,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
                        freqs.flags = 0;
 
                        pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
-                                       __func__, policy->cpu, freqs.old,
-                                       freqs.new);
+                                __func__, policy->cpu, freqs.old, freqs.new);
 
                        cpufreq_notify_transition(policy, &freqs,
                                        CPUFREQ_PRECHANGE);
@@ -1822,7 +1839,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
                retval = cpufreq_driver->target_index(policy, index);
                if (retval)
                        pr_err("%s: Failed to change cpu frequency: %d\n",
-                                       __func__, retval);
+                              __func__, retval);
 
                if (notify)
                        cpufreq_notify_post_transition(policy, &freqs, retval);
@@ -1868,17 +1885,18 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        struct cpufreq_governor *gov = NULL;
 #endif
 
+       /* Don't start any governor operations if we are entering suspend */
+       if (cpufreq_suspended)
+               return 0;
+
        if (policy->governor->max_transition_latency &&
            policy->cpuinfo.transition_latency >
            policy->governor->max_transition_latency) {
                if (!gov)
                        return -EINVAL;
                else {
-                       printk(KERN_WARNING "%s governor failed, too long"
-                              " transition latency of HW, fallback"
-                              " to %s governor\n",
-                              policy->governor->name,
-                              gov->name);
+                       pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
+                               policy->governor->name, gov->name);
                        policy->governor = gov;
                }
        }
@@ -1888,7 +1906,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                        return -EINVAL;
 
        pr_debug("__cpufreq_governor for CPU %u, event %u\n",
-                                               policy->cpu, event);
+                policy->cpu, event);
 
        mutex_lock(&cpufreq_governor_lock);
        if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
@@ -1955,9 +1973,7 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
 
 void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 {
-#ifdef CONFIG_HOTPLUG_CPU
        int cpu;
-#endif
 
        if (!governor)
                return;
@@ -1965,14 +1981,12 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
        if (cpufreq_disabled())
                return;
 
-#ifdef CONFIG_HOTPLUG_CPU
        for_each_present_cpu(cpu) {
                if (cpu_online(cpu))
                        continue;
                if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
                        strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
        }
-#endif
 
        mutex_lock(&cpufreq_governor_mutex);
        list_del(&governor->governor_list);
@@ -2017,22 +2031,21 @@ EXPORT_SYMBOL(cpufreq_get_policy);
 static int cpufreq_set_policy(struct cpufreq_policy *policy,
                                struct cpufreq_policy *new_policy)
 {
-       int ret = 0, failed = 1;
+       struct cpufreq_governor *old_gov;
+       int ret;
 
-       pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
-               new_policy->min, new_policy->max);
+       pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
+                new_policy->cpu, new_policy->min, new_policy->max);
 
        memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-       if (new_policy->min > policy->max || new_policy->max < policy->min) {
-               ret = -EINVAL;
-               goto error_out;
-       }
+       if (new_policy->min > policy->max || new_policy->max < policy->min)
+               return -EINVAL;
 
        /* verify the cpu speed can be set within this limit */
        ret = cpufreq_driver->verify(new_policy);
        if (ret)
-               goto error_out;
+               return ret;
 
        /* adjust if necessary - all reasons */
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
@@ -2048,7 +2061,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
         */
        ret = cpufreq_driver->verify(new_policy);
        if (ret)
-               goto error_out;
+               return ret;
 
        /* notification of the new policy */
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
@@ -2058,63 +2071,53 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        policy->max = new_policy->max;
 
        pr_debug("new min and max freqs are %u - %u kHz\n",
-                                       policy->min, policy->max);
+                policy->min, policy->max);
 
        if (cpufreq_driver->setpolicy) {
                policy->policy = new_policy->policy;
                pr_debug("setting range\n");
-               ret = cpufreq_driver->setpolicy(new_policy);
-       } else {
-               if (new_policy->governor != policy->governor) {
-                       /* save old, working values */
-                       struct cpufreq_governor *old_gov = policy->governor;
-
-                       pr_debug("governor switch\n");
-
-                       /* end old governor */
-                       if (policy->governor) {
-                               __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
-                               up_write(&policy->rwsem);
-                               __cpufreq_governor(policy,
-                                               CPUFREQ_GOV_POLICY_EXIT);
-                               down_write(&policy->rwsem);
-                       }
+               return cpufreq_driver->setpolicy(new_policy);
+       }
 
-                       /* start new governor */
-                       policy->governor = new_policy->governor;
-                       if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
-                               if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
-                                       failed = 0;
-                               } else {
-                                       up_write(&policy->rwsem);
-                                       __cpufreq_governor(policy,
-                                                       CPUFREQ_GOV_POLICY_EXIT);
-                                       down_write(&policy->rwsem);
-                               }
-                       }
+       if (new_policy->governor == policy->governor)
+               goto out;
 
-                       if (failed) {
-                               /* new governor failed, so re-start old one */
-                               pr_debug("starting governor %s failed\n",
-                                                       policy->governor->name);
-                               if (old_gov) {
-                                       policy->governor = old_gov;
-                                       __cpufreq_governor(policy,
-                                                       CPUFREQ_GOV_POLICY_INIT);
-                                       __cpufreq_governor(policy,
-                                                          CPUFREQ_GOV_START);
-                               }
-                               ret = -EINVAL;
-                               goto error_out;
-                       }
-                       /* might be a policy change, too, so fall through */
-               }
-               pr_debug("governor: change or update limits\n");
-               ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+       pr_debug("governor switch\n");
+
+       /* save old, working values */
+       old_gov = policy->governor;
+       /* end old governor */
+       if (old_gov) {
+               __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+               up_write(&policy->rwsem);
+               __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+               down_write(&policy->rwsem);
        }
 
-error_out:
-       return ret;
+       /* start new governor */
+       policy->governor = new_policy->governor;
+       if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
+               if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))
+                       goto out;
+
+               up_write(&policy->rwsem);
+               __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+               down_write(&policy->rwsem);
+       }
+
+       /* new governor failed, so re-start old one */
+       pr_debug("starting governor %s failed\n", policy->governor->name);
+       if (old_gov) {
+               policy->governor = old_gov;
+               __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
+               __cpufreq_governor(policy, CPUFREQ_GOV_START);
+       }
+
+       return -EINVAL;
+
+ out:
+       pr_debug("governor: change or update limits\n");
+       return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
 }
 
 /**
@@ -2148,10 +2151,15 @@ int cpufreq_update_policy(unsigned int cpu)
         * BIOS might change freq behind our back
         * -> ask driver for current freq and notify governors about a change
         */
-       if (cpufreq_driver->get) {
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
                new_policy.cur = cpufreq_driver->get(cpu);
+               if (WARN_ON(!new_policy.cur)) {
+                       ret = -EIO;
+                       goto no_policy;
+               }
+
                if (!policy->cur) {
-                       pr_debug("Driver did not initialize current freq");
+                       pr_debug("Driver did not initialize current freq\n");
                        policy->cur = new_policy.cur;
                } else {
                        if (policy->cur != new_policy.cur && has_target())
@@ -2175,30 +2183,24 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
 {
        unsigned int cpu = (unsigned long)hcpu;
        struct device *dev;
-       bool frozen = false;
 
        dev = get_cpu_device(cpu);
        if (dev) {
-
-               if (action & CPU_TASKS_FROZEN)
-                       frozen = true;
-
                switch (action & ~CPU_TASKS_FROZEN) {
                case CPU_ONLINE:
-                       __cpufreq_add_dev(dev, NULL, frozen);
-                       cpufreq_update_policy(cpu);
+                       __cpufreq_add_dev(dev, NULL);
                        break;
 
                case CPU_DOWN_PREPARE:
-                       __cpufreq_remove_dev_prepare(dev, NULL, frozen);
+                       __cpufreq_remove_dev_prepare(dev, NULL);
                        break;
 
                case CPU_POST_DEAD:
-                       __cpufreq_remove_dev_finish(dev, NULL, frozen);
+                       __cpufreq_remove_dev_finish(dev, NULL);
                        break;
 
                case CPU_DOWN_FAILED:
-                       __cpufreq_add_dev(dev, NULL, frozen);
+                       __cpufreq_add_dev(dev, NULL);
                        break;
                }
        }
@@ -2254,8 +2256,8 @@ int cpufreq_boost_trigger_state(int state)
                cpufreq_driver->boost_enabled = !state;
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-               pr_err("%s: Cannot %s BOOST\n", __func__,
-                      state ? "enable" : "disable");
+               pr_err("%s: Cannot %s BOOST\n",
+                      __func__, state ? "enable" : "disable");
        }
 
        return ret;
@@ -2300,7 +2302,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 
        if (!driver_data || !driver_data->verify || !driver_data->init ||
            !(driver_data->setpolicy || driver_data->target_index ||
-                   driver_data->target))
+                   driver_data->target) ||
+            (driver_data->setpolicy && (driver_data->target_index ||
+                   driver_data->target)))
                return -EINVAL;
 
        pr_debug("trying to register driver %s\n", driver_data->name);
@@ -2327,7 +2331,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                ret = cpufreq_sysfs_create_file(&boost.attr);
                if (ret) {
                        pr_err("%s: cannot register global BOOST sysfs file\n",
-                               __func__);
+                              __func__);
                        goto err_null_driver;
                }
        }
@@ -2350,7 +2354,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                /* if all ->init() calls failed, unregister */
                if (ret) {
                        pr_debug("no CPU initialized for driver %s\n",
-                                                       driver_data->name);
+                                driver_data->name);
                        goto err_if_unreg;
                }
        }
@@ -2414,7 +2418,6 @@ static int __init cpufreq_core_init(void)
 
        cpufreq_global_kobject = kobject_create();
        BUG_ON(!cpufreq_global_kobject);
-       register_syscore_ops(&cpufreq_syscore_ops);
 
        return 0;
 }
index 5793e1447fb177f476f5f38ee117857444ba98c0..ecaaebf969fc4e5427464dfce53d0bb321e3c39b 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/cpufreq.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
 
 static spinlock_t cpufreq_stats_lock;
 
@@ -180,27 +180,25 @@ static void cpufreq_stats_free_table(unsigned int cpu)
        cpufreq_cpu_put(policy);
 }
 
-static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
-               struct cpufreq_frequency_table *table)
+static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
 {
        unsigned int i, j, count = 0, ret = 0;
        struct cpufreq_stats *stat;
-       struct cpufreq_policy *current_policy;
        unsigned int alloc_size;
        unsigned int cpu = policy->cpu;
+       struct cpufreq_frequency_table *table;
+
+       table = cpufreq_frequency_get_table(cpu);
+       if (unlikely(!table))
+               return 0;
+
        if (per_cpu(cpufreq_stats_table, cpu))
                return -EBUSY;
        stat = kzalloc(sizeof(*stat), GFP_KERNEL);
        if ((stat) == NULL)
                return -ENOMEM;
 
-       current_policy = cpufreq_cpu_get(cpu);
-       if (current_policy == NULL) {
-               ret = -EINVAL;
-               goto error_get_fail;
-       }
-
-       ret = sysfs_create_group(&current_policy->kobj, &stats_attr_group);
+       ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
        if (ret)
                goto error_out;
 
@@ -223,7 +221,7 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
        stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
        if (!stat->time_in_state) {
                ret = -ENOMEM;
-               goto error_out;
+               goto error_alloc;
        }
        stat->freq_table = (unsigned int *)(stat->time_in_state + count);
 
@@ -243,11 +241,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
        stat->last_time = get_jiffies_64();
        stat->last_index = freq_table_get_index(stat, policy->cur);
        spin_unlock(&cpufreq_stats_lock);
-       cpufreq_cpu_put(current_policy);
        return 0;
+error_alloc:
+       sysfs_remove_group(&policy->kobj, &stats_attr_group);
 error_out:
-       cpufreq_cpu_put(current_policy);
-error_get_fail:
        kfree(stat);
        per_cpu(cpufreq_stats_table, cpu) = NULL;
        return ret;
@@ -256,7 +253,6 @@ error_get_fail:
 static void cpufreq_stats_create_table(unsigned int cpu)
 {
        struct cpufreq_policy *policy;
-       struct cpufreq_frequency_table *table;
 
        /*
         * "likely(!policy)" because normally cpufreq_stats will be registered
@@ -266,9 +262,7 @@ static void cpufreq_stats_create_table(unsigned int cpu)
        if (likely(!policy))
                return;
 
-       table = cpufreq_frequency_get_table(policy->cpu);
-       if (likely(table))
-               __cpufreq_stats_create_table(policy, table);
+       __cpufreq_stats_create_table(policy);
 
        cpufreq_cpu_put(policy);
 }
@@ -291,20 +285,14 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
 {
        int ret = 0;
        struct cpufreq_policy *policy = data;
-       struct cpufreq_frequency_table *table;
-       unsigned int cpu = policy->cpu;
 
        if (val == CPUFREQ_UPDATE_POLICY_CPU) {
                cpufreq_stats_update_policy_cpu(policy);
                return 0;
        }
 
-       table = cpufreq_frequency_get_table(cpu);
-       if (!table)
-               return 0;
-
        if (val == CPUFREQ_CREATE_POLICY)
-               ret = __cpufreq_stats_create_table(policy, table);
+               ret = __cpufreq_stats_create_table(policy);
        else if (val == CPUFREQ_REMOVE_POLICY)
                __cpufreq_stats_free_table(policy);
 
index 86559040c54c83daad0778160cccdb7b19f43c22..d4573032cbbc6e5cdf522951a1ee4e3d86c2c47e 100644 (file)
@@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = cris_freq_target,
        .init   = cris_freq_cpu_init,
-       .exit   = cpufreq_generic_exit,
        .name   = "cris_freq",
        .attr   = cpufreq_generic_attr,
 };
index 26d940d40b1dcb1e19208a17176afe88e5632f35..13c3361437f7be274fec5b49be8f8aba1c43dd55 100644 (file)
@@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = cris_freq_target,
        .init = cris_freq_cpu_init,
-       .exit = cpufreq_generic_exit,
        .name = "cris_freq",
        .attr = cpufreq_generic_attr,
 };
index 2cf33848d86e44d25bba1ca9b440d752337f8227..28a16dc6e02ec8786e529ad176185846efcaf735 100644 (file)
@@ -125,7 +125,6 @@ static struct cpufreq_driver davinci_driver = {
        .target_index   = davinci_target,
        .get            = cpufreq_generic_get,
        .init           = davinci_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .name           = "davinci",
        .attr           = cpufreq_generic_attr,
 };
index 9012b8bb6b649abc18e6e1a623df56de69249a38..a0d2a423cea97e70b6745d48b63884c03e57d1de 100644 (file)
@@ -382,7 +382,6 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
        unsigned int cpu = policy->cpu;
 
        /* Bye */
-       cpufreq_frequency_table_put_attr(policy->cpu);
        kfree(eps_cpu[cpu]);
        eps_cpu[cpu] = NULL;
        return 0;
index de08acff5101dd64b93a913905a8961bfd08c69f..c987e94708f5015b7c48ce62795d0f93c0ed8c49 100644 (file)
@@ -198,7 +198,6 @@ static struct cpufreq_driver elanfreq_driver = {
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = elanfreq_target,
        .init           = elanfreq_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .name           = "elanfreq",
        .attr           = cpufreq_generic_attr,
 };
index fcd2914d081a8852620d3f420b433393fd66ec5e..f99cfe24e7bca6489dcbf592372a38d1d019f4f1 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/regulator/consumer.h>
 #include <linux/cpufreq.h>
-#include <linux/suspend.h>
 #include <linux/platform_device.h>
 
 #include <plat/cpu.h>
 #include "exynos-cpufreq.h"
 
 static struct exynos_dvfs_info *exynos_info;
-
 static struct regulator *arm_regulator;
-
 static unsigned int locking_frequency;
-static bool frequency_locked;
-static DEFINE_MUTEX(cpufreq_lock);
 
 static int exynos_cpufreq_get_index(unsigned int freq)
 {
@@ -134,83 +129,13 @@ out:
 
 static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
 {
-       struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
-       int ret = 0;
-
-       mutex_lock(&cpufreq_lock);
-
-       if (frequency_locked)
-               goto out;
-
-       ret = exynos_cpufreq_scale(freq_table[index].frequency);
-
-out:
-       mutex_unlock(&cpufreq_lock);
-
-       return ret;
-}
-
-#ifdef CONFIG_PM
-static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-
-static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-#endif
-
-/**
- * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
- *                     context
- * @notifier
- * @pm_event
- * @v
- *
- * While frequency_locked == true, target() ignores every frequency but
- * locking_frequency. The locking_frequency value is the initial frequency,
- * which is set by the bootloader. In order to eliminate possible
- * inconsistency in clock values, we save and restore frequencies during
- * suspend and resume and block CPUFREQ activities. Note that the standard
- * suspend/resume cannot be used as they are too deep (syscore_ops) for
- * regulator actions.
- */
-static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
-                                      unsigned long pm_event, void *v)
-{
-       int ret;
-
-       switch (pm_event) {
-       case PM_SUSPEND_PREPARE:
-               mutex_lock(&cpufreq_lock);
-               frequency_locked = true;
-               mutex_unlock(&cpufreq_lock);
-
-               ret = exynos_cpufreq_scale(locking_frequency);
-               if (ret < 0)
-                       return NOTIFY_BAD;
-
-               break;
-
-       case PM_POST_SUSPEND:
-               mutex_lock(&cpufreq_lock);
-               frequency_locked = false;
-               mutex_unlock(&cpufreq_lock);
-               break;
-       }
-
-       return NOTIFY_OK;
+       return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
 }
 
-static struct notifier_block exynos_cpufreq_nb = {
-       .notifier_call = exynos_cpufreq_pm_notifier,
-};
-
 static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
        policy->clk = exynos_info->cpu_clk;
+       policy->suspend_freq = locking_frequency;
        return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
 }
 
@@ -220,15 +145,13 @@ static struct cpufreq_driver exynos_driver = {
        .target_index   = exynos_target,
        .get            = cpufreq_generic_get,
        .init           = exynos_cpufreq_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .name           = "exynos_cpufreq",
        .attr           = cpufreq_generic_attr,
 #ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
        .boost_supported = true,
 #endif
 #ifdef CONFIG_PM
-       .suspend        = exynos_cpufreq_suspend,
-       .resume         = exynos_cpufreq_resume,
+       .suspend        = cpufreq_generic_suspend,
 #endif
 };
 
@@ -263,19 +186,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
                goto err_vdd_arm;
        }
 
+       /* Done here as we want to capture boot frequency */
        locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
 
-       register_pm_notifier(&exynos_cpufreq_nb);
-
-       if (cpufreq_register_driver(&exynos_driver)) {
-               pr_err("%s: failed to register cpufreq driver\n", __func__);
-               goto err_cpufreq;
-       }
-
-       return 0;
-err_cpufreq:
-       unregister_pm_notifier(&exynos_cpufreq_nb);
+       if (!cpufreq_register_driver(&exynos_driver))
+               return 0;
 
+       pr_err("%s: failed to register cpufreq driver\n", __func__);
        regulator_put(arm_regulator);
 err_vdd_arm:
        kfree(exynos_info);
index 49b756015316948fd783a0450441e30e285c1d8c..7f776aa91e2ff431f972bbb3995fcee82b941c66 100644 (file)
@@ -312,7 +312,6 @@ static struct cpufreq_driver exynos_driver = {
        .target_index   = exynos_target,
        .get            = cpufreq_generic_get,
        .init           = exynos_cpufreq_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .name           = CPUFREQ_NAME,
        .attr           = cpufreq_generic_attr,
 };
index 8e54f97899ba6feb7225275b7ddf2473ff8dc35b..65a477075b3f2d8c424bec5e39682550140051c0 100644 (file)
@@ -91,8 +91,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
 
 /*
- * Generic routine to verify policy & frequency table, requires driver to call
- * cpufreq_frequency_table_get_attr() prior to it.
+ * Generic routine to verify policy & frequency table, requires driver to set
+ * policy->freq_table prior to it.
  */
 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
 {
@@ -203,8 +203,6 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
 
-static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
-
 /**
  * show_available_freqs - show available frequencies for the specified CPU
  */
@@ -212,15 +210,12 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
                                    bool show_boost)
 {
        unsigned int i = 0;
-       unsigned int cpu = policy->cpu;
        ssize_t count = 0;
-       struct cpufreq_frequency_table *table;
+       struct cpufreq_frequency_table *table = policy->freq_table;
 
-       if (!per_cpu(cpufreq_show_table, cpu))
+       if (!table)
                return -ENODEV;
 
-       table = per_cpu(cpufreq_show_table, cpu);
-
        for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
@@ -283,49 +278,24 @@ struct freq_attr *cpufreq_generic_attr[] = {
 };
 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
 
-/*
- * if you use these, you must assure that the frequency table is valid
- * all the time between get_attr and put_attr!
- */
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
-                                     unsigned int cpu)
-{
-       pr_debug("setting show_table for cpu %u to %p\n", cpu, table);
-       per_cpu(cpufreq_show_table, cpu) = table;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
-
-void cpufreq_frequency_table_put_attr(unsigned int cpu)
-{
-       pr_debug("clearing show_table for cpu %u\n", cpu);
-       per_cpu(cpufreq_show_table, cpu) = NULL;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
-
 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
                                      struct cpufreq_frequency_table *table)
 {
        int ret = cpufreq_frequency_table_cpuinfo(policy, table);
 
        if (!ret)
-               cpufreq_frequency_table_get_attr(table, policy->cpu);
+               policy->freq_table = table;
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
 
-void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy)
-{
-       pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n",
-                       policy->cpu, policy->last_cpu);
-       per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table,
-                       policy->last_cpu);
-       per_cpu(cpufreq_show_table, policy->last_cpu) = NULL;
-}
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
 
 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
 {
-       return per_cpu(cpufreq_show_table, cpu);
+       struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
+       return policy ? policy->freq_table : NULL;
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
 
index 53c6ac637e10c437e12570d77c39e496b273276a..a22b5d182e0eb1767f96fd65063d1eebc935ec7c 100644 (file)
@@ -332,7 +332,6 @@ acpi_cpufreq_cpu_exit (
        pr_debug("acpi_cpufreq_cpu_exit\n");
 
        if (data) {
-               cpufreq_frequency_table_put_attr(policy->cpu);
                acpi_io_data[policy->cpu] = NULL;
                acpi_processor_unregister_performance(&data->acpi_data,
                                                      policy->cpu);
index ce69059be1fc95318284a9aecf0c21916244e1c9..e27fca86fe4f8e22547fa3f90d3bde5cec81fca6 100644 (file)
@@ -144,7 +144,6 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
        .target_index = imx6q_set_target,
        .get = cpufreq_generic_get,
        .init = imx6q_cpufreq_init,
-       .exit = cpufreq_generic_exit,
        .name = "imx6q-cpufreq",
        .attr = cpufreq_generic_attr,
 };
index 2cd36b9297f3de01a4b5f2ed246d738e123d7991..bcb9a6d0ae115fbb50ae369296f142a981fa0ceb 100644 (file)
@@ -99,8 +99,7 @@ struct cpudata {
        u64     prev_aperf;
        u64     prev_mperf;
        unsigned long long prev_tsc;
-       int     sample_ptr;
-       struct sample samples[SAMPLE_COUNT];
+       struct sample sample;
 };
 
 static struct cpudata **all_cpu_data;
@@ -154,7 +153,7 @@ static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
        pid->setpoint = setpoint;
        pid->deadband  = deadband;
        pid->integral  = int_tofp(integral);
-       pid->last_err  = setpoint - busy;
+       pid->last_err  = int_tofp(setpoint) - int_tofp(busy);
 }
 
 static inline void pid_p_gain_set(struct _pid *pid, int percent)
@@ -447,7 +446,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
        if (limits.no_turbo)
                val |= (u64)1 << 32;
 
-       wrmsrl(MSR_IA32_PERF_CTL, val);
+       wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
 }
 
 static struct cpu_defaults core_params = {
@@ -586,15 +585,14 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
        mperf = mperf >> FRAC_BITS;
        tsc = tsc >> FRAC_BITS;
 
-       cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
-       cpu->samples[cpu->sample_ptr].aperf = aperf;
-       cpu->samples[cpu->sample_ptr].mperf = mperf;
-       cpu->samples[cpu->sample_ptr].tsc = tsc;
-       cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
-       cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
-       cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc;
+       cpu->sample.aperf = aperf;
+       cpu->sample.mperf = mperf;
+       cpu->sample.tsc = tsc;
+       cpu->sample.aperf -= cpu->prev_aperf;
+       cpu->sample.mperf -= cpu->prev_mperf;
+       cpu->sample.tsc -= cpu->prev_tsc;
 
-       intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
+       intel_pstate_calc_busy(cpu, &cpu->sample);
 
        cpu->prev_aperf = aperf;
        cpu->prev_mperf = mperf;
@@ -614,7 +612,7 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
 {
        int32_t core_busy, max_pstate, current_pstate;
 
-       core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
+       core_busy = cpu->sample.core_pct_busy;
        max_pstate = int_tofp(cpu->pstate.max_pstate);
        current_pstate = int_tofp(cpu->pstate.current_pstate);
        core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
@@ -648,7 +646,7 @@ static void intel_pstate_timer_func(unsigned long __data)
 
        intel_pstate_sample(cpu);
 
-       sample = &cpu->samples[cpu->sample_ptr];
+       sample = &cpu->sample;
 
        intel_pstate_adjust_busy_pstate(cpu);
 
@@ -729,7 +727,7 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
        cpu = all_cpu_data[cpu_num];
        if (!cpu)
                return 0;
-       sample = &cpu->samples[cpu->sample_ptr];
+       sample = &cpu->sample;
        return sample->freq;
 }
 
@@ -773,14 +771,17 @@ static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
        return 0;
 }
 
-static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
+static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
 {
-       int cpu = policy->cpu;
+       int cpu_num = policy->cpu;
+       struct cpudata *cpu = all_cpu_data[cpu_num];
 
-       del_timer(&all_cpu_data[cpu]->timer);
-       kfree(all_cpu_data[cpu]);
-       all_cpu_data[cpu] = NULL;
-       return 0;
+       pr_info("intel_pstate CPU %d exiting\n", cpu_num);
+
+       del_timer(&all_cpu_data[cpu_num]->timer);
+       intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+       kfree(all_cpu_data[cpu_num]);
+       all_cpu_data[cpu_num] = NULL;
 }
 
 static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
@@ -818,7 +819,7 @@ static struct cpufreq_driver intel_pstate_driver = {
        .setpolicy      = intel_pstate_set_policy,
        .get            = intel_pstate_get,
        .init           = intel_pstate_cpu_init,
-       .exit           = intel_pstate_cpu_exit,
+       .stop_cpu       = intel_pstate_stop_cpu,
        .name           = "intel_pstate",
 };
 
index eb7abe345b50dd147351d8f9c22d6be892e5ad0a..3d114bc5a97ad56999b03d2f03d9c701a8c72f6b 100644 (file)
@@ -102,7 +102,6 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = {
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = kirkwood_cpufreq_target,
        .init   = kirkwood_cpufreq_cpu_init,
-       .exit   = cpufreq_generic_exit,
        .name   = "kirkwood-cpufreq",
        .attr   = cpufreq_generic_attr,
 };
index 45bafddfd8ea488ba24362b44a8aa58bf58304eb..7b94da3d2d1012e3075f73eb5dcb49523841a985 100644 (file)
@@ -913,7 +913,6 @@ static struct cpufreq_driver longhaul_driver = {
        .target_index = longhaul_target,
        .get    = longhaul_get,
        .init   = longhaul_cpu_init,
-       .exit   = cpufreq_generic_exit,
        .name   = "longhaul",
        .attr   = cpufreq_generic_attr,
 };
index b6581abc92078e44f40135045b38fddff3556584..a3588d61d933f62f313767b7034ca749e5dce163 100644 (file)
@@ -104,7 +104,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
 static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
 {
-       cpufreq_frequency_table_put_attr(policy->cpu);
        clk_put(policy->clk);
        return 0;
 }
index 590f5b66d18171e1034567c900164d06f7809ce1..5f69c9aa703cc3a58db0d254c1a3c77a816649f3 100644 (file)
@@ -143,7 +143,6 @@ fail:
 
 static int omap_cpu_exit(struct cpufreq_policy *policy)
 {
-       cpufreq_frequency_table_put_attr(policy->cpu);
        freq_table_free();
        clk_put(policy->clk);
        return 0;
index 3d1cba9fd5f93525d7e5117fe90e537fa019fae7..74f593e70e191ffdd8c297377cf347a833a9dbce 100644 (file)
@@ -237,7 +237,6 @@ static struct cpufreq_driver p4clockmod_driver = {
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = cpufreq_p4_target,
        .init           = cpufreq_p4_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .get            = cpufreq_p4_get,
        .name           = "p4-clockmod",
        .attr           = cpufreq_generic_attr,
index 0426008380d863d0d428526450efe9533c402a52..6a2b7d3e85a7bf408c926037a0949e4d0cf0143c 100644 (file)
@@ -234,7 +234,6 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
        if (sdcpwr_mapbase)
                iounmap(sdcpwr_mapbase);
 
-       cpufreq_frequency_table_put_attr(policy->cpu);
        return 0;
 }
 
index b9a444e358b5cfeb25da13739b374d02124cf011..ce27e6c26c94de3de132407b168acb1c06ac7782 100644 (file)
@@ -231,7 +231,6 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
                if (i == max_multiplier)
                        powernow_k6_target(policy, i);
        }
-       cpufreq_frequency_table_put_attr(policy->cpu);
        return 0;
 }
 
index 946708a1d7452d87adc932aac1e1edf7ce1fd29d..0e68e027562135fd34214d440abeaab4dc2405ed 100644 (file)
@@ -664,8 +664,6 @@ static int powernow_cpu_init(struct cpufreq_policy *policy)
 
 static int powernow_cpu_exit(struct cpufreq_policy *policy)
 {
-       cpufreq_frequency_table_put_attr(policy->cpu);
-
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
        if (acpi_processor_perf) {
                acpi_processor_unregister_performance(acpi_processor_perf, 0);
index 6684e0342792517577fde32d56542b3ad84d15af..27eb2be44de56cbae978069c5251fd74c2b76afb 100644 (file)
@@ -1164,8 +1164,6 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
 
        powernow_k8_cpu_exit_acpi(data);
 
-       cpufreq_frequency_table_put_attr(pol->cpu);
-
        kfree(data->powernow_table);
        kfree(data);
        for_each_cpu(cpu, pol->cpus)
index 051000f44ca2c788a839326ce4e99b81d90f82fb..3bd9123e702667e29f33d62ffae237a5e44ffdcd 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
+#include <sysdev/fsl_soc.h>
 
 /**
  * struct cpu_data - per CPU data struct
@@ -205,7 +206,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
        for_each_cpu(i, per_cpu(cpu_mask, cpu))
                per_cpu(cpu_data, i) = data;
 
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       policy->cpuinfo.transition_latency =
+                               (12 * NSEC_PER_SEC) / fsl_get_sys_freq();
        of_node_put(np);
 
        return 0;
@@ -228,7 +230,6 @@ 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);
index e42ca9c31ceaf03852206c92419b25e81dc45883..af7b1cabd1e76f643ae652de1b05e4b57107429c 100644 (file)
@@ -141,7 +141,6 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = cbe_cpufreq_target,
        .init           = cbe_cpufreq_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .name           = "cbe-cpufreq",
        .flags          = CPUFREQ_CONST_LOOPS,
 };
index a9195a86b069806e0c54e694a1c15e76b6bb56e2..e24269ab4e9bd91208b9971f2378b4a69a92648d 100644 (file)
@@ -427,7 +427,6 @@ static struct cpufreq_driver pxa_cpufreq_driver = {
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = pxa_set_target,
        .init   = pxa_cpufreq_init,
-       .exit   = cpufreq_generic_exit,
        .get    = pxa_cpufreq_get,
        .name   = "PXA2xx",
 };
index 3785687e9d70f2d04dc16769e7188a1b2e8e6326..a012759003897e2340baf74b1d1aa3519f99f278 100644 (file)
@@ -205,7 +205,6 @@ static struct cpufreq_driver pxa3xx_cpufreq_driver = {
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = pxa3xx_cpufreq_set,
        .init           = pxa3xx_cpufreq_init,
-       .exit           = cpufreq_generic_exit,
        .get            = pxa3xx_cpufreq_get,
        .name           = "pxa3xx-cpufreq",
 };
index 55a8e9fa9435f3226982de7e0f3133b2146b728e..72421534fff57753a5fec3b9660c4842578acd69 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/cpufreq.h>
 #include <linux/reboot.h>
 #include <linux/regulator/consumer.h>
-#include <linux/suspend.h>
 
 #include <mach/map.h>
 #include <mach/regs-clock.h>
@@ -435,18 +434,6 @@ exit:
        return ret;
 }
 
-#ifdef CONFIG_PM
-static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-
-static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-#endif
-
 static int check_mem_type(void __iomem *dmc_reg)
 {
        unsigned long val;
@@ -502,6 +489,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
        s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000);
        s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
 
+       policy->suspend_freq = SLEEP_FREQ;
        return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
 
 out_dmc1:
@@ -511,32 +499,6 @@ out_dmc0:
        return ret;
 }
 
-static int s5pv210_cpufreq_notifier_event(struct notifier_block *this,
-                                         unsigned long event, void *ptr)
-{
-       int ret;
-
-       switch (event) {
-       case PM_SUSPEND_PREPARE:
-               ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
-               if (ret < 0)
-                       return NOTIFY_BAD;
-
-               /* Disable updation of cpu frequency */
-               no_cpufreq_access = true;
-               return NOTIFY_OK;
-       case PM_POST_RESTORE:
-       case PM_POST_SUSPEND:
-               /* Enable updation of cpu frequency */
-               no_cpufreq_access = false;
-               cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
-
-               return NOTIFY_OK;
-       }
-
-       return NOTIFY_DONE;
-}
-
 static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
                                                 unsigned long event, void *ptr)
 {
@@ -558,15 +520,11 @@ static struct cpufreq_driver s5pv210_driver = {
        .init           = s5pv210_cpu_init,
        .name           = "s5pv210",
 #ifdef CONFIG_PM
-       .suspend        = s5pv210_cpufreq_suspend,
-       .resume         = s5pv210_cpufreq_resume,
+       .suspend        = cpufreq_generic_suspend,
+       .resume         = cpufreq_generic_suspend, /* We need to set SLEEP FREQ again */
 #endif
 };
 
-static struct notifier_block s5pv210_cpufreq_notifier = {
-       .notifier_call = s5pv210_cpufreq_notifier_event,
-};
-
 static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
        .notifier_call = s5pv210_cpufreq_reboot_notifier_event,
 };
@@ -586,7 +544,6 @@ static int __init s5pv210_cpufreq_init(void)
                return PTR_ERR(int_regulator);
        }
 
-       register_pm_notifier(&s5pv210_cpufreq_notifier);
        register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
 
        return cpufreq_register_driver(&s5pv210_driver);
index 6adb354e359cc5fef14b1844592abc905117b486..69371bf0886d11a17a86bb169dd624777f4b6048 100644 (file)
@@ -93,7 +93,6 @@ static struct cpufreq_driver sc520_freq_driver = {
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = sc520_freq_target,
        .init   = sc520_freq_cpu_init,
-       .exit   = cpufreq_generic_exit,
        .name   = "sc520_freq",
        .attr   = cpufreq_generic_attr,
 };
index 387af12503a64e43f15d8fd0fa1d6e108a741f62..696170ebd3a3efb8a92f1946215e863d58ce7e9a 100644 (file)
@@ -143,7 +143,6 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
        unsigned int cpu = policy->cpu;
        struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
 
-       cpufreq_frequency_table_put_attr(cpu);
        clk_put(cpuclk);
 
        return 0;
index 62aa23e219d4a993da1233cdaa23e1f85ee94f21..b73feeb666f9f9ecdf64e1afc3ecb605f4bd262b 100644 (file)
@@ -301,10 +301,8 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
 
 static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
 {
-       if (cpufreq_us2e_driver) {
-               cpufreq_frequency_table_put_attr(policy->cpu);
+       if (cpufreq_us2e_driver)
                us2e_freq_target(policy, 0);
-       }
 
        return 0;
 }
index 724ffbd7105d3611a0cb7112ba184a912954dc90..9bb42ba50efaf90d9b773fa1767422dd3c1f7c98 100644 (file)
@@ -156,10 +156,8 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
 
 static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
 {
-       if (cpufreq_us3_driver) {
-               cpufreq_frequency_table_put_attr(policy->cpu);
+       if (cpufreq_us3_driver)
                us3_freq_target(policy, 0);
-       }
 
        return 0;
 }
index 5c86e3fa55934c686ce5bc44fea45e254977e478..4cfdcff8a3109826195979495f307c4ff1902d65 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
@@ -163,11 +164,10 @@ static struct cpufreq_driver spear_cpufreq_driver = {
        .target_index   = spear_cpufreq_target,
        .get            = cpufreq_generic_get,
        .init           = spear_cpufreq_init,
-       .exit           = cpufreq_generic_exit,
        .attr           = cpufreq_generic_attr,
 };
 
-static int spear_cpufreq_driver_init(void)
+static int spear_cpufreq_probe(struct platform_device *pdev)
 {
        struct device_node *np;
        const struct property *prop;
@@ -235,7 +235,15 @@ out_put_node:
        of_node_put(np);
        return ret;
 }
-late_initcall(spear_cpufreq_driver_init);
+
+static struct platform_driver spear_cpufreq_platdrv = {
+       .driver = {
+               .name   = "spear-cpufreq",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = spear_cpufreq_probe,
+};
+module_platform_driver(spear_cpufreq_platdrv);
 
 MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>");
 MODULE_DESCRIPTION("SPEAr CPUFreq driver");
index 4e1daca5ce3b900c21955dda15b62c11415f6bee..6723f0390f20dace530f77f4d94c4109af48b351 100644 (file)
@@ -406,8 +406,6 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
        if (!per_cpu(centrino_model, cpu))
                return -ENODEV;
 
-       cpufreq_frequency_table_put_attr(cpu);
-
        per_cpu(centrino_model, cpu) = NULL;
 
        return 0;
index 7639b2be2a90495ef68c1fca8db8363a1b0caf08..394ac159312a03ffbd359db7c9e30efda9c044eb 100644 (file)
@@ -311,7 +311,6 @@ static struct cpufreq_driver speedstep_driver = {
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = speedstep_target,
        .init   = speedstep_cpu_init,
-       .exit   = cpufreq_generic_exit,
        .get    = speedstep_get,
        .attr   = cpufreq_generic_attr,
 };
index 998c17b4220073f5fddcbe784ba8e6850f6e0d20..db5d274dc13ad4e800c0bd51547c92b6619668ed 100644 (file)
@@ -280,7 +280,6 @@ static struct cpufreq_driver speedstep_driver = {
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = speedstep_target,
        .init           = speedstep_cpu_init,
-       .exit           = cpufreq_generic_exit,
        .get            = speedstep_get,
        .resume         = speedstep_resume,
        .attr           = cpufreq_generic_attr,
index e652c1bd8d0f57433c348053f0cc2edb13deba00..63f00598a251e9304d27092f74b2a4b9e7c0e636 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/suspend.h>
 
 static struct cpufreq_frequency_table freq_table[] = {
        { .frequency = 216000 },
@@ -47,9 +46,6 @@ static struct clk *pll_x_clk;
 static struct clk *pll_p_clk;
 static struct clk *emc_clk;
 
-static DEFINE_MUTEX(tegra_cpu_lock);
-static bool is_suspended;
-
 static int tegra_cpu_clk_set_rate(unsigned long rate)
 {
        int ret;
@@ -112,42 +108,9 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
 
 static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
 {
-       int ret = -EBUSY;
-
-       mutex_lock(&tegra_cpu_lock);
-
-       if (!is_suspended)
-               ret = tegra_update_cpu_speed(policy,
-                               freq_table[index].frequency);
-
-       mutex_unlock(&tegra_cpu_lock);
-       return ret;
+       return tegra_update_cpu_speed(policy, freq_table[index].frequency);
 }
 
-static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
-       void *dummy)
-{
-       mutex_lock(&tegra_cpu_lock);
-       if (event == PM_SUSPEND_PREPARE) {
-               struct cpufreq_policy *policy = cpufreq_cpu_get(0);
-               is_suspended = true;
-               pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
-                       freq_table[0].frequency);
-               if (clk_get_rate(cpu_clk) / 1000 != freq_table[0].frequency)
-                       tegra_update_cpu_speed(policy, freq_table[0].frequency);
-               cpufreq_cpu_put(policy);
-       } else if (event == PM_POST_SUSPEND) {
-               is_suspended = false;
-       }
-       mutex_unlock(&tegra_cpu_lock);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block tegra_cpu_pm_notifier = {
-       .notifier_call = tegra_pm_notify,
-};
-
 static int tegra_cpu_init(struct cpufreq_policy *policy)
 {
        int ret;
@@ -166,16 +129,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
                return ret;
        }
 
-       if (policy->cpu == 0)
-               register_pm_notifier(&tegra_cpu_pm_notifier);
-
        policy->clk = cpu_clk;
+       policy->suspend_freq = freq_table[0].frequency;
        return 0;
 }
 
 static int tegra_cpu_exit(struct cpufreq_policy *policy)
 {
-       cpufreq_frequency_table_put_attr(policy->cpu);
        clk_disable_unprepare(cpu_clk);
        clk_disable_unprepare(emc_clk);
        return 0;
@@ -190,6 +150,9 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
        .exit           = tegra_cpu_exit,
        .name           = "tegra",
        .attr           = cpufreq_generic_attr,
+#ifdef CONFIG_PM
+       .suspend        = cpufreq_generic_suspend,
+#endif
 };
 
 static int __init tegra_cpufreq_init(void)
index 78fd174c57e86dfb4608a12f4af44d334ab1da7c..f48607cd254024f07501bd802112e90991d697b1 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <asm/machdep.h>
 #include <asm/firmware.h>
+#include <asm/runlatch.h>
 
 struct cpuidle_driver powernv_idle_driver = {
        .name             = "powernv_idle",
@@ -30,12 +31,14 @@ static int snooze_loop(struct cpuidle_device *dev,
        local_irq_enable();
        set_thread_flag(TIF_POLLING_NRFLAG);
 
+       ppc64_runlatch_off();
        while (!need_resched()) {
                HMT_low();
                HMT_very_low();
        }
 
        HMT_medium();
+       ppc64_runlatch_on();
        clear_thread_flag(TIF_POLLING_NRFLAG);
        smp_mb();
        return index;
@@ -45,7 +48,9 @@ static int nap_loop(struct cpuidle_device *dev,
                        struct cpuidle_driver *drv,
                        int index)
 {
+       ppc64_runlatch_off();
        power7_idle();
+       ppc64_runlatch_on();
        return index;
 }
 
index 7ab564aa0b1c8c141e0b64f750592dc44bbbba3f..6f7b019568850c68478abcaae6de2238a4fac934 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/reg.h>
 #include <asm/machdep.h>
 #include <asm/firmware.h>
+#include <asm/runlatch.h>
 #include <asm/plpar_wrappers.h>
 
 struct cpuidle_driver pseries_idle_driver = {
@@ -29,6 +30,7 @@ static struct cpuidle_state *cpuidle_state_table;
 
 static inline void idle_loop_prolog(unsigned long *in_purr)
 {
+       ppc64_runlatch_off();
        *in_purr = mfspr(SPRN_PURR);
        /*
         * Indicate to the HV that we are idle. Now would be
@@ -45,6 +47,10 @@ static inline void idle_loop_epilog(unsigned long in_purr)
        wait_cycles += mfspr(SPRN_PURR) - in_purr;
        get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles);
        get_lppaca()->idle = 0;
+
+       if (irqs_disabled())
+               local_irq_enable();
+       ppc64_runlatch_on();
 }
 
 static int snooze_loop(struct cpuidle_device *dev,
index a55e68f2cfc8bfad02a85957c9d9ddc55823c6fe..cb20fd915be8cefb87c0a35a338dfedc70374a08 100644 (file)
@@ -85,7 +85,8 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
 
        time_end = ktime_get();
 
-       local_irq_enable();
+       if (!cpuidle_state_is_coupled(dev, drv, entered_state))
+               local_irq_enable();
 
        diff = ktime_to_us(ktime_sub(time_end, time_start));
        if (diff > INT_MAX)
@@ -140,12 +141,14 @@ int cpuidle_idle_call(void)
                return 0;
        }
 
-       trace_cpu_idle_rcuidle(next_state, dev->cpu);
-
        broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP);
 
-       if (broadcast)
-               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+       if (broadcast &&
+           clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu))
+               return -EBUSY;
+
+
+       trace_cpu_idle_rcuidle(next_state, dev->cpu);
 
        if (cpuidle_state_is_coupled(dev, drv, next_state))
                entered_state = cpuidle_enter_state_coupled(dev, drv,
@@ -153,11 +156,11 @@ int cpuidle_idle_call(void)
        else
                entered_state = cpuidle_enter_state(dev, drv, next_state);
 
+       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
+
        if (broadcast)
                clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
 
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
-
        /* give the governor an opportunity to reflect on the outcome */
        if (cpuidle_curr_governor->reflect)
                cpuidle_curr_governor->reflect(dev, entered_state);
index 06dbe7c86199808aefdf3d9e6b447c0e0b697b1c..136d6a283e0a3818846eab4e78e7e9245b7d6f07 100644 (file)
@@ -209,7 +209,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
        state->exit_latency = 0;
        state->target_residency = 0;
        state->power_usage = -1;
-       state->flags = 0;
+       state->flags = CPUIDLE_FLAG_TIME_VALID;
        state->enter = poll_idle;
        state->disabled = false;
 }
index cf7f2f0e4ef54d05ee1cc3babeb0555314c894f9..71b52329335472b7a888e16b4075c6ea7a4f58c5 100644 (file)
@@ -122,9 +122,8 @@ struct menu_device {
        int             last_state_idx;
        int             needs_update;
 
-       unsigned int    expected_us;
+       unsigned int    next_timer_us;
        unsigned int    predicted_us;
-       unsigned int    exit_us;
        unsigned int    bucket;
        unsigned int    correction_factor[BUCKETS];
        unsigned int    intervals[INTERVALS];
@@ -257,7 +256,7 @@ again:
                stddev = int_sqrt(stddev);
                if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
                                                        || stddev <= 20) {
-                       if (data->expected_us > avg)
+                       if (data->next_timer_us > avg)
                                data->predicted_us = avg;
                        return;
                }
@@ -289,7 +288,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        struct menu_device *data = &__get_cpu_var(menu_devices);
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
        int i;
-       int multiplier;
+       unsigned int interactivity_req;
        struct timespec t;
 
        if (data->needs_update) {
@@ -298,7 +297,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        }
 
        data->last_state_idx = 0;
-       data->exit_us = 0;
 
        /* Special case when user has set very strict latency requirement */
        if (unlikely(latency_req == 0))
@@ -306,13 +304,11 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 
        /* determine the expected residency time, round up */
        t = ktime_to_timespec(tick_nohz_get_sleep_length());
-       data->expected_us =
+       data->next_timer_us =
                t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
 
 
-       data->bucket = which_bucket(data->expected_us);
-
-       multiplier = performance_multiplier();
+       data->bucket = which_bucket(data->next_timer_us);
 
        /*
         * if the correction factor is 0 (eg first time init or cpu hotplug
@@ -326,17 +322,26 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
         * operands are 32 bits.
         * Make sure to round up for half microseconds.
         */
-       data->predicted_us = div_round64((uint64_t)data->expected_us *
+       data->predicted_us = div_round64((uint64_t)data->next_timer_us *
                                         data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
        get_typical_interval(data);
 
+       /*
+        * Performance multiplier defines a minimum predicted idle
+        * duration / latency ratio. Adjust the latency limit if
+        * necessary.
+        */
+       interactivity_req = data->predicted_us / performance_multiplier();
+       if (latency_req > interactivity_req)
+               latency_req = interactivity_req;
+
        /*
         * We want to default to C1 (hlt), not to busy polling
         * unless the timer is happening really really soon.
         */
-       if (data->expected_us > 5 &&
+       if (data->next_timer_us > 5 &&
            !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
                dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
                data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
@@ -355,11 +360,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                        continue;
                if (s->exit_latency > latency_req)
                        continue;
-               if (s->exit_latency * multiplier > data->predicted_us)
-                       continue;
 
                data->last_state_idx = i;
-               data->exit_us = s->exit_latency;
        }
 
        return data->last_state_idx;
@@ -390,36 +392,47 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
        struct menu_device *data = &__get_cpu_var(menu_devices);
        int last_idx = data->last_state_idx;
-       unsigned int last_idle_us = cpuidle_get_last_residency(dev);
        struct cpuidle_state *target = &drv->states[last_idx];
        unsigned int measured_us;
        unsigned int new_factor;
 
        /*
-        * Ugh, this idle state doesn't support residency measurements, so we
-        * are basically lost in the dark.  As a compromise, assume we slept
-        * for the whole expected time.
+        * Try to figure out how much time passed between entry to low
+        * power state and occurrence of the wakeup event.
+        *
+        * If the entered idle state didn't support residency measurements,
+        * we are basically lost in the dark how much time passed.
+        * As a compromise, assume we slept for the whole expected time.
+        *
+        * Any measured amount of time will include the exit latency.
+        * Since we are interested in when the wakeup begun, not when it
+        * was completed, we must substract the exit latency. However, if
+        * the measured amount of time is less than the exit latency,
+        * assume the state was never reached and the exit latency is 0.
         */
-       if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID)))
-               last_idle_us = data->expected_us;
+       if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) {
+               /* Use timer value as is */
+               measured_us = data->next_timer_us;
 
+       } else {
+               /* Use measured value */
+               measured_us = cpuidle_get_last_residency(dev);
 
-       measured_us = last_idle_us;
-
-       /*
-        * We correct for the exit latency; we are assuming here that the
-        * exit latency happens after the event that we're interested in.
-        */
-       if (measured_us > data->exit_us)
-               measured_us -= data->exit_us;
+               /* Deduct exit latency */
+               if (measured_us > target->exit_latency)
+                       measured_us -= target->exit_latency;
 
+               /* Make sure our coefficients do not exceed unity */
+               if (measured_us > data->next_timer_us)
+                       measured_us = data->next_timer_us;
+       }
 
        /* Update our correction ratio */
        new_factor = data->correction_factor[data->bucket];
        new_factor -= new_factor / DECAY;
 
-       if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
-               new_factor += RESOLUTION * measured_us / data->expected_us;
+       if (data->next_timer_us > 0 && measured_us < MAX_INTERESTING)
+               new_factor += RESOLUTION * measured_us / data->next_timer_us;
        else
                /*
                 * we were idle so long that we count it as a perfect
@@ -439,7 +452,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        data->correction_factor[data->bucket] = new_factor;
 
        /* update the repeating-pattern data */
-       data->intervals[data->interval_ptr++] = last_idle_us;
+       data->intervals[data->interval_ptr++] = measured_us;
        if (data->interval_ptr >= INTERVALS)
                data->interval_ptr = 0;
 }
index a0b2f7e0eedb774fbfa3e8fc0e41b73f10cfefd0..2042ec3656bac3b4227d63df358d6454923a5ef5 100644 (file)
@@ -91,26 +91,35 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
  */
 static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
 {
-       int lev, prev_lev;
+       int lev, prev_lev, ret = 0;
        unsigned long cur_time;
 
-       lev = devfreq_get_freq_level(devfreq, freq);
-       if (lev < 0)
-               return lev;
-
        cur_time = jiffies;
-       devfreq->time_in_state[lev] +=
+
+       prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
+       if (prev_lev < 0) {
+               ret = prev_lev;
+               goto out;
+       }
+
+       devfreq->time_in_state[prev_lev] +=
                         cur_time - devfreq->last_stat_updated;
-       if (freq != devfreq->previous_freq) {
-               prev_lev = devfreq_get_freq_level(devfreq,
-                                               devfreq->previous_freq);
+
+       lev = devfreq_get_freq_level(devfreq, freq);
+       if (lev < 0) {
+               ret = lev;
+               goto out;
+       }
+
+       if (lev != prev_lev) {
                devfreq->trans_table[(prev_lev *
                                devfreq->profile->max_state) + lev]++;
                devfreq->total_trans++;
        }
-       devfreq->last_stat_updated = cur_time;
 
-       return 0;
+out:
+       devfreq->last_stat_updated = cur_time;
+       return ret;
 }
 
 /**
index 98e14ee4833c4d26b805843bcbe30daf29f99bb3..f8bf00010d45a78652c9a922ddb5a2d5c65a7448 100644 (file)
@@ -1239,9 +1239,17 @@ static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
        if (num_dcts_intlv == 2) {
                select = (sys_addr >> 8) & 0x3;
                channel = select ? 0x3 : 0;
-       } else if (num_dcts_intlv == 4)
-               channel = (sys_addr >> 8) & 0x7;
-
+       } else if (num_dcts_intlv == 4) {
+               u8 intlv_addr = dct_sel_interleave_addr(pvt);
+               switch (intlv_addr) {
+               case 0x4:
+                       channel = (sys_addr >> 8) & 0x3;
+                       break;
+               case 0x5:
+                       channel = (sys_addr >> 9) & 0x3;
+                       break;
+               }
+       }
        return channel;
 }
 
@@ -1799,6 +1807,17 @@ static struct amd64_family_type family_types[] = {
                        .read_dct_pci_cfg       = f10_read_dct_pci_cfg,
                }
        },
+       [F16_M30H_CPUS] = {
+               .ctl_name = "F16h_M30h",
+               .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
+               .f3_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F3,
+               .ops = {
+                       .early_channel_count    = f1x_early_channel_count,
+                       .map_sysaddr_to_csrow   = f1x_map_sysaddr_to_csrow,
+                       .dbam_to_cs             = f16_dbam_to_chip_select,
+                       .read_dct_pci_cfg       = f10_read_dct_pci_cfg,
+               }
+       },
 };
 
 /*
@@ -2578,6 +2597,11 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
                break;
 
        case 0x16:
+               if (pvt->model == 0x30) {
+                       fam_type = &family_types[F16_M30H_CPUS];
+                       pvt->ops = &family_types[F16_M30H_CPUS].ops;
+                       break;
+               }
                fam_type        = &family_types[F16_CPUS];
                pvt->ops        = &family_types[F16_CPUS].ops;
                break;
@@ -2830,6 +2854,14 @@ static const struct pci_device_id amd64_pci_table[] = {
                .class          = 0,
                .class_mask     = 0,
        },
+       {
+               .vendor         = PCI_VENDOR_ID_AMD,
+               .device         = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .class          = 0,
+               .class_mask     = 0,
+       },
 
        {0, }
 };
index 6dc1fcc25afb8ac7ad04df3c58a462e9996f557b..d903e0c21144814862032e453c811cee8b998b91 100644 (file)
 #define PCI_DEVICE_ID_AMD_15H_NB_F2    0x1602
 #define PCI_DEVICE_ID_AMD_16H_NB_F1    0x1531
 #define PCI_DEVICE_ID_AMD_16H_NB_F2    0x1532
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582
 
 /*
  * Function 1 - Address Map
@@ -300,6 +302,7 @@ enum amd_families {
        F15_CPUS,
        F15_M30H_CPUS,
        F16_CPUS,
+       F16_M30H_CPUS,
        NUM_FAMILIES,
 };
 
index ddd890052ce2c344673d09d31e24d8436cb47e92..2b63f7c2d6d217d91c32591d2329e448797b37b5 100644 (file)
@@ -350,6 +350,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
 {
        struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+       int ret = -ENODEV;
 
        dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
                                        dev_info->err_dev, NULL);
@@ -359,16 +360,15 @@ static int amd8111_dev_probe(struct pci_dev *dev,
                        "vendor %x, device %x, name %s\n",
                        PCI_VENDOR_ID_AMD, dev_info->err_dev,
                        dev_info->ctl_name);
-               return -ENODEV;
+               goto err;
        }
 
        if (pci_enable_device(dev_info->dev)) {
-               pci_dev_put(dev_info->dev);
                printk(KERN_ERR "failed to enable:"
                        "vendor %x, device %x, name %s\n",
                        PCI_VENDOR_ID_AMD, dev_info->err_dev,
                        dev_info->ctl_name);
-               return -ENODEV;
+               goto err_dev_put;
        }
 
        /*
@@ -381,8 +381,10 @@ static int amd8111_dev_probe(struct pci_dev *dev,
                edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
                                           NULL, 0, 0,
                                           NULL, 0, dev_info->edac_idx);
-       if (!dev_info->edac_dev)
-               return -ENOMEM;
+       if (!dev_info->edac_dev) {
+               ret = -ENOMEM;
+               goto err_dev_put;
+       }
 
        dev_info->edac_dev->pvt_info = dev_info;
        dev_info->edac_dev->dev = &dev_info->dev->dev;
@@ -399,8 +401,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
        if (edac_device_add_device(dev_info->edac_dev) > 0) {
                printk(KERN_ERR "failed to add edac_dev for %s\n",
                        dev_info->ctl_name);
-               edac_device_free_ctl_info(dev_info->edac_dev);
-               return -ENODEV;
+               goto err_edac_free_ctl;
        }
 
        printk(KERN_INFO "added one edac_dev on AMD8111 "
@@ -409,6 +410,13 @@ static int amd8111_dev_probe(struct pci_dev *dev,
                dev_info->ctl_name);
 
        return 0;
+
+err_edac_free_ctl:
+       edac_device_free_ctl_info(dev_info->edac_dev);
+err_dev_put:
+       pci_dev_put(dev_info->dev);
+err:
+       return ret;
 }
 
 static void amd8111_dev_remove(struct pci_dev *dev)
@@ -437,6 +445,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
 {
        struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+       int ret = -ENODEV;
 
        pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
                                        pci_info->err_dev, NULL);
@@ -446,16 +455,15 @@ static int amd8111_pci_probe(struct pci_dev *dev,
                        "vendor %x, device %x, name %s\n",
                        PCI_VENDOR_ID_AMD, pci_info->err_dev,
                        pci_info->ctl_name);
-               return -ENODEV;
+               goto err;
        }
 
        if (pci_enable_device(pci_info->dev)) {
-               pci_dev_put(pci_info->dev);
                printk(KERN_ERR "failed to enable:"
                        "vendor %x, device %x, name %s\n",
                        PCI_VENDOR_ID_AMD, pci_info->err_dev,
                        pci_info->ctl_name);
-               return -ENODEV;
+               goto err_dev_put;
        }
 
        /*
@@ -465,8 +473,10 @@ static int amd8111_pci_probe(struct pci_dev *dev,
        */
        pci_info->edac_idx = edac_pci_alloc_index();
        pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
-       if (!pci_info->edac_dev)
-               return -ENOMEM;
+       if (!pci_info->edac_dev) {
+               ret = -ENOMEM;
+               goto err_dev_put;
+       }
 
        pci_info->edac_dev->pvt_info = pci_info;
        pci_info->edac_dev->dev = &pci_info->dev->dev;
@@ -483,8 +493,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
        if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
                printk(KERN_ERR "failed to add edac_pci for %s\n",
                        pci_info->ctl_name);
-               edac_pci_free_ctl_info(pci_info->edac_dev);
-               return -ENODEV;
+               goto err_edac_free_ctl;
        }
 
        printk(KERN_INFO "added one edac_pci on AMD8111 "
@@ -493,6 +502,13 @@ static int amd8111_pci_probe(struct pci_dev *dev,
                pci_info->ctl_name);
 
        return 0;
+
+err_edac_free_ctl:
+       edac_pci_free_ctl_info(pci_info->edac_dev);
+err_dev_put:
+       pci_dev_put(pci_info->dev);
+err:
+       return ret;
 }
 
 static void amd8111_pci_remove(struct pci_dev *dev)
index 92d54fa65f939d57f7f18332bed3f6d55a03d33d..b2d71388172bc4082cff91483a4cc23ca1b85c4b 100644 (file)
@@ -209,7 +209,6 @@ enum e752x_chips {
  */
 
 struct e752x_pvt {
-       struct pci_dev *bridge_ck;
        struct pci_dev *dev_d0f0;
        struct pci_dev *dev_d0f1;
        u32 tolm;
@@ -891,7 +890,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
                                        info->buf_ferr);
 
                if (info->dram_ferr)
-                       pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
+                       pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR,
                                         info->dram_ferr, info->dram_ferr);
 
                pci_write_config_dword(dev, E752X_FERR_GLOBAL,
@@ -936,7 +935,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
                                        info->buf_nerr);
 
                if (info->dram_nerr)
-                       pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
+                       pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR,
                                         info->dram_nerr, info->dram_nerr);
 
                pci_write_config_dword(dev, E752X_NERR_GLOBAL,
@@ -1177,38 +1176,33 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
 static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
                        struct e752x_pvt *pvt)
 {
-       struct pci_dev *dev;
-
-       pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-                               pvt->dev_info->err_dev, pvt->bridge_ck);
+       pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL,
+                               pvt->dev_info->err_dev, NULL);
 
-       if (pvt->bridge_ck == NULL) {
-               pvt->bridge_ck = pci_scan_single_device(pdev->bus,
+       if (pvt->dev_d0f1 == NULL) {
+               pvt->dev_d0f1 = pci_scan_single_device(pdev->bus,
                                                        PCI_DEVFN(0, 1));
-               pci_dev_get(pvt->bridge_ck);
+               pci_dev_get(pvt->dev_d0f1);
        }
 
-       if (pvt->bridge_ck == NULL) {
+       if (pvt->dev_d0f1 == NULL) {
                e752x_printk(KERN_ERR, "error reporting device not found:"
                        "vendor %x device 0x%x (broken BIOS?)\n",
                        PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
                return 1;
        }
 
-       dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+       pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL,
                                e752x_devs[dev_idx].ctl_dev,
                                NULL);
 
-       if (dev == NULL)
+       if (pvt->dev_d0f0 == NULL)
                goto fail;
 
-       pvt->dev_d0f0 = dev;
-       pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
-
        return 0;
 
 fail:
-       pci_dev_put(pvt->bridge_ck);
+       pci_dev_put(pvt->dev_d0f1);
        return 1;
 }
 
@@ -1385,7 +1379,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 fail:
        pci_dev_put(pvt->dev_d0f0);
        pci_dev_put(pvt->dev_d0f1);
-       pci_dev_put(pvt->bridge_ck);
        edac_mc_free(mci);
 
        return -ENODEV;
@@ -1419,7 +1412,6 @@ static void e752x_remove_one(struct pci_dev *pdev)
        pvt = (struct e752x_pvt *)mci->pvt_info;
        pci_dev_put(pvt->dev_d0f0);
        pci_dev_put(pvt->dev_d0f1);
-       pci_dev_put(pvt->bridge_ck);
        edac_mc_free(mci);
 }
 
index fa1326e5a4b06d61c2c5fc7756121acc4a8f44bc..022a70273ada730a1c6afe6355387041dda36f2b 100644 (file)
@@ -464,6 +464,8 @@ static void i3200_remove_one(struct pci_dev *pdev)
        iounmap(priv->window);
 
        edac_mc_free(mci);
+
+       pci_disable_device(pdev);
 }
 
 static const struct pci_device_id i3200_pci_tbl[] = {
index 36a38ee94fa8a5236a27d9899b5c1481ac7fb981..6247d186177ed6c7ff4660c5644ae8d49a604ebd 100644 (file)
@@ -869,16 +869,13 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)
                               chan, rank, 0);
 
                dimm->nr_pages = npages;
-               if (npages) {
-                       dimm->grain = 32;
-                       dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
-                                       DEV_X4 : DEV_X8;
-                       dimm->mtype = MEM_RDDR2;
-                       dimm->edac_mode = EDAC_SECDED;
-                       snprintf(dimm->label, sizeof(dimm->label),
-                               "DIMM%u",
-                               i5100_rank_to_slot(mci, chan, rank));
-               }
+               dimm->grain = 32;
+               dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
+                               DEV_X4 : DEV_X8;
+               dimm->mtype = MEM_RDDR2;
+               dimm->edac_mode = EDAC_SECDED;
+               snprintf(dimm->label, sizeof(dimm->label), "DIMM%u",
+                        i5100_rank_to_slot(mci, chan, rank));
 
                edac_dbg(2, "dimm channel %d, rank %d, size %ld\n",
                         chan, rank, (long)PAGES_TO_MiB(npages));
index e080cbfa8fc9d0e4c8c255ac1165306be716c336..5381e98d9c0cff20998a111dc492f74f2288947c 100644 (file)
@@ -1408,6 +1408,8 @@ static void i5400_remove_one(struct pci_dev *pdev)
        /* retrieve references to resources, and free those resources */
        i5400_put_devices(mci);
 
+       pci_disable_device(pdev);
+
        edac_mc_free(mci);
 }
 
index d871275196f6f04b6542e4941ee433e41fcfdf64..8bc83b99974b946f170e44d70d8d0c00f9182be3 100644 (file)
@@ -1708,7 +1708,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
                                    const struct mce *m)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
-       char *type, *optype, *err;
+       char *optype, *err;
        enum hw_event_mc_err_type tp_event;
        unsigned long error = m->status & 0x1ff0000l;
        bool uncorrected_error = m->mcgstatus & 1ll << 61;
@@ -1721,15 +1721,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
        u32 errnum = find_first_bit(&error, 32);
 
        if (uncorrected_error) {
-               if (ripv) {
-                       type = "FATAL";
+               if (ripv)
                        tp_event = HW_EVENT_ERR_FATAL;
-               } else {
-                       type = "NON_FATAL";
+               else
                        tp_event = HW_EVENT_ERR_UNCORRECTED;
-               }
        } else {
-               type = "CORRECTED";
                tp_event = HW_EVENT_ERR_CORRECTED;
        }
 
index 80573df0a4d77d9e083af858735f619addef8948..8d0450b9b9af42e5b4db08ab68b94f44a971a0ae 100644 (file)
@@ -406,8 +406,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 
        edac_dbg(0, "\n");
 
-       ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
-
        if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
                return -ENODEV;
        drc = readl(ovrfl_window + I82875P_DRC);
index 30f7309446a68e8786fa8c26dccc66684880cd43..51b9caa0b024c9c08da23b7224179f5cc5b7a4bc 100644 (file)
@@ -741,6 +741,36 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
        if (amd_filter_mce(m))
                return NOTIFY_STOP;
 
+       pr_emerg(HW_ERR "%s\n", decode_error_status(m));
+
+       pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
+               m->extcpu,
+               c->x86, c->x86_model, c->x86_mask,
+               m->bank,
+               ((m->status & MCI_STATUS_OVER)  ? "Over"  : "-"),
+               ((m->status & MCI_STATUS_UC)    ? "UE"    : "CE"),
+               ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
+               ((m->status & MCI_STATUS_PCC)   ? "PCC"   : "-"),
+               ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
+
+       if (c->x86 == 0x15 || c->x86 == 0x16)
+               pr_cont("|%s|%s",
+                       ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
+                       ((m->status & MCI_STATUS_POISON)   ? "Poison"   : "-"));
+
+       /* do the two bits[14:13] together */
+       ecc = (m->status >> 45) & 0x3;
+       if (ecc)
+               pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
+
+       pr_cont("]: 0x%016llx\n", m->status);
+
+       if (m->status & MCI_STATUS_ADDRV)
+               pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
+
+       if (!fam_ops)
+               goto err_code;
+
        switch (m->bank) {
        case 0:
                decode_mc0_mce(m);
@@ -774,33 +804,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
                break;
        }
 
-       pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m));
-
-       pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
-               m->extcpu,
-               c->x86, c->x86_model, c->x86_mask,
-               m->bank,
-               ((m->status & MCI_STATUS_OVER)  ? "Over"  : "-"),
-               ((m->status & MCI_STATUS_UC)    ? "UE"    : "CE"),
-               ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
-               ((m->status & MCI_STATUS_PCC)   ? "PCC"   : "-"),
-               ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
-
-       if (c->x86 == 0x15 || c->x86 == 0x16)
-               pr_cont("|%s|%s",
-                       ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
-                       ((m->status & MCI_STATUS_POISON)   ? "Poison"   : "-"));
-
-       /* do the two bits[14:13] together */
-       ecc = (m->status >> 45) & 0x3;
-       if (ecc)
-               pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
-
-       pr_cont("]: 0x%016llx\n", m->status);
-
-       if (m->status & MCI_STATUS_ADDRV)
-               pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
-
+ err_code:
        amd_decode_err_code(m->status & 0xffff);
 
        return NOTIFY_STOP;
@@ -816,10 +820,7 @@ static int __init mce_amd_init(void)
        struct cpuinfo_x86 *c = &boot_cpu_data;
 
        if (c->x86_vendor != X86_VENDOR_AMD)
-               return 0;
-
-       if (c->x86 < 0xf || c->x86 > 0x16)
-               return 0;
+               return -ENODEV;
 
        fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
        if (!fam_ops)
@@ -874,7 +875,7 @@ static int __init mce_amd_init(void)
        default:
                printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
                kfree(fam_ops);
-               return -EINVAL;
+               fam_ops = NULL;
        }
 
        pr_info("MCE: In-kernel MCE decoding enabled.\n");
index 8f9182179a7c804088d1889ac96c7f90a28d804e..f4aec2e6ef56d62e03bc2f5cf8c44e129e998f6c 100644 (file)
@@ -357,7 +357,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
                pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
                res = devm_request_irq(&op->dev, pdata->irq,
                                       mpc85xx_pci_isr,
-                                      IRQF_DISABLED | IRQF_SHARED,
+                                      IRQF_SHARED,
                                       "[EDAC] PCI err", pci);
                if (res < 0) {
                        printk(KERN_ERR
@@ -633,7 +633,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op)
        if (edac_op_state == EDAC_OPSTATE_INT) {
                pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
                res = devm_request_irq(&op->dev, pdata->irq,
-                                      mpc85xx_l2_isr, IRQF_DISABLED,
+                                      mpc85xx_l2_isr, 0,
                                       "[EDAC] L2 err", edac_dev);
                if (res < 0) {
                        printk(KERN_ERR
@@ -1133,7 +1133,7 @@ static int mpc85xx_mc_err_probe(struct platform_device *op)
                pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
                res = devm_request_irq(&op->dev, pdata->irq,
                                       mpc85xx_mc_isr,
-                                       IRQF_DISABLED | IRQF_SHARED,
+                                      IRQF_SHARED,
                                       "[EDAC] MC err", mci);
                if (res < 0) {
                        printk(KERN_ERR "%s: Unable to request irq %d for "
index 54e2abe671f70acef2965ec5f74cd8b877ac7089..347c7a1c27255199eaf9de93381b4c50e754f872 100644 (file)
@@ -1263,7 +1263,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
        struct pci_dev *pdev = NULL;
        u8 bus = 0;
 
-       sbridge_printk(KERN_INFO,
+       sbridge_printk(KERN_DEBUG,
                "Seeking for: dev %02x.%d PCI ID %04x:%04x\n",
                dev_descr->dev, dev_descr->func,
                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
index bdb5a00f1dfa9e092484c4105102409b5e7c0311..be56e8ac95e6e3d6240ec1039739f0efbaba74e1 100644 (file)
@@ -14,10 +14,6 @@ if EXTCON
 
 comment "Extcon Device Drivers"
 
-config OF_EXTCON
-       def_tristate y
-       depends on OF
-
 config EXTCON_GPIO
        tristate "GPIO extcon support"
        depends on GPIOLIB
index 43eccc0e3448de15be8db549c7519993cebbe7b5..bf7861ec090607b881fc3b75d4113c69f10bd2c4 100644 (file)
@@ -2,8 +2,6 @@
 # Makefile for external connector class (extcon) devices
 #
 
-obj-$(CONFIG_OF_EXTCON)                += of_extcon.o
-
 obj-$(CONFIG_EXTCON)           += extcon-class.o
 obj-$(CONFIG_EXTCON_GPIO)      += extcon-gpio.o
 obj-$(CONFIG_EXTCON_ADC_JACK)  += extcon-adc-jack.o
index 76322330cbd7a10b427ff5d011b83abbd0abb0e8..7ab21aa6eaa15fa362829c9ee72fa6be3269bc53 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/extcon.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
+#include <linux/of.h>
 
 /*
  * extcon_cable_name suggests the standard cable names for commonly used
@@ -818,6 +819,47 @@ void extcon_dev_unregister(struct extcon_dev *edev)
 }
 EXPORT_SYMBOL_GPL(extcon_dev_unregister);
 
+#ifdef CONFIG_OF
+/*
+ * extcon_get_edev_by_phandle - Get the extcon device from devicetree
+ * @dev - instance to the given device
+ * @index - index into list of extcon_dev
+ *
+ * return the instance of extcon device
+ */
+struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
+{
+       struct device_node *node;
+       struct extcon_dev *edev;
+
+       if (!dev->of_node) {
+               dev_err(dev, "device does not have a device node entry\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       node = of_parse_phandle(dev->of_node, "extcon", index);
+       if (!node) {
+               dev_err(dev, "failed to get phandle in %s node\n",
+                       dev->of_node->full_name);
+               return ERR_PTR(-ENODEV);
+       }
+
+       edev = extcon_get_extcon_dev(node->name);
+       if (!edev) {
+               dev_err(dev, "unable to get extcon device : %s\n", node->name);
+               return ERR_PTR(-ENODEV);
+       }
+
+       return edev;
+}
+#else
+struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
+{
+       return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_OF */
+EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
+
 static int __init extcon_class_init(void)
 {
        return create_extcon_class();
index a63a6b21c9ad4a539e311ff17899491922efaa54..13d522255d818e924465d8c63fb653a5737a4bef 100644 (file)
@@ -176,9 +176,7 @@ static int gpio_extcon_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops gpio_extcon_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(NULL, gpio_extcon_resume)
-};
+static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume);
 
 static struct platform_driver gpio_extcon_driver = {
        .probe          = gpio_extcon_probe,
index 2aea4bcdd7f3944abe04f60997157f5222b52eb1..ddff2b72f0a898b4e50fe69800dab356e3af9358 100644 (file)
@@ -271,10 +271,7 @@ static int palmas_usb_resume(struct device *dev)
 };
 #endif
 
-static const struct dev_pm_ops palmas_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
-                               palmas_usb_resume)
-};
+static SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_usb_suspend, palmas_usb_resume);
 
 static struct of_device_id of_palmas_match_tbl[] = {
        { .compatible = "ti,palmas-usb", },
diff --git a/drivers/extcon/of_extcon.c b/drivers/extcon/of_extcon.c
deleted file mode 100644 (file)
index 72173ec..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * OF helpers for External connector (extcon) framework
- *
- * Copyright (C) 2013 Texas Instruments, Inc.
- * Kishon Vijay Abraham I <kishon@ti.com>
- *
- * Copyright (C) 2013 Samsung Electronics
- * Chanwoo Choi <cw00.choi@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.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/extcon.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/extcon/of_extcon.h>
-
-/*
- * of_extcon_get_extcon_dev - Get the name of extcon device from devicetree
- * @dev - instance to the given device
- * @index - index into list of extcon_dev
- *
- * return the instance of extcon device
- */
-struct extcon_dev *of_extcon_get_extcon_dev(struct device *dev, int index)
-{
-       struct device_node *node;
-       struct extcon_dev *edev;
-       struct platform_device *extcon_parent_dev;
-
-       if (!dev->of_node) {
-               dev_dbg(dev, "device does not have a device node entry\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       node = of_parse_phandle(dev->of_node, "extcon", index);
-       if (!node) {
-               dev_dbg(dev, "failed to get phandle in %s node\n",
-                       dev->of_node->full_name);
-               return ERR_PTR(-ENODEV);
-       }
-
-       extcon_parent_dev = of_find_device_by_node(node);
-       if (!extcon_parent_dev) {
-               dev_dbg(dev, "unable to find device by node\n");
-               return ERR_PTR(-EPROBE_DEFER);
-       }
-
-       edev = extcon_get_extcon_dev(dev_name(&extcon_parent_dev->dev));
-       if (!edev) {
-               dev_dbg(dev, "unable to get extcon device : %s\n",
-                               dev_name(&extcon_parent_dev->dev));
-               return ERR_PTR(-ENODEV);
-       }
-
-       return edev;
-}
-EXPORT_SYMBOL_GPL(of_extcon_get_extcon_dev);
index de4aa409abe2988d8dc5b421e969ab5256fb4009..2c6d5e118ac129e5ab9c24f09557b27e3248f3ea 100644 (file)
@@ -916,7 +916,7 @@ static int lookup_existing_device(struct device *dev, void *data)
                old->config_rom_retries = 0;
                fw_notice(card, "rediscovered device %s\n", dev_name(dev));
 
-               PREPARE_DELAYED_WORK(&old->work, fw_device_update);
+               old->workfn = fw_device_update;
                fw_schedule_device_work(old, 0);
 
                if (current_node == card->root_node)
@@ -1075,7 +1075,7 @@ static void fw_device_init(struct work_struct *work)
        if (atomic_cmpxchg(&device->state,
                           FW_DEVICE_INITIALIZING,
                           FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
-               PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+               device->workfn = fw_device_shutdown;
                fw_schedule_device_work(device, SHUTDOWN_DELAY);
        } else {
                fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
@@ -1196,13 +1196,20 @@ static void fw_device_refresh(struct work_struct *work)
                  dev_name(&device->device), fw_rcode_string(ret));
  gone:
        atomic_set(&device->state, FW_DEVICE_GONE);
-       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+       device->workfn = fw_device_shutdown;
        fw_schedule_device_work(device, SHUTDOWN_DELAY);
  out:
        if (node_id == card->root_node->node_id)
                fw_schedule_bm_work(card, 0);
 }
 
+static void fw_device_workfn(struct work_struct *work)
+{
+       struct fw_device *device = container_of(to_delayed_work(work),
+                                               struct fw_device, work);
+       device->workfn(work);
+}
+
 void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 {
        struct fw_device *device;
@@ -1252,7 +1259,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                 * power-up after getting plugged in.  We schedule the
                 * first config rom scan half a second after bus reset.
                 */
-               INIT_DELAYED_WORK(&device->work, fw_device_init);
+               device->workfn = fw_device_init;
+               INIT_DELAYED_WORK(&device->work, fw_device_workfn);
                fw_schedule_device_work(device, INITIAL_DELAY);
                break;
 
@@ -1268,7 +1276,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                if (atomic_cmpxchg(&device->state,
                            FW_DEVICE_RUNNING,
                            FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
+                       device->workfn = fw_device_refresh;
                        fw_schedule_device_work(device,
                                device->is_local ? 0 : INITIAL_DELAY);
                }
@@ -1283,7 +1291,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                smp_wmb();  /* update node_id before generation */
                device->generation = card->generation;
                if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+                       device->workfn = fw_device_update;
                        fw_schedule_device_work(device, 0);
                }
                break;
@@ -1308,7 +1316,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device = node->data;
                if (atomic_xchg(&device->state,
                                FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+                       device->workfn = fw_device_shutdown;
                        fw_schedule_device_work(device,
                                list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
                }
index 6b895986dc225115573add201958e60897934853..4af0a7bad7f21561cc4e7a29031c238a34f0135d 100644 (file)
@@ -929,8 +929,6 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
        if (rcode == RCODE_COMPLETE) {
                fwnet_transmit_packet_done(ptask);
        } else {
-               fwnet_transmit_packet_failed(ptask);
-
                if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
                        dev_err(&ptask->dev->netdev->dev,
                                "fwnet_write_complete failed: %x (skipped %d)\n",
@@ -938,8 +936,10 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
 
                        errors_skipped = 0;
                        last_rcode = rcode;
-               } else
+               } else {
                        errors_skipped++;
+               }
+               fwnet_transmit_packet_failed(ptask);
        }
 }
 
index 6f74d8d3f70015a089f02948294454863cb6bcd7..8db66321956068701cde997e0bc25e167e781eb3 100644 (file)
@@ -290,7 +290,6 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
 #define QUIRK_NO_MSI                   0x10
 #define QUIRK_TI_SLLZ059               0x20
 #define QUIRK_IR_WAKE                  0x40
-#define QUIRK_PHY_LCTRL_TIMEOUT                0x80
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
@@ -303,10 +302,7 @@ static const struct {
                QUIRK_BE_HEADERS},
 
        {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
-               QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI},
-
-       {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID,
-               QUIRK_PHY_LCTRL_TIMEOUT},
+               QUIRK_NO_MSI},
 
        {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID,
                QUIRK_RESET_PACKET},
@@ -353,7 +349,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
        ", disable MSI = "              __stringify(QUIRK_NO_MSI)
        ", TI SLLZ059 erratum = "       __stringify(QUIRK_TI_SLLZ059)
        ", IR wake unreliable = "       __stringify(QUIRK_IR_WAKE)
-       ", phy LCtrl timeout = "        __stringify(QUIRK_PHY_LCTRL_TIMEOUT)
        ")");
 
 #define OHCI_PARAM_DEBUG_AT_AR         1
@@ -2299,9 +2294,6 @@ static int ohci_enable(struct fw_card *card,
         * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but
         * cannot actually use the phy at that time.  These need tens of
         * millisecods pause between LPS write and first phy access too.
-        *
-        * But do not wait for 50msec on Agere/LSI cards.  Their phy
-        * arbitration state machine may time out during such a long wait.
         */
 
        reg_write(ohci, OHCI1394_HCControlSet,
@@ -2309,11 +2301,8 @@ static int ohci_enable(struct fw_card *card,
                  OHCI1394_HCControl_postedWriteEnable);
        flush_writes(ohci);
 
-       if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT))
+       for (lps = 0, i = 0; !lps && i < 3; i++) {
                msleep(50);
-
-       for (lps = 0, i = 0; !lps && i < 150; i++) {
-               msleep(1);
                lps = reg_read(ohci, OHCI1394_HCControlSet) &
                      OHCI1394_HCControl_LPS;
        }
index 281029daf98c7ea291886d46ecf05378bfa98718..7aef911fdc716d4874b7152b3c0d6e27bc8c1642 100644 (file)
@@ -146,6 +146,7 @@ struct sbp2_logical_unit {
         */
        int generation;
        int retries;
+       work_func_t workfn;
        struct delayed_work work;
        bool has_sdev;
        bool blocked;
@@ -864,7 +865,7 @@ static void sbp2_login(struct work_struct *work)
        /* set appropriate retry limit(s) in BUSY_TIMEOUT register */
        sbp2_set_busy_timeout(lu);
 
-       PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+       lu->workfn = sbp2_reconnect;
        sbp2_agent_reset(lu);
 
        /* This was a re-login. */
@@ -918,7 +919,7 @@ static void sbp2_login(struct work_struct *work)
         * If a bus reset happened, sbp2_update will have requeued
         * lu->work already.  Reset the work from reconnect to login.
         */
-       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+       lu->workfn = sbp2_login;
 }
 
 static void sbp2_reconnect(struct work_struct *work)
@@ -952,7 +953,7 @@ static void sbp2_reconnect(struct work_struct *work)
                    lu->retries++ >= 5) {
                        dev_err(tgt_dev(tgt), "failed to reconnect\n");
                        lu->retries = 0;
-                       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+                       lu->workfn = sbp2_login;
                }
                sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
 
@@ -972,6 +973,13 @@ static void sbp2_reconnect(struct work_struct *work)
        sbp2_conditionally_unblock(lu);
 }
 
+static void sbp2_lu_workfn(struct work_struct *work)
+{
+       struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
+                                               struct sbp2_logical_unit, work);
+       lu->workfn(work);
+}
+
 static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
 {
        struct sbp2_logical_unit *lu;
@@ -998,7 +1006,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
        lu->blocked  = false;
        ++tgt->dont_block;
        INIT_LIST_HEAD(&lu->orb_list);
-       INIT_DELAYED_WORK(&lu->work, sbp2_login);
+       lu->workfn = sbp2_login;
+       INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);
 
        list_add_tail(&lu->link, &tgt->lu_list);
        return 0;
index 1b5e8e46226d5f3d6bebdb770d8b29de9f04fc43..7160c43c59fcc31af1fbbbf79c1b44d87a68e22f 100644 (file)
@@ -584,7 +584,7 @@ static struct platform_driver dcdbas_driver = {
        .remove         = dcdbas_remove,
 };
 
-static const struct platform_device_info dcdbas_dev_info __initdata = {
+static const struct platform_device_info dcdbas_dev_info __initconst = {
        .name           = DRIVER_NAME,
        .id             = -1,
        .dma_mask       = DMA_BIT_MASK(32),
index b6bffbfd3be7a14131c7735960a12db3f43b122d..ff50aeebf0d98828072eea4b40944ebfa7594c77 100644 (file)
@@ -16,18 +16,6 @@ struct file_info {
        u64 size;
 };
 
-
-
-
-static void efi_char16_printk(efi_system_table_t *sys_table_arg,
-                             efi_char16_t *str)
-{
-       struct efi_simple_text_output_protocol *out;
-
-       out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
-       efi_call_phys2(out->output_string, out, str);
-}
-
 static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
 {
        char *s8;
@@ -65,20 +53,23 @@ again:
         * allocation which may be in a new descriptor region.
         */
        *map_size += sizeof(*m);
-       status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
-                               EFI_LOADER_DATA, *map_size, (void **)&m);
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               *map_size, (void **)&m);
        if (status != EFI_SUCCESS)
                goto fail;
 
-       status = efi_call_phys5(sys_table_arg->boottime->get_memory_map,
-                               map_size, m, &key, desc_size, &desc_version);
+       *desc_size = 0;
+       key = 0;
+       status = efi_call_early(get_memory_map, map_size, m,
+                               &key, desc_size, &desc_version);
        if (status == EFI_BUFFER_TOO_SMALL) {
-               efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+               efi_call_early(free_pool, m);
                goto again;
        }
 
        if (status != EFI_SUCCESS)
-               efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+               efi_call_early(free_pool, m);
+
        if (key_ptr && status == EFI_SUCCESS)
                *key_ptr = key;
        if (desc_ver && status == EFI_SUCCESS)
@@ -158,7 +149,7 @@ again:
        if (!max_addr)
                status = EFI_NOT_FOUND;
        else {
-               status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+               status = efi_call_early(allocate_pages,
                                        EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
                                        nr_pages, &max_addr);
                if (status != EFI_SUCCESS) {
@@ -170,8 +161,7 @@ again:
                *addr = max_addr;
        }
 
-       efi_call_phys1(sys_table_arg->boottime->free_pool, map);
-
+       efi_call_early(free_pool, map);
 fail:
        return status;
 }
@@ -231,7 +221,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
                if ((start + size) > end)
                        continue;
 
-               status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+               status = efi_call_early(allocate_pages,
                                        EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
                                        nr_pages, &start);
                if (status == EFI_SUCCESS) {
@@ -243,7 +233,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
        if (i == map_size / desc_size)
                status = EFI_NOT_FOUND;
 
-       efi_call_phys1(sys_table_arg->boottime->free_pool, map);
+       efi_call_early(free_pool, map);
 fail:
        return status;
 }
@@ -257,7 +247,7 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
                return;
 
        nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-       efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages);
+       efi_call_early(free_pages, addr, nr_pages);
 }
 
 
@@ -276,9 +266,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 {
        struct file_info *files;
        unsigned long file_addr;
-       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
        u64 file_size_total;
-       efi_file_io_interface_t *io;
        efi_file_handle_t *fh;
        efi_status_t status;
        int nr_files;
@@ -319,10 +307,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
        if (!nr_files)
                return EFI_SUCCESS;
 
-       status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
-                               EFI_LOADER_DATA,
-                               nr_files * sizeof(*files),
-                               (void **)&files);
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               nr_files * sizeof(*files), (void **)&files);
        if (status != EFI_SUCCESS) {
                efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
                goto fail;
@@ -331,13 +317,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
        str = cmd_line;
        for (i = 0; i < nr_files; i++) {
                struct file_info *file;
-               efi_file_handle_t *h;
-               efi_file_info_t *info;
                efi_char16_t filename_16[256];
-               unsigned long info_sz;
-               efi_guid_t info_guid = EFI_FILE_INFO_ID;
                efi_char16_t *p;
-               u64 file_sz;
 
                str = strstr(str, option_string);
                if (!str)
@@ -368,71 +349,18 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 
                /* Only open the volume once. */
                if (!i) {
-                       efi_boot_services_t *boottime;
-
-                       boottime = sys_table_arg->boottime;
-
-                       status = efi_call_phys3(boottime->handle_protocol,
-                                       image->device_handle, &fs_proto,
-                                               (void **)&io);
-                       if (status != EFI_SUCCESS) {
-                               efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
-                               goto free_files;
-                       }
-
-                       status = efi_call_phys2(io->open_volume, io, &fh);
-                       if (status != EFI_SUCCESS) {
-                               efi_printk(sys_table_arg, "Failed to open volume\n");
+                       status = efi_open_volume(sys_table_arg, image,
+                                                (void **)&fh);
+                       if (status != EFI_SUCCESS)
                                goto free_files;
-                       }
                }
 
-               status = efi_call_phys5(fh->open, fh, &h, filename_16,
-                                       EFI_FILE_MODE_READ, (u64)0);
-               if (status != EFI_SUCCESS) {
-                       efi_printk(sys_table_arg, "Failed to open file: ");
-                       efi_char16_printk(sys_table_arg, filename_16);
-                       efi_printk(sys_table_arg, "\n");
+               status = efi_file_size(sys_table_arg, fh, filename_16,
+                                      (void **)&file->handle, &file->size);
+               if (status != EFI_SUCCESS)
                        goto close_handles;
-               }
 
-               file->handle = h;
-
-               info_sz = 0;
-               status = efi_call_phys4(h->get_info, h, &info_guid,
-                                       &info_sz, NULL);
-               if (status != EFI_BUFFER_TOO_SMALL) {
-                       efi_printk(sys_table_arg, "Failed to get file info size\n");
-                       goto close_handles;
-               }
-
-grow:
-               status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
-                                       EFI_LOADER_DATA, info_sz,
-                                       (void **)&info);
-               if (status != EFI_SUCCESS) {
-                       efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
-                       goto close_handles;
-               }
-
-               status = efi_call_phys4(h->get_info, h, &info_guid,
-                                       &info_sz, info);
-               if (status == EFI_BUFFER_TOO_SMALL) {
-                       efi_call_phys1(sys_table_arg->boottime->free_pool,
-                                      info);
-                       goto grow;
-               }
-
-               file_sz = info->file_size;
-               efi_call_phys1(sys_table_arg->boottime->free_pool, info);
-
-               if (status != EFI_SUCCESS) {
-                       efi_printk(sys_table_arg, "Failed to get file info\n");
-                       goto close_handles;
-               }
-
-               file->size = file_sz;
-               file_size_total += file_sz;
+               file_size_total += file->size;
        }
 
        if (file_size_total) {
@@ -468,10 +396,10 @@ grow:
                                        chunksize = EFI_READ_CHUNK_SIZE;
                                else
                                        chunksize = size;
-                               status = efi_call_phys3(fh->read,
-                                                       files[j].handle,
-                                                       &chunksize,
-                                                       (void *)addr);
+
+                               status = efi_file_read(fh, files[j].handle,
+                                                      &chunksize,
+                                                      (void *)addr);
                                if (status != EFI_SUCCESS) {
                                        efi_printk(sys_table_arg, "Failed to read file\n");
                                        goto free_file_total;
@@ -480,12 +408,12 @@ grow:
                                size -= chunksize;
                        }
 
-                       efi_call_phys1(fh->close, files[j].handle);
+                       efi_file_close(fh, files[j].handle);
                }
 
        }
 
-       efi_call_phys1(sys_table_arg->boottime->free_pool, files);
+       efi_call_early(free_pool, files);
 
        *load_addr = file_addr;
        *load_size = file_size_total;
@@ -497,9 +425,9 @@ free_file_total:
 
 close_handles:
        for (k = j; k < i; k++)
-               efi_call_phys1(fh->close, files[k].handle);
+               efi_file_close(fh, files[k].handle);
 free_files:
-       efi_call_phys1(sys_table_arg->boottime->free_pool, files);
+       efi_call_early(free_pool, files);
 fail:
        *load_addr = 0;
        *load_size = 0;
@@ -545,7 +473,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
         * as possible while respecting the required alignment.
         */
        nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-       status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+       status = efi_call_early(allocate_pages,
                                EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
                                nr_pages, &efi_addr);
        new_addr = efi_addr;
index 4753bac652798501cc79caeb50bd6c9ebd2b2dd3..af20f17123374f9ba4f6b4ab2d1e4faa47ef43c5 100644 (file)
@@ -233,7 +233,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
        {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
        {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
        {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
-       {NULL_GUID, NULL, 0},
+       {NULL_GUID, NULL, NULL},
 };
 
 static __init int match_config_table(efi_guid_t *guid,
@@ -313,5 +313,8 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
        }
        pr_cont("\n");
        early_iounmap(config_tables, efi.systab->nr_tables * sz);
+
+       set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
        return 0;
 }
index 3dc24823919749ebb110f62b9ca5696cdaf67511..50ea412a25e64058a58b3de92b8f141f5db4e5a5 100644 (file)
@@ -227,7 +227,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
        memcpy(&entry->var, new_var, count);
 
        err = efivar_entry_set(entry, new_var->Attributes,
-                              new_var->DataSize, new_var->Data, false);
+                              new_var->DataSize, new_var->Data, NULL);
        if (err) {
                printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
                return -EIO;
index 24d52497524dce7b8935cb678c6084d39c6f2510..353fc546fb08f1214d7ea741ba787110f8a2ec8b 100644 (file)
@@ -99,10 +99,23 @@ static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj,
        return count;
 }
 
+static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
+                               struct bin_attribute *bin_attr,
+                               char *buf, loff_t off, size_t count)
+{
+       struct device *dev;
+       struct fmc_device *fmc;
+
+       dev = container_of(kobj, struct device, kobj);
+       fmc = container_of(dev, struct fmc_device, dev);
+       return fmc->op->write_ee(fmc, off, buf, count);
+}
+
 static struct bin_attribute fmc_eeprom_attr = {
-       .attr = { .name = "eeprom", .mode = S_IRUGO, },
+       .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, },
        .size = 8192, /* more or less standard */
        .read = fmc_read_eeprom,
+       .write = fmc_write_eeprom,
 };
 
 /*
@@ -154,7 +167,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
                        ret = -EINVAL;
                        break;
                }
-               if (fmc->flags == FMC_DEVICE_NO_MEZZANINE) {
+               if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) {
                        dev_info(fmc->hwdev, "absent mezzanine in slot %d\n",
                                 fmc->slot_id);
                        continue;
@@ -189,9 +202,6 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
        for (i = 0; i < n; i++) {
                fmc = devarray[i];
 
-               if (fmc->flags == FMC_DEVICE_NO_MEZZANINE)
-                       continue; /* dev_info already done above */
-
                fmc->nr_slots = n; /* each slot must know how many are there */
                fmc->devarray = devarray;
 
@@ -263,8 +273,6 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n)
        kfree(devs[0]->devarray);
 
        for (i = 0; i < n; i++) {
-               if (devs[i]->flags == FMC_DEVICE_NO_MEZZANINE)
-                       continue;
                sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
                device_del(&devs[i]->dev);
                fmc_free_id_info(devs[i]);
index 79adc39221ea745f1a403a9eb6b1434f9cb20618..4603fdb74465c7ef6dee2f35e544241157290fb7 100644 (file)
@@ -150,23 +150,36 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
 }
 EXPORT_SYMBOL(fmc_reprogram);
 
+static char *__strip_trailing_space(char *buf, char *str, int len)
+{
+       int i = len - 1;
+
+       memcpy(buf, str, len);
+       while(i >= 0 && buf[i] == ' ')
+               buf[i--] = '\0';
+       return buf;
+}
+
+#define __sdb_string(buf, field) ({                    \
+       BUILD_BUG_ON(sizeof(buf) < sizeof(field));      \
+       __strip_trailing_space(buf, (void *)(field), sizeof(field));    \
+               })
+
 static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
                                const struct sdb_array *arr)
 {
+       unsigned long base = arr->baseaddr;
        int i, j, n = arr->len, level = arr->level;
-       const struct sdb_array *ap;
+       char buf[64];
 
        for (i = 0; i < n; i++) {
-               unsigned long base;
                union  sdb_record *r;
                struct sdb_product *p;
                struct sdb_component *c;
                r = &arr->record[i];
                c = &r->dev.sdb_component;
                p = &c->product;
-               base = 0;
-               for (ap = arr; ap; ap = ap->parent)
-                       base += ap->baseaddr;
+
                dev_info(&fmc->dev, "SDB: ");
 
                for (j = 0; j < level; j++)
@@ -193,8 +206,8 @@ static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
                               p->name,
                               __be64_to_cpu(c->addr_first) + base);
                        if (IS_ERR(arr->subtree[i])) {
-                               printk(KERN_CONT "(bridge error %li)\n",
-                                      PTR_ERR(arr->subtree[i]));
+                               dev_info(&fmc->dev, "SDB: (bridge error %li)\n",
+                                        PTR_ERR(arr->subtree[i]));
                                break;
                        }
                        __fmc_show_sdb_tree(fmc, arr->subtree[i]);
@@ -203,10 +216,20 @@ static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
                        printk(KERN_CONT "integration\n");
                        break;
                case sdb_type_repo_url:
-                       printk(KERN_CONT "repo-url\n");
+                       printk(KERN_CONT "Synthesis repository: %s\n",
+                              __sdb_string(buf, r->repo_url.repo_url));
                        break;
                case sdb_type_synthesis:
-                       printk(KERN_CONT "synthesis-info\n");
+                       printk(KERN_CONT "Bitstream '%s' ",
+                              __sdb_string(buf, r->synthesis.syn_name));
+                       printk(KERN_CONT "synthesized %08x by %s ",
+                              __be32_to_cpu(r->synthesis.date),
+                              __sdb_string(buf, r->synthesis.user_name));
+                       printk(KERN_CONT "(%s version %x), ",
+                              __sdb_string(buf, r->synthesis.tool_name),
+                              __be32_to_cpu(r->synthesis.tool_version));
+                       printk(KERN_CONT "commit %pm\n",
+                              r->synthesis.commit_id);
                        break;
                case sdb_type_empty:
                        printk(KERN_CONT "empty\n");
index acf3a36c9ebc453737b1a849aa6715f41b241d68..32982da82694be753d1072c90136d842a8a866ec 100644 (file)
@@ -68,15 +68,7 @@ void __armada_drm_queue_unref_work(struct drm_device *dev,
 {
        struct armada_private *priv = dev->dev_private;
 
-       /*
-        * Yes, we really must jump through these hoops just to store a
-        * _pointer_ to something into the kfifo.  This is utterly insane
-        * and idiotic, because it kfifo requires the _data_ pointed to by
-        * the pointer const, not the pointer itself.  Not only that, but
-        * you have to pass a pointer _to_ the pointer you want stored.
-        */
-       const struct drm_framebuffer *silly_api_alert = fb;
-       WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
+       WARN_ON(!kfifo_put(&priv->fb_unref, fb));
        schedule_work(&priv->fb_unref_work);
 }
 
index c8fcf12019f09c1eaffff1d72ea72c74714325e2..5f8b0c2b9a4461d2e07b1d7a3abb25f69837fc90 100644 (file)
@@ -2,6 +2,7 @@ config DRM_BOCHS
        tristate "DRM Support for bochs dispi vga interface (qemu stdvga)"
        depends on DRM && PCI
        select DRM_KMS_HELPER
+       select DRM_KMS_FB_HELPER
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index bb8f58012189af7651c20c2d9b1da1ed390ebcfd..534cb89b160d686d60218dad53082be9b0f331ea 100644 (file)
 #include <drm/drmP.h>
 
 #if defined(CONFIG_X86)
+
+/*
+ * clflushopt is an unordered instruction which needs fencing with mfence or
+ * sfence to avoid ordering issues.  For drm_clflush_page this fencing happens
+ * in the caller.
+ */
 static void
 drm_clflush_page(struct page *page)
 {
@@ -44,7 +50,7 @@ drm_clflush_page(struct page *page)
 
        page_virtual = kmap_atomic(page);
        for (i = 0; i < PAGE_SIZE; i += size)
-               clflush(page_virtual + i);
+               clflushopt(page_virtual + i);
        kunmap_atomic(page_virtual);
 }
 
@@ -133,7 +139,7 @@ drm_clflush_virt_range(char *addr, unsigned long length)
                mb();
                for (; addr < end; addr += boot_cpu_data.x86_clflush_size)
                        clflush(addr);
-               clflush(end - 1);
+               clflushopt(end - 1);
                mb();
                return;
        }
index 7f2af9aca03895b97c75af76968093a61930b501..309023f12d7ff7ab5413baf14af4f580c2a5ccbc 100644 (file)
@@ -319,7 +319,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                        pci_dev_put(pci_dev);
                }
                if (!dev->hose) {
-                       struct pci_bus *b = pci_bus_b(pci_root_buses.next);
+                       struct pci_bus *b = list_entry(pci_root_buses.next,
+                               struct pci_bus, node);
                        if (b)
                                dev->hose = b->sysdata;
                }
index 5736aaa7e86cb069d30fd458b5842fd42defae17..f7af69bcf3f452aff52647d830e3f1497ad21dca 100644 (file)
@@ -468,8 +468,8 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
        } else {
                list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
                                         legacy_dev_list) {
-                       drm_put_dev(dev);
                        list_del(&dev->legacy_dev_list);
+                       drm_put_dev(dev);
                }
        }
        DRM_INFO("Module unloaded\n");
index 215131ab1dd2f2b65c707c6d367d50ec967c27d6..c204b4e3356e80db01b736595d854075065768c0 100644 (file)
@@ -172,20 +172,24 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 
        ret = exynos_drm_subdrv_open(dev, file);
        if (ret)
-               goto out;
+               goto err_file_priv_free;
 
        anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
                                        NULL, 0);
        if (IS_ERR(anon_filp)) {
                ret = PTR_ERR(anon_filp);
-               goto out;
+               goto err_subdrv_close;
        }
 
        anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
        file_priv->anon_filp = anon_filp;
 
        return ret;
-out:
+
+err_subdrv_close:
+       exynos_drm_subdrv_close(dev, file);
+
+err_file_priv_free:
        kfree(file_priv);
        file->driver_priv = NULL;
        return ret;
index 508cf99a292df18c569cc9ffd3466e8b598629e0..17f928ec84ea77790e4fef756bee55757f42d8e1 100644 (file)
@@ -10,7 +10,6 @@ config DRM_GMA500
        # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
        select ACPI_VIDEO if ACPI
        select BACKLIGHT_CLASS_DEVICE if ACPI
-       select VIDEO_OUTPUT_CONTROL if ACPI
        select INPUT if ACPI
        help
          Say yes for an experimental 2D KMS framebuffer driver for the
index 49bac41beefb3251ecc6a63f04e86d0d36de9974..c3e67ba94446d34a24b420c72804e029384948d7 100644 (file)
@@ -520,7 +520,7 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
 
        driver->has_clflush = 0;
 
-       if (boot_cpu_has(X86_FEATURE_CLFLSH)) {
+       if (boot_cpu_has(X86_FEATURE_CLFLUSH)) {
                uint32_t tfms, misc, cap0, cap4, clflush_size;
 
                /*
index 73ed59eff139a88948c7766dcc0c999398f59254..bea2d67196fb47b95f87d03ed80cd6dd53f250d4 100644 (file)
@@ -14,7 +14,6 @@ config DRM_I915
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select BACKLIGHT_LCD_SUPPORT if ACPI
        select BACKLIGHT_CLASS_DEVICE if ACPI
-       select VIDEO_OUTPUT_CONTROL if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
        select ACPI_BUTTON if ACPI
index 04f1f02c4019f57873caeb0c70fea14e0816ddeb..ec7bb0fc71bcfc8c19c2231c9bb0e3165f89e047 100644 (file)
@@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 void intel_detect_pch(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct pci_dev *pch;
+       struct pci_dev *pch = NULL;
 
        /* In all current cases, num_pipes is equivalent to the PCH_NOP setting
         * (which really amounts to a PCH but no South Display).
@@ -424,12 +424,9 @@ void intel_detect_pch(struct drm_device *dev)
         * all the ISA bridge devices and check for the first match, instead
         * of only checking the first one.
         */
-       pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
-       while (pch) {
-               struct pci_dev *curr = pch;
+       while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
                if (pch->vendor == PCI_VENDOR_ID_INTEL) {
-                       unsigned short id;
-                       id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+                       unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
                        dev_priv->pch_id = id;
 
                        if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
@@ -461,18 +458,16 @@ void intel_detect_pch(struct drm_device *dev)
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
                                WARN_ON(!IS_ULT(dev));
-                       } else {
-                               goto check_next;
-                       }
-                       pci_dev_put(pch);
+                       } else
+                               continue;
+
                        break;
                }
-check_next:
-               pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
-               pci_dev_put(curr);
        }
        if (!pch)
-               DRM_DEBUG_KMS("No PCH found?\n");
+               DRM_DEBUG_KMS("No PCH found.\n");
+
+       pci_dev_put(pch);
 }
 
 bool i915_semaphore_is_enabled(struct drm_device *dev)
index 40a2b36b276baa774028b56ae60b6ae6c59e919d..d278be110805ba50965f1e071213720434cb9e78 100644 (file)
@@ -842,7 +842,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
                                       dev_priv->gtt.base.start / PAGE_SIZE,
                                       dev_priv->gtt.base.total / PAGE_SIZE,
-                                      false);
+                                      true);
 }
 
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
index 1a24e84f231578ae772d40ad75adda4c356b8d68..28d24caa49f3f7720c63e208c4831c79f5433d8d 100644 (file)
@@ -82,9 +82,22 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
        r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
                                    "Graphics Stolen Memory");
        if (r == NULL) {
-               DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
-                         base, base + (uint32_t)dev_priv->gtt.stolen_size);
-               base = 0;
+               /*
+                * One more attempt but this time requesting region from
+                * base + 1, as we have seen that this resolves the region
+                * conflict with the PCI Bus.
+                * This is a BIOS w/a: Some BIOS wrap stolen in the root
+                * PCI bus, but have an off-by-one error. Hence retry the
+                * reservation starting from 1 instead of 0.
+                */
+               r = devm_request_mem_region(dev->dev, base + 1,
+                                           dev_priv->gtt.stolen_size - 1,
+                                           "Graphics Stolen Memory");
+               if (r == NULL) {
+                       DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
+                                 base, base + (uint32_t)dev_priv->gtt.stolen_size);
+                       base = 0;
+               }
        }
 
        return base;
@@ -201,6 +214,13 @@ int i915_gem_init_stolen(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int bios_reserved = 0;
 
+#ifdef CONFIG_INTEL_IOMMU
+       if (intel_iommu_gfx_mapped) {
+               DRM_INFO("DMAR active, disabling use of stolen memory\n");
+               return 0;
+       }
+#endif
+
        if (dev_priv->gtt.stolen_size == 0)
                return 0;
 
index 9fec71175571e068cce957973431fe21eca962d2..d554169ac59274fbcaeaa2978078d0c71b822a33 100644 (file)
@@ -618,33 +618,25 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 
 /* raw reads, only for fast reads of display block, no need for forcewake etc. */
 #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
 
 static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t status;
-
-       if (INTEL_INFO(dev)->gen < 7) {
-               status = pipe == PIPE_A ?
-                       DE_PIPEA_VBLANK :
-                       DE_PIPEB_VBLANK;
+       int reg;
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               status = GEN8_PIPE_VBLANK;
+               reg = GEN8_DE_PIPE_ISR(pipe);
+       } else if (INTEL_INFO(dev)->gen >= 7) {
+               status = DE_PIPE_VBLANK_IVB(pipe);
+               reg = DEISR;
        } else {
-               switch (pipe) {
-               default:
-               case PIPE_A:
-                       status = DE_PIPEA_VBLANK_IVB;
-                       break;
-               case PIPE_B:
-                       status = DE_PIPEB_VBLANK_IVB;
-                       break;
-               case PIPE_C:
-                       status = DE_PIPEC_VBLANK_IVB;
-                       break;
-               }
+               status = DE_PIPE_VBLANK(pipe);
+               reg = DEISR;
        }
 
-       return __raw_i915_read32(dev_priv, DEISR) & status;
+       return __raw_i915_read32(dev_priv, reg) & status;
 }
 
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -702,7 +694,28 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                else
                        position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
-               if (HAS_PCH_SPLIT(dev)) {
+               if (HAS_DDI(dev)) {
+                       /*
+                        * On HSW HDMI outputs there seems to be a 2 line
+                        * difference, whereas eDP has the normal 1 line
+                        * difference that earlier platforms have. External
+                        * DP is unknown. For now just check for the 2 line
+                        * difference case on all output types on HSW+.
+                        *
+                        * This might misinterpret the scanline counter being
+                        * one line too far along on eDP, but that's less
+                        * dangerous than the alternative since that would lead
+                        * the vblank timestamp code astray when it sees a
+                        * scanline count before vblank_start during a vblank
+                        * interrupt.
+                        */
+                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
+                       if ((in_vbl && (position == vbl_start - 2 ||
+                                       position == vbl_start - 1)) ||
+                           (!in_vbl && (position == vbl_end - 2 ||
+                                        position == vbl_end - 1)))
+                               position = (position + 2) % vtotal;
+               } else if (HAS_PCH_SPLIT(dev)) {
                        /*
                         * The scanline counter increments at the leading edge
                         * of hsync, ie. it completely misses the active portion
@@ -2769,10 +2782,9 @@ static void ibx_irq_postinstall(struct drm_device *dev)
                return;
 
        if (HAS_PCH_IBX(dev)) {
-               mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
-                      SDE_TRANSA_FIFO_UNDER | SDE_POISON;
+               mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
        } else {
-               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
+               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
 
                I915_WRITE(SERR_INT, I915_READ(SERR_INT));
        }
@@ -2832,20 +2844,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
                                DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
                                DE_PLANEB_FLIP_DONE_IVB |
-                               DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB |
-                               DE_ERR_INT_IVB);
+                               DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
                extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
-                             DE_PIPEA_VBLANK_IVB);
+                             DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
 
                I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
        } else {
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                                DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
                                DE_AUX_CHANNEL_A |
-                               DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
                                DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
                                DE_POISON);
-               extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
+               extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+                               DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN;
        }
 
        dev_priv->irq_mask = ~display_mask;
@@ -2961,9 +2972,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        struct drm_device *dev = dev_priv->dev;
        uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
                GEN8_PIPE_CDCLK_CRC_DONE |
-               GEN8_PIPE_FIFO_UNDERRUN |
                GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
-       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
+       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
+               GEN8_PIPE_FIFO_UNDERRUN;
        int pipe;
        dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
index e06b9e017d6ba918b87557de301df47076852434..234ac5f7bc5aba1013f2ad62650baa05c1d1559a 100644 (file)
@@ -1244,6 +1244,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+               ironlake_edp_panel_vdd_on(intel_dp);
                ironlake_edp_panel_off(intel_dp);
        }
 
index 4c1672809493c795714bc3eddaa1238c258451ed..9b8a7c7ea7fc1925610b4dcb11ca9f768057fd41 100644 (file)
@@ -1092,12 +1092,12 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        bool cur_state;
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-               cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
-       else if (IS_845G(dev) || IS_I865G(dev))
+       if (IS_845G(dev) || IS_I865G(dev))
                cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
-       else
+       else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
                cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+       else
+               cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
 
        WARN(cur_state != state,
             "cursor on pipe %c assertion failure (expected %s, current %s)\n",
index 57552eb386b0b1b6d735a7fb0f9b770405e5f411..2688f6d64bb9f3e6883e5a8a9216a38fd794d880 100644 (file)
@@ -1249,17 +1249,24 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power off\n");
 
+       WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
+
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
         * panels get very unhappy and cease to work. */
-       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
 
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
 
+       intel_dp->want_panel_vdd = false;
+
        ironlake_wait_panel_off(intel_dp);
+
+       /* We got a reference when we enabled the VDD. */
+       intel_runtime_pm_put(dev_priv);
 }
 
 void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
@@ -1639,7 +1646,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
                val |= EDP_PSR_LINK_DISABLE;
 
        I915_WRITE(EDP_PSR_CTL(dev), val |
-                  IS_BROADWELL(dev) ? 0 : link_entry_time |
+                  (IS_BROADWELL(dev) ? 0 : link_entry_time) |
                   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
                   idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
                   EDP_PSR_ENABLE);
@@ -1784,6 +1791,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)
 
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
+       ironlake_edp_panel_vdd_on(intel_dp);
        ironlake_edp_backlight_off(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        ironlake_edp_panel_off(intel_dp);
index 6db0d9d17f47e7b5ce5c43a7aa7795de71ea6346..ee3181ebcc9236078835ee18a48fe86c97525ff9 100644 (file)
@@ -845,7 +845,7 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
 {
        struct drm_device *dev = intel_hdmi_to_dev(hdmi);
 
-       if (IS_G4X(dev))
+       if (!hdmi->has_hdmi_sink || IS_G4X(dev))
                return 165000;
        else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
                return 300000;
@@ -899,8 +899,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * outputs. We also need to check that the higher clock still fits
         * within limits.
         */
-       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
-           && HAS_PCH_SPLIT(dev)) {
+       if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
+           clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
index 350de359123af9cbd42354c182424f356281aa16..079ea38f14d9b4b54092a1ebeca4cd77dac27cec 100644 (file)
@@ -698,7 +698,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
                freq /= 0xff;
 
        ctl = freq << 17;
-       if (IS_GEN2(dev) && panel->backlight.combination_mode)
+       if (panel->backlight.combination_mode)
                ctl |= BLM_LEGACY_MODE;
        if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
                ctl |= BLM_POLARITY_PNV;
@@ -979,7 +979,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector)
 
        ctl = I915_READ(BLC_PWM_CTL);
 
-       if (IS_GEN2(dev))
+       if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
                panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
 
        if (IS_PINEVIEW(dev))
index d77cc81900f92100ba2f61d7130bc9b0b60454b5..e1fc35a726564cc9f3526231780672d09d151838 100644 (file)
@@ -3493,6 +3493,8 @@ static void valleyview_setup_pctx(struct drm_device *dev)
        u32 pcbr;
        int pctx_size = 24*1024;
 
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
        pcbr = I915_READ(VLV_PCBR);
        if (pcbr) {
                /* BIOS set it up already, grab the pre-alloc'd space */
@@ -3542,8 +3544,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
                I915_WRITE(GTFIFODBG, gtfifodbg);
        }
 
-       valleyview_setup_pctx(dev);
-
        /* If VLV, Forcewake all wells, else re-direct to regular path */
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
@@ -4395,6 +4395,8 @@ void intel_enable_gt_powersave(struct drm_device *dev)
                ironlake_enable_rc6(dev);
                intel_init_emon(dev);
        } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+               if (IS_VALLEYVIEW(dev))
+                       valleyview_setup_pctx(dev);
                /*
                 * PCU communication is slow and this doesn't need to be
                 * done at any specific time, so do this out of our fast path
index 7cf787d697b111aade40bf0cb34a1db52a2c41a6..637c29a33127f98ad341ba6d4aa097857c5ea9c9 100644 (file)
@@ -11,7 +11,7 @@ config DRM_NOUVEAU
        select FB
        select FRAMEBUFFER_CONSOLE if !EXPERT
        select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
-       select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+       select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT
        select X86_PLATFORM_DEVICES if ACPI && X86
        select ACPI_WMI if ACPI && X86
        select MXM_WMI if ACPI && X86
@@ -19,7 +19,6 @@ config DRM_NOUVEAU
        # Similar to i915, we need to select ACPI_VIDEO and it's dependencies
        select BACKLIGHT_LCD_SUPPORT if ACPI && X86
        select BACKLIGHT_CLASS_DEVICE if ACPI && X86
-       select VIDEO_OUTPUT_CONTROL if ACPI && X86
        select INPUT if ACPI && X86
        select THERMAL if ACPI && X86
        select ACPI_VIDEO if ACPI && X86
index 89c484d8ac2666d8b3c04bb818cb5eec2665bb38..4ee702ac8907bcc3d486000b525ad61857cdf5ff 100644 (file)
@@ -866,13 +866,16 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        int ret;
 
-       if (nouveau_runtime_pm == 0)
-               return -EINVAL;
+       if (nouveau_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
 
        /* are we optimus enabled? */
        if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
                DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
-               return -EINVAL;
+               pm_runtime_forbid(dev);
+               return -EBUSY;
        }
 
        nv_debug_level(SILENT);
@@ -923,12 +926,15 @@ static int nouveau_pmops_runtime_idle(struct device *dev)
        struct nouveau_drm *drm = nouveau_drm(drm_dev);
        struct drm_crtc *crtc;
 
-       if (nouveau_runtime_pm == 0)
+       if (nouveau_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
                return -EBUSY;
+       }
 
        /* are we optimus enabled? */
        if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
                DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
+               pm_runtime_forbid(dev);
                return -EBUSY;
        }
 
index 2cec2ab02f80c193ce929393cd3d0c86bdd3d7c9..607dc14d195e3540f103bf798d2e6f0e10e5634f 100644 (file)
@@ -1314,7 +1314,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                        }
                        if (is_dp)
                                args.v5.ucLaneNum = dp_lane_count;
-                       else if (radeon_encoder->pixel_clock > 165000)
+                       else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                args.v5.ucLaneNum = 8;
                        else
                                args.v5.ucLaneNum = 4;
index e6419ca7cd375d6958ebcd339fb68a004c56cd1a..bbb17841a9e57ad2fdc44425a26d658848892f4c 100644 (file)
@@ -3046,7 +3046,7 @@ static u32 cik_create_bitmask(u32 bit_width)
 }
 
 /**
- * cik_select_se_sh - select which SE, SH to address
+ * cik_get_rb_disabled - computes the mask of disabled RBs
  *
  * @rdev: radeon_device pointer
  * @max_rb_num: max RBs (render backends) for the asic
@@ -4134,8 +4134,11 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
 {
        if (enable)
                WREG32(CP_MEC_CNTL, 0);
-       else
+       else {
                WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+               rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+               rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+       }
        udelay(50);
 }
 
@@ -7902,7 +7905,8 @@ int cik_resume(struct radeon_device *rdev)
        /* init golden registers */
        cik_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = cik_startup(rdev);
index 1ecb3f1070e35c6ed3516e5f325eeeb61bc795b2..94626ea90fa57abc5efca249ab4d0d08cfc9566d 100644 (file)
@@ -264,6 +264,8 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)
                WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
                WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
        }
+       rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
+       rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;
 }
 
 /**
@@ -291,6 +293,11 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)
        u32 me_cntl, reg_offset;
        int i;
 
+       if (enable == false) {
+               cik_sdma_gfx_stop(rdev);
+               cik_sdma_rlc_stop(rdev);
+       }
+
        for (i = 0; i < 2; i++) {
                if (i == 0)
                        reg_offset = SDMA0_REGISTER_OFFSET;
@@ -420,10 +427,6 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev)
        if (!rdev->sdma_fw)
                return -EINVAL;
 
-       /* stop the gfx rings and rlc compute queues */
-       cik_sdma_gfx_stop(rdev);
-       cik_sdma_rlc_stop(rdev);
-
        /* halt the MEs */
        cik_sdma_enable(rdev, false);
 
@@ -492,9 +495,6 @@ int cik_sdma_resume(struct radeon_device *rdev)
  */
 void cik_sdma_fini(struct radeon_device *rdev)
 {
-       /* stop the gfx rings and rlc compute queues */
-       cik_sdma_gfx_stop(rdev);
-       cik_sdma_rlc_stop(rdev);
        /* halt the MEs */
        cik_sdma_enable(rdev, false);
        radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
index 8a2c010b7dc53b22f0c6ead8dec361c66538a041..27b0ff16082ebbbe10eb385b8bce24e127b5091d 100644 (file)
@@ -5299,7 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev)
        /* init golden registers */
        evergreen_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = evergreen_startup(rdev);
index 76ada8cfe902a4d9eaa9890404c390371f856621..3a03ba37d04346fb5200d67ee002716ae549a600 100644 (file)
@@ -57,7 +57,7 @@ typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
 
 #define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
 
-#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x8
 #define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable      0xC
 #define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
 
index ea932ac66fc6647da43a8cf775b60ade25d478de..bf6300cfd62d0799deaefbd698027cf8d811dbc6 100644 (file)
@@ -2105,7 +2105,8 @@ int cayman_resume(struct radeon_device *rdev)
        /* init golden registers */
        ni_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = cayman_startup(rdev);
index ef024ce3f7ccfd39b1be47be9840a401b588b1dc..3cc78bb66042fc5509f26825560847374888288e 100644 (file)
@@ -3942,8 +3942,6 @@ int r100_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r100_startup(rdev);
        if (r) {
index 7c63ef840e86abaf04f216201b32ee2f40323b9b..0b658b34b33ab1d2874c0c85a668b4fa48da0ecc 100644 (file)
@@ -1430,8 +1430,6 @@ int r300_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r300_startup(rdev);
        if (r) {
index 3768aab2710b3943261312c4fcc5184b4f18a6fb..802b19220a21358712dc304a894db892ec3537fb 100644 (file)
@@ -325,8 +325,6 @@ int r420_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r420_startup(rdev);
        if (r) {
index e209eb75024f9dc1c441518cbe8f8d70a41844f5..98d6053c36c678aaf598e7a0b63193d00d042f5b 100644 (file)
@@ -240,8 +240,6 @@ int r520_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r520_startup(rdev);
        if (r) {
index cdbc4171fe73743bd9bcf9ce2bbb74020ad6ece5..647ef407921764692758c56e03f92b737202e317 100644 (file)
@@ -2968,7 +2968,8 @@ int r600_resume(struct radeon_device *rdev)
        /* post card */
        atom_asic_init(rdev->mode_info.atom_context);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = r600_startup(rdev);
index b012cbbc3ed5a9b892b433eff0ee5f3134a130de..044bc98fb459e46fac62b929696ad047f835360d 100644 (file)
@@ -1521,13 +1521,16 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        if (r)
                DRM_ERROR("ib ring test failed (%d).\n", r);
 
-       if (rdev->pm.dpm_enabled) {
+       if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
                /* do dpm late init */
                r = radeon_pm_late_init(rdev);
                if (r) {
                        rdev->pm.dpm_enabled = false;
                        DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
                }
+       } else {
+               /* resume old pm late */
+               radeon_pm_resume(rdev);
        }
 
        radeon_restore_bios_scratch_regs(rdev);
index 84a1bbb75f914a7bd914ad9120b8a2e2ac9aac5a..f633c2782170b09bcc8722d1568cbe0a8c665f12 100644 (file)
@@ -403,11 +403,15 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        int ret;
 
-       if (radeon_runtime_pm == 0)
-               return -EINVAL;
+       if (radeon_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
 
-       if (radeon_runtime_pm == -1 && !radeon_is_px())
-               return -EINVAL;
+       if (radeon_runtime_pm == -1 && !radeon_is_px()) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
 
        drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
        drm_kms_helper_poll_disable(drm_dev);
@@ -456,12 +460,15 @@ static int radeon_pmops_runtime_idle(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        struct drm_crtc *crtc;
 
-       if (radeon_runtime_pm == 0)
+       if (radeon_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
                return -EBUSY;
+       }
 
        /* are we PX enabled? */
        if (radeon_runtime_pm == -1 && !radeon_is_px()) {
                DRM_DEBUG_DRIVER("failing to power off - not px\n");
+               pm_runtime_forbid(dev);
                return -EBUSY;
        }
 
index 2aecd6dc26109653741bc3671ea4b82136106954..66ed3ea7144010e7c95bc0d07c01ad5499242947 100644 (file)
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_is_px(void);
+#else
+static inline bool radeon_is_px(void) { return false; }
+#endif
+
 /**
  * radeon_driver_unload_kms - Main unload function for KMS.
  *
@@ -130,7 +137,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
                                "Error during ACPI methods call\n");
        }
 
-       if (radeon_runtime_pm != 0) {
+       if ((radeon_runtime_pm == 1) ||
+           ((radeon_runtime_pm == -1) && radeon_is_px())) {
                pm_runtime_use_autosuspend(dev->dev);
                pm_runtime_set_autosuspend_delay(dev->dev, 5000);
                pm_runtime_set_active(dev->dev);
index 77f5b0c3edb8d8b1f4835620d626c3981171c7a6..040a2a10ea17e8136a4274decc83de131ad79e3f 100644 (file)
@@ -714,6 +714,9 @@ int radeon_ttm_init(struct radeon_device *rdev)
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
        }
+       /* Change the size here instead of the init above so only lpfn is affected */
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
        r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
                             RADEON_GEM_DOMAIN_VRAM,
                             NULL, &rdev->stollen_vga_memory);
@@ -935,7 +938,7 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
        while (size) {
                loff_t p = *pos / PAGE_SIZE;
                unsigned off = *pos & ~PAGE_MASK;
-               ssize_t cur_size = min(size, PAGE_SIZE - off);
+               size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
                struct page *page;
                void *ptr;
 
index b5c2369cda2fe28ca043fe91f4fcfe12fc227fc6..130d5cc50d436fd90c1d3055bd03e177ba2dce6c 100644 (file)
@@ -474,8 +474,6 @@ int rs400_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs400_startup(rdev);
        if (r) {
index fdcde7693032c28cc30008b494fd573fd82e58f3..72d3616de08e054efe6199fcd529f59cef3e18d5 100644 (file)
@@ -1048,8 +1048,6 @@ int rs600_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs600_startup(rdev);
        if (r) {
index 35950738bd5e449465e0e5062d096e3e8ae9ff0e..3462b64369bfe6142a4c8acfaec09e0bb7d8826c 100644 (file)
@@ -756,8 +756,6 @@ int rs690_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs690_startup(rdev);
        if (r) {
index 98e8138ff77945ecdba447bdcb94310c30dcb1c7..237dd29d9f1c893b1e17600fec59660848b394c3 100644 (file)
@@ -586,8 +586,6 @@ int rv515_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r =  rv515_startup(rdev);
        if (r) {
index 4e37a42305d83be2df8b3853bdff0e13b7b0f46f..fef310773aadc71260888372b896df0afcced749 100644 (file)
@@ -1811,7 +1811,8 @@ int rv770_resume(struct radeon_device *rdev)
        /* init golden registers */
        rv770_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = rv770_startup(rdev);
index 83578324e5d1383167f75071cdaf47d85a0e60ea..9a124d0608b36f3ae594709ac92c4d4ad563b6d7 100644 (file)
@@ -6618,7 +6618,8 @@ int si_resume(struct radeon_device *rdev)
        /* init golden registers */
        si_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = si_startup(rdev);
index a066513093880a218d185624589ec07efce66b0b..214b7992a3aa74296eeb2a083b28398c08c3cb4d 100644 (file)
@@ -351,9 +351,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 
 moved:
        if (bo->evicted) {
-               ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
-               if (ret)
-                       pr_err("Can not flush read caches\n");
+               if (bdev->driver->invalidate_caches) {
+                       ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
+                       if (ret)
+                               pr_err("Can not flush read caches\n");
+               }
                bo->evicted = false;
        }
 
index 801231c9ae483980afe0e93a0af73a7f07123864..0ce48e5a9cb4a70b56461f0ceb529e2c48ed58aa 100644 (file)
@@ -339,11 +339,13 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
        vma->vm_private_data = bo;
 
        /*
-        * PFNMAP is faster than MIXEDMAP due to reduced page
-        * administration. So use MIXEDMAP only if private VMA, where
-        * we need to support COW.
+        * We'd like to use VM_PFNMAP on shared mappings, where
+        * (vma->vm_flags & VM_SHARED) != 0, for performance reasons,
+        * but for some reason VM_PFNMAP + x86 PAT + write-combine is very
+        * bad for performance. Until that has been sorted out, use
+        * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719
         */
-       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
        vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
        return 0;
 out_unref:
@@ -359,7 +361,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
 
        vma->vm_ops = &ttm_bo_vm_ops;
        vma->vm_private_data = ttm_bo_reference(bo);
-       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
        vma->vm_flags |= VM_IO | VM_DONTEXPAND;
        return 0;
 }
index 8d67b943ac05ce2d1dd44597d00a1e5a07fd9bdb..0394811251bd7e8dd75159d9d01b045d089d2290 100644 (file)
@@ -177,8 +177,10 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)
        if (obj->vmapping)
                udl_gem_vunmap(obj);
 
-       if (gem_obj->import_attach)
+       if (gem_obj->import_attach) {
                drm_prime_gem_destroy(gem_obj, obj->sg);
+               put_device(gem_obj->dev->dev);
+       }
 
        if (obj->pages)
                udl_gem_put_pages(obj);
@@ -256,9 +258,12 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
        int ret;
 
        /* need to attach */
+       get_device(dev->dev);
        attach = dma_buf_attach(dma_buf, dev->dev);
-       if (IS_ERR(attach))
+       if (IS_ERR(attach)) {
+               put_device(dev->dev);
                return ERR_CAST(attach);
+       }
 
        get_dma_buf(dma_buf);
 
@@ -282,6 +287,6 @@ fail_unmap:
 fail_detach:
        dma_buf_detach(dma_buf, attach);
        dma_buf_put(dma_buf);
-
+       put_device(dev->dev);
        return ERR_PTR(ret);
 }
index 82468d9029156c6588a4480a9c0ed8c0aed82736..e7af580ab977f5932629b8d45e5d5e68a52942a5 100644 (file)
@@ -830,6 +830,24 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        if (unlikely(ret != 0))
                goto out_unlock;
 
+       /*
+        * A gb-aware client referencing a shared surface will
+        * expect a backup buffer to be present.
+        */
+       if (dev_priv->has_mob && req->shareable) {
+               uint32_t backup_handle;
+
+               ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
+                                           res->backup_size,
+                                           true,
+                                           &backup_handle,
+                                           &res->backup);
+               if (unlikely(ret != 0)) {
+                       vmw_resource_unreference(&res);
+                       goto out_unlock;
+               }
+       }
+
        tmp = vmw_resource_reference(&srf->res);
        ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
                                    req->shareable, VMW_RES_SURFACE,
index befe0e336471b0f36e34473ee97c3ba72759ddf9..24883b4d1a49d40a2bb3462ee36ed094f474b3cd 100644 (file)
@@ -43,6 +43,7 @@
 #define G25_REV_MIN 0x22
 #define G27_REV_MAJ 0x12
 #define G27_REV_MIN 0x38
+#define G27_2_REV_MIN 0x39
 
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
@@ -130,6 +131,7 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = {
        {DFP_REV_MAJ,  DFP_REV_MIN,  &native_dfp},      /* Driving Force Pro */
        {G25_REV_MAJ,  G25_REV_MIN,  &native_g25},      /* G25 */
        {G27_REV_MAJ,  G27_REV_MIN,  &native_g27},      /* G27 */
+       {G27_REV_MAJ,  G27_2_REV_MIN,  &native_g27},    /* G27 v2 */
 };
 
 /* Recalculates X axis value accordingly to currently selected range */
index 7ed82805641477e5556dff5f12898f2f42095559..91fab975063ce889b1ceae0bafbab2273d77186b 100644 (file)
@@ -624,7 +624,8 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
 
        /* Setup sound card */
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pm->pk->hdev->dev, index[dev], id[dev],
+                          THIS_MODULE, 0, &card);
        if (err < 0) {
                pk_error("failed to create pc-midi sound card\n");
                err = -ENOMEM;
@@ -660,8 +661,6 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
        snd_rawmidi_set_ops(rwmidi, SNDRV_RAWMIDI_STREAM_INPUT,
                &pcmidi_in_ops);
 
-       snd_card_set_dev(card, &pm->pk->hdev->dev);
-
        /* create sysfs variables */
        err = device_create_file(&pm->pk->hdev->dev,
                                 sysfs_device_attr_channel);
index 12354055d4745a4a50e783f624ec8b24bee46dc4..2f19b15f47f2ffca68de731ef0e0ba3ae53c972b 100644 (file)
@@ -42,6 +42,7 @@
 #define DUALSHOCK4_CONTROLLER_BT  BIT(6)
 
 #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
+#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER_USB | DUALSHOCK4_CONTROLLER_USB)
 
 #define MAX_LEDS 4
 
@@ -499,6 +500,7 @@ struct sony_sc {
        __u8 right;
 #endif
 
+       __u8 worker_initialized;
        __u8 led_state[MAX_LEDS];
        __u8 led_count;
 };
@@ -993,22 +995,11 @@ static int sony_init_ff(struct hid_device *hdev)
        return input_ff_create_memless(input_dev, NULL, sony_play_effect);
 }
 
-static void sony_destroy_ff(struct hid_device *hdev)
-{
-       struct sony_sc *sc = hid_get_drvdata(hdev);
-
-       cancel_work_sync(&sc->state_worker);
-}
-
 #else
 static int sony_init_ff(struct hid_device *hdev)
 {
        return 0;
 }
-
-static void sony_destroy_ff(struct hid_device *hdev)
-{
-}
 #endif
 
 static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
@@ -1077,6 +1068,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
                hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
                ret = sixaxis_set_operational_usb(hdev);
+
+               sc->worker_initialized = 1;
                INIT_WORK(&sc->state_worker, sixaxis_state_worker);
        }
        else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
@@ -1087,6 +1080,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                if (ret < 0)
                        goto err_stop;
 
+               sc->worker_initialized = 1;
                INIT_WORK(&sc->state_worker, dualshock4_state_worker);
        } else {
                ret = 0;
@@ -1101,9 +1095,11 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                        goto err_stop;
        }
 
-       ret = sony_init_ff(hdev);
-       if (ret < 0)
-               goto err_stop;
+       if (sc->quirks & SONY_FF_SUPPORT) {
+               ret = sony_init_ff(hdev);
+               if (ret < 0)
+                       goto err_stop;
+       }
 
        return 0;
 err_stop:
@@ -1120,7 +1116,8 @@ static void sony_remove(struct hid_device *hdev)
        if (sc->quirks & SONY_LED_SUPPORT)
                sony_leds_remove(hdev);
 
-       sony_destroy_ff(hdev);
+       if (sc->worker_initialized)
+               cancel_work_sync(&sc->state_worker);
 
        hid_hw_stop(hdev);
 }
index cb0137b3718d8cd0a42d6483a9817a26733452c6..ab24ce2eb28f484e30fa0994cd2781994ff7d22d 100644 (file)
@@ -320,13 +320,13 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
                        hid_hw_close(hidraw->hid);
                        wake_up_interruptible(&hidraw->wait);
                }
+               device_destroy(hidraw_class,
+                              MKDEV(hidraw_major, hidraw->minor));
        } else {
                --hidraw->open;
        }
        if (!hidraw->open) {
                if (!hidraw->exist) {
-                       device_destroy(hidraw_class,
-                                       MKDEV(hidraw_major, hidraw->minor));
                        hidraw_table[hidraw->minor] = NULL;
                        kfree(hidraw);
                } else {
index 0a74b5661186e6b6b8bc6dfbe01d4419bcf40c6a..5e4dfa4cfe2250ebde44869a280196dbc184d76d 100644 (file)
@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON)    += hv_balloon.o
 hv_vmbus-y := vmbus_drv.o \
                 hv.o connection.o channel.o \
                 channel_mgmt.o ring_buffer.o
-hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o
+hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o
index 69ea36f07b4d6b47c2030fe9c82bb8bb3fe866d0..602ca86a6488d6d90e4927d79ed99ca6c5df42b8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/hyperv.h>
+#include <linux/uio.h>
 
 #include "hyperv_vmbus.h"
 
@@ -554,14 +555,14 @@ EXPORT_SYMBOL_GPL(vmbus_close);
  *
  * Mainly used by Hyper-V drivers.
  */
-int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
+int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
                           u32 bufferlen, u64 requestid,
                           enum vmbus_packet_type type, u32 flags)
 {
        struct vmpacket_descriptor desc;
        u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
        u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
-       struct scatterlist bufferlist[3];
+       struct kvec bufferlist[3];
        u64 aligned_data = 0;
        int ret;
        bool signal = false;
@@ -575,11 +576,12 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
        desc.len8 = (u16)(packetlen_aligned >> 3);
        desc.trans_id = requestid;
 
-       sg_init_table(bufferlist, 3);
-       sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
-       sg_set_buf(&bufferlist[1], buffer, bufferlen);
-       sg_set_buf(&bufferlist[2], &aligned_data,
-                  packetlen_aligned - packetlen);
+       bufferlist[0].iov_base = &desc;
+       bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor);
+       bufferlist[1].iov_base = buffer;
+       bufferlist[1].iov_len = bufferlen;
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
 
@@ -605,7 +607,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
        u32 descsize;
        u32 packetlen;
        u32 packetlen_aligned;
-       struct scatterlist bufferlist[3];
+       struct kvec bufferlist[3];
        u64 aligned_data = 0;
        bool signal = false;
 
@@ -637,11 +639,12 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
                desc.range[i].pfn        = pagebuffers[i].pfn;
        }
 
-       sg_init_table(bufferlist, 3);
-       sg_set_buf(&bufferlist[0], &desc, descsize);
-       sg_set_buf(&bufferlist[1], buffer, bufferlen);
-       sg_set_buf(&bufferlist[2], &aligned_data,
-               packetlen_aligned - packetlen);
+       bufferlist[0].iov_base = &desc;
+       bufferlist[0].iov_len = descsize;
+       bufferlist[1].iov_base = buffer;
+       bufferlist[1].iov_len = bufferlen;
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
 
@@ -665,7 +668,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
        u32 descsize;
        u32 packetlen;
        u32 packetlen_aligned;
-       struct scatterlist bufferlist[3];
+       struct kvec bufferlist[3];
        u64 aligned_data = 0;
        bool signal = false;
        u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
@@ -700,11 +703,12 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
        memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
               pfncount * sizeof(u64));
 
-       sg_init_table(bufferlist, 3);
-       sg_set_buf(&bufferlist[0], &desc, descsize);
-       sg_set_buf(&bufferlist[1], buffer, bufferlen);
-       sg_set_buf(&bufferlist[2], &aligned_data,
-               packetlen_aligned - packetlen);
+       bufferlist[0].iov_base = &desc;
+       bufferlist[0].iov_len = descsize;
+       bufferlist[1].iov_base = buffer;
+       bufferlist[1].iov_len = bufferlen;
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
 
index 7e17a5495e029cc02b127f4c0cb997b43aa09dfe..7e6d78dc9437def19b24ac588ed6171a469aed51 100644 (file)
@@ -1171,7 +1171,8 @@ static int dm_thread_func(void *dm_dev)
        int t;
 
        while (!kthread_should_stop()) {
-               t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ);
+               t = wait_for_completion_interruptible_timeout(
+                                               &dm_device.config_event, 1*HZ);
                /*
                 * The host expects us to post information on the memory
                 * pressure every second.
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
new file mode 100644 (file)
index 0000000..eaaa3d8
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * An implementation of file copy service.
+ *
+ * Copyright (C) 2014, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/nls.h>
+#include <linux/workqueue.h>
+#include <linux/cdev.h>
+#include <linux/hyperv.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+
+#include "hyperv_vmbus.h"
+
+#define WIN8_SRV_MAJOR         1
+#define WIN8_SRV_MINOR         1
+#define WIN8_SRV_VERSION       (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
+
+/*
+ * Global state maintained for transaction that is being processed.
+ * For a class of integration services, including the "file copy service",
+ * the specified protocol is a "request/response" protocol which means that
+ * there can only be single outstanding transaction from the host at any
+ * given point in time. We use this to simplify memory management in this
+ * driver - we cache and process only one message at a time.
+ *
+ * While the request/response protocol is guaranteed by the host, we further
+ * ensure this by serializing packet processing in this driver - we do not
+ * read additional packets from the VMBUs until the current packet is fully
+ * handled.
+ *
+ * The transaction "active" state is set when we receive a request from the
+ * host and we cleanup this state when the transaction is completed - when we
+ * respond to the host with our response. When the transaction active state is
+ * set, we defer handling incoming packets.
+ */
+
+static struct {
+       bool active; /* transaction status - active or not */
+       int recv_len; /* number of bytes received. */
+       struct hv_fcopy_hdr  *fcopy_msg; /* current message */
+       struct hv_start_fcopy  message; /*  sent to daemon */
+       struct vmbus_channel *recv_channel; /* chn we got the request */
+       u64 recv_req_id; /* request ID. */
+       void *fcopy_context; /* for the channel callback */
+       struct semaphore read_sema;
+} fcopy_transaction;
+
+static bool opened; /* currently device opened */
+
+/*
+ * Before we can accept copy messages from the host, we need
+ * to handshake with the user level daemon. This state tracks
+ * if we are in the handshake phase.
+ */
+static bool in_hand_shake = true;
+static void fcopy_send_data(void);
+static void fcopy_respond_to_host(int error);
+static void fcopy_work_func(struct work_struct *dummy);
+static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func);
+static u8 *recv_buffer;
+
+static void fcopy_work_func(struct work_struct *dummy)
+{
+       /*
+        * If the timer fires, the user-mode component has not responded;
+        * process the pending transaction.
+        */
+       fcopy_respond_to_host(HV_E_FAIL);
+}
+
+static int fcopy_handle_handshake(u32 version)
+{
+       switch (version) {
+       case FCOPY_CURRENT_VERSION:
+               break;
+       default:
+               /*
+                * For now we will fail the registration.
+                * If and when we have multiple versions to
+                * deal with, we will be backward compatible.
+                * We will add this code when needed.
+                */
+               return -EINVAL;
+       }
+       pr_info("FCP: user-mode registering done. Daemon version: %d\n",
+               version);
+       fcopy_transaction.active = false;
+       if (fcopy_transaction.fcopy_context)
+               hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context);
+       in_hand_shake = false;
+       return 0;
+}
+
+static void fcopy_send_data(void)
+{
+       struct hv_start_fcopy *smsg_out = &fcopy_transaction.message;
+       int operation = fcopy_transaction.fcopy_msg->operation;
+       struct hv_start_fcopy *smsg_in;
+
+       /*
+        * The  strings sent from the host are encoded in
+        * in utf16; convert it to utf8 strings.
+        * The host assures us that the utf16 strings will not exceed
+        * the max lengths specified. We will however, reserve room
+        * for the string terminating character - in the utf16s_utf8s()
+        * function we limit the size of the buffer where the converted
+        * string is placed to W_MAX_PATH -1 to guarantee
+        * that the strings can be properly terminated!
+        */
+
+       switch (operation) {
+       case START_FILE_COPY:
+               memset(smsg_out, 0, sizeof(struct hv_start_fcopy));
+               smsg_out->hdr.operation = operation;
+               smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
+
+               utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
+                               UTF16_LITTLE_ENDIAN,
+                               (__u8 *)smsg_out->file_name, W_MAX_PATH - 1);
+
+               utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
+                               UTF16_LITTLE_ENDIAN,
+                               (__u8 *)smsg_out->path_name, W_MAX_PATH - 1);
+
+               smsg_out->copy_flags = smsg_in->copy_flags;
+               smsg_out->file_size = smsg_in->file_size;
+               break;
+
+       default:
+               break;
+       }
+       up(&fcopy_transaction.read_sema);
+       return;
+}
+
+/*
+ * Send a response back to the host.
+ */
+
+static void
+fcopy_respond_to_host(int error)
+{
+       struct icmsg_hdr *icmsghdr;
+       u32 buf_len;
+       struct vmbus_channel *channel;
+       u64 req_id;
+
+       /*
+        * Copy the global state for completing the transaction. Note that
+        * only one transaction can be active at a time. This is guaranteed
+        * by the file copy protocol implemented by the host. Furthermore,
+        * the "transaction active" state we maintain ensures that there can
+        * only be one active transaction at a time.
+        */
+
+       buf_len = fcopy_transaction.recv_len;
+       channel = fcopy_transaction.recv_channel;
+       req_id = fcopy_transaction.recv_req_id;
+
+       fcopy_transaction.active = false;
+
+       icmsghdr = (struct icmsg_hdr *)
+                       &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
+       if (channel->onchannel_callback == NULL)
+               /*
+                * We have raced with util driver being unloaded;
+                * silently return.
+                */
+               return;
+
+       icmsghdr->status = error;
+       icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+       vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
+                               VM_PKT_DATA_INBAND, 0);
+}
+
+void hv_fcopy_onchannelcallback(void *context)
+{
+       struct vmbus_channel *channel = context;
+       u32 recvlen;
+       u64 requestid;
+       struct hv_fcopy_hdr *fcopy_msg;
+       struct icmsg_hdr *icmsghdr;
+       struct icmsg_negotiate *negop = NULL;
+       int util_fw_version;
+       int fcopy_srv_version;
+
+       if (fcopy_transaction.active) {
+               /*
+                * We will defer processing this callback once
+                * the current transaction is complete.
+                */
+               fcopy_transaction.fcopy_context = context;
+               return;
+       }
+
+       vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+                        &requestid);
+       if (recvlen <= 0)
+               return;
+
+       icmsghdr = (struct icmsg_hdr *)&recv_buffer[
+                       sizeof(struct vmbuspipe_hdr)];
+       if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+               util_fw_version = UTIL_FW_VERSION;
+               fcopy_srv_version = WIN8_SRV_VERSION;
+               vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer,
+                               util_fw_version, fcopy_srv_version);
+       } else {
+               fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
+                               sizeof(struct vmbuspipe_hdr) +
+                               sizeof(struct icmsg_hdr)];
+
+               /*
+                * Stash away this global state for completing the
+                * transaction; note transactions are serialized.
+                */
+
+               fcopy_transaction.active = true;
+               fcopy_transaction.recv_len = recvlen;
+               fcopy_transaction.recv_channel = channel;
+               fcopy_transaction.recv_req_id = requestid;
+               fcopy_transaction.fcopy_msg = fcopy_msg;
+
+               /*
+                * Send the information to the user-level daemon.
+                */
+               fcopy_send_data();
+               schedule_delayed_work(&fcopy_work, 5*HZ);
+               return;
+       }
+       icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+       vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
+                       VM_PKT_DATA_INBAND, 0);
+}
+
+/*
+ * Create a char device that can support read/write for passing
+ * the payload.
+ */
+
+static ssize_t fcopy_read(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       void *src;
+       size_t copy_size;
+       int operation;
+
+       /*
+        * Wait until there is something to be read.
+        */
+       if (down_interruptible(&fcopy_transaction.read_sema))
+               return -EINTR;
+
+       /*
+        * The channel may be rescinded and in this case, we will wakeup the
+        * the thread blocked on the semaphore and we will use the opened
+        * state to correctly handle this case.
+        */
+       if (!opened)
+               return -ENODEV;
+
+       operation = fcopy_transaction.fcopy_msg->operation;
+
+       if (operation == START_FILE_COPY) {
+               src = &fcopy_transaction.message;
+               copy_size = sizeof(struct hv_start_fcopy);
+               if (count < copy_size)
+                       return 0;
+       } else {
+               src = fcopy_transaction.fcopy_msg;
+               copy_size = sizeof(struct hv_do_fcopy);
+               if (count < copy_size)
+                       return 0;
+       }
+       if (copy_to_user(buf, src, copy_size))
+               return -EFAULT;
+
+       return copy_size;
+}
+
+static ssize_t fcopy_write(struct file *file, const char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       int response = 0;
+
+       if (count != sizeof(int))
+               return -EINVAL;
+
+       if (copy_from_user(&response, buf, sizeof(int)))
+               return -EFAULT;
+
+       if (in_hand_shake) {
+               if (fcopy_handle_handshake(response))
+                       return -EINVAL;
+               return sizeof(int);
+       }
+
+       /*
+        * Complete the transaction by forwarding the result
+        * to the host. But first, cancel the timeout.
+        */
+       if (cancel_delayed_work_sync(&fcopy_work))
+               fcopy_respond_to_host(response);
+
+       return sizeof(int);
+}
+
+static int fcopy_open(struct inode *inode, struct file *f)
+{
+       /*
+        * The user level daemon that will open this device is
+        * really an extension of this driver. We can have only
+        * active open at a time.
+        */
+       if (opened)
+               return -EBUSY;
+
+       /*
+        * The daemon is alive; setup the state.
+        */
+       opened = true;
+       return 0;
+}
+
+static int fcopy_release(struct inode *inode, struct file *f)
+{
+       /*
+        * The daemon has exited; reset the state.
+        */
+       in_hand_shake = true;
+       opened = false;
+       return 0;
+}
+
+
+static const struct file_operations fcopy_fops = {
+       .read           = fcopy_read,
+       .write          = fcopy_write,
+       .release        = fcopy_release,
+       .open           = fcopy_open,
+};
+
+static struct miscdevice fcopy_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "vmbus/hv_fcopy",
+       .fops           = &fcopy_fops,
+};
+
+static int fcopy_dev_init(void)
+{
+       return misc_register(&fcopy_misc);
+}
+
+static void fcopy_dev_deinit(void)
+{
+
+       /*
+        * The device is going away - perhaps because the
+        * host has rescinded the channel. Setup state so that
+        * user level daemon can gracefully exit if it is blocked
+        * on the read semaphore.
+        */
+       opened = false;
+       /*
+        * Signal the semaphore as the device is
+        * going away.
+        */
+       up(&fcopy_transaction.read_sema);
+       misc_deregister(&fcopy_misc);
+}
+
+int hv_fcopy_init(struct hv_util_service *srv)
+{
+       recv_buffer = srv->recv_buffer;
+
+       /*
+        * When this driver loads, the user level daemon that
+        * processes the host requests may not yet be running.
+        * Defer processing channel callbacks until the daemon
+        * has registered.
+        */
+       fcopy_transaction.active = true;
+       sema_init(&fcopy_transaction.read_sema, 0);
+
+       return fcopy_dev_init();
+}
+
+void hv_fcopy_deinit(void)
+{
+       cancel_delayed_work_sync(&fcopy_work);
+       fcopy_dev_deinit();
+}
index 09988b2896226552e4be5cd69d5f09ba3f842d11..ea852537307e8596f5a624ac5f5c44b11286360b 100644 (file)
@@ -113,7 +113,7 @@ kvp_register(int reg_value)
                kvp_msg->kvp_hdr.operation = reg_value;
                strcpy(version, HV_DRV_VERSION);
                msg->len = sizeof(struct hv_kvp_msg);
-               cn_netlink_send(msg, 0, GFP_ATOMIC);
+               cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
                kfree(msg);
        }
 }
@@ -435,7 +435,7 @@ kvp_send_key(struct work_struct *dummy)
        }
 
        msg->len = sizeof(struct hv_kvp_msg);
-       cn_netlink_send(msg, 0, GFP_ATOMIC);
+       cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
        kfree(msg);
 
        return;
index 0c354622437681d1b6dd157f718bb27cf8dbdbed..34f14fddb666bb753c92e3ea955264a862ef8976 100644 (file)
@@ -98,7 +98,7 @@ static void vss_send_op(struct work_struct *dummy)
        vss_msg->vss_hdr.operation = op;
        msg->len = sizeof(struct hv_vss_msg);
 
-       cn_netlink_send(msg, 0, GFP_ATOMIC);
+       cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
        kfree(msg);
 
        return;
index 62dfd246b94838e622c02bd125650a79a21c3f32..dd761806f0e82659bd230699e859f622b9be3c61 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
 
+#include "hyperv_vmbus.h"
 
 #define SD_MAJOR       3
 #define SD_MINOR       0
@@ -82,6 +83,12 @@ static struct hv_util_service util_vss = {
        .util_deinit = hv_vss_deinit,
 };
 
+static struct hv_util_service util_fcopy = {
+       .util_cb = hv_fcopy_onchannelcallback,
+       .util_init = hv_fcopy_init,
+       .util_deinit = hv_fcopy_deinit,
+};
+
 static void perform_shutdown(struct work_struct *dummy)
 {
        orderly_poweroff(true);
@@ -401,6 +408,10 @@ static const struct hv_vmbus_device_id id_table[] = {
        { HV_VSS_GUID,
          .driver_data = (unsigned long)&util_vss
        },
+       /* File copy GUID */
+       { HV_FCOPY_GUID,
+         .driver_data = (unsigned long)&util_fcopy
+       },
        { },
 };
 
index e05517616a06e549407f422a4713145b0f44e1de..860134da80396c0013303eac1a37ae94f935e73e 100644 (file)
@@ -559,8 +559,8 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
 
 int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
-                   struct scatterlist *sglist,
-                   u32 sgcount, bool *signal);
+                   struct kvec *kv_list,
+                   u32 kv_count, bool *signal);
 
 int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
                   u32 buflen);
@@ -669,5 +669,9 @@ int vmbus_set_event(struct vmbus_channel *channel);
 
 void vmbus_on_event(unsigned long data);
 
+int hv_fcopy_init(struct hv_util_service *);
+void hv_fcopy_deinit(void);
+void hv_fcopy_onchannelcallback(void *);
+
 
 #endif /* _HYPERV_VMBUS_H */
index 26c93cf9f6be4a083f47615318699e3110d39983..15db66b74141cb6c92a180197c4261c77a2eeaa3 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/hyperv.h>
+#include <linux/uio.h>
 
 #include "hyperv_vmbus.h"
 
@@ -387,23 +388,20 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
  *
  */
 int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
-                   struct scatterlist *sglist, u32 sgcount, bool *signal)
+                   struct kvec *kv_list, u32 kv_count, bool *signal)
 {
        int i = 0;
        u32 bytes_avail_towrite;
        u32 bytes_avail_toread;
        u32 totalbytes_towrite = 0;
 
-       struct scatterlist *sg;
        u32 next_write_location;
        u32 old_write;
        u64 prev_indices = 0;
        unsigned long flags;
 
-       for_each_sg(sglist, sg, sgcount, i)
-       {
-               totalbytes_towrite += sg->length;
-       }
+       for (i = 0; i < kv_count; i++)
+               totalbytes_towrite += kv_list[i].iov_len;
 
        totalbytes_towrite += sizeof(u64);
 
@@ -427,12 +425,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
 
        old_write = next_write_location;
 
-       for_each_sg(sglist, sg, sgcount, i)
-       {
+       for (i = 0; i < kv_count; i++) {
                next_write_location = hv_copyto_ringbuffer(outring_info,
                                                     next_write_location,
-                                                    sg_virt(sg),
-                                                    sg->length);
+                                                    kv_list[i].iov_base,
+                                                    kv_list[i].iov_len);
        }
 
        /* Set previous packet start */
index 077bb1bdac34ef4ed87c65c7bf0d204fd42001b4..8e53a3c2607e00c07e066b28f11c056aef4a6abd 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
 #include <linux/slab.h>
@@ -44,6 +43,12 @@ static struct tasklet_struct msg_dpc;
 static struct completion probe_event;
 static int irq;
 
+struct resource hyperv_mmio = {
+       .name  = "hyperv mmio",
+       .flags = IORESOURCE_MEM,
+};
+EXPORT_SYMBOL_GPL(hyperv_mmio);
+
 static int vmbus_exists(void)
 {
        if (hv_acpi_dev == NULL)
@@ -558,9 +563,6 @@ static struct bus_type  hv_bus = {
        .dev_groups =           vmbus_groups,
 };
 
-static const char *driver_name = "hyperv";
-
-
 struct onmessage_work_context {
        struct work_struct work;
        struct hv_message msg;
@@ -619,7 +621,7 @@ static void vmbus_on_msg_dpc(unsigned long data)
        }
 }
 
-static irqreturn_t vmbus_isr(int irq, void *dev_id)
+static void vmbus_isr(void)
 {
        int cpu = smp_processor_id();
        void *page_addr;
@@ -629,7 +631,7 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
 
        page_addr = hv_context.synic_event_page[cpu];
        if (page_addr == NULL)
-               return IRQ_NONE;
+               return;
 
        event = (union hv_synic_event_flags *)page_addr +
                                         VMBUS_MESSAGE_SINT;
@@ -665,28 +667,8 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
        msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 
        /* Check if there are actual msgs to be processed */
-       if (msg->header.message_type != HVMSG_NONE) {
-               handled = true;
+       if (msg->header.message_type != HVMSG_NONE)
                tasklet_schedule(&msg_dpc);
-       }
-
-       if (handled)
-               return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
-}
-
-/*
- * vmbus interrupt flow handler:
- * vmbus interrupts can concurrently occur on multiple CPUs and
- * can be handled concurrently.
- */
-
-static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
-{
-       kstat_incr_irqs_this_cpu(irq, desc);
-
-       desc->action->handler(irq, desc->action->dev_id);
 }
 
 /*
@@ -715,25 +697,7 @@ static int vmbus_bus_init(int irq)
        if (ret)
                goto err_cleanup;
 
-       ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev);
-
-       if (ret != 0) {
-               pr_err("Unable to request IRQ %d\n",
-                          irq);
-               goto err_unregister;
-       }
-
-       /*
-        * Vmbus interrupts can be handled concurrently on
-        * different CPUs. Establish an appropriate interrupt flow
-        * handler that can support this model.
-        */
-       irq_set_handler(irq, vmbus_flow_handler);
-
-       /*
-        * Register our interrupt handler.
-        */
-       hv_register_vmbus_handler(irq, vmbus_isr);
+       hv_setup_vmbus_irq(vmbus_isr);
 
        ret = hv_synic_alloc();
        if (ret)
@@ -753,9 +717,8 @@ static int vmbus_bus_init(int irq)
 
 err_alloc:
        hv_synic_free();
-       free_irq(irq, hv_acpi_dev);
+       hv_remove_vmbus_irq();
 
-err_unregister:
        bus_unregister(&hv_bus);
 
 err_cleanup:
@@ -886,18 +849,21 @@ void vmbus_device_unregister(struct hv_device *device_obj)
 
 
 /*
- * VMBUS is an acpi enumerated device. Get the the IRQ information
- * from DSDT.
+ * VMBUS is an acpi enumerated device. Get the the information we
+ * need from DSDT.
  */
 
-static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
+static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
 {
+       switch (res->type) {
+       case ACPI_RESOURCE_TYPE_IRQ:
+               irq = res->data.irq.interrupts[0];
+               break;
 
-       if (res->type == ACPI_RESOURCE_TYPE_IRQ) {
-               struct acpi_resource_irq *irqp;
-               irqp = &res->data.irq;
-
-               *((unsigned int *)irq) = irqp->interrupts[0];
+       case ACPI_RESOURCE_TYPE_ADDRESS64:
+               hyperv_mmio.start = res->data.address64.minimum;
+               hyperv_mmio.end = res->data.address64.maximum;
+               break;
        }
 
        return AE_OK;
@@ -906,18 +872,34 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
 static int vmbus_acpi_add(struct acpi_device *device)
 {
        acpi_status result;
+       int ret_val = -ENODEV;
 
        hv_acpi_dev = device;
 
        result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                                       vmbus_walk_resources, &irq);
+                                       vmbus_walk_resources, NULL);
 
-       if (ACPI_FAILURE(result)) {
-               complete(&probe_event);
-               return -ENODEV;
+       if (ACPI_FAILURE(result))
+               goto acpi_walk_err;
+       /*
+        * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that
+        * has the mmio ranges. Get that.
+        */
+       if (device->parent) {
+               result = acpi_walk_resources(device->parent->handle,
+                                       METHOD_NAME__CRS,
+                                       vmbus_walk_resources, NULL);
+
+               if (ACPI_FAILURE(result))
+                       goto acpi_walk_err;
+               if (hyperv_mmio.start && hyperv_mmio.end)
+                       request_resource(&iomem_resource, &hyperv_mmio);
        }
+       ret_val = 0;
+
+acpi_walk_err:
        complete(&probe_event);
-       return 0;
+       return ret_val;
 }
 
 static const struct acpi_device_id vmbus_acpi_device_ids[] = {
@@ -947,7 +929,6 @@ static int __init hv_acpi_init(void)
        /*
         * Get irq resources first.
         */
-
        ret = acpi_bus_register_driver(&vmbus_acpi_driver);
 
        if (ret)
@@ -978,8 +959,7 @@ cleanup:
 
 static void __exit vmbus_exit(void)
 {
-
-       free_irq(irq, hv_acpi_dev);
+       hv_remove_vmbus_irq();
        vmbus_free_channels();
        bus_unregister(&hv_bus);
        hv_cleanup();
index 5ce43d8dfa98e635f039eaad29b5ec4627557b78..f288b60a87be5ca0a24399ae11f2d565338f12a3 100644 (file)
@@ -111,22 +111,6 @@ config SENSORS_AD7418
          This driver can also be built as a module. If so, the module
          will be called ad7418.
 
-config SENSORS_ADCXX
-       tristate "National Semiconductor ADCxxxSxxx"
-       depends on SPI_MASTER
-       help
-         If you say yes here you get support for the National Semiconductor
-         ADC<bb><c>S<sss> chip family, where
-         * bb  is the resolution in number of bits (8, 10, 12)
-         * c   is the number of channels (1, 2, 4, 8)
-         * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
-           kSPS and 101 for 1 MSPS)
-
-         Examples : ADC081S101, ADC124S501, ...
-
-         This driver can also be built as a module.  If so, the module
-         will be called adcxx.
-
 config SENSORS_ADM1021
        tristate "Analog Devices ADM1021 and compatibles"
        depends on I2C
@@ -312,6 +296,31 @@ config SENSORS_FAM15H_POWER
          This driver can also be built as a module.  If so, the module
          will be called fam15h_power.
 
+config SENSORS_APPLESMC
+       tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
+       depends on INPUT && X86
+       select NEW_LEDS
+       select LEDS_CLASS
+       select INPUT_POLLDEV
+       default n
+       help
+         This driver provides support for the Apple System Management
+         Controller, which provides an accelerometer (Apple Sudden Motion
+         Sensor), light sensors, temperature sensors, keyboard backlight
+         control and fan control.
+
+         Only Intel-based Apple's computers are supported (MacBook Pro,
+         MacBook, MacMini).
+
+         Data from the different sensors, keyboard backlight control and fan
+         control are accessible via sysfs.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         Say Y here if you have an applicable laptop and want to experience
+         the awesome power of applesmc.
+
 config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
        depends on X86 && I2C
@@ -435,6 +444,12 @@ config SENSORS_F75375S
          This driver can also be built as a module.  If so, the module
          will be called f75375s.
 
+config SENSORS_MC13783_ADC
+        tristate "Freescale MC13783/MC13892 ADC"
+        depends on MFD_MC13XXX
+        help
+          Support for the A/D converter on MC13783 and MC13892 PMIC.
+
 config SENSORS_FSCHMD
        tristate "Fujitsu Siemens Computers sensor chips"
        depends on X86 && I2C
@@ -451,26 +466,6 @@ config SENSORS_FSCHMD
          This driver can also be built as a module.  If so, the module
          will be called fschmd.
 
-config SENSORS_G760A
-       tristate "GMT G760A"
-       depends on I2C
-       help
-         If you say yes here you get support for Global Mixed-mode
-         Technology Inc G760A fan speed PWM controller chips.
-
-         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
@@ -492,6 +487,26 @@ config SENSORS_GL520SM
          This driver can also be built as a module.  If so, the module
          will be called gl520sm.
 
+config SENSORS_G760A
+       tristate "GMT G760A"
+       depends on I2C
+       help
+         If you say yes here you get support for Global Mixed-mode
+         Technology Inc G760A fan speed PWM controller chips.
+
+         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_GPIO_FAN
        tristate "GPIO fan"
        depends on GPIOLIB
@@ -511,24 +526,6 @@ config SENSORS_HIH6130
          This driver can also be built as a module.  If so, the module
          will be called hih6130.
 
-config SENSORS_HTU21
-       tristate "Measurement Specialties HTU21D humidity/temperature sensors"
-       depends on I2C
-       help
-         If you say yes here you get support for the Measurement Specialties
-         HTU21D humidity and temperature sensors.
-
-         This driver can also be built as a module.  If so, the module
-         will be called htu21.
-
-config SENSORS_CORETEMP
-       tristate "Intel Core/Core2/Atom temperature sensor"
-       depends on X86
-       help
-         If you say yes here you get support for the temperature
-         sensor inside your CPU. Most of the family 6 CPUs
-         are supported. Check Documentation/hwmon/coretemp for details.
-
 config SENSORS_IBMAEM
        tristate "IBM Active Energy Manager temperature/power sensors and control"
        select IPMI_SI
@@ -566,6 +563,14 @@ config SENSORS_IIO_HWMON
          for those channels specified in the map.  This map can be provided
          either via platform data or the device tree bindings.
 
+config SENSORS_CORETEMP
+       tristate "Intel Core/Core2/Atom temperature sensor"
+       depends on X86
+       help
+         If you say yes here you get support for the temperature
+         sensor inside your CPU. Most of the family 6 CPUs
+         are supported. Check Documentation/hwmon/coretemp for details.
+
 config SENSORS_IT87
        tristate "ITE IT87xx and compatibles"
        depends on !PPC
@@ -614,374 +619,409 @@ config SENSORS_LINEAGE
          This driver can also be built as a module.  If so, the module
          will be called lineage-pem.
 
-config SENSORS_LM63
-       tristate "National Semiconductor LM63 and compatibles"
+config SENSORS_LTC2945
+       tristate "Linear Technology LTC2945"
        depends on I2C
+       select REGMAP_I2C
+       default n
        help
-         If you say yes here you get support for the National
-         Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
-         sensors with integrated fan control.  Such chips are found
-         on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
-         others.
+         If you say yes here you get support for Linear Technology LTC2945
+         I2C System Monitor.
 
-         This driver can also be built as a module.  If so, the module
-         will be called lm63.
+         This driver can also be built as a module. If so, the module will
+         be called ltc2945.
 
-config SENSORS_LM70
-       tristate "National Semiconductor LM70 and compatibles"
-       depends on SPI_MASTER
+config SENSORS_LTC4151
+       tristate "Linear Technology LTC4151"
+       depends on I2C
+       default n
        help
-         If you say yes here you get support for the National Semiconductor
-         LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
-         ture sensor chips.
+         If you say yes here you get support for Linear Technology LTC4151
+         High Voltage I2C Current and Voltage Monitor interface.
 
-         This driver can also be built as a module.  If so, the module
-         will be called lm70.
+         This driver can also be built as a module. If so, the module will
+         be called ltc4151.
 
-config SENSORS_LM73
-       tristate "National Semiconductor LM73"
+config SENSORS_LTC4215
+       tristate "Linear Technology LTC4215"
        depends on I2C
+       default n
        help
-         If you say yes here you get support for National Semiconductor LM73
-         sensor chips.
-         This driver can also be built as a module.  If so, the module
-         will be called lm73.
+         If you say yes here you get support for Linear Technology LTC4215
+         Hot Swap Controller I2C interface.
 
-config SENSORS_LM75
-       tristate "National Semiconductor LM75 and compatibles"
+         This driver can also be built as a module. If so, the module will
+         be called ltc4215.
+
+config SENSORS_LTC4222
+       tristate "Linear Technology LTC4222"
        depends on I2C
-       depends on THERMAL || !THERMAL_OF
+       select REGMAP_I2C
+       default n
        help
-         If you say yes here you get support for one common type of
-         temperature sensor chip, with models including:
+         If you say yes here you get support for Linear Technology LTC4222
+         Dual Hot Swap Controller I2C interface.
 
-               - Analog Devices ADT75
-               - Dallas Semiconductor DS75, DS1775 and DS7505
-               - Global Mixed-mode Technology (GMT) G751
-               - Maxim MAX6625 and MAX6626
-               - Microchip MCP980x
-               - National Semiconductor LM75, LM75A
-               - NXP's LM75A
-               - ST Microelectronics STDS75
-               - TelCom (now Microchip) TCN75
-               - Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175,
-                 TMP275
+         This driver can also be built as a module. If so, the module will
+         be called ltc4222.
 
-         This driver supports driver model based binding through board
-         specific I2C device tables.
+config SENSORS_LTC4245
+       tristate "Linear Technology LTC4245"
+       depends on I2C
+       default n
+       help
+         If you say yes here you get support for Linear Technology LTC4245
+         Multiple Supply Hot Swap Controller I2C interface.
 
-         It also supports the "legacy" style of driver binding.  To use
-         that with some chips which don't replicate LM75 quirks exactly,
-         you may need the "force" module parameter.
+         This driver can also be built as a module. If so, the module will
+         be called ltc4245.
 
-         This driver can also be built as a module.  If so, the module
-         will be called lm75.
+config SENSORS_LTC4260
+       tristate "Linear Technology LTC4260"
+       depends on I2C
+       select REGMAP_I2C
+       default n
+       help
+         If you say yes here you get support for Linear Technology LTC4260
+         Positive Voltage Hot Swap Controller I2C interface.
 
-config SENSORS_LM77
-       tristate "National Semiconductor LM77"
+         This driver can also be built as a module. If so, the module will
+         be called ltc4260.
+
+config SENSORS_LTC4261
+       tristate "Linear Technology LTC4261"
        depends on I2C
+       default n
        help
-         If you say yes here you get support for National Semiconductor LM77
-         sensor chips.
+         If you say yes here you get support for Linear Technology LTC4261
+         Negative Voltage Hot Swap Controller I2C interface.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc4261.
+
+config SENSORS_MAX1111
+       tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
+       depends on SPI_MASTER
+       help
+         Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
+         ADC chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm77.
+         will be called max1111.
 
-config SENSORS_LM78
-       tristate "National Semiconductor LM78 and compatibles"
+config SENSORS_MAX16065
+       tristate "Maxim MAX16065 System Manager and compatibles"
        depends on I2C
-       select HWMON_VID
        help
-         If you say yes here you get support for National Semiconductor LM78,
-         LM78-J and LM79.
+         If you say yes here you get support for hardware monitoring
+         capabilities of the following Maxim System Manager chips.
+           MAX16065
+           MAX16066
+           MAX16067
+           MAX16068
+           MAX16070
+           MAX16071
 
          This driver can also be built as a module.  If so, the module
-         will be called lm78.
+         will be called max16065.
 
-config SENSORS_LM80
-       tristate "National Semiconductor LM80 and LM96080"
+config SENSORS_MAX1619
+       tristate "Maxim MAX1619 sensor chip"
        depends on I2C
        help
-         If you say yes here you get support for National Semiconductor
-         LM80 and LM96080 sensor chips.
+         If you say yes here you get support for MAX1619 sensor chip.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm80.
+         will be called max1619.
 
-config SENSORS_LM83
-       tristate "National Semiconductor LM83 and compatibles"
+config SENSORS_MAX1668
+       tristate "Maxim MAX1668 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for National Semiconductor
-         LM82 and LM83 sensor chips.
+         If you say yes here you get support for MAX1668, MAX1989 and
+         MAX1805 chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm83.
+         will be called max1668.
 
-config SENSORS_LM85
-       tristate "National Semiconductor LM85 and compatibles"
+config SENSORS_MAX197
+       tristate "Maxim MAX197 and compatibles"
+       help
+         Support for the Maxim MAX197 A/D converter.
+         Support will include, but not be limited to, MAX197, and MAX199.
+
+         This driver can also be built as a module. If so, the module
+         will be called max197.
+
+config SENSORS_MAX6639
+       tristate "Maxim MAX6639 sensor chip"
        depends on I2C
-       select HWMON_VID
        help
-         If you say yes here you get support for National Semiconductor LM85
-         sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100,
-         EMC6D101, EMC6D102, and EMC6D103.
+         If you say yes here you get support for the MAX6639
+         sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm85.
+         will be called max6639.
 
-config SENSORS_LM87
-       tristate "National Semiconductor LM87 and compatibles"
+config SENSORS_MAX6642
+       tristate "Maxim MAX6642 sensor chip"
        depends on I2C
-       select HWMON_VID
        help
-         If you say yes here you get support for National Semiconductor LM87
-         and Analog Devices ADM1024 sensor chips.
+         If you say yes here you get support for MAX6642 sensor chip.
+         MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
+         with Overtemperature Alarm from Maxim.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm87.
+         will be called max6642.
 
-config SENSORS_LM90
-       tristate "National Semiconductor LM90 and compatibles"
+config SENSORS_MAX6650
+       tristate "Maxim MAX6650 sensor chip"
        depends on I2C
        help
-         If you say yes here you get support for National Semiconductor LM90,
-         LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
-         Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
-         MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
-         Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781
+         If you say yes here you get support for the MAX6650 / MAX6651
          sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm90.
+         will be called max6650.
 
-config SENSORS_LM92
-       tristate "National Semiconductor LM92 and compatibles"
+config SENSORS_MAX6697
+       tristate "Maxim MAX6697 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for National Semiconductor LM92
-         and Maxim MAX6635 sensor chips.
+         If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+         MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+         temperature sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm92.
+         will be called max6697.
 
-config SENSORS_LM93
-       tristate "National Semiconductor LM93 and compatibles"
+config SENSORS_HTU21
+       tristate "Measurement Specialties HTU21D humidity/temperature sensors"
        depends on I2C
-       select HWMON_VID
        help
-         If you say yes here you get support for National Semiconductor LM93,
-         LM94, and compatible sensor chips.
+         If you say yes here you get support for the Measurement Specialties
+         HTU21D humidity and temperature sensors.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm93.
+         will be called htu21.
 
-config SENSORS_LTC4151
-       tristate "Linear Technology LTC4151"
+config SENSORS_MCP3021
+       tristate "Microchip MCP3021 and compatibles"
        depends on I2C
-       default n
        help
-         If you say yes here you get support for Linear Technology LTC4151
-         High Voltage I2C Current and Voltage Monitor interface.
+         If you say yes here you get support for MCP3021 and MCP3221.
+         The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
+         with 12-bit resolution.
 
-         This driver can also be built as a module. If so, the module will
-         be called ltc4151.
+         This driver can also be built as a module.  If so, the module
+         will be called mcp3021.
 
-config SENSORS_LTC4215
-       tristate "Linear Technology LTC4215"
-       depends on I2C
-       default n
+config SENSORS_ADCXX
+       tristate "National Semiconductor ADCxxxSxxx"
+       depends on SPI_MASTER
        help
-         If you say yes here you get support for Linear Technology LTC4215
-         Hot Swap Controller I2C interface.
+         If you say yes here you get support for the National Semiconductor
+         ADC<bb><c>S<sss> chip family, where
+         * bb  is the resolution in number of bits (8, 10, 12)
+         * c   is the number of channels (1, 2, 4, 8)
+         * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
+           kSPS and 101 for 1 MSPS)
 
-         This driver can also be built as a module. If so, the module will
-         be called ltc4215.
+         Examples : ADC081S101, ADC124S501, ...
 
-config SENSORS_LTC4245
-       tristate "Linear Technology LTC4245"
+         This driver can also be built as a module.  If so, the module
+         will be called adcxx.
+
+config SENSORS_LM63
+       tristate "National Semiconductor LM63 and compatibles"
        depends on I2C
-       default n
        help
-         If you say yes here you get support for Linear Technology LTC4245
-         Multiple Supply Hot Swap Controller I2C interface.
+         If you say yes here you get support for the National
+         Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
+         sensors with integrated fan control.  Such chips are found
+         on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
+         others.
 
-         This driver can also be built as a module. If so, the module will
-         be called ltc4245.
+         This driver can also be built as a module.  If so, the module
+         will be called lm63.
 
-config SENSORS_LTC4261
-       tristate "Linear Technology LTC4261"
-       depends on I2C
-       default n
+config SENSORS_LM70
+       tristate "National Semiconductor LM70 and compatibles"
+       depends on SPI_MASTER
        help
-         If you say yes here you get support for Linear Technology LTC4261
-         Negative Voltage Hot Swap Controller I2C interface.
+         If you say yes here you get support for the National Semiconductor
+         LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
+         ture sensor chips.
 
-         This driver can also be built as a module. If so, the module will
-         be called ltc4261.
+         This driver can also be built as a module.  If so, the module
+         will be called lm70.
 
-config SENSORS_LM95234
-       tristate "National Semiconductor LM95234"
+config SENSORS_LM73
+       tristate "National Semiconductor LM73"
        depends on I2C
        help
-         If you say yes here you get support for the LM95234 temperature
-         sensor.
-
+         If you say yes here you get support for National Semiconductor LM73
+         sensor chips.
          This driver can also be built as a module.  If so, the module
-         will be called lm95234.
+         will be called lm73.
 
-config SENSORS_LM95241
-       tristate "National Semiconductor LM95241 and compatibles"
+config SENSORS_LM75
+       tristate "National Semiconductor LM75 and compatibles"
        depends on I2C
+       depends on THERMAL || !THERMAL_OF
        help
-         If you say yes here you get support for LM95231 and LM95241 sensor
-         chips.
+         If you say yes here you get support for one common type of
+         temperature sensor chip, with models including:
+
+               - Analog Devices ADT75
+               - Dallas Semiconductor DS75, DS1775 and DS7505
+               - Global Mixed-mode Technology (GMT) G751
+               - Maxim MAX6625 and MAX6626
+               - Microchip MCP980x
+               - National Semiconductor LM75, LM75A
+               - NXP's LM75A
+               - ST Microelectronics STDS75
+               - TelCom (now Microchip) TCN75
+               - Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175,
+                 TMP275
+
+         This driver supports driver model based binding through board
+         specific I2C device tables.
+
+         It also supports the "legacy" style of driver binding.  To use
+         that with some chips which don't replicate LM75 quirks exactly,
+         you may need the "force" module parameter.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm95241.
+         will be called lm75.
 
-config SENSORS_LM95245
-       tristate "National Semiconductor LM95245 sensor chip"
+config SENSORS_LM77
+       tristate "National Semiconductor LM77"
        depends on I2C
        help
-         If you say yes here you get support for LM95245 sensor chip.
+         If you say yes here you get support for National Semiconductor LM77
+         sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called lm95245.
+         will be called lm77.
 
-config SENSORS_MAX1111
-       tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
-       depends on SPI_MASTER
+config SENSORS_LM78
+       tristate "National Semiconductor LM78 and compatibles"
+       depends on I2C
+       select HWMON_VID
        help
-         Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
-         ADC chips.
+         If you say yes here you get support for National Semiconductor LM78,
+         LM78-J and LM79.
 
          This driver can also be built as a module.  If so, the module
-         will be called max1111.
+         will be called lm78.
 
-config SENSORS_MAX16065
-       tristate "Maxim MAX16065 System Manager and compatibles"
+config SENSORS_LM80
+       tristate "National Semiconductor LM80 and LM96080"
        depends on I2C
        help
-         If you say yes here you get support for hardware monitoring
-         capabilities of the following Maxim System Manager chips.
-           MAX16065
-           MAX16066
-           MAX16067
-           MAX16068
-           MAX16070
-           MAX16071
+         If you say yes here you get support for National Semiconductor
+         LM80 and LM96080 sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called max16065.
+         will be called lm80.
 
-config SENSORS_MAX1619
-       tristate "Maxim MAX1619 sensor chip"
+config SENSORS_LM83
+       tristate "National Semiconductor LM83 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for MAX1619 sensor chip.
+         If you say yes here you get support for National Semiconductor
+         LM82 and LM83 sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called max1619.
+         will be called lm83.
 
-config SENSORS_MAX1668
-       tristate "Maxim MAX1668 and compatibles"
+config SENSORS_LM85
+       tristate "National Semiconductor LM85 and compatibles"
        depends on I2C
+       select HWMON_VID
        help
-         If you say yes here you get support for MAX1668, MAX1989 and
-         MAX1805 chips.
+         If you say yes here you get support for National Semiconductor LM85
+         sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100,
+         EMC6D101, EMC6D102, and EMC6D103.
 
          This driver can also be built as a module.  If so, the module
-         will be called max1668.
-
-config SENSORS_MAX197
-       tristate "Maxim MAX197 and compatibles"
-       help
-         Support for the Maxim MAX197 A/D converter.
-         Support will include, but not be limited to, MAX197, and MAX199.
-
-         This driver can also be built as a module. If so, the module
-         will be called max197.
+         will be called lm85.
 
-config SENSORS_MAX6639
-       tristate "Maxim MAX6639 sensor chip"
+config SENSORS_LM87
+       tristate "National Semiconductor LM87 and compatibles"
        depends on I2C
+       select HWMON_VID
        help
-         If you say yes here you get support for the MAX6639
-         sensor chips.
+         If you say yes here you get support for National Semiconductor LM87
+         and Analog Devices ADM1024 sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called max6639.
+         will be called lm87.
 
-config SENSORS_MAX6642
-       tristate "Maxim MAX6642 sensor chip"
+config SENSORS_LM90
+       tristate "National Semiconductor LM90 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for MAX6642 sensor chip.
-         MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
-         with Overtemperature Alarm from Maxim.
+         If you say yes here you get support for National Semiconductor LM90,
+         LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
+         Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
+         MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
+         Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781
+         sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called max6642.
+         will be called lm90.
 
-config SENSORS_MAX6650
-       tristate "Maxim MAX6650 sensor chip"
+config SENSORS_LM92
+       tristate "National Semiconductor LM92 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for the MAX6650 / MAX6651
-         sensor chips.
+         If you say yes here you get support for National Semiconductor LM92
+         and Maxim MAX6635 sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called max6650.
+         will be called lm92.
 
-config SENSORS_MAX6697
-       tristate "Maxim MAX6697 and compatibles"
+config SENSORS_LM93
+       tristate "National Semiconductor LM93 and compatibles"
        depends on I2C
+       select HWMON_VID
        help
-         If you say yes here you get support for MAX6581, MAX6602, MAX6622,
-         MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
-         temperature sensor chips.
+         If you say yes here you get support for National Semiconductor LM93,
+         LM94, and compatible sensor chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called max6697.
+         will be called lm93.
 
-config SENSORS_MCP3021
-       tristate "Microchip MCP3021 and compatibles"
+config SENSORS_LM95234
+       tristate "National Semiconductor LM95234"
        depends on I2C
        help
-         If you say yes here you get support for MCP3021 and MCP3221.
-         The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
-         with 12-bit resolution.
+         If you say yes here you get support for the LM95234 temperature
+         sensor.
 
          This driver can also be built as a module.  If so, the module
-         will be called mcp3021.
+         will be called lm95234.
 
-config SENSORS_NCT6775
-       tristate "Nuvoton NCT6775F and compatibles"
-       depends on !PPC
-       select HWMON_VID
+config SENSORS_LM95241
+       tristate "National Semiconductor LM95241 and compatibles"
+       depends on I2C
        help
-         If you say yes here you get support for the hardware monitoring
-         functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
-         and compatible Super-I/O chips. This driver replaces the
-         w83627ehf driver for NCT6775F and NCT6776F.
+         If you say yes here you get support for LM95231 and LM95241 sensor
+         chips.
 
          This driver can also be built as a module.  If so, the module
-         will be called nct6775.
+         will be called lm95241.
 
-config SENSORS_NTC_THERMISTOR
-       tristate "NTC thermistor support"
-       depends on (!OF && !IIO) || (OF && IIO)
+config SENSORS_LM95245
+       tristate "National Semiconductor LM95245 sensor chip"
+       depends on I2C
        help
-         This driver supports NTC thermistors sensor reading and its
-         interpretation. The driver can also monitor the temperature and
-         send notifications about the temperature.
-
-         Currently, this driver supports
-         NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333.
+         If you say yes here you get support for LM95245 sensor chip.
 
          This driver can also be built as a module.  If so, the module
-         will be called ntc-thermistor.
+         will be called lm95245.
 
 config SENSORS_PC87360
        tristate "National Semiconductor PC87360 family"
@@ -1011,6 +1051,33 @@ config SENSORS_PC87427
          This driver can also be built as a module.  If so, the module
          will be called pc87427.
 
+config SENSORS_NTC_THERMISTOR
+       tristate "NTC thermistor support"
+       depends on (!OF && !IIO) || (OF && IIO)
+       help
+         This driver supports NTC thermistors sensor reading and its
+         interpretation. The driver can also monitor the temperature and
+         send notifications about the temperature.
+
+         Currently, this driver supports
+         NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ntc-thermistor.
+
+config SENSORS_NCT6775
+       tristate "Nuvoton NCT6775F and compatibles"
+       depends on !PPC
+       select HWMON_VID
+       help
+         If you say yes here you get support for the hardware monitoring
+         functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
+         and compatible Super-I/O chips. This driver replaces the
+         w83627ehf driver for NCT6775F and NCT6776F.
+
+         This driver can also be built as a module.  If so, the module
+         will be called nct6775.
+
 config SENSORS_PCF8591
        tristate "Philips PCF8591 ADC/DAC"
        depends on I2C
@@ -1074,21 +1141,6 @@ config SENSORS_SIS5595
          This driver can also be built as a module.  If so, the module
          will be called sis5595.
 
-config SENSORS_SMM665
-       tristate "Summit Microelectronics SMM665"
-       depends on I2C
-       default n
-       help
-         If you say yes here you get support for the hardware monitoring
-         features of the Summit Microelectronics SMM665/SMM665B Six-Channel
-         Active DC Output Controller / Monitor.
-
-         Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
-         Support for those chips is untested.
-
-         This driver can also be built as a module. If so, the module will
-         be called smm665.
-
 config SENSORS_DME1737
        tristate "SMSC DME1737, SCH311x and compatibles"
        depends on I2C && !PPC
@@ -1210,6 +1262,31 @@ config SENSORS_SCH5636
          This driver can also be built as a module.  If so, the module
          will be called sch5636.
 
+config SENSORS_SMM665
+       tristate "Summit Microelectronics SMM665"
+       depends on I2C
+       default n
+       help
+         If you say yes here you get support for the hardware monitoring
+         features of the Summit Microelectronics SMM665/SMM665B Six-Channel
+         Active DC Output Controller / Monitor.
+
+         Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
+         Support for those chips is untested.
+
+         This driver can also be built as a module. If so, the module will
+         be called smm665.
+
+config SENSORS_ADC128D818
+       tristate "Texas Instruments ADC128D818"
+       depends on I2C
+       help
+         If you say yes here you get support for the Texas Instruments
+         ADC128D818 System Monitor with Temperature Sensor chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called adc128d818.
+
 config SENSORS_ADS1015
        tristate "Texas Instruments ADS1015"
        depends on I2C
@@ -1525,37 +1602,6 @@ config SENSORS_ULTRA45
          This driver provides support for the Ultra45 workstation environmental
          sensors.
 
-config SENSORS_APPLESMC
-       tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
-       depends on INPUT && X86
-       select NEW_LEDS
-       select LEDS_CLASS
-       select INPUT_POLLDEV
-       default n
-       help
-         This driver provides support for the Apple System Management
-         Controller, which provides an accelerometer (Apple Sudden Motion
-         Sensor), light sensors, temperature sensors, keyboard backlight
-         control and fan control.
-
-         Only Intel-based Apple's computers are supported (MacBook Pro,
-         MacBook, MacMini).
-
-         Data from the different sensors, keyboard backlight control and fan
-         control are accessible via sysfs.
-
-         This driver also provides an absolute input class device, allowing
-         the laptop to act as a pinball machine-esque joystick.
-
-         Say Y here if you have an applicable laptop and want to experience
-         the awesome power of applesmc.
-
-config SENSORS_MC13783_ADC
-        tristate "Freescale MC13783/MC13892 ADC"
-        depends on MFD_MC13XXX
-        help
-          Support for the A/D converter on MC13783 and MC13892 PMIC.
-
 if ACPI
 
 comment "ACPI drivers"
index ec7cde06eb52bb628e1eb67d661d3d652ee91d97..c48f9873ac7367034a584d7e3aa5ad0231be9ffe 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
 obj-$(CONFIG_SENSORS_AD7314)   += ad7314.o
 obj-$(CONFIG_SENSORS_AD7414)   += ad7414.o
 obj-$(CONFIG_SENSORS_AD7418)   += ad7418.o
+obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o
 obj-$(CONFIG_SENSORS_ADCXX)    += adcxx.o
 obj-$(CONFIG_SENSORS_ADM1021)  += adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)  += adm1025.o
@@ -95,9 +96,12 @@ obj-$(CONFIG_SENSORS_LM93)   += lm93.o
 obj-$(CONFIG_SENSORS_LM95234)  += lm95234.o
 obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
 obj-$(CONFIG_SENSORS_LM95245)  += lm95245.o
+obj-$(CONFIG_SENSORS_LTC2945)  += ltc2945.o
 obj-$(CONFIG_SENSORS_LTC4151)  += ltc4151.o
 obj-$(CONFIG_SENSORS_LTC4215)  += ltc4215.o
+obj-$(CONFIG_SENSORS_LTC4222)  += ltc4222.o
 obj-$(CONFIG_SENSORS_LTC4245)  += ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4260)  += ltc4260.o
 obj-$(CONFIG_SENSORS_LTC4261)  += ltc4261.o
 obj-$(CONFIG_SENSORS_MAX1111)  += max1111.o
 obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c
new file mode 100644 (file)
index 0000000..5ffd81f
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Driver for TI ADC128D818 System Monitor with Temperature Sensor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * Derived from lm80.c
+ * Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ *                          and Philip Edelbrock <phil@netroedge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan
+ * The chip also supports addresses 0x35..0x37. Don't scan those addresses
+ * since they are also used by some EEPROMs, which may result in false
+ * positives.
+ */
+static const unsigned short normal_i2c[] = {
+       0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* registers */
+#define ADC128_REG_IN_MAX(nr)          (0x2a + (nr) * 2)
+#define ADC128_REG_IN_MIN(nr)          (0x2b + (nr) * 2)
+#define ADC128_REG_IN(nr)              (0x20 + (nr))
+
+#define ADC128_REG_TEMP                        0x27
+#define ADC128_REG_TEMP_MAX            0x38
+#define ADC128_REG_TEMP_HYST           0x39
+
+#define ADC128_REG_CONFIG              0x00
+#define ADC128_REG_ALARM               0x01
+#define ADC128_REG_MASK                        0x03
+#define ADC128_REG_CONV_RATE           0x07
+#define ADC128_REG_ONESHOT             0x09
+#define ADC128_REG_SHUTDOWN            0x0a
+#define ADC128_REG_CONFIG_ADV          0x0b
+#define ADC128_REG_BUSY_STATUS         0x0c
+
+#define ADC128_REG_MAN_ID              0x3e
+#define ADC128_REG_DEV_ID              0x3f
+
+struct adc128_data {
+       struct i2c_client *client;
+       struct regulator *regulator;
+       int vref;               /* Reference voltage in mV */
+       struct mutex update_lock;
+       bool valid;             /* true if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       u16 in[3][7];           /* Register value, normalized to 12 bit
+                                * 0: input voltage
+                                * 1: min limit
+                                * 2: max limit
+                                */
+       s16 temp[3];            /* Register value, normalized to 9 bit
+                                * 0: sensor 1: limit 2: hyst
+                                */
+       u8 alarms;              /* alarm register value */
+};
+
+static struct adc128_data *adc128_update_device(struct device *dev)
+{
+       struct adc128_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       struct adc128_data *ret = data;
+       int i, rv;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               for (i = 0; i < 7; i++) {
+                       rv = i2c_smbus_read_word_swapped(client,
+                                                        ADC128_REG_IN(i));
+                       if (rv < 0)
+                               goto abort;
+                       data->in[0][i] = rv >> 4;
+
+                       rv = i2c_smbus_read_byte_data(client,
+                                                     ADC128_REG_IN_MIN(i));
+                       if (rv < 0)
+                               goto abort;
+                       data->in[1][i] = rv << 4;
+
+                       rv = i2c_smbus_read_byte_data(client,
+                                                     ADC128_REG_IN_MAX(i));
+                       if (rv < 0)
+                               goto abort;
+                       data->in[2][i] = rv << 4;
+               }
+
+               rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP);
+               if (rv < 0)
+                       goto abort;
+               data->temp[0] = rv >> 7;
+
+               rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX);
+               if (rv < 0)
+                       goto abort;
+               data->temp[1] = rv << 1;
+
+               rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST);
+               if (rv < 0)
+                       goto abort;
+               data->temp[2] = rv << 1;
+
+               rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM);
+               if (rv < 0)
+                       goto abort;
+               data->alarms |= rv;
+
+               data->last_updated = jiffies;
+               data->valid = true;
+       }
+       goto done;
+
+abort:
+       ret = ERR_PTR(rv);
+       data->valid = false;
+done:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t adc128_show_in(struct device *dev, struct device_attribute *attr,
+                             char *buf)
+{
+       struct adc128_data *data = adc128_update_device(dev);
+       int index = to_sensor_dev_attr_2(attr)->index;
+       int nr = to_sensor_dev_attr_2(attr)->nr;
+       int val;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       val = DIV_ROUND_CLOSEST(data->in[index][nr] * data->vref, 4095);
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t adc128_set_in(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct adc128_data *data = dev_get_drvdata(dev);
+       int index = to_sensor_dev_attr_2(attr)->index;
+       int nr = to_sensor_dev_attr_2(attr)->nr;
+       u8 reg, regval;
+       long val;
+       int err;
+
+       err = kstrtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&data->update_lock);
+       /* 10 mV LSB on limit registers */
+       regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
+       data->in[index][nr] = regval << 4;
+       reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
+       i2c_smbus_write_byte_data(data->client, reg, regval);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t adc128_show_temp(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct adc128_data *data = adc128_update_device(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+       int temp;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       temp = (data->temp[index] << 7) >> 7;   /* sign extend */
+       return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */
+}
+
+static ssize_t adc128_set_temp(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct adc128_data *data = dev_get_drvdata(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+       long val;
+       int err;
+       s8 regval;
+
+       err = kstrtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&data->update_lock);
+       regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+       data->temp[index] = regval << 1;
+       i2c_smbus_write_byte_data(data->client,
+                                 index == 1 ? ADC128_REG_TEMP_MAX
+                                            : ADC128_REG_TEMP_HYST,
+                                 regval);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t adc128_show_alarm(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct adc128_data *data = adc128_update_device(dev);
+       int mask = 1 << to_sensor_dev_attr(attr)->index;
+       u8 alarms;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       /*
+        * Clear an alarm after reporting it to user space. If it is still
+        * active, the next update sequence will set the alarm bit again.
+        */
+       alarms = data->alarms;
+       data->alarms &= ~mask;
+
+       return sprintf(buf, "%u\n", !!(alarms & mask));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 0, 2);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 2, 2);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 3, 2);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 5, 2);
+
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
+                           adc128_show_in, adc128_set_in, 6, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+                         adc128_show_temp, adc128_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+                         adc128_show_temp, adc128_set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, adc128_show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, adc128_show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, adc128_show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7);
+
+static struct attribute *adc128_attrs[] = {
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in6_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
+       &sensor_dev_attr_in6_max.dev_attr.attr,
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(adc128);
+
+static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+       int man_id, dev_id;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA |
+                                    I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
+
+       man_id = i2c_smbus_read_byte_data(client, ADC128_REG_MAN_ID);
+       dev_id = i2c_smbus_read_byte_data(client, ADC128_REG_DEV_ID);
+       if (man_id != 0x01 || dev_id != 0x09)
+               return -ENODEV;
+
+       /* Check unused bits for confirmation */
+       if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG) & 0xf4)
+               return -ENODEV;
+       if (i2c_smbus_read_byte_data(client, ADC128_REG_CONV_RATE) & 0xfe)
+               return -ENODEV;
+       if (i2c_smbus_read_byte_data(client, ADC128_REG_ONESHOT) & 0xfe)
+               return -ENODEV;
+       if (i2c_smbus_read_byte_data(client, ADC128_REG_SHUTDOWN) & 0xfe)
+               return -ENODEV;
+       if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV) & 0xf8)
+               return -ENODEV;
+       if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc)
+               return -ENODEV;
+
+       strlcpy(info->type, "adc128d818", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int adc128_init_client(struct adc128_data *data)
+{
+       struct i2c_client *client = data->client;
+       int err;
+
+       /*
+        * Reset chip to defaults.
+        * This makes most other initializations unnecessary.
+        */
+       err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x80);
+       if (err)
+               return err;
+
+       /* Start monitoring */
+       err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01);
+       if (err)
+               return err;
+
+       /* If external vref is selected, configure the chip to use it */
+       if (data->regulator) {
+               err = i2c_smbus_write_byte_data(client,
+                                               ADC128_REG_CONFIG_ADV, 0x01);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int adc128_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct regulator *regulator;
+       struct device *hwmon_dev;
+       struct adc128_data *data;
+       int err, vref;
+
+       data = devm_kzalloc(dev, sizeof(struct adc128_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       /* vref is optional. If specified, is used as chip reference voltage */
+       regulator = devm_regulator_get_optional(dev, "vref");
+       if (!IS_ERR(regulator)) {
+               data->regulator = regulator;
+               err = regulator_enable(regulator);
+               if (err < 0)
+                       return err;
+               vref = regulator_get_voltage(regulator);
+               if (vref < 0) {
+                       err = vref;
+                       goto error;
+               }
+               data->vref = DIV_ROUND_CLOSEST(vref, 1000);
+       } else {
+               data->vref = 2560;      /* 2.56V, in mV */
+       }
+
+       data->client = client;
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the chip */
+       err = adc128_init_client(data);
+       if (err < 0)
+               goto error;
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data, adc128_groups);
+       if (IS_ERR(hwmon_dev)) {
+               err = PTR_ERR(hwmon_dev);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       if (data->regulator)
+               regulator_disable(data->regulator);
+       return err;
+}
+
+static int adc128_remove(struct i2c_client *client)
+{
+       struct adc128_data *data = i2c_get_clientdata(client);
+
+       if (data->regulator)
+               regulator_disable(data->regulator);
+
+       return 0;
+}
+
+static const struct i2c_device_id adc128_id[] = {
+       { "adc128d818", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adc128_id);
+
+static struct i2c_driver adc128_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "adc128d818",
+       },
+       .probe          = adc128_probe,
+       .remove         = adc128_remove,
+       .id_table       = adc128_id,
+       .detect         = adc128_detect,
+       .address_list   = normal_i2c,
+};
+
+module_i2c_driver(adc128_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Driver for ADC128D818");
+MODULE_LICENSE("GPL");
index bbb0b0d463f7e0c7cf489a3b30ff2057563d1749..f31bc4c4864411ae8bd3267d27575c5444ac71e1 100644 (file)
@@ -94,6 +94,8 @@ struct temp_data {
        bool valid;
        struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
        char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
+       struct attribute *attrs[TOTAL_ATTRS + 1];
+       struct attribute_group attr_group;
        struct mutex update_lock;
 };
 
@@ -114,12 +116,6 @@ struct pdev_entry {
 static LIST_HEAD(pdev_list);
 static DEFINE_MUTEX(pdev_list_mutex);
 
-static ssize_t show_name(struct device *dev,
-                       struct device_attribute *devattr, char *buf)
-{
-       return sprintf(buf, "%s\n", DRVNAME);
-}
-
 static ssize_t show_label(struct device *dev,
                                struct device_attribute *devattr, char *buf)
 {
@@ -393,20 +389,10 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
        return adjust_tjmax(c, id, dev);
 }
 
-static int create_name_attr(struct platform_data *pdata,
-                                     struct device *dev)
-{
-       sysfs_attr_init(&pdata->name_attr.attr);
-       pdata->name_attr.attr.name = "name";
-       pdata->name_attr.attr.mode = S_IRUGO;
-       pdata->name_attr.show = show_name;
-       return device_create_file(dev, &pdata->name_attr);
-}
-
 static int create_core_attrs(struct temp_data *tdata, struct device *dev,
                             int attr_no)
 {
-       int err, i;
+       int i;
        static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
                        struct device_attribute *devattr, char *buf) = {
                        show_label, show_crit_alarm, show_temp, show_tjmax,
@@ -424,16 +410,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
                tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
                tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
                tdata->sd_attrs[i].index = attr_no;
-               err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
-               if (err)
-                       goto exit_free;
+               tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
        }
-       return 0;
-
-exit_free:
-       while (--i >= 0)
-               device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
-       return err;
+       tdata->attr_group.attrs = tdata->attrs;
+       return sysfs_create_group(&dev->kobj, &tdata->attr_group);
 }
 
 
@@ -548,7 +528,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
        pdata->core_data[attr_no] = tdata;
 
        /* Create sysfs interfaces */
-       err = create_core_attrs(tdata, &pdev->dev, attr_no);
+       err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
        if (err)
                goto exit_free;
 
@@ -573,14 +553,12 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag)
 }
 
 static void coretemp_remove_core(struct platform_data *pdata,
-                               struct device *dev, int indx)
+                                int indx)
 {
-       int i;
        struct temp_data *tdata = pdata->core_data[indx];
 
        /* Remove the sysfs attributes */
-       for (i = 0; i < tdata->attr_size; i++)
-               device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+       sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
 
        kfree(pdata->core_data[indx]);
        pdata->core_data[indx] = NULL;
@@ -588,34 +566,20 @@ static void coretemp_remove_core(struct platform_data *pdata,
 
 static int coretemp_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct platform_data *pdata;
-       int err;
 
        /* Initialize the per-package data structures */
-       pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
+       pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
 
-       err = create_name_attr(pdata, &pdev->dev);
-       if (err)
-               goto exit_free;
-
        pdata->phys_proc_id = pdev->id;
        platform_set_drvdata(pdev, pdata);
 
-       pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(pdata->hwmon_dev)) {
-               err = PTR_ERR(pdata->hwmon_dev);
-               dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
-               goto exit_name;
-       }
-       return 0;
-
-exit_name:
-       device_remove_file(&pdev->dev, &pdata->name_attr);
-exit_free:
-       kfree(pdata);
-       return err;
+       pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
+                                                                 pdata, NULL);
+       return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
 }
 
 static int coretemp_remove(struct platform_device *pdev)
@@ -625,11 +589,8 @@ static int coretemp_remove(struct platform_device *pdev)
 
        for (i = MAX_CORE_DATA - 1; i >= 0; --i)
                if (pdata->core_data[i])
-                       coretemp_remove_core(pdata, &pdev->dev, i);
+                       coretemp_remove_core(pdata, i);
 
-       device_remove_file(&pdev->dev, &pdata->name_attr);
-       hwmon_device_unregister(pdata->hwmon_dev);
-       kfree(pdata);
        return 0;
 }
 
@@ -777,7 +738,7 @@ static void put_core_offline(unsigned int cpu)
                return;
 
        if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
-               coretemp_remove_core(pdata, &pdev->dev, indx);
+               coretemp_remove_core(pdata, indx);
 
        /*
         * If a HT sibling of a core is taken offline, but another HT sibling
index 2c137b26acb48bbe188243a189f05c1c8ed693c5..fd892dd48e4c28ffe70c323f2238e893df20f63c 100644 (file)
@@ -349,7 +349,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
                dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
                        REG_FAN_CONF1, status);
                mutex_unlock(&data->update_lock);
-               return -EIO;
+               return status;
        }
        status &= 0x9F;
        status |= (new_range_bits << 5);
index e176a43af63d7700a3f92753732cc16aabd08aeb..a26c385a435ba345d4cee632eca4fc5575188c68 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/gfp.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
+#include <linux/string.h>
 
 #define HWMON_ID_PREFIX "hwmon"
 #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -99,6 +100,10 @@ hwmon_device_register_with_groups(struct device *dev, const char *name,
        struct hwmon_device *hwdev;
        int err, id;
 
+       /* Do not accept invalid characters in hwmon name attribute */
+       if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
+               return ERR_PTR(-EINVAL);
+
        id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
        if (id < 0)
                return ERR_PTR(id);
index 708081b68c6fc7007ec0524d8d0ee5745d0419f9..9fbb1b1fdff30e3de44086364d99833f612b9302 100644 (file)
@@ -31,6 +31,7 @@ struct iio_hwmon_state {
        int num_channels;
        struct device *hwmon_dev;
        struct attribute_group attr_group;
+       const struct attribute_group *groups[2];
        struct attribute **attrs;
 };
 
@@ -56,19 +57,6 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
        return sprintf(buf, "%d\n", result);
 }
 
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       const char *name = "iio_hwmon";
-
-       if (dev->of_node && dev->of_node->name)
-               name = dev->of_node->name;
-
-       return sprintf(buf, "%s\n", name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
 static int iio_hwmon_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -78,6 +66,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
        int in_i = 1, temp_i = 1, curr_i = 1;
        enum iio_chan_type type;
        struct iio_channel *channels;
+       const char *name = "iio_hwmon";
+
+       if (dev->of_node && dev->of_node->name)
+               name = dev->of_node->name;
 
        channels = iio_channel_get_all(dev);
        if (IS_ERR(channels))
@@ -96,7 +88,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
                st->num_channels++;
 
        st->attrs = devm_kzalloc(dev,
-                                sizeof(*st->attrs) * (st->num_channels + 2),
+                                sizeof(*st->attrs) * (st->num_channels + 1),
                                 GFP_KERNEL);
        if (st->attrs == NULL) {
                ret = -ENOMEM;
@@ -144,22 +136,18 @@ static int iio_hwmon_probe(struct platform_device *pdev)
                a->index = i;
                st->attrs[i] = &a->dev_attr.attr;
        }
-       st->attrs[st->num_channels] = &dev_attr_name.attr;
-       st->attr_group.attrs = st->attrs;
-       platform_set_drvdata(pdev, st);
-       ret = sysfs_create_group(&dev->kobj, &st->attr_group);
-       if (ret < 0)
-               goto error_release_channels;
 
-       st->hwmon_dev = hwmon_device_register(dev);
+       st->attr_group.attrs = st->attrs;
+       st->groups[0] = &st->attr_group;
+       st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st,
+                                                         st->groups);
        if (IS_ERR(st->hwmon_dev)) {
                ret = PTR_ERR(st->hwmon_dev);
-               goto error_remove_group;
+               goto error_release_channels;
        }
+       platform_set_drvdata(pdev, st);
        return 0;
 
-error_remove_group:
-       sysfs_remove_group(&dev->kobj, &st->attr_group);
 error_release_channels:
        iio_channel_release_all(channels);
        return ret;
@@ -170,7 +158,6 @@ static int iio_hwmon_remove(struct platform_device *pdev)
        struct iio_hwmon_state *st = platform_get_drvdata(pdev);
 
        hwmon_device_unregister(st->hwmon_dev);
-       sysfs_remove_group(&pdev->dev.kobj, &st->attr_group);
        iio_channel_release_all(st->channels);
 
        return 0;
index a183e488db78ba2531f349c688ff0283764f2578..7488e36809c87605e52beec263357e05eca1c4a5 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/hwmon.h>
 
 struct jz4740_hwmon {
-       struct resource *mem;
        void __iomem *base;
 
        int irq;
@@ -106,6 +105,7 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz4740_hwmon *hwmon;
+       struct resource *mem;
 
        hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
        if (!hwmon)
@@ -120,25 +120,10 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
                return hwmon->irq;
        }
 
-       hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!hwmon->mem) {
-               dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
-               return -ENOENT;
-       }
-
-       hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
-                       resource_size(hwmon->mem), pdev->name);
-       if (!hwmon->mem) {
-               dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-               return -EBUSY;
-       }
-
-       hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
-                                          resource_size(hwmon->mem));
-       if (!hwmon->base) {
-               dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-               return -EBUSY;
-       }
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hwmon->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(hwmon->base))
+               return PTR_ERR(hwmon->base);
 
        init_completion(&hwmon->read_completion);
        mutex_init(&hwmon->lock);
index 4b68fb2a31d75728da51e50eb66d9a72cd420bd7..cdf19adaec79b5a30c84d5ff824a085e028875d4 100644 (file)
@@ -89,7 +89,7 @@ static const u8 lm95241_reg_address[] = {
 
 /* Client data (each client gets its own) */
 struct lm95241_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex update_lock;
        unsigned long last_updated, interval;   /* in jiffies */
        char valid;             /* zero until following fields are valid */
@@ -113,8 +113,8 @@ static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
 
 static struct lm95241_data *lm95241_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
 
        mutex_lock(&data->update_lock);
 
@@ -122,7 +122,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
            !data->valid) {
                int i;
 
-               dev_dbg(&client->dev, "Updating lm95241 data.\n");
+               dev_dbg(dev, "Updating lm95241 data.\n");
                for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
                        data->temp[i]
                          = i2c_smbus_read_byte_data(client,
@@ -153,8 +153,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
 static ssize_t show_type(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE - 1,
                data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
@@ -163,8 +162,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
 static ssize_t set_type(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
        int shift;
        u8 mask = to_sensor_dev_attr(attr)->index;
@@ -201,8 +200,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr,
 static ssize_t show_min(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE - 1,
                        data->config & to_sensor_dev_attr(attr)->index ?
@@ -212,8 +210,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr,
 static ssize_t set_min(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
        long val;
 
        if (kstrtol(buf, 10, &val) < 0)
@@ -229,7 +226,8 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
                data->config &= ~to_sensor_dev_attr(attr)->index;
        data->valid = 0;
 
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+       i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+                                 data->config);
 
        mutex_unlock(&data->update_lock);
 
@@ -239,8 +237,7 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
 static ssize_t show_max(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE - 1,
                        data->config & to_sensor_dev_attr(attr)->index ?
@@ -250,8 +247,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr,
 static ssize_t set_max(struct device *dev, struct device_attribute *attr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
        long val;
 
        if (kstrtol(buf, 10, &val) < 0)
@@ -267,7 +263,8 @@ static ssize_t set_max(struct device *dev, struct device_attribute *attr,
                data->config &= ~to_sensor_dev_attr(attr)->index;
        data->valid = 0;
 
-       i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+       i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+                                 data->config);
 
        mutex_unlock(&data->update_lock);
 
@@ -286,8 +283,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
 static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95241_data *data = i2c_get_clientdata(client);
+       struct lm95241_data *data = dev_get_drvdata(dev);
        unsigned long val;
 
        if (kstrtoul(buf, 10, &val) < 0)
@@ -316,7 +312,7 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
 static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
                   set_interval);
 
-static struct attribute *lm95241_attributes[] = {
+static struct attribute *lm95241_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
        &sensor_dev_attr_temp3_input.dev_attr.attr,
@@ -329,10 +325,7 @@ static struct attribute *lm95241_attributes[] = {
        &dev_attr_update_interval.attr,
        NULL
 };
-
-static const struct attribute_group lm95241_group = {
-       .attrs = lm95241_attributes,
-};
+ATTRIBUTE_GROUPS(lm95241);
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int lm95241_detect(struct i2c_client *new_client,
@@ -366,14 +359,11 @@ static int lm95241_detect(struct i2c_client *new_client,
        return 0;
 }
 
-static void lm95241_init_client(struct i2c_client *client)
+static void lm95241_init_client(struct i2c_client *client,
+                               struct lm95241_data *data)
 {
-       struct lm95241_data *data = i2c_get_clientdata(client);
-
        data->interval = HZ;    /* 1 sec default */
-       data->valid = 0;
        data->config = CFG_CR0076;
-       data->model = 0;
        data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
 
        i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
@@ -385,49 +375,27 @@ static void lm95241_init_client(struct i2c_client *client)
                                  data->model);
 }
 
-static int lm95241_probe(struct i2c_client *new_client,
+static int lm95241_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        struct lm95241_data *data;
-       int err;
+       struct device *hwmon_dev;
 
-       data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(new_client, data);
+       data->client = client;
        mutex_init(&data->update_lock);
 
        /* Initialize the LM95241 chip */
-       lm95241_init_client(new_client);
+       lm95241_init_client(client, data);
 
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove_files;
-       }
-
-       return 0;
-
-exit_remove_files:
-       sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
-       return err;
-}
-
-static int lm95241_remove(struct i2c_client *client)
-{
-       struct lm95241_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &lm95241_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data,
+                                                          lm95241_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 /* Driver data (common to all clients) */
@@ -444,7 +412,6 @@ static struct i2c_driver lm95241_driver = {
                .name   = DEVNAME,
        },
        .probe          = lm95241_probe,
-       .remove         = lm95241_remove,
        .id_table       = lm95241_id,
        .detect         = lm95241_detect,
        .address_list   = normal_i2c,
index a6c85f0ff8f3e5a9ebf099a8d251b95a7fe636d6..0ae0dfdafdff9814993113a142f24a5192fe094e 100644 (file)
@@ -115,7 +115,7 @@ static const u8 lm95245_reg_address[] = {
 
 /* Client data (each client gets its own) */
 struct lm95245_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex update_lock;
        unsigned long last_updated;     /* in jiffies */
        unsigned long interval; /* in msecs */
@@ -140,8 +140,8 @@ static int temp_from_reg_signed(u8 val_h, u8 val_l)
 
 static struct lm95245_data *lm95245_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95245_data *data = i2c_get_clientdata(client);
+       struct lm95245_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
 
        mutex_lock(&data->update_lock);
 
@@ -149,7 +149,6 @@ static struct lm95245_data *lm95245_update_device(struct device *dev)
                + msecs_to_jiffies(data->interval)) || !data->valid) {
                int i;
 
-               dev_dbg(&client->dev, "Updating lm95245 data.\n");
                for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
                        data->regs[i]
                          = i2c_smbus_read_byte_data(client,
@@ -249,9 +248,9 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
 static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95245_data *data = i2c_get_clientdata(client);
+       struct lm95245_data *data = dev_get_drvdata(dev);
        int index = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = data->client;
        unsigned long val;
 
        if (kstrtoul(buf, 10, &val) < 0)
@@ -272,27 +271,38 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static ssize_t show_crit_hyst(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+       int hyst = data->regs[index] - data->regs[8];
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n", hyst * 1000);
+}
+
 static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95245_data *data = i2c_get_clientdata(client);
+       struct lm95245_data *data = dev_get_drvdata(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = data->client;
        unsigned long val;
+       int hyst, limit;
 
        if (kstrtoul(buf, 10, &val) < 0)
                return -EINVAL;
 
-       val /= 1000;
-
-       val = clamp_val(val, 0, 31);
-
        mutex_lock(&data->update_lock);
 
-       data->valid = 0;
+       limit = i2c_smbus_read_byte_data(client, lm95245_reg_address[index]);
+       hyst = limit - val / 1000;
+       hyst = clamp_val(hyst, 0, 31);
+       data->regs[8] = hyst;
 
        /* shared crit hysteresis */
        i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
-               val);
+               hyst);
 
        mutex_unlock(&data->update_lock);
 
@@ -302,8 +312,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
 static ssize_t show_type(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95245_data *data = i2c_get_clientdata(client);
+       struct lm95245_data *data = dev_get_drvdata(dev);
 
        return snprintf(buf, PAGE_SIZE - 1,
                data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
@@ -312,8 +321,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
 static ssize_t set_type(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95245_data *data = i2c_get_clientdata(client);
+       struct lm95245_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
 
        if (kstrtoul(buf, 10, &val) < 0)
@@ -359,8 +368,8 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
 static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm95245_data *data = i2c_get_clientdata(client);
+       struct lm95245_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
 
        if (kstrtoul(buf, 10, &val) < 0)
@@ -378,16 +387,15 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
                set_limit, 6);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
-               set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_crit_hyst,
+               set_crit_hyst, 6);
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
                STATUS1_LOC);
 
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
                set_limit, 7);
-static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
-               set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_crit_hyst, NULL, 7);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
                STATUS1_RTCRIT);
 static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
@@ -398,7 +406,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
 static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
                set_interval);
 
-static struct attribute *lm95245_attributes[] = {
+static struct attribute *lm95245_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp1_crit.dev_attr.attr,
        &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
@@ -412,10 +420,7 @@ static struct attribute *lm95245_attributes[] = {
        &dev_attr_update_interval.attr,
        NULL
 };
-
-static const struct attribute_group lm95245_group = {
-       .attrs = lm95245_attributes,
-};
+ATTRIBUTE_GROUPS(lm95245);
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int lm95245_detect(struct i2c_client *new_client,
@@ -436,11 +441,9 @@ static int lm95245_detect(struct i2c_client *new_client,
        return 0;
 }
 
-static void lm95245_init_client(struct i2c_client *client)
+static void lm95245_init_client(struct i2c_client *client,
+                               struct lm95245_data *data)
 {
-       struct lm95245_data *data = i2c_get_clientdata(client);
-
-       data->valid = 0;
        data->interval = lm95245_read_conversion_rate(client);
 
        data->config1 = i2c_smbus_read_byte_data(client,
@@ -456,49 +459,27 @@ static void lm95245_init_client(struct i2c_client *client)
        }
 }
 
-static int lm95245_probe(struct i2c_client *new_client,
+static int lm95245_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        struct lm95245_data *data;
-       int err;
+       struct device *hwmon_dev;
 
-       data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(new_client, data);
+       data->client = client;
        mutex_init(&data->update_lock);
 
        /* Initialize the LM95245 chip */
-       lm95245_init_client(new_client);
-
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove_files;
-       }
-
-       return 0;
-
-exit_remove_files:
-       sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
-       return err;
-}
+       lm95245_init_client(client, data);
 
-static int lm95245_remove(struct i2c_client *client)
-{
-       struct lm95245_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &lm95245_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data,
+                                                          lm95245_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 /* Driver data (common to all clients) */
@@ -514,7 +495,6 @@ static struct i2c_driver lm95245_driver = {
                .name   = DEVNAME,
        },
        .probe          = lm95245_probe,
-       .remove         = lm95245_remove,
        .id_table       = lm95245_id,
        .detect         = lm95245_detect,
        .address_list   = normal_i2c,
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
new file mode 100644 (file)
index 0000000..c104cc3
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * Driver for Linear Technology LTC2945 I2C Power Monitor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC2945_CONTROL                        0x00
+#define LTC2945_ALERT                  0x01
+#define LTC2945_STATUS                 0x02
+#define LTC2945_FAULT                  0x03
+#define LTC2945_POWER_H                        0x05
+#define LTC2945_MAX_POWER_H            0x08
+#define LTC2945_MIN_POWER_H            0x0b
+#define LTC2945_MAX_POWER_THRES_H      0x0e
+#define LTC2945_MIN_POWER_THRES_H      0x11
+#define LTC2945_SENSE_H                        0x14
+#define LTC2945_MAX_SENSE_H            0x16
+#define LTC2945_MIN_SENSE_H            0x18
+#define LTC2945_MAX_SENSE_THRES_H      0x1a
+#define LTC2945_MIN_SENSE_THRES_H      0x1c
+#define LTC2945_VIN_H                  0x1e
+#define LTC2945_MAX_VIN_H              0x20
+#define LTC2945_MIN_VIN_H              0x22
+#define LTC2945_MAX_VIN_THRES_H                0x24
+#define LTC2945_MIN_VIN_THRES_H                0x26
+#define LTC2945_ADIN_H                 0x28
+#define LTC2945_MAX_ADIN_H             0x2a
+#define LTC2945_MIN_ADIN_H             0x2c
+#define LTC2945_MAX_ADIN_THRES_H       0x2e
+#define LTC2945_MIN_ADIN_THRES_H       0x30
+#define LTC2945_MIN_ADIN_THRES_L       0x31
+
+/* Fault register bits */
+
+#define FAULT_ADIN_UV          (1 << 0)
+#define FAULT_ADIN_OV          (1 << 1)
+#define FAULT_VIN_UV           (1 << 2)
+#define FAULT_VIN_OV           (1 << 3)
+#define FAULT_SENSE_UV         (1 << 4)
+#define FAULT_SENSE_OV         (1 << 5)
+#define FAULT_POWER_UV         (1 << 6)
+#define FAULT_POWER_OV         (1 << 7)
+
+/* Control register bits */
+
+#define CONTROL_MULT_SELECT    (1 << 0)
+#define CONTROL_TEST_MODE      (1 << 4)
+
+static inline bool is_power_reg(u8 reg)
+{
+       return reg < LTC2945_SENSE_H;
+}
+
+/* Return the value from the given register in uW, mV, or mA */
+static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
+{
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int control;
+       u8 buf[3];
+       long long val;
+       int ret;
+
+       ret = regmap_bulk_read(regmap, reg, buf,
+                              is_power_reg(reg) ? 3 : 2);
+       if (ret < 0)
+               return ret;
+
+       if (is_power_reg(reg)) {
+               /* power */
+               val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
+       } else {
+               /* current, voltage */
+               val = (buf[0] << 4) + (buf[1] >> 4);
+       }
+
+       switch (reg) {
+       case LTC2945_POWER_H:
+       case LTC2945_MAX_POWER_H:
+       case LTC2945_MIN_POWER_H:
+       case LTC2945_MAX_POWER_THRES_H:
+       case LTC2945_MIN_POWER_THRES_H:
+               /*
+                * Convert to uW by assuming current is measured with
+                * an 1mOhm sense resistor, similar to current
+                * measurements.
+                * Control register bit 0 selects if voltage at SENSE+/VDD
+                * or voltage at ADIN is used to measure power.
+                */
+               ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+               if (ret < 0)
+                       return ret;
+               if (control & CONTROL_MULT_SELECT) {
+                       /* 25 mV * 25 uV = 0.625 uV resolution. */
+                       val *= 625LL;
+               } else {
+                       /* 0.5 mV * 25 uV = 0.0125 uV resolution. */
+                       val = (val * 25LL) >> 1;
+               }
+               break;
+       case LTC2945_VIN_H:
+       case LTC2945_MAX_VIN_H:
+       case LTC2945_MIN_VIN_H:
+       case LTC2945_MAX_VIN_THRES_H:
+       case LTC2945_MIN_VIN_THRES_H:
+               /* 25 mV resolution. Convert to mV. */
+               val *= 25;
+               break;
+       case LTC2945_ADIN_H:
+       case LTC2945_MAX_ADIN_H:
+       case LTC2945_MIN_ADIN_THRES_H:
+       case LTC2945_MAX_ADIN_THRES_H:
+       case LTC2945_MIN_ADIN_H:
+               /* 0.5mV resolution. Convert to mV. */
+               val = val >> 1;
+               break;
+       case LTC2945_SENSE_H:
+       case LTC2945_MAX_SENSE_H:
+       case LTC2945_MIN_SENSE_H:
+       case LTC2945_MAX_SENSE_THRES_H:
+       case LTC2945_MIN_SENSE_THRES_H:
+               /*
+                * 25 uV resolution. Convert to current as measured with
+                * an 1 mOhm sense resistor, in mA. If a different sense
+                * resistor is installed, calculate the actual current by
+                * dividing the reported current by the sense resistor value
+                * in mOhm.
+                */
+               val *= 25;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return val;
+}
+
+static int ltc2945_val_to_reg(struct device *dev, u8 reg,
+                             unsigned long val)
+{
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int control;
+       int ret;
+
+       switch (reg) {
+       case LTC2945_POWER_H:
+       case LTC2945_MAX_POWER_H:
+       case LTC2945_MIN_POWER_H:
+       case LTC2945_MAX_POWER_THRES_H:
+       case LTC2945_MIN_POWER_THRES_H:
+               /*
+                * Convert to register value by assuming current is measured
+                * with an 1mOhm sense resistor, similar to current
+                * measurements.
+                * Control register bit 0 selects if voltage at SENSE+/VDD
+                * or voltage at ADIN is used to measure power, which in turn
+                * determines register calculations.
+                */
+               ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+               if (ret < 0)
+                       return ret;
+               if (control & CONTROL_MULT_SELECT) {
+                       /* 25 mV * 25 uV = 0.625 uV resolution. */
+                       val = DIV_ROUND_CLOSEST(val, 625);
+               } else {
+                       /*
+                        * 0.5 mV * 25 uV = 0.0125 uV resolution.
+                        * Divide first to avoid overflow;
+                        * accept loss of accuracy.
+                        */
+                       val = DIV_ROUND_CLOSEST(val, 25) * 2;
+               }
+               break;
+       case LTC2945_VIN_H:
+       case LTC2945_MAX_VIN_H:
+       case LTC2945_MIN_VIN_H:
+       case LTC2945_MAX_VIN_THRES_H:
+       case LTC2945_MIN_VIN_THRES_H:
+               /* 25 mV resolution. */
+               val /= 25;
+               break;
+       case LTC2945_ADIN_H:
+       case LTC2945_MAX_ADIN_H:
+       case LTC2945_MIN_ADIN_THRES_H:
+       case LTC2945_MAX_ADIN_THRES_H:
+       case LTC2945_MIN_ADIN_H:
+               /* 0.5mV resolution. */
+               val *= 2;
+               break;
+       case LTC2945_SENSE_H:
+       case LTC2945_MAX_SENSE_H:
+       case LTC2945_MIN_SENSE_H:
+       case LTC2945_MAX_SENSE_THRES_H:
+       case LTC2945_MIN_SENSE_THRES_H:
+               /*
+                * 25 uV resolution. Convert to current as measured with
+                * an 1 mOhm sense resistor, in mA. If a different sense
+                * resistor is installed, calculate the actual current by
+                * dividing the reported current by the sense resistor value
+                * in mOhm.
+                */
+               val = DIV_ROUND_CLOSEST(val, 25);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return val;
+}
+
+static ssize_t ltc2945_show_value(struct device *dev,
+                                 struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       long long value;
+
+       value = ltc2945_reg_to_val(dev, attr->index);
+       if (value < 0)
+               return value;
+       return snprintf(buf, PAGE_SIZE, "%lld\n", value);
+}
+
+static ssize_t ltc2945_set_value(struct device *dev,
+                                    struct device_attribute *da,
+                                    const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct regmap *regmap = dev_get_drvdata(dev);
+       u8 reg = attr->index;
+       unsigned long val;
+       u8 regbuf[3];
+       int num_regs;
+       int regval;
+       int ret;
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       /* convert to register value, then clamp and write result */
+       regval = ltc2945_val_to_reg(dev, reg, val);
+       if (is_power_reg(reg)) {
+               regval = clamp_val(regval, 0, 0xffffff);
+               regbuf[0] = regval >> 16;
+               regbuf[1] = (regval >> 8) & 0xff;
+               regbuf[2] = regval;
+               num_regs = 3;
+       } else {
+               regval = clamp_val(regval, 0, 0xfff) << 4;
+               regbuf[0] = regval >> 8;
+               regbuf[1] = regval & 0xff;
+               num_regs = 2;
+       }
+       ret = regmap_bulk_write(regmap, reg, regbuf, num_regs);
+       return ret < 0 ? ret : count;
+}
+
+static ssize_t ltc2945_reset_history(struct device *dev,
+                                    struct device_attribute *da,
+                                    const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct regmap *regmap = dev_get_drvdata(dev);
+       u8 reg = attr->index;
+       int num_regs = is_power_reg(reg) ? 3 : 2;
+       u8 buf_min[3] = { 0xff, 0xff, 0xff };
+       u8 buf_max[3] = { 0, 0, 0 };
+       unsigned long val;
+       int ret;
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+       if (val != 1)
+               return -EINVAL;
+
+       ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE,
+                                CONTROL_TEST_MODE);
+
+       /* Reset minimum */
+       ret = regmap_bulk_write(regmap, reg, buf_min, num_regs);
+       if (ret)
+               return ret;
+
+       switch (reg) {
+       case LTC2945_MIN_POWER_H:
+               reg = LTC2945_MAX_POWER_H;
+               break;
+       case LTC2945_MIN_SENSE_H:
+               reg = LTC2945_MAX_SENSE_H;
+               break;
+       case LTC2945_MIN_VIN_H:
+               reg = LTC2945_MAX_VIN_H;
+               break;
+       case LTC2945_MIN_ADIN_H:
+               reg = LTC2945_MAX_ADIN_H;
+               break;
+       default:
+               BUG();
+               break;
+       }
+       /* Reset maximum */
+       ret = regmap_bulk_write(regmap, reg, buf_max, num_regs);
+
+       /* Try resetting test mode even if there was an error */
+       regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0);
+
+       return ret ? : count;
+}
+
+static ssize_t ltc2945_show_bool(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int fault;
+       int ret;
+
+       ret = regmap_read(regmap, LTC2945_FAULT, &fault);
+       if (ret < 0)
+               return ret;
+
+       fault &= attr->index;
+       if (fault)              /* Clear reported faults in chip register */
+               regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Input voltages */
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MIN_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MAX_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_MIN_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_MAX_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+                         ltc2945_reset_history, LTC2945_MIN_VIN_H);
+
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MIN_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MAX_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_lowest, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_MIN_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_MAX_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_reset_history, S_IWUSR, NULL,
+                         ltc2945_reset_history, LTC2945_MIN_ADIN_H);
+
+/* Voltage alarms */
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_VIN_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_VIN_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_ADIN_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_ADIN_OV);
+
+/* Currents (via sense resistor) */
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MIN_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MAX_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_MIN_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_MAX_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL,
+                         ltc2945_reset_history, LTC2945_MIN_SENSE_H);
+
+/* Current alarms */
+
+static SENSOR_DEVICE_ATTR(curr1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_SENSE_UV);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_SENSE_OV);
+
+/* Power */
+
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc2945_show_value, NULL,
+                         LTC2945_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MIN_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+                         ltc2945_set_value, LTC2945_MAX_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_input_lowest, S_IRUGO, ltc2945_show_value,
+                         NULL, LTC2945_MIN_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ltc2945_show_value,
+                         NULL, LTC2945_MAX_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+                         ltc2945_reset_history, LTC2945_MIN_POWER_H);
+
+/* Power alarms */
+
+static SENSOR_DEVICE_ATTR(power1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_POWER_UV);
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+                         FAULT_POWER_OV);
+
+static struct attribute *ltc2945_attrs[] = {
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in1_lowest.dev_attr.attr,
+       &sensor_dev_attr_in1_highest.dev_attr.attr,
+       &sensor_dev_attr_in1_reset_history.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in2_lowest.dev_attr.attr,
+       &sensor_dev_attr_in2_highest.dev_attr.attr,
+       &sensor_dev_attr_in2_reset_history.dev_attr.attr,
+       &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_min.dev_attr.attr,
+       &sensor_dev_attr_curr1_max.dev_attr.attr,
+       &sensor_dev_attr_curr1_lowest.dev_attr.attr,
+       &sensor_dev_attr_curr1_highest.dev_attr.attr,
+       &sensor_dev_attr_curr1_reset_history.dev_attr.attr,
+       &sensor_dev_attr_curr1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_power1_input.dev_attr.attr,
+       &sensor_dev_attr_power1_min.dev_attr.attr,
+       &sensor_dev_attr_power1_max.dev_attr.attr,
+       &sensor_dev_attr_power1_input_lowest.dev_attr.attr,
+       &sensor_dev_attr_power1_input_highest.dev_attr.attr,
+       &sensor_dev_attr_power1_reset_history.dev_attr.attr,
+       &sensor_dev_attr_power1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+
+       NULL,
+};
+ATTRIBUTE_GROUPS(ltc2945);
+
+static struct regmap_config ltc2945_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = LTC2945_MIN_ADIN_THRES_L,
+};
+
+static int ltc2945_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device *hwmon_dev;
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "failed to allocate register map\n");
+               return PTR_ERR(regmap);
+       }
+
+       /* Clear faults */
+       regmap_write(regmap, LTC2945_FAULT, 0x00);
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          regmap,
+                                                          ltc2945_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc2945_id[] = {
+       {"ltc2945", 0},
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc2945_id);
+
+static struct i2c_driver ltc2945_driver = {
+       .driver = {
+                  .name = "ltc2945",
+                  },
+       .probe = ltc2945_probe,
+       .id_table = ltc2945_id,
+};
+
+module_i2c_driver(ltc2945_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC2945 driver");
+MODULE_LICENSE("GPL");
index 8a142960d69ef1cbdbf884bf1b382cb78c1d5eb9..c8a9bd9b050ffb78a3ee2da6bf35b2cdeec5e600 100644 (file)
@@ -33,7 +33,7 @@ enum ltc4215_cmd {
 };
 
 struct ltc4215_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
 
        struct mutex update_lock;
        bool valid;
@@ -45,8 +45,8 @@ struct ltc4215_data {
 
 static struct ltc4215_data *ltc4215_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ltc4215_data *data = i2c_get_clientdata(client);
+       struct ltc4215_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        s32 val;
        int i;
 
@@ -214,7 +214,7 @@ static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
  * Finally, construct an array of pointers to members of the above objects,
  * as required for sysfs_create_group()
  */
-static struct attribute *ltc4215_attributes[] = {
+static struct attribute *ltc4215_attrs[] = {
        &sensor_dev_attr_curr1_input.dev_attr.attr,
        &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
 
@@ -229,57 +229,33 @@ static struct attribute *ltc4215_attributes[] = {
 
        NULL,
 };
-
-static const struct attribute_group ltc4215_group = {
-       .attrs = ltc4215_attributes,
-};
+ATTRIBUTE_GROUPS(ltc4215);
 
 static int ltc4215_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = client->adapter;
+       struct device *dev = &client->dev;
        struct ltc4215_data *data;
-       int ret;
+       struct device *hwmon_dev;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, data);
+       data->client = client;
        mutex_init(&data->update_lock);
 
        /* Initialize the LTC4215 chip */
        i2c_smbus_write_byte_data(client, LTC4215_FAULT, 0x00);
 
-       /* Register sysfs hooks */
-       ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
-       if (ret)
-               return ret;
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               ret = PTR_ERR(data->hwmon_dev);
-               goto out_hwmon_device_register;
-       }
-
-       return 0;
-
-out_hwmon_device_register:
-       sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-       return ret;
-}
-
-static int ltc4215_remove(struct i2c_client *client)
-{
-       struct ltc4215_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data,
+                                                          ltc4215_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static const struct i2c_device_id ltc4215_id[] = {
@@ -294,7 +270,6 @@ static struct i2c_driver ltc4215_driver = {
                .name   = "ltc4215",
        },
        .probe          = ltc4215_probe,
-       .remove         = ltc4215_remove,
        .id_table       = ltc4215_id,
 };
 
diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c
new file mode 100644 (file)
index 0000000..07c2565
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Driver for Linear Technology LTC4222 Dual Hot Swap controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+
+#define LTC4222_CONTROL1       0xd0
+#define LTC4222_ALERT1         0xd1
+#define LTC4222_STATUS1                0xd2
+#define LTC4222_FAULT1         0xd3
+#define LTC4222_CONTROL2       0xd4
+#define LTC4222_ALERT2         0xd5
+#define LTC4222_STATUS2                0xd6
+#define LTC4222_FAULT2         0xd7
+#define LTC4222_SOURCE1                0xd8
+#define LTC4222_SOURCE2                0xda
+#define LTC4222_ADIN1          0xdc
+#define LTC4222_ADIN2          0xde
+#define LTC4222_SENSE1         0xe0
+#define LTC4222_SENSE2         0xe2
+#define LTC4222_ADC_CONTROL    0xe4
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV       BIT(0)
+#define FAULT_UV       BIT(1)
+#define FAULT_OC       BIT(2)
+#define FAULT_POWER_BAD        BIT(3)
+#define FAULT_FET_BAD  BIT(5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4222_get_value(struct device *dev, u8 reg)
+{
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int val;
+       u8 buf[2];
+       int ret;
+
+       ret = regmap_bulk_read(regmap, reg, buf, 2);
+       if (ret < 0)
+               return ret;
+
+       val = ((buf[0] << 8) + buf[1]) >> 6;
+
+       switch (reg) {
+       case LTC4222_ADIN1:
+       case LTC4222_ADIN2:
+               /* 1.25 mV resolution. Convert to mV. */
+               val = DIV_ROUND_CLOSEST(val * 5, 4);
+               break;
+       case LTC4222_SOURCE1:
+       case LTC4222_SOURCE2:
+               /* 31.25 mV resolution. Convert to mV. */
+               val = DIV_ROUND_CLOSEST(val * 125, 4);
+               break;
+       case LTC4222_SENSE1:
+       case LTC4222_SENSE2:
+               /*
+                * 62.5 uV resolution. Convert to current as measured with
+                * an 1 mOhm sense resistor, in mA. If a different sense
+                * resistor is installed, calculate the actual current by
+                * dividing the reported current by the sense resistor value
+                * in mOhm.
+                */
+               val = DIV_ROUND_CLOSEST(val * 125, 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return val;
+}
+
+static ssize_t ltc4222_show_value(struct device *dev,
+                                 struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int value;
+
+       value = ltc4222_get_value(dev, attr->index);
+       if (value < 0)
+               return value;
+       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4222_show_bool(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int fault;
+       int ret;
+
+       ret = regmap_read(regmap, attr->nr, &fault);
+       if (ret < 0)
+               return ret;
+       fault &= attr->index;
+       if (fault)              /* Clear reported faults in chip register */
+               regmap_update_bits(regmap, attr->nr, attr->index, 0);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL,
+                         LTC4222_SOURCE1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL,
+                         LTC4222_ADIN1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL,
+                         LTC4222_SOURCE2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL,
+                         LTC4222_ADIN2);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and power bad and fet
+ * faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT1, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT1, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT2, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT2, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL,
+                         LTC4222_SENSE1);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL,
+                         LTC4222_SENSE2);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT1, FAULT_OC);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+                           LTC4222_FAULT2, FAULT_OC);
+
+static struct attribute *ltc4222_attrs[] = {
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_curr2_input.dev_attr.attr,
+       &sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
+
+       NULL,
+};
+ATTRIBUTE_GROUPS(ltc4222);
+
+static struct regmap_config ltc4222_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = LTC4222_ADC_CONTROL,
+};
+
+static int ltc4222_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device *hwmon_dev;
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(client, &ltc4222_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "failed to allocate register map\n");
+               return PTR_ERR(regmap);
+       }
+
+       /* Clear faults */
+       regmap_write(regmap, LTC4222_FAULT1, 0x00);
+       regmap_write(regmap, LTC4222_FAULT2, 0x00);
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          regmap,
+                                                          ltc4222_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4222_id[] = {
+       {"ltc4222", 0},
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4222_id);
+
+static struct i2c_driver ltc4222_driver = {
+       .driver = {
+                  .name = "ltc4222",
+                  },
+       .probe = ltc4222_probe,
+       .id_table = ltc4222_id,
+};
+
+module_i2c_driver(ltc4222_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4222 driver");
+MODULE_LICENSE("GPL");
index d4172933ce4f2b67d8696b97527d25e7fd5fab48..681b5b7b3c3b5d2b9de7316e1a217d2b2eaf164a 100644 (file)
@@ -95,7 +95,6 @@ static void ltc4245_update_gpios(struct device *dev)
         * readings as stale by setting them to -EAGAIN
         */
        if (time_after(jiffies, data->last_updated + 5 * HZ)) {
-               dev_dbg(&client->dev, "Marking GPIOs invalid\n");
                for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
                        data->gpios[i] = -EAGAIN;
        }
@@ -141,8 +140,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
 
        if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 
-               dev_dbg(&client->dev, "Starting ltc4245 update\n");
-
                /* Read control registers -- 0x00 to 0x07 */
                for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
                        val = i2c_smbus_read_byte_data(client, i);
@@ -470,19 +467,15 @@ static void ltc4245_sysfs_add_groups(struct ltc4245_data *data)
 static bool ltc4245_use_extra_gpios(struct i2c_client *client)
 {
        struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
-#ifdef CONFIG_OF
        struct device_node *np = client->dev.of_node;
-#endif
 
        /* prefer platform data */
        if (pdata)
                return pdata->use_extra_gpios;
 
-#ifdef CONFIG_OF
        /* fallback on OF */
        if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
                return true;
-#endif
 
        return false;
 }
@@ -512,24 +505,10 @@ static int ltc4245_probe(struct i2c_client *client,
        /* Add sysfs hooks */
        ltc4245_sysfs_add_groups(data);
 
-       hwmon_dev = hwmon_device_register_with_groups(&client->dev,
-                                                     client->name, data,
-                                                     data->groups);
-       if (IS_ERR(hwmon_dev))
-               return PTR_ERR(hwmon_dev);
-
-       i2c_set_clientdata(client, hwmon_dev);
-
-       return 0;
-}
-
-static int ltc4245_remove(struct i2c_client *client)
-{
-       struct device *hwmon_dev = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(hwmon_dev);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+                                                          client->name, data,
+                                                          data->groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static const struct i2c_device_id ltc4245_id[] = {
@@ -544,7 +523,6 @@ static struct i2c_driver ltc4245_driver = {
                .name   = "ltc4245",
        },
        .probe          = ltc4245_probe,
-       .remove         = ltc4245_remove,
        .id_table       = ltc4245_id,
 };
 
diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c
new file mode 100644 (file)
index 0000000..453a250
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC4260_CONTROL        0x00
+#define LTC4260_ALERT  0x01
+#define LTC4260_STATUS 0x02
+#define LTC4260_FAULT  0x03
+#define LTC4260_SENSE  0x04
+#define LTC4260_SOURCE 0x05
+#define LTC4260_ADIN   0x06
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV       (1 << 0)
+#define FAULT_UV       (1 << 1)
+#define FAULT_OC       (1 << 2)
+#define FAULT_POWER_BAD        (1 << 3)
+#define FAULT_FET_SHORT        (1 << 5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4260_get_value(struct device *dev, u8 reg)
+{
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(regmap, reg, &val);
+       if (ret < 0)
+               return ret;
+
+       switch (reg) {
+       case LTC4260_ADIN:
+               /* 10 mV resolution. Convert to mV. */
+               val = val * 10;
+               break;
+       case LTC4260_SOURCE:
+               /* 400 mV resolution. Convert to mV. */
+               val = val * 400;
+               break;
+       case LTC4260_SENSE:
+               /*
+                * 300 uV resolution. Convert to current as measured with
+                * an 1 mOhm sense resistor, in mA. If a different sense
+                * resistor is installed, calculate the actual current by
+                * dividing the reported current by the sense resistor value
+                * in mOhm.
+                */
+               val = val * 300;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return val;
+}
+
+static ssize_t ltc4260_show_value(struct device *dev,
+                                 struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int value;
+
+       value = ltc4260_get_value(dev, attr->index);
+       if (value < 0)
+               return value;
+       return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4260_show_bool(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct regmap *regmap = dev_get_drvdata(dev);
+       unsigned int fault;
+       int ret;
+
+       ret = regmap_read(regmap, LTC4260_FAULT, &fault);
+       if (ret < 0)
+               return ret;
+
+       fault &= attr->index;
+       if (fault)              /* Clear reported faults in chip register */
+               regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL,
+                         LTC4260_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL,
+                         LTC4260_ADIN);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and the POWER BAD and
+ * FET SHORT faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+                         FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+                         FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+                         FAULT_POWER_BAD | FAULT_FET_SHORT);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL,
+                         LTC4260_SENSE);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+                         FAULT_OC);
+
+static struct attribute *ltc4260_attrs[] = {
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_curr1_input.dev_attr.attr,
+       &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+       NULL,
+};
+ATTRIBUTE_GROUPS(ltc4260);
+
+static struct regmap_config ltc4260_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = LTC4260_ADIN,
+};
+
+static int ltc4260_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device *hwmon_dev;
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(client, &ltc4260_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "failed to allocate register map\n");
+               return PTR_ERR(regmap);
+       }
+
+       /* Clear faults */
+       regmap_write(regmap, LTC4260_FAULT, 0x00);
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          regmap,
+                                                          ltc4260_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4260_id[] = {
+       {"ltc4260", 0},
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4260_id);
+
+static struct i2c_driver ltc4260_driver = {
+       .driver = {
+                  .name = "ltc4260",
+                  },
+       .probe = ltc4260_probe,
+       .id_table = ltc4260_id,
+};
+
+module_i2c_driver(ltc4260_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4260 driver");
+MODULE_LICENSE("GPL");
index 029b65e6c58914d36061914e35738bda0c1e385c..e3ed0a5b6d9485dc293048d7aa3c298a95b7551f 100644 (file)
@@ -66,7 +66,8 @@ MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
 enum chips { max1668, max1805, max1989 };
 
 struct max1668_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
+       const struct attribute_group *groups[3];
        enum chips type;
 
        struct mutex update_lock;
@@ -82,8 +83,8 @@ struct max1668_data {
 
 static struct max1668_data *max1668_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max1668_data *data = i2c_get_clientdata(client);
+       struct max1668_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        struct max1668_data *ret = data;
        s32 val;
        int i;
@@ -205,8 +206,8 @@ static ssize_t set_temp_max(struct device *dev,
                            const char *buf, size_t count)
 {
        int index = to_sensor_dev_attr(devattr)->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max1668_data *data = i2c_get_clientdata(client);
+       struct max1668_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long temp;
        int ret;
 
@@ -216,10 +217,11 @@ static ssize_t set_temp_max(struct device *dev,
 
        mutex_lock(&data->update_lock);
        data->temp_max[index] = clamp_val(temp/1000, -128, 127);
-       if (i2c_smbus_write_byte_data(client,
+       ret = i2c_smbus_write_byte_data(client,
                                        MAX1668_REG_LIMH_WR(index),
-                                       data->temp_max[index]))
-               count = -EIO;
+                                       data->temp_max[index]);
+       if (ret < 0)
+               count = ret;
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -230,8 +232,8 @@ static ssize_t set_temp_min(struct device *dev,
                            const char *buf, size_t count)
 {
        int index = to_sensor_dev_attr(devattr)->index;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max1668_data *data = i2c_get_clientdata(client);
+       struct max1668_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        long temp;
        int ret;
 
@@ -241,10 +243,11 @@ static ssize_t set_temp_min(struct device *dev,
 
        mutex_lock(&data->update_lock);
        data->temp_min[index] = clamp_val(temp/1000, -128, 127);
-       if (i2c_smbus_write_byte_data(client,
+       ret = i2c_smbus_write_byte_data(client,
                                        MAX1668_REG_LIML_WR(index),
-                                       data->temp_min[index]))
-               count = -EIO;
+                                       data->temp_min[index]);
+       if (ret < 0)
+               count = ret;
        mutex_unlock(&data->update_lock);
 
        return count;
@@ -405,60 +408,29 @@ static int max1668_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = client->adapter;
+       struct device *dev = &client->dev;
+       struct device *hwmon_dev;
        struct max1668_data *data;
-       int err;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct max1668_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, data);
+       data->client = client;
        data->type = id->driver_data;
        mutex_init(&data->update_lock);
 
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
-       if (err)
-               return err;
-
-       if (data->type == max1668 || data->type == max1989) {
-               err = sysfs_create_group(&client->dev.kobj,
-                                        &max1668_group_unique);
-               if (err)
-                       goto error_sysrem0;
-       }
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto error_sysrem1;
-       }
-
-       return 0;
-
-error_sysrem1:
+       /* sysfs hooks */
+       data->groups[0] = &max1668_group_common;
        if (data->type == max1668 || data->type == max1989)
-               sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
-error_sysrem0:
-       sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-       return err;
-}
-
-static int max1668_remove(struct i2c_client *client)
-{
-       struct max1668_data *data = i2c_get_clientdata(client);
+               data->groups[1] = &max1668_group_unique;
 
-       hwmon_device_unregister(data->hwmon_dev);
-       if (data->type == max1668 || data->type == max1989)
-               sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
-
-       sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data, data->groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 static const struct i2c_device_id max1668_id[] = {
@@ -476,7 +448,6 @@ static struct i2c_driver max1668_driver = {
                  .name = "max1668",
                  },
        .probe = max1668_probe,
-       .remove = max1668_remove,
        .id_table = max1668_id,
        .detect = max1668_detect,
        .address_list = max1668_addr_list,
index 066e587a18a5a280f29db1f19dd14e3d30ea4f48..70650de2cbd167f34eeab9997e62e99933d893ef 100644 (file)
@@ -80,7 +80,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
  * Client data (each client gets its own)
  */
 struct max6639_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
        struct mutex update_lock;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
@@ -104,8 +104,8 @@ struct max6639_data {
 
 static struct max6639_data *max6639_update_device(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
+       struct max6639_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        struct max6639_data *ret = data;
        int i;
        int status_reg;
@@ -191,9 +191,8 @@ static ssize_t show_temp_fault(struct device *dev,
 static ssize_t show_temp_max(struct device *dev,
                             struct device_attribute *dev_attr, char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
 }
@@ -202,9 +201,9 @@ static ssize_t set_temp_max(struct device *dev,
                            struct device_attribute *dev_attr,
                            const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
        int res;
 
@@ -224,9 +223,8 @@ static ssize_t set_temp_max(struct device *dev,
 static ssize_t show_temp_crit(struct device *dev,
                              struct device_attribute *dev_attr, char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
 }
@@ -235,9 +233,9 @@ static ssize_t set_temp_crit(struct device *dev,
                             struct device_attribute *dev_attr,
                             const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
        int res;
 
@@ -258,9 +256,8 @@ static ssize_t show_temp_emergency(struct device *dev,
                                   struct device_attribute *dev_attr,
                                   char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
 }
@@ -269,9 +266,9 @@ static ssize_t set_temp_emergency(struct device *dev,
                                  struct device_attribute *dev_attr,
                                  const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
        int res;
 
@@ -291,9 +288,8 @@ static ssize_t set_temp_emergency(struct device *dev,
 static ssize_t show_pwm(struct device *dev,
                        struct device_attribute *dev_attr, char *buf)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
 }
@@ -302,9 +298,9 @@ static ssize_t set_pwm(struct device *dev,
                       struct device_attribute *dev_attr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+       struct max6639_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long val;
        int res;
 
@@ -378,7 +374,7 @@ static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5);
 static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4);
 
 
-static struct attribute *max6639_attributes[] = {
+static struct attribute *max6639_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
        &sensor_dev_attr_temp1_fault.dev_attr.attr,
@@ -403,10 +399,7 @@ static struct attribute *max6639_attributes[] = {
        &sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
        NULL
 };
-
-static const struct attribute_group max6639_group = {
-       .attrs = max6639_attributes,
-};
+ATTRIBUTE_GROUPS(max6639);
 
 /*
  *  returns respective index in rpm_ranges table
@@ -424,9 +417,9 @@ static int rpm_range_to_reg(int range)
        return 1; /* default: 4000 RPM */
 }
 
-static int max6639_init_client(struct i2c_client *client)
+static int max6639_init_client(struct i2c_client *client,
+                              struct max6639_data *data)
 {
-       struct max6639_data *data = i2c_get_clientdata(client);
        struct max6639_platform_data *max6639_info =
                dev_get_platdata(&client->dev);
        int i;
@@ -545,50 +538,27 @@ static int max6639_detect(struct i2c_client *client,
 static int max6639_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        struct max6639_data *data;
+       struct device *hwmon_dev;
        int err;
 
-       data = devm_kzalloc(&client->dev, sizeof(struct max6639_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, data);
+       data->client = client;
        mutex_init(&data->update_lock);
 
        /* Initialize the max6639 chip */
-       err = max6639_init_client(client);
+       err = max6639_init_client(client, data);
        if (err < 0)
                return err;
 
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&client->dev.kobj, &max6639_group);
-       if (err)
-               return err;
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto error_remove;
-       }
-
-       dev_info(&client->dev, "temperature sensor and fan control found\n");
-
-       return 0;
-
-error_remove:
-       sysfs_remove_group(&client->dev.kobj, &max6639_group);
-       return err;
-}
-
-static int max6639_remove(struct i2c_client *client)
-{
-       struct max6639_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &max6639_group);
-
-       return 0;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+                                                          data,
+                                                          max6639_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -622,9 +592,7 @@ static const struct i2c_device_id max6639_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, max6639_id);
 
-static const struct dev_pm_ops max6639_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume)
-};
+static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
 
 static struct i2c_driver max6639_driver = {
        .class = I2C_CLASS_HWMON,
@@ -633,7 +601,6 @@ static struct i2c_driver max6639_driver = {
                   .pm = &max6639_pm_ops,
                   },
        .probe = max6639_probe,
-       .remove = max6639_remove,
        .id_table = max6639_id,
        .detect = max6639_detect,
        .address_list = normal_i2c,
index 0cafc390db4dd5fc1413ffe0814d6a15567dd352..162a520f4bd6a5627a8927d56d52ea6daaba9baf 100644 (file)
@@ -105,38 +105,13 @@ module_param(clock, int, S_IRUGO);
 
 #define DIV_FROM_REG(reg) (1 << (reg & 7))
 
-static int max6650_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id);
-static int max6650_init_client(struct i2c_client *client);
-static int max6650_remove(struct i2c_client *client);
-static struct max6650_data *max6650_update_device(struct device *dev);
-
-/*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id max6650_id[] = {
-       { "max6650", 1 },
-       { "max6651", 4 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, max6650_id);
-
-static struct i2c_driver max6650_driver = {
-       .driver = {
-               .name   = "max6650",
-       },
-       .probe          = max6650_probe,
-       .remove         = max6650_remove,
-       .id_table       = max6650_id,
-};
-
 /*
  * Client data (each client gets its own)
  */
 
 struct max6650_data {
-       struct device *hwmon_dev;
+       struct i2c_client *client;
+       const struct attribute_group *groups[3];
        struct mutex update_lock;
        int nr_fans;
        char valid; /* zero until following fields are valid */
@@ -151,6 +126,51 @@ struct max6650_data {
        u8 alarm;
 };
 
+static const u8 tach_reg[] = {
+       MAX6650_REG_TACH0,
+       MAX6650_REG_TACH1,
+       MAX6650_REG_TACH2,
+       MAX6650_REG_TACH3,
+};
+
+static struct max6650_data *max6650_update_device(struct device *dev)
+{
+       struct max6650_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               data->speed = i2c_smbus_read_byte_data(client,
+                                                      MAX6650_REG_SPEED);
+               data->config = i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_CONFIG);
+               for (i = 0; i < data->nr_fans; i++) {
+                       data->tach[i] = i2c_smbus_read_byte_data(client,
+                                                                tach_reg[i]);
+               }
+               data->count = i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_COUNT);
+               data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+
+               /*
+                * Alarms are cleared on read in case the condition that
+                * caused the alarm is removed. Keep the value latched here
+                * for providing the register through different alarm files.
+                */
+               data->alarm |= i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_ALARM);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
 static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
                       char *buf)
 {
@@ -235,8 +255,8 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
 static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
                         const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6650_data *data = i2c_get_clientdata(client);
+       struct max6650_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int kscale, ktach;
        unsigned long rpm;
        int err;
@@ -304,8 +324,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
 static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
                        const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6650_data *data = i2c_get_clientdata(client);
+       struct max6650_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long pwm;
        int err;
 
@@ -350,8 +370,8 @@ static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
 static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
                          const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6650_data *data = i2c_get_clientdata(client);
+       struct max6650_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        int max6650_modes[3] = {0, 3, 2};
        unsigned long mode;
        int err;
@@ -400,8 +420,8 @@ static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
 static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
                       const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6650_data *data = i2c_get_clientdata(client);
+       struct max6650_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        unsigned long div;
        int err;
 
@@ -446,7 +466,7 @@ static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct max6650_data *data = max6650_update_device(dev);
-       struct i2c_client *client = to_i2c_client(dev);
+       struct i2c_client *client = data->client;
        int alarm = 0;
 
        if (data->alarm & attr->index) {
@@ -484,7 +504,8 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
                                    int n)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
-       struct i2c_client *client = to_i2c_client(dev);
+       struct max6650_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
        u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
        struct device_attribute *devattr;
 
@@ -519,7 +540,7 @@ static struct attribute *max6650_attrs[] = {
        NULL
 };
 
-static struct attribute_group max6650_attr_grp = {
+static const struct attribute_group max6650_group = {
        .attrs = max6650_attrs,
        .is_visible = max6650_attrs_visible,
 };
@@ -531,7 +552,7 @@ static struct attribute *max6651_attrs[] = {
        NULL
 };
 
-static const struct attribute_group max6651_attr_grp = {
+static const struct attribute_group max6651_group = {
        .attrs = max6651_attrs,
 };
 
@@ -539,74 +560,17 @@ static const struct attribute_group max6651_attr_grp = {
  * Real code
  */
 
-static int max6650_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       struct max6650_data *data;
-       int err;
-
-       data = devm_kzalloc(&client->dev, sizeof(struct max6650_data),
-                           GFP_KERNEL);
-       if (!data) {
-               dev_err(&client->dev, "out of memory.\n");
-               return -ENOMEM;
-       }
-
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-       data->nr_fans = id->driver_data;
-
-       /*
-        * Initialize the max6650 chip
-        */
-       err = max6650_init_client(client);
-       if (err)
-               return err;
-
-       err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
-       if (err)
-               return err;
-       /* 3 additional fan inputs for the MAX6651 */
-       if (data->nr_fans == 4) {
-               err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
-               if (err)
-                       goto err_remove;
-       }
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (!IS_ERR(data->hwmon_dev))
-               return 0;
-
-       err = PTR_ERR(data->hwmon_dev);
-       dev_err(&client->dev, "error registering hwmon device.\n");
-       if (data->nr_fans == 4)
-               sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
-err_remove:
-       sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
-       return err;
-}
-
-static int max6650_remove(struct i2c_client *client)
+static int max6650_init_client(struct max6650_data *data,
+                              struct i2c_client *client)
 {
-       struct max6650_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       if (data->nr_fans == 4)
-               sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
-       sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
-       return 0;
-}
-
-static int max6650_init_client(struct i2c_client *client)
-{
-       struct max6650_data *data = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
        int config;
        int err = -EIO;
 
        config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
 
        if (config < 0) {
-               dev_err(&client->dev, "Error reading config, aborting.\n");
+               dev_err(dev, "Error reading config, aborting.\n");
                return err;
        }
 
@@ -620,11 +584,11 @@ static int max6650_init_client(struct i2c_client *client)
                config |= MAX6650_CFG_V12;
                break;
        default:
-               dev_err(&client->dev, "illegal value for fan_voltage (%d)\n",
+               dev_err(dev, "illegal value for fan_voltage (%d)\n",
                        fan_voltage);
        }
 
-       dev_info(&client->dev, "Fan voltage is set to %dV.\n",
+       dev_info(dev, "Fan voltage is set to %dV.\n",
                 (config & MAX6650_CFG_V12) ? 12 : 5);
 
        switch (prescaler) {
@@ -650,11 +614,10 @@ static int max6650_init_client(struct i2c_client *client)
                         | MAX6650_CFG_PRESCALER_16;
                break;
        default:
-               dev_err(&client->dev, "illegal value for prescaler (%d)\n",
-                       prescaler);
+               dev_err(dev, "illegal value for prescaler (%d)\n", prescaler);
        }
 
-       dev_info(&client->dev, "Prescaler is set to %d.\n",
+       dev_info(dev, "Prescaler is set to %d.\n",
                 1 << (config & MAX6650_CFG_PRESCALER_MASK));
 
        /*
@@ -664,17 +627,17 @@ static int max6650_init_client(struct i2c_client *client)
         */
 
        if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
-               dev_dbg(&client->dev, "Change mode to open loop, full off.\n");
+               dev_dbg(dev, "Change mode to open loop, full off.\n");
                config = (config & ~MAX6650_CFG_MODE_MASK)
                         | MAX6650_CFG_MODE_OPEN_LOOP;
                if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
-                       dev_err(&client->dev, "DAC write error, aborting.\n");
+                       dev_err(dev, "DAC write error, aborting.\n");
                        return err;
                }
        }
 
        if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
-               dev_err(&client->dev, "Config write error, aborting.\n");
+               dev_err(dev, "Config write error, aborting.\n");
                return err;
        }
 
@@ -684,51 +647,55 @@ static int max6650_init_client(struct i2c_client *client)
        return 0;
 }
 
-static const u8 tach_reg[] = {
-       MAX6650_REG_TACH0,
-       MAX6650_REG_TACH1,
-       MAX6650_REG_TACH2,
-       MAX6650_REG_TACH3,
-};
-
-static struct max6650_data *max6650_update_device(struct device *dev)
+static int max6650_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
-       int i;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct max6650_data *data = i2c_get_clientdata(client);
-
-       mutex_lock(&data->update_lock);
+       struct device *dev = &client->dev;
+       struct max6650_data *data;
+       struct device *hwmon_dev;
+       int err;
 
-       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-               data->speed = i2c_smbus_read_byte_data(client,
-                                                      MAX6650_REG_SPEED);
-               data->config = i2c_smbus_read_byte_data(client,
-                                                       MAX6650_REG_CONFIG);
-               for (i = 0; i < data->nr_fans; i++) {
-                       data->tach[i] = i2c_smbus_read_byte_data(client,
-                                                                tach_reg[i]);
-               }
-               data->count = i2c_smbus_read_byte_data(client,
-                                                       MAX6650_REG_COUNT);
-               data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+       data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-               /*
-                * Alarms are cleared on read in case the condition that
-                * caused the alarm is removed. Keep the value latched here
-                * for providing the register through different alarm files.
-                */
-               data->alarm |= i2c_smbus_read_byte_data(client,
-                                                       MAX6650_REG_ALARM);
+       data->client = client;
+       mutex_init(&data->update_lock);
+       data->nr_fans = id->driver_data;
 
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
+       /*
+        * Initialize the max6650 chip
+        */
+       err = max6650_init_client(data, client);
+       if (err)
+               return err;
 
-       mutex_unlock(&data->update_lock);
+       data->groups[0] = &max6650_group;
+       /* 3 additional fan inputs for the MAX6651 */
+       if (data->nr_fans == 4)
+               data->groups[1] = &max6651_group;
 
-       return data;
+       hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+                                                          client->name, data,
+                                                          data->groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
+static const struct i2c_device_id max6650_id[] = {
+       { "max6650", 1 },
+       { "max6651", 4 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max6650_id);
+
+static struct i2c_driver max6650_driver = {
+       .driver = {
+               .name   = "max6650",
+       },
+       .probe          = max6650_probe,
+       .id_table       = max6650_id,
+};
+
 module_i2c_driver(max6650_driver);
 
 MODULE_AUTHOR("Hans J. Koch");
index de3c152a1d9a1f2ed011b679f04ed2f6de74308b..e24ed521051a4a1f7b799849a5c5feee1fa6b369 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880,
- * and LTC3883
+ * LTC3883, and LTM4676
  *
  * Copyright (c) 2011 Ericsson AB.
- * Copyright (c) 2013 Guenter Roeck
+ * Copyright (c) 2013, 2014 Guenter Roeck
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
@@ -28,7 +24,7 @@
 #include <linux/i2c.h>
 #include "pmbus.h"
 
-enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
+enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
 
 /* Common for all chips */
 #define LTC2978_MFR_VOUT_PEAK          0xdd
@@ -45,7 +41,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
 #define LTC2974_MFR_IOUT_PEAK          0xd7
 #define LTC2974_MFR_IOUT_MIN           0xd8
 
-/* LTC3880 and LTC3883 */
+/* LTC3880, LTC3883, and LTM4676 */
 #define LTC3880_MFR_IOUT_PEAK          0xd7
 #define LTC3880_MFR_CLEAR_PEAKS                0xe3
 #define LTC3880_MFR_TEMPERATURE2_PEAK  0xf4
@@ -53,7 +49,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
 /* LTC3883 only */
 #define LTC3883_MFR_IIN_PEAK           0xe1
 
-#define LTC2974_ID                     0x0212
+#define LTC2974_ID_REV1                        0x0212
+#define LTC2974_ID_REV2                        0x0213
 #define LTC2977_ID                     0x0130
 #define LTC2978_ID_REV1                        0x0121
 #define LTC2978_ID_REV2                        0x0122
@@ -62,6 +59,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
 #define LTC3880_ID_MASK                        0xff00
 #define LTC3883_ID                     0x4300
 #define LTC3883_ID_MASK                        0xff00
+#define LTM4676_ID                     0x4480  /* datasheet claims 0x440X */
+#define LTM4676_ID_MASK                        0xfff0
 
 #define LTC2974_NUM_PAGES              4
 #define LTC2978_NUM_PAGES              8
@@ -370,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = {
        {"ltc2978", ltc2978},
        {"ltc3880", ltc3880},
        {"ltc3883", ltc3883},
+       {"ltm4676", ltm4676},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -394,7 +394,7 @@ static int ltc2978_probe(struct i2c_client *client,
        if (chip_id < 0)
                return chip_id;
 
-       if (chip_id == LTC2974_ID) {
+       if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) {
                data->id = ltc2974;
        } else if (chip_id == LTC2977_ID) {
                data->id = ltc2977;
@@ -405,6 +405,8 @@ static int ltc2978_probe(struct i2c_client *client,
                data->id = ltc3880;
        } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
                data->id = ltc3883;
+       } else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) {
+               data->id = ltm4676;
        } else {
                dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
                return -ENODEV;
@@ -458,6 +460,7 @@ static int ltc2978_probe(struct i2c_client *client,
                }
                break;
        case ltc3880:
+       case ltm4676:
                info->read_word_data = ltc3880_read_word_data;
                info->pages = LTC3880_NUM_PAGES;
                info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
@@ -500,5 +503,5 @@ static struct i2c_driver ltc2978_driver = {
 module_i2c_driver(ltc2978_driver);
 
 MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
+MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676");
 MODULE_LICENSE("GPL");
index d9e1b7de78da7798b2a7103282ad4c7d176aaaaf..4ef5802df6d85f9a4bf9910c67f11cdebf868a36 100644 (file)
@@ -222,7 +222,7 @@ static int smm665_read_adc(struct smm665_data *data, int adc)
        rv = i2c_smbus_read_word_swapped(client, 0);
        if (rv < 0) {
                dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
-               return -1;
+               return rv;
        }
        /*
         * Validate/verify readback adc channel (in bit 11..14).
index f5ed03164d86c314942453d244f103d6e9276070..de17c5593d97c1d702563217f0932aa0a0aee6bd 100644 (file)
@@ -387,7 +387,7 @@ config I2C_CBUS_GPIO
 
 config I2C_CPM
        tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
-       depends on (CPM1 || CPM2) && OF_I2C
+       depends on CPM1 || CPM2
        help
          This supports the use of the I2C interface on Freescale
          processors with CPM1 or CPM2.
index be7f0a20d634d1107a7bb3147b32edf0256546ed..f3b89a4698b6192a24d031bab358796e51fbb767 100644 (file)
@@ -39,7 +39,9 @@
 #include <linux/i2c.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
 #include <asm/cpm.h>
index 2209f28441e94d013ef435a100c17d6920677e08..5c63f0918d12d3e077aa3e095337adb8ae7657f6 100644 (file)
@@ -155,6 +155,16 @@ config MCP3422
          This driver can also be built as a module. If so, the module will be
          called mcp3422.
 
+config MEN_Z188_ADC
+       tristate "MEN 16z188 ADC IP Core support"
+       depends on MCB
+       help
+         Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB
+         carrier.
+
+         This driver can also be built as a module. If so, the module will be
+         called men_z188_adc.
+
 config NAU7802
        tristate "Nuvoton NAU7802 ADC driver"
        depends on I2C
index ba9a10a24cd03ee4d80f4bc2e0a9fd56b106d908..85a4a045f1f0e8af4f9af1958130f1386754849c 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c
new file mode 100644 (file)
index 0000000..6989c16
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * MEN 16z188 Analog to Digial Converter
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mcb.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+#define Z188_ADC_MAX_CHAN      8
+#define Z188_ADC_GAIN          0x0700000
+#define Z188_MODE_VOLTAGE      BIT(27)
+#define Z188_CFG_AUTO          0x1
+#define Z188_CTRL_REG          0x40
+
+#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
+#define ADC_OVR(x) ((x) & 0x1)
+
+struct z188_adc {
+       struct resource *mem;
+       void __iomem *base;
+};
+
+#define Z188_ADC_CHANNEL(idx) {                                        \
+               .type = IIO_VOLTAGE,                            \
+               .indexed = 1,                                   \
+               .channel = (idx),                               \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
+}
+
+static const struct iio_chan_spec z188_adc_iio_channels[] = {
+       Z188_ADC_CHANNEL(0),
+       Z188_ADC_CHANNEL(1),
+       Z188_ADC_CHANNEL(2),
+       Z188_ADC_CHANNEL(3),
+       Z188_ADC_CHANNEL(4),
+       Z188_ADC_CHANNEL(5),
+       Z188_ADC_CHANNEL(6),
+       Z188_ADC_CHANNEL(7),
+};
+
+static int z188_iio_read_raw(struct iio_dev *iio_dev,
+                       struct iio_chan_spec const *chan,
+                       int *val,
+                       int *val2,
+                       long info)
+{
+       struct z188_adc *adc = iio_priv(iio_dev);
+       int ret;
+       u16 tmp;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               tmp = readw(adc->base + chan->channel * 4);
+
+               if (ADC_OVR(tmp)) {
+                       dev_info(&iio_dev->dev,
+                               "Oversampling error on ADC channel %d\n",
+                               chan->channel);
+                       return -EIO;
+               }
+               *val = ADC_DATA(tmp);
+               ret = IIO_VAL_INT;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static struct iio_info z188_adc_info = {
+       .read_raw = &z188_iio_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static void men_z188_config_channels(void __iomem *addr)
+{
+       int i;
+       u32 cfg;
+       u32 ctl;
+
+       ctl = readl(addr + Z188_CTRL_REG);
+       ctl |= Z188_CFG_AUTO;
+       writel(ctl, addr + Z188_CTRL_REG);
+
+       for (i = 0; i < Z188_ADC_MAX_CHAN; i++) {
+               cfg = readl(addr + i);
+               cfg &= ~Z188_ADC_GAIN;
+               cfg |= Z188_MODE_VOLTAGE;
+               writel(cfg, addr + i);
+       }
+}
+
+static int men_z188_probe(struct mcb_device *dev,
+                       const struct mcb_device_id *id)
+{
+       struct z188_adc *adc;
+       struct iio_dev *indio_dev;
+       struct resource *mem;
+
+       indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       adc = iio_priv(indio_dev);
+       indio_dev->name = "z188-adc";
+       indio_dev->dev.parent = &dev->dev;
+       indio_dev->info = &z188_adc_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = z188_adc_iio_channels;
+       indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels);
+
+       mem = mcb_request_mem(dev, "z188-adc");
+       if (!mem)
+               return -ENOMEM;
+
+       adc->base = ioremap(mem->start, resource_size(mem));
+       if (adc->base == NULL)
+               goto err;
+
+       men_z188_config_channels(adc->base);
+
+       adc->mem = mem;
+       mcb_set_drvdata(dev, indio_dev);
+
+       return iio_device_register(indio_dev);
+
+err:
+       mcb_release_mem(mem);
+       return -ENXIO;
+}
+
+static void men_z188_remove(struct mcb_device *dev)
+{
+       struct iio_dev *indio_dev  = mcb_get_drvdata(dev);
+       struct z188_adc *adc = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       iounmap(adc->base);
+       mcb_release_mem(adc->mem);
+}
+
+static const struct mcb_device_id men_z188_ids[] = {
+       { .device = 0xbc },
+};
+MODULE_DEVICE_TABLE(mcb, men_z188_ids);
+
+static struct mcb_driver men_z188_driver = {
+       .driver = {
+               .name = "z188-adc",
+               .owner = THIS_MODULE,
+       },
+       .probe = men_z188_probe,
+       .remove = men_z188_remove,
+       .id_table = men_z188_ids,
+};
+module_mcb_driver(men_z188_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
+MODULE_ALIAS("mcb:16z188");
index e81c5547e6479a87683dba621c169529f4209d5a..f9c12e92fdd661a4e639790c9b2b2dd19ba7eb36 100644 (file)
@@ -53,8 +53,8 @@
 #include "user.h"
 
 #define DRV_NAME       MLX4_IB_DRV_NAME
-#define DRV_VERSION    "1.0"
-#define DRV_RELDATE    "April 4, 2008"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb 2014"
 
 #define MLX4_IB_FLOW_MAX_PRIO 0xFFF
 #define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
index aa03e732b6a88d7cfa81a3d9ba4dee61d8f6c70d..bf900579ac08b4cae5ac09320b5189727b292485 100644 (file)
@@ -46,8 +46,8 @@
 #include "mlx5_ib.h"
 
 #define DRIVER_NAME "mlx5_ib"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
index d18d08a076e8e4a15a67f71d8eb8089dd976198d..8ee228e9ab5aa28b85ee2893a92b3ab243c35388 100644 (file)
@@ -492,12 +492,11 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        isert_conn->state = ISER_CONN_INIT;
        INIT_LIST_HEAD(&isert_conn->conn_accept_node);
        init_completion(&isert_conn->conn_login_comp);
-       init_waitqueue_head(&isert_conn->conn_wait);
-       init_waitqueue_head(&isert_conn->conn_wait_comp_err);
+       init_completion(&isert_conn->conn_wait);
+       init_completion(&isert_conn->conn_wait_comp_err);
        kref_init(&isert_conn->conn_kref);
        kref_get(&isert_conn->conn_kref);
        mutex_init(&isert_conn->conn_mutex);
-       mutex_init(&isert_conn->conn_comp_mutex);
        spin_lock_init(&isert_conn->conn_lock);
 
        cma_id->context = isert_conn;
@@ -688,11 +687,11 @@ isert_disconnect_work(struct work_struct *work)
 
        pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
        mutex_lock(&isert_conn->conn_mutex);
-       isert_conn->state = ISER_CONN_DOWN;
+       if (isert_conn->state == ISER_CONN_UP)
+               isert_conn->state = ISER_CONN_TERMINATING;
 
        if (isert_conn->post_recv_buf_count == 0 &&
            atomic_read(&isert_conn->post_send_buf_count) == 0) {
-               pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
                mutex_unlock(&isert_conn->conn_mutex);
                goto wake_up;
        }
@@ -712,7 +711,7 @@ isert_disconnect_work(struct work_struct *work)
        mutex_unlock(&isert_conn->conn_mutex);
 
 wake_up:
-       wake_up(&isert_conn->conn_wait);
+       complete(&isert_conn->conn_wait);
        isert_put_conn(isert_conn);
 }
 
@@ -888,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
         * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
         * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
         */
-       mutex_lock(&isert_conn->conn_comp_mutex);
-       if (coalesce &&
+       mutex_lock(&isert_conn->conn_mutex);
+       if (coalesce && isert_conn->state == ISER_CONN_UP &&
            ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
+               tx_desc->llnode_active = true;
                llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
-               mutex_unlock(&isert_conn->conn_comp_mutex);
+               mutex_unlock(&isert_conn->conn_mutex);
                return;
        }
        isert_conn->conn_comp_batch = 0;
        tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
-       mutex_unlock(&isert_conn->conn_comp_mutex);
+       mutex_unlock(&isert_conn->conn_mutex);
 
        send_wr->send_flags = IB_SEND_SIGNALED;
 }
@@ -1464,7 +1464,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_SCSI_CMD:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                if (cmd->data_direction == DMA_TO_DEVICE)
@@ -1476,7 +1476,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_SCSI_TMFUNC:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                transport_generic_free_cmd(&cmd->se_cmd, 0);
@@ -1486,7 +1486,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_TEXT:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                /*
@@ -1549,6 +1549,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
        iscsit_stop_dataout_timer(cmd);
        device->unreg_rdma_mem(isert_cmd, isert_conn);
        cmd->write_data_done = wr->cur_rdma_length;
+       wr->send_wr_num = 0;
 
        pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
        spin_lock_bh(&cmd->istate_lock);
@@ -1589,7 +1590,7 @@ isert_do_control_comp(struct work_struct *work)
                pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
                /*
                 * Call atomic_dec(&isert_conn->post_send_buf_count)
-                * from isert_free_conn()
+                * from isert_wait_conn()
                 */
                isert_conn->logout_posted = true;
                iscsit_logout_post_handler(cmd, cmd->conn);
@@ -1613,6 +1614,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                          struct ib_device *ib_dev)
 {
        struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
+       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
 
        if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
            cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
@@ -1624,7 +1626,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                queue_work(isert_comp_wq, &isert_cmd->comp_work);
                return;
        }
-       atomic_dec(&isert_conn->post_send_buf_count);
+       atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
 
        cmd->i_state = ISTATE_SENT_STATUS;
        isert_completion_put(tx_desc, isert_cmd, ib_dev);
@@ -1662,7 +1664,7 @@ __isert_send_completion(struct iser_tx_desc *tx_desc,
        case ISER_IB_RDMA_READ:
                pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
 
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
                isert_completion_rdma_read(tx_desc, isert_cmd);
                break;
        default:
@@ -1691,31 +1693,76 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
 }
 
 static void
-isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
+{
+       struct llist_node *llnode;
+       struct isert_rdma_wr *wr;
+       struct iser_tx_desc *t;
+
+       mutex_lock(&isert_conn->conn_mutex);
+       llnode = llist_del_all(&isert_conn->conn_comp_llist);
+       isert_conn->conn_comp_batch = 0;
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       while (llnode) {
+               t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+               llnode = llist_next(llnode);
+               wr = &t->isert_cmd->rdma_wr;
+
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+               isert_completion_put(t, t->isert_cmd, ib_dev);
+       }
+}
+
+static void
+isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
 {
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+       struct llist_node *llnode = tx_desc->comp_llnode_batch;
+       struct isert_rdma_wr *wr;
+       struct iser_tx_desc *t;
 
-       if (tx_desc) {
-               struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+       while (llnode) {
+               t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+               llnode = llist_next(llnode);
+               wr = &t->isert_cmd->rdma_wr;
 
-               if (!isert_cmd)
-                       isert_unmap_tx_desc(tx_desc, ib_dev);
-               else
-                       isert_completion_put(tx_desc, isert_cmd, ib_dev);
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+               isert_completion_put(t, t->isert_cmd, ib_dev);
        }
+       tx_desc->comp_llnode_batch = NULL;
 
-       if (isert_conn->post_recv_buf_count == 0 &&
-           atomic_read(&isert_conn->post_send_buf_count) == 0) {
-               pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-               pr_debug("Calling wake_up from isert_cq_comp_err\n");
+       if (!isert_cmd)
+               isert_unmap_tx_desc(tx_desc, ib_dev);
+       else
+               isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
 
-               mutex_lock(&isert_conn->conn_mutex);
-               if (isert_conn->state != ISER_CONN_DOWN)
-                       isert_conn->state = ISER_CONN_TERMINATING;
-               mutex_unlock(&isert_conn->conn_mutex);
+static void
+isert_cq_rx_comp_err(struct isert_conn *isert_conn)
+{
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct iscsi_conn *conn = isert_conn->conn;
 
-               wake_up(&isert_conn->conn_wait_comp_err);
+       if (isert_conn->post_recv_buf_count)
+               return;
+
+       isert_cq_drain_comp_llist(isert_conn, ib_dev);
+
+       if (conn->sess) {
+               target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+               target_wait_for_sess_cmds(conn->sess->se_sess);
        }
+
+       while (atomic_read(&isert_conn->post_send_buf_count))
+               msleep(3000);
+
+       mutex_lock(&isert_conn->conn_mutex);
+       isert_conn->state = ISER_CONN_DOWN;
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       complete(&isert_conn->conn_wait_comp_err);
 }
 
 static void
@@ -1740,8 +1787,14 @@ isert_cq_tx_work(struct work_struct *work)
                        pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
                        pr_debug("TX wc.status: 0x%08x\n", wc.status);
                        pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
-                       atomic_dec(&isert_conn->post_send_buf_count);
-                       isert_cq_comp_err(tx_desc, isert_conn);
+
+                       if (wc.wr_id != ISER_FASTREG_LI_WRID) {
+                               if (tx_desc->llnode_active)
+                                       continue;
+
+                               atomic_dec(&isert_conn->post_send_buf_count);
+                               isert_cq_tx_comp_err(tx_desc, isert_conn);
+                       }
                }
        }
 
@@ -1784,7 +1837,7 @@ isert_cq_rx_work(struct work_struct *work)
                                         wc.vendor_err);
                        }
                        isert_conn->post_recv_buf_count--;
-                       isert_cq_comp_err(NULL, isert_conn);
+                       isert_cq_rx_comp_err(isert_conn);
                }
        }
 
@@ -2202,6 +2255,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 
        if (!fr_desc->valid) {
                memset(&inv_wr, 0, sizeof(inv_wr));
+               inv_wr.wr_id = ISER_FASTREG_LI_WRID;
                inv_wr.opcode = IB_WR_LOCAL_INV;
                inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
                wr = &inv_wr;
@@ -2212,6 +2266,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 
        /* Prepare FASTREG WR */
        memset(&fr_wr, 0, sizeof(fr_wr));
+       fr_wr.wr_id = ISER_FASTREG_LI_WRID;
        fr_wr.opcode = IB_WR_FAST_REG_MR;
        fr_wr.wr.fast_reg.iova_start =
                fr_desc->data_frpl->page_list[0] + page_off;
@@ -2377,12 +2432,12 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
        isert_init_send_wr(isert_conn, isert_cmd,
                           &isert_cmd->tx_desc.send_wr, true);
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
 
        rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
        if (rc) {
                pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
        }
        pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
                 isert_cmd);
@@ -2410,12 +2465,12 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
                return rc;
        }
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);
 
        rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
        if (rc) {
                pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
        }
        pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
                 isert_cmd);
@@ -2702,22 +2757,11 @@ isert_free_np(struct iscsi_np *np)
        kfree(isert_np);
 }
 
-static int isert_check_state(struct isert_conn *isert_conn, int state)
-{
-       int ret;
-
-       mutex_lock(&isert_conn->conn_mutex);
-       ret = (isert_conn->state == state);
-       mutex_unlock(&isert_conn->conn_mutex);
-
-       return ret;
-}
-
-static void isert_free_conn(struct iscsi_conn *conn)
+static void isert_wait_conn(struct iscsi_conn *conn)
 {
        struct isert_conn *isert_conn = conn->context;
 
-       pr_debug("isert_free_conn: Starting \n");
+       pr_debug("isert_wait_conn: Starting \n");
        /*
         * Decrement post_send_buf_count for special case when called
         * from isert_do_control_comp() -> iscsit_logout_post_handler()
@@ -2727,38 +2771,29 @@ static void isert_free_conn(struct iscsi_conn *conn)
                atomic_dec(&isert_conn->post_send_buf_count);
 
        if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
-               pr_debug("Calling rdma_disconnect from isert_free_conn\n");
+               pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
                rdma_disconnect(isert_conn->conn_cm_id);
        }
        /*
         * Only wait for conn_wait_comp_err if the isert_conn made it
         * into full feature phase..
         */
-       if (isert_conn->state == ISER_CONN_UP) {
-               pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
-                        isert_conn->state);
-               mutex_unlock(&isert_conn->conn_mutex);
-
-               wait_event(isert_conn->conn_wait_comp_err,
-                         (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
-
-               wait_event(isert_conn->conn_wait,
-                         (isert_check_state(isert_conn, ISER_CONN_DOWN)));
-
-               isert_put_conn(isert_conn);
-               return;
-       }
        if (isert_conn->state == ISER_CONN_INIT) {
                mutex_unlock(&isert_conn->conn_mutex);
-               isert_put_conn(isert_conn);
                return;
        }
-       pr_debug("isert_free_conn: wait_event conn_wait %d\n",
-                isert_conn->state);
+       if (isert_conn->state == ISER_CONN_UP)
+               isert_conn->state = ISER_CONN_TERMINATING;
        mutex_unlock(&isert_conn->conn_mutex);
 
-       wait_event(isert_conn->conn_wait,
-                 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+       wait_for_completion(&isert_conn->conn_wait_comp_err);
+
+       wait_for_completion(&isert_conn->conn_wait);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+       struct isert_conn *isert_conn = conn->context;
 
        isert_put_conn(isert_conn);
 }
@@ -2771,6 +2806,7 @@ static struct iscsit_transport iser_target_transport = {
        .iscsit_setup_np        = isert_setup_np,
        .iscsit_accept_np       = isert_accept_np,
        .iscsit_free_np         = isert_free_np,
+       .iscsit_wait_conn       = isert_wait_conn,
        .iscsit_free_conn       = isert_free_conn,
        .iscsit_get_login_rx    = isert_get_login_rx,
        .iscsit_put_login_tx    = isert_put_login_tx,
index 708a069002f3530e00002c5d1e454c1823119bb4..f6ae7f5dd4082768f3b6f0dfb36c1d45506b5eb6 100644 (file)
@@ -6,6 +6,7 @@
 
 #define ISERT_RDMA_LISTEN_BACKLOG      10
 #define ISCSI_ISER_SG_TABLESIZE                256
+#define ISER_FASTREG_LI_WRID           0xffffffffffffffffULL
 
 enum isert_desc_type {
        ISCSI_TX_CONTROL,
@@ -45,6 +46,7 @@ struct iser_tx_desc {
        struct isert_cmd *isert_cmd;
        struct llist_node *comp_llnode_batch;
        struct llist_node comp_llnode;
+       bool            llnode_active;
        struct ib_send_wr send_wr;
 } __packed;
 
@@ -116,8 +118,8 @@ struct isert_conn {
        struct isert_device     *conn_device;
        struct work_struct      conn_logout_work;
        struct mutex            conn_mutex;
-       wait_queue_head_t       conn_wait;
-       wait_queue_head_t       conn_wait_comp_err;
+       struct completion       conn_wait;
+       struct completion       conn_wait_comp_err;
        struct kref             conn_kref;
        struct list_head        conn_fr_pool;
        int                     conn_fr_pool_size;
@@ -126,7 +128,6 @@ struct isert_conn {
 #define ISERT_COMP_BATCH_COUNT 8
        int                     conn_comp_batch;
        struct llist_head       conn_comp_llist;
-       struct mutex            conn_comp_mutex;
 };
 
 #define ISERT_MAX_CQ 64
index a06e12552886fa57ffbe1731eb744762666cd787..ce953d895f5b2b92d3bbb0d1a19be8a86d563d6b 100644 (file)
@@ -954,11 +954,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                        return -EFAULT;
 
                error = input_ff_upload(dev, &effect, file);
+               if (error)
+                       return error;
 
                if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
                        return -EFAULT;
 
-               return error;
+               return 0;
        }
 
        /* Multi-number variable-length handlers */
index bb3b57bea8ba4578df5d29c72230882ac29bd62a..5ef7fcf0e2509b8196cf69a993247febae4c20b7 100644 (file)
@@ -76,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
        unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
        unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
+       int val;
 
-       return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+       mutex_lock(&kpad->gpio_lock);
+
+       if (kpad->dir[bank] & bit)
+               val = kpad->dat_out[bank];
+       else
+               val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return !!(val & bit);
 }
 
 static void adp5588_gpio_set_value(struct gpio_chip *chip,
index 1f695f229ea8988001da801bb60db7b6d939f293..184c8f21ab59a9736feb262f79331cae878af1ff 100644 (file)
@@ -27,29 +27,32 @@ struct da9052_onkey {
 
 static void da9052_onkey_query(struct da9052_onkey *onkey)
 {
-       int key_stat;
+       int ret;
 
-       key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
-       if (key_stat < 0) {
+       ret = da9052_reg_read(onkey->da9052, DA9052_STATUS_A_REG);
+       if (ret < 0) {
                dev_err(onkey->da9052->dev,
-                       "Failed to read onkey event %d\n", key_stat);
+                       "Failed to read onkey event err=%d\n", ret);
        } else {
                /*
                 * Since interrupt for deassertion of ONKEY pin is not
                 * generated, onkey event state determines the onkey
                 * button state.
                 */
-               key_stat &= DA9052_EVENTB_ENONKEY;
-               input_report_key(onkey->input, KEY_POWER, key_stat);
+               bool pressed = !(ret & DA9052_STATUSA_NONKEY);
+
+               input_report_key(onkey->input, KEY_POWER, pressed);
                input_sync(onkey->input);
-       }
 
-       /*
-        * Interrupt is generated only when the ONKEY pin is asserted.
-        * Hence the deassertion of the pin is simulated through work queue.
-        */
-       if (key_stat)
-               schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+               /*
+                * Interrupt is generated only when the ONKEY pin
+                * is asserted.  Hence the deassertion of the pin
+                * is simulated through work queue.
+                */
+               if (pressed)
+                       schedule_delayed_work(&onkey->work,
+                                               msecs_to_jiffies(50));
+       }
 }
 
 static void da9052_onkey_work(struct work_struct *work)
index 87095e2f5153c7dedeae38a18cd10efaa62a9e0c..8af34ffe208b16eff1ab240de45967fb84b6610f 100644 (file)
@@ -409,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
        __clear_bit(REL_X, input->relbit);
        __clear_bit(REL_Y, input->relbit);
 
-       __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
        __set_bit(EV_KEY, input->evbit);
        __set_bit(BTN_LEFT, input->keybit);
        __set_bit(BTN_RIGHT, input->keybit);
index 26386f9d25696841584f4b7f698a3cc8727fdc54..d8d49d10f9bb60d477124bba603fb9f61be1efdb 100644 (file)
@@ -265,11 +265,22 @@ static int synaptics_identify(struct psmouse *psmouse)
  * Read touchpad resolution and maximum reported coordinates
  * Resolution is left zero if touchpad does not support the query
  */
+
+static const int *quirk_min_max;
+
 static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char resp[3];
 
+       if (quirk_min_max) {
+               priv->x_min = quirk_min_max[0];
+               priv->x_max = quirk_min_max[1];
+               priv->y_min = quirk_min_max[2];
+               priv->y_max = quirk_min_max[3];
+               return 0;
+       }
+
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
 
@@ -1485,10 +1496,54 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
        { }
 };
 
+static const struct dmi_system_id min_max_dmi_table[] __initconst = {
+#if defined(CONFIG_DMI)
+       {
+               /* Lenovo ThinkPad Helix */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
+               },
+               .driver_data = (int []){1024, 5052, 2258, 4832},
+       },
+       {
+               /* Lenovo ThinkPad X240 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
+               },
+               .driver_data = (int []){1232, 5710, 1156, 4696},
+       },
+       {
+               /* Lenovo ThinkPad T440s */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
+               },
+               .driver_data = (int []){1024, 5112, 2024, 4832},
+       },
+       {
+               /* Lenovo ThinkPad T540p */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
+               },
+               .driver_data = (int []){1024, 5056, 2058, 4832},
+       },
+#endif
+       { }
+};
+
 void __init synaptics_module_init(void)
 {
+       const struct dmi_system_id *min_max_dmi;
+
        impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
        broken_olpc_ec = dmi_check_system(olpc_dmi_table);
+
+       min_max_dmi = dmi_first_match(min_max_dmi_table);
+       if (min_max_dmi)
+               quirk_min_max = min_max_dmi->driver_data;
 }
 
 static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
index 4c842c320c2ede9f2bf42d507ee5c91f00eef7e3..b604564dec5c9a5d8d154ac18a61c02341f77e5d 100644 (file)
@@ -67,7 +67,6 @@ struct mousedev {
        struct device dev;
        struct cdev cdev;
        bool exist;
-       bool is_mixdev;
 
        struct list_head mixdev_node;
        bool opened_by_mixdev;
@@ -77,6 +76,9 @@ struct mousedev {
        int old_x[4], old_y[4];
        int frac_dx, frac_dy;
        unsigned long touch;
+
+       int (*open_device)(struct mousedev *mousedev);
+       void (*close_device)(struct mousedev *mousedev);
 };
 
 enum mousedev_emul {
@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 static struct mousedev *mousedev_mix;
 static LIST_HEAD(mousedev_mix_list);
 
-static void mixdev_open_devices(void);
-static void mixdev_close_devices(void);
-
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
 
@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
        if (retval)
                return retval;
 
-       if (mousedev->is_mixdev)
-               mixdev_open_devices();
-       else if (!mousedev->exist)
+       if (!mousedev->exist)
                retval = -ENODEV;
        else if (!mousedev->open++) {
                retval = input_open_device(&mousedev->handle);
@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
 {
        mutex_lock(&mousedev->mutex);
 
-       if (mousedev->is_mixdev)
-               mixdev_close_devices();
-       else if (mousedev->exist && !--mousedev->open)
+       if (mousedev->exist && !--mousedev->open)
                input_close_device(&mousedev->handle);
 
        mutex_unlock(&mousedev->mutex);
@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)
  * stream. Note that this function is called with mousedev_mix->mutex
  * held.
  */
-static void mixdev_open_devices(void)
+static int mixdev_open_devices(struct mousedev *mixdev)
 {
-       struct mousedev *mousedev;
+       int error;
+
+       error = mutex_lock_interruptible(&mixdev->mutex);
+       if (error)
+               return error;
 
-       if (mousedev_mix->open++)
-               return;
+       if (!mixdev->open++) {
+               struct mousedev *mousedev;
 
-       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-               if (!mousedev->opened_by_mixdev) {
-                       if (mousedev_open_device(mousedev))
-                               continue;
+               list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+                       if (!mousedev->opened_by_mixdev) {
+                               if (mousedev_open_device(mousedev))
+                                       continue;
 
-                       mousedev->opened_by_mixdev = true;
+                               mousedev->opened_by_mixdev = true;
+                       }
                }
        }
+
+       mutex_unlock(&mixdev->mutex);
+       return 0;
 }
 
 /*
@@ -481,19 +484,22 @@ static void mixdev_open_devices(void)
  * device. Note that this function is called with mousedev_mix->mutex
  * held.
  */
-static void mixdev_close_devices(void)
+static void mixdev_close_devices(struct mousedev *mixdev)
 {
-       struct mousedev *mousedev;
+       mutex_lock(&mixdev->mutex);
 
-       if (--mousedev_mix->open)
-               return;
+       if (!--mixdev->open) {
+               struct mousedev *mousedev;
 
-       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-               if (mousedev->opened_by_mixdev) {
-                       mousedev->opened_by_mixdev = false;
-                       mousedev_close_device(mousedev);
+               list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+                       if (mousedev->opened_by_mixdev) {
+                               mousedev->opened_by_mixdev = false;
+                               mousedev_close_device(mousedev);
+                       }
                }
        }
+
+       mutex_unlock(&mixdev->mutex);
 }
 
 
@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)
        mousedev_detach_client(mousedev, client);
        kfree(client);
 
-       mousedev_close_device(mousedev);
+       mousedev->close_device(mousedev);
 
        return 0;
 }
@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
        client->mousedev = mousedev;
        mousedev_attach_client(mousedev, client);
 
-       error = mousedev_open_device(mousedev);
+       error = mousedev->open_device(mousedev);
        if (error)
                goto err_free_client;
 
@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
 
        if (mixdev) {
                dev_set_name(&mousedev->dev, "mice");
+
+               mousedev->open_device = mixdev_open_devices;
+               mousedev->close_device = mixdev_close_devices;
        } else {
                int dev_no = minor;
                /* Normalize device number if it falls into legacy range */
                if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
                        dev_no -= MOUSEDEV_MINOR_BASE;
                dev_set_name(&mousedev->dev, "mouse%d", dev_no);
+
+               mousedev->open_device = mousedev_open_device;
+               mousedev->close_device = mousedev_close_device;
        }
 
        mousedev->exist = true;
-       mousedev->is_mixdev = mixdev;
        mousedev->handle.dev = input_get_device(dev);
        mousedev->handle.name = dev_name(&mousedev->dev);
        mousedev->handle.handler = handler;
@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)
        device_del(&mousedev->dev);
        mousedev_cleanup(mousedev);
        input_free_minor(MINOR(mousedev->dev.devt));
-       if (!mousedev->is_mixdev)
+       if (mousedev != mousedev_mix)
                input_unregister_handle(&mousedev->handle);
        put_device(&mousedev->dev);
 }
index 5c342b3139e8989ed737a91180cb6b3fa0f58f9c..3c0f57efe7b16154f36b7b564f4210b5cf4e88f6 100644 (file)
@@ -134,7 +134,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
        } else if (!ts->low_latency_req.dev) {
                /* First contact, request 100 us latency. */
                dev_pm_qos_add_ancestor_request(&ts->client->dev,
-                                               &ts->low_latency_req, 100);
+                                               &ts->low_latency_req,
+                                               DEV_PM_QOS_RESUME_LATENCY, 100);
        }
 
        /* SYN_REPORT */
index e400fbe411dead310bada51fb74d1475eab55bd0..cff039df056ee614ea578a2cf678c1a8b72c39e4 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
+#include <linux/irqreturn.h>
 
 /*
  * Maximum number of IOMMUs supported
index 5194afb39e781062bc6e82d55163174494fbb751..1c0c151d108c2fe40d3cf8c4bda1d0b4c4d9112c 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)  += irq-metag.o
 obj-$(CONFIG_ARCH_MOXART)              += irq-moxart.o
 obj-$(CONFIG_ORION_IRQCHIP)            += irq-orion.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sun4i.o
+obj-$(CONFIG_ARCH_SUNXI)               += irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
 obj-$(CONFIG_ARM_GIC)                  += irq-gic.o
 obj-$(CONFIG_ARM_NVIC)                 += irq-nvic.o
index 540956465ed2db759ca72eae11a26b16a4c17047..41be897df8d5521250d79dee5362c08fe0f80067 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/io.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -42,6 +43,7 @@
 #define ARMADA_370_XP_INT_SOURCE_CTL(irq)      (0x100 + irq*4)
 
 #define ARMADA_370_XP_CPU_INTACK_OFFS          (0x44)
+#define ARMADA_375_PPI_CAUSE                   (0x10)
 
 #define ARMADA_370_XP_SW_TRIG_INT_OFFS           (0x4)
 #define ARMADA_370_XP_IN_DRBEL_MSK_OFFS          (0xc)
@@ -352,7 +354,63 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
        .xlate = irq_domain_xlate_onecell,
 };
 
-static asmlinkage void __exception_irq_entry
+#ifdef CONFIG_PCI_MSI
+static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
+{
+       u32 msimask, msinr;
+
+       msimask = readl_relaxed(per_cpu_int_base +
+                               ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
+               & PCI_MSI_DOORBELL_MASK;
+
+       writel(~msimask, per_cpu_int_base +
+              ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
+
+       for (msinr = PCI_MSI_DOORBELL_START;
+            msinr < PCI_MSI_DOORBELL_END; msinr++) {
+               int irq;
+
+               if (!(msimask & BIT(msinr)))
+                       continue;
+
+               irq = irq_find_mapping(armada_370_xp_msi_domain,
+                                      msinr - 16);
+
+               if (is_chained)
+                       generic_handle_irq(irq);
+               else
+                       handle_IRQ(irq, regs);
+       }
+}
+#else
+static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
+#endif
+
+static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
+                                                 struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       unsigned long irqmap, irqn;
+       unsigned int cascade_irq;
+
+       chained_irq_enter(chip, desc);
+
+       irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
+
+       if (irqmap & BIT(0)) {
+               armada_370_xp_handle_msi_irq(NULL, true);
+               irqmap &= ~BIT(0);
+       }
+
+       for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
+               cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
+               generic_handle_irq(cascade_irq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void __exception_irq_entry
 armada_370_xp_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
@@ -372,31 +430,9 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
                        continue;
                }
 
-#ifdef CONFIG_PCI_MSI
                /* MSI handling */
-               if (irqnr == 1) {
-                       u32 msimask, msinr;
-
-                       msimask = readl_relaxed(per_cpu_int_base +
-                                               ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
-                               & PCI_MSI_DOORBELL_MASK;
-
-                       writel(~msimask, per_cpu_int_base +
-                              ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
-
-                       for (msinr = PCI_MSI_DOORBELL_START;
-                            msinr < PCI_MSI_DOORBELL_END; msinr++) {
-                               int irq;
-
-                               if (!(msimask & BIT(msinr)))
-                                       continue;
-
-                               irq = irq_find_mapping(armada_370_xp_msi_domain,
-                                                      msinr - 16);
-                               handle_IRQ(irq, regs);
-                       }
-               }
-#endif
+               if (irqnr == 1)
+                       armada_370_xp_handle_msi_irq(regs, false);
 
 #ifdef CONFIG_SMP
                /* IPI Handling */
@@ -427,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
                                             struct device_node *parent)
 {
        struct resource main_int_res, per_cpu_int_res;
+       int parent_irq;
        u32 control;
 
        BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -455,8 +492,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
 
        BUG_ON(!armada_370_xp_mpic_domain);
 
-       irq_set_default_host(armada_370_xp_mpic_domain);
-
 #ifdef CONFIG_SMP
        armada_xp_mpic_smp_cpu_init();
 
@@ -472,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
 
        armada_370_xp_msi_init(node, main_int_res.start);
 
-       set_handle_irq(armada_370_xp_handle_irq);
+       parent_irq = irq_of_parse_and_map(node, 0);
+       if (parent_irq <= 0) {
+               irq_set_default_host(armada_370_xp_mpic_domain);
+               set_handle_irq(armada_370_xp_handle_irq);
+       } else {
+               irq_set_chained_handler(parent_irq,
+                                       armada_370_xp_mpic_handle_cascade_irq);
+       }
 
        return 0;
 }
index 1693b8e7f26ad83c9686af3af7273e41c5e4af04..5916d6cdafa1c9b8b1909ce0aa77027e2ce2759f 100644 (file)
@@ -95,7 +95,7 @@ struct armctrl_ic {
 };
 
 static struct armctrl_ic intc __read_mostly;
-static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+static void __exception_irq_entry bcm2835_handle_irq(
        struct pt_regs *regs);
 
 static void armctrl_mask_irq(struct irq_data *d)
@@ -196,7 +196,7 @@ static void armctrl_handle_shortcut(int bank, struct pt_regs *regs,
        handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
 }
 
-static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+static void __exception_irq_entry bcm2835_handle_irq(
        struct pt_regs *regs)
 {
        u32 stat, irq;
index 341c6016812de0e17fbd4c1601708723409351c5..531769b2433a6dc3c305784e7836b11915f91ff2 100644 (file)
@@ -50,7 +50,7 @@
 
 union gic_base {
        void __iomem *common_base;
-       void __percpu __iomem **percpu_base;
+       void __percpu * __iomem *percpu_base;
 };
 
 struct gic_chip_data {
@@ -279,7 +279,7 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake   NULL
 #endif
 
-static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqstat, irqnr;
        struct gic_chip_data *gic = &gic_data[0];
@@ -648,7 +648,7 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
 #endif
 
 #ifdef CONFIG_SMP
-void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
        int cpu;
        unsigned long flags, map = 0;
@@ -869,7 +869,7 @@ static struct notifier_block gic_cpu_notifier = {
 };
 #endif
 
-const struct irq_domain_ops gic_irq_domain_ops = {
+static const struct irq_domain_ops gic_irq_domain_ops = {
        .map = gic_irq_domain_map,
        .xlate = gic_irq_domain_xlate,
 };
@@ -974,7 +974,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 #ifdef CONFIG_OF
 static int gic_cnt __initdata;
 
-int __init gic_of_init(struct device_node *node, struct device_node *parent)
+static int __init
+gic_of_init(struct device_node *node, struct device_node *parent)
 {
        void __iomem *cpu_base;
        void __iomem *dist_base;
index 2cb7cd0bc2f527136d8e430137436480332d2512..3c8827fe83f37544a9a5b1e8a01ae1486c7c4440 100644 (file)
@@ -194,8 +194,7 @@ static struct mmp_intc_conf mmp2_conf = {
        .conf_mask      = 0x7f,
 };
 
-static asmlinkage void __exception_irq_entry
-mmp_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
 {
        int irq, hwirq;
 
@@ -207,8 +206,7 @@ mmp_handle_irq(struct pt_regs *regs)
        handle_IRQ(irq, regs);
 }
 
-static asmlinkage void __exception_irq_entry
-mmp2_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
 {
        int irq, hwirq;
 
index 5552fc2bf28a0147550d4cb22914af9dff12d3e0..00b3cc908f762d58fd92720d73fd2e3f1cb28e3f 100644 (file)
@@ -44,7 +44,7 @@ struct moxart_irq_data {
 
 static struct moxart_irq_data intc;
 
-static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry handle_irq(struct pt_regs *regs)
 {
        u32 irqstat;
        int hwirq;
index 8e41be62812e1663df05b58f75c52ecfdc7b844f..e25f246cd2fb9a75d90ab57a4d1d1e12feb494f1 100644 (file)
@@ -30,7 +30,7 @@
 
 static struct irq_domain *orion_irq_domain;
 
-static asmlinkage void
+static void
 __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
 {
        struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
index 3a070c587ed969f426bbaa2d4141a395e1f92424..581eefe331ae44a58512680bc5462137ae6b21d4 100644 (file)
@@ -47,7 +47,7 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
        ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
 }
 
-static asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
 {
        void __iomem *base = sirfsoc_irqdomain->host_data;
        u32 irqstat, irqnr;
index a5438d8892454971b07b1f917f849de0e3e56f45..6fcef4a95a18af9462431a1d1ef39cd0f100aaa2 100644 (file)
 static void __iomem *sun4i_irq_base;
 static struct irq_domain *sun4i_irq_domain;
 
-static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
+static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
 
 static void sun4i_irq_ack(struct irq_data *irqd)
 {
        unsigned int irq = irqd_to_hwirq(irqd);
-       unsigned int irq_off = irq % 32;
-       int reg = irq / 32;
-       u32 val;
 
-       val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
-       writel(val | (1 << irq_off),
-              sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+       if (irq != 0)
+               return; /* Only IRQ 0 / the ENMI needs to be acked */
+
+       writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
 }
 
 static void sun4i_irq_mask(struct irq_data *irqd)
@@ -76,16 +74,16 @@ static void sun4i_irq_unmask(struct irq_data *irqd)
 
 static struct irq_chip sun4i_irq_chip = {
        .name           = "sun4i_irq",
-       .irq_ack        = sun4i_irq_ack,
+       .irq_eoi        = sun4i_irq_ack,
        .irq_mask       = sun4i_irq_mask,
        .irq_unmask     = sun4i_irq_unmask,
+       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
 };
 
 static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
                         irq_hw_number_t hw)
 {
-       irq_set_chip_and_handler(virq, &sun4i_irq_chip,
-                                handle_level_irq);
+       irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq);
        set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
 
        return 0;
@@ -109,7 +107,7 @@ static int __init sun4i_of_init(struct device_node *node,
        writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
        writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
 
-       /* Mask all the interrupts */
+       /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */
        writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
        writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
        writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
@@ -134,16 +132,30 @@ static int __init sun4i_of_init(struct device_node *node,
 
        return 0;
 }
-IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init);
+IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-a10-ic", sun4i_of_init);
 
-static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
 {
        u32 irq, hwirq;
 
+       /*
+        * hwirq == 0 can mean one of 3 things:
+        * 1) no more irqs pending
+        * 2) irq 0 pending
+        * 3) spurious irq
+        * So if we immediately get a reading of 0, check the irq-pending reg
+        * to differentiate between 2 and 3. We only do this once to avoid
+        * the extra check in the common case of 1 hapening after having
+        * read the vector-reg once.
+        */
        hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
-       while (hwirq != 0) {
+       if (hwirq == 0 &&
+                 !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0)))
+               return;
+
+       do {
                irq = irq_find_mapping(sun4i_irq_domain, hwirq);
                handle_IRQ(irq, regs);
                hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
-       }
+       } while (hwirq != 0);
 }
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
new file mode 100644 (file)
index 0000000..12f547a
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Allwinner A20/A31 SoCs NMI IRQ chip driver.
+ *
+ * Carlo Caione <carlo.caione@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/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip/chained_irq.h>
+#include "irqchip.h"
+
+#define SUNXI_NMI_SRC_TYPE_MASK        0x00000003
+
+enum {
+       SUNXI_SRC_TYPE_LEVEL_LOW = 0,
+       SUNXI_SRC_TYPE_EDGE_FALLING,
+       SUNXI_SRC_TYPE_LEVEL_HIGH,
+       SUNXI_SRC_TYPE_EDGE_RISING,
+};
+
+struct sunxi_sc_nmi_reg_offs {
+       u32 ctrl;
+       u32 pend;
+       u32 enable;
+};
+
+static struct sunxi_sc_nmi_reg_offs sun7i_reg_offs = {
+       .ctrl   = 0x00,
+       .pend   = 0x04,
+       .enable = 0x08,
+};
+
+static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
+       .ctrl   = 0x00,
+       .pend   = 0x04,
+       .enable = 0x34,
+};
+
+static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
+                                     u32 val)
+{
+       irq_reg_writel(val, gc->reg_base + off);
+}
+
+static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
+{
+       return irq_reg_readl(gc->reg_base + off);
+}
+
+static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_domain *domain = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_get_chip(irq);
+       unsigned int virq = irq_find_mapping(domain, 0);
+
+       chained_irq_enter(chip, desc);
+       generic_handle_irq(virq);
+       chained_irq_exit(chip, desc);
+}
+
+static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+       struct irq_chip_type *ct = gc->chip_types;
+       u32 src_type_reg;
+       u32 ctrl_off = ct->regs.type;
+       unsigned int src_type;
+       unsigned int i;
+
+       irq_gc_lock(gc);
+
+       switch (flow_type & IRQF_TRIGGER_MASK) {
+       case IRQ_TYPE_EDGE_FALLING:
+               src_type = SUNXI_SRC_TYPE_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               src_type = SUNXI_SRC_TYPE_EDGE_RISING;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               src_type = SUNXI_SRC_TYPE_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_NONE:
+       case IRQ_TYPE_LEVEL_LOW:
+               src_type = SUNXI_SRC_TYPE_LEVEL_LOW;
+               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);
+
+       for (i = 0; i <= gc->num_ct; i++, ct++)
+               if (ct->type & flow_type)
+                       ctrl_off = ct->regs.type;
+
+       src_type_reg = sunxi_sc_nmi_read(gc, ctrl_off);
+       src_type_reg &= ~SUNXI_NMI_SRC_TYPE_MASK;
+       src_type_reg |= src_type;
+       sunxi_sc_nmi_write(gc, ctrl_off, src_type_reg);
+
+       irq_gc_unlock(gc);
+
+       return IRQ_SET_MASK_OK;
+}
+
+static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
+                                       struct sunxi_sc_nmi_reg_offs *reg_offs)
+{
+       struct irq_domain *domain;
+       struct irq_chip_generic *gc;
+       unsigned int irq;
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       int ret;
+
+
+       domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL);
+       if (!domain) {
+               pr_err("%s: Could not register interrupt domain.\n", node->name);
+               return -ENOMEM;
+       }
+
+       ret = irq_alloc_domain_generic_chips(domain, 1, 2, node->name,
+                                            handle_fasteoi_irq, clr, 0,
+                                            IRQ_GC_INIT_MASK_CACHE);
+       if (ret) {
+                pr_err("%s: Could not allocate generic interrupt chip.\n",
+                        node->name);
+                goto fail_irqd_remove;
+       }
+
+       irq = irq_of_parse_and_map(node, 0);
+       if (irq <= 0) {
+               pr_err("%s: unable to parse irq\n", node->name);
+               ret = -EINVAL;
+               goto fail_irqd_remove;
+       }
+
+       gc = irq_get_domain_generic_chip(domain, 0);
+       gc->reg_base = of_iomap(node, 0);
+       if (!gc->reg_base) {
+               pr_err("%s: unable to map resource\n", node->name);
+               ret = -ENOMEM;
+               goto fail_irqd_remove;
+       }
+
+       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_eoi          = irq_gc_ack_set_bit;
+       gc->chip_types[0].chip.irq_set_type     = sunxi_sc_nmi_set_type;
+       gc->chip_types[0].chip.flags            = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
+       gc->chip_types[0].regs.ack              = reg_offs->pend;
+       gc->chip_types[0].regs.mask             = reg_offs->enable;
+       gc->chip_types[0].regs.type             = reg_offs->ctrl;
+
+       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     = sunxi_sc_nmi_set_type;
+       gc->chip_types[1].regs.ack              = reg_offs->pend;
+       gc->chip_types[1].regs.mask             = reg_offs->enable;
+       gc->chip_types[1].regs.type             = reg_offs->ctrl;
+       gc->chip_types[1].handler               = handle_edge_irq;
+
+       sunxi_sc_nmi_write(gc, reg_offs->enable, 0);
+       sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1);
+
+       irq_set_handler_data(irq, domain);
+       irq_set_chained_handler(irq, sunxi_sc_nmi_handle_irq);
+
+       return 0;
+
+fail_irqd_remove:
+       irq_domain_remove(domain);
+
+       return ret;
+}
+
+static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
+                                       struct device_node *parent)
+{
+       return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs);
+}
+IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init);
+
+static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
+                                       struct device_node *parent)
+{
+       return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
+}
+IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
index 8e21ae0bab4658a2ee2beb15a07a7a396411261f..473f09a74d4d4c53f80777f3173753e89d82b33e 100644 (file)
@@ -228,7 +228,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
  * Keep iterating over all registered VIC's until there are no pending
  * interrupts.
  */
-static asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
 {
        int i, handled;
 
index 1846e7d666819ded083bb366ed20bee1e01fafa8..eb6e91efdec8bca0babc0d098e9e11aa7b66f257 100644 (file)
@@ -178,8 +178,7 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
        .xlate = irq_domain_xlate_onecell,
 };
 
-static asmlinkage
-void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
 {
        u32 stat, i;
        int irqnr, virq;
index f693f1bc1348e1ca178add91c86cde036dda4d7b..e1c2f963289374b38a3a7bce93c930cb6565b376 100644 (file)
@@ -122,7 +122,7 @@ static int xtensa_mx_irq_retrigger(struct irq_data *d)
 static int xtensa_mx_irq_set_affinity(struct irq_data *d,
                const struct cpumask *dest, bool force)
 {
-       unsigned mask = 1u << cpumask_any(dest);
+       unsigned mask = 1u << cpumask_any_and(dest, cpu_online_mask);
 
        set_er(mask, MIROUT(d->hwirq - HW_IRQ_MX_BASE));
        return 0;
index 8ed04c4a43eef7dc2a48710b8a9107d754d757bd..ceb3a4318f73a2be0f8cad589b5e45da00becdf0 100644 (file)
@@ -50,7 +50,7 @@ static void zevio_irq_ack(struct irq_data *irqd)
        readl(gc->reg_base + regs->ack);
 }
 
-static asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
 {
        int irqnr;
 
index f496afce29deba24b782c4cc108d39b8312c2f46..cad3e24955526be2c8f745eb7dbaf1f8d5623813 100644 (file)
@@ -10,8 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/of_irq.h>
-
-#include "irqchip.h"
+#include <linux/irqchip.h>
 
 /*
  * This special of_device_id is the sentinel at the end of the
index f046865800405664ae73ec6dc761635327b7b55a..9816c51eb5c240be8c19b9c26bbd25d50fbca652 100644 (file)
@@ -16,9 +16,17 @@ config CAPI_TRACE
          This will increase the size of the kernelcapi module by 20 KB.
          If unsure, say Y.
 
+config ISDN_CAPI_CAPI20
+       tristate "CAPI2.0 /dev/capi support"
+       help
+         This option will provide the CAPI 2.0 interface to userspace
+         applications via /dev/capi20. Applications should use the
+         standardized libcapi20 to access this functionality.  You should say
+         Y/M here.
+
 config ISDN_CAPI_MIDDLEWARE
        bool "CAPI2.0 Middleware support"
-       depends on TTY
+       depends on ISDN_CAPI_CAPI20 && TTY
        help
          This option will enhance the capabilities of the /dev/capi20
          interface.  It will provide a means of moving a data connection,
@@ -26,14 +34,6 @@ config ISDN_CAPI_MIDDLEWARE
          device.  If you want to use pppd with pppdcapiplugin to dial up to
          your ISP, say Y here.
 
-config ISDN_CAPI_CAPI20
-       tristate "CAPI2.0 /dev/capi support"
-       help
-         This option will provide the CAPI 2.0 interface to userspace
-         applications via /dev/capi20. Applications should use the
-         standardized libcapi20 to access this functionality.  You should say
-         Y/M here.
-
 config ISDN_CAPI_CAPIDRV
        tristate "CAPI2.0 capidrv interface support"
        depends on ISDN_I4L
diff --git a/drivers/mcb/Kconfig b/drivers/mcb/Kconfig
new file mode 100644 (file)
index 0000000..e9a6976
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# MEN Chameleon Bus (MCB) support
+#
+
+menuconfig MCB
+          tristate "MCB support"
+          default n
+          depends on HAS_IOMEM
+          help
+
+          The MCB (MEN Chameleon Bus) is a Bus specific to MEN Mikroelektronik
+          FPGA based devices. It is used to identify MCB based IP-Cores within
+          an FPGA and provide the necessary framework for instantiating drivers
+          for these devices.
+
+          If build as a module, the module is called mcb.ko
+
+if MCB
+config MCB_PCI
+          tristate "PCI based MCB carrier"
+          default n
+          depends on PCI
+          help
+
+          This is a MCB carrier on a PCI device. Both PCI attached on-board
+          FPGAs as well as CompactPCI attached MCB FPGAs are supported with
+          this driver.
+
+          If build as a module, the module is called mcb-pci.ko
+
+endif # MCB
diff --git a/drivers/mcb/Makefile b/drivers/mcb/Makefile
new file mode 100644 (file)
index 0000000..1ae1413
--- /dev/null
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_MCB) += mcb.o
+
+mcb-y += mcb-core.o
+mcb-y += mcb-parse.o
+
+obj-$(CONFIG_MCB_PCI) += mcb-pci.o
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
new file mode 100644 (file)
index 0000000..bbe1293
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+#include <linux/mcb.h>
+
+static DEFINE_IDA(mcb_ida);
+
+static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
+                                               struct mcb_device *dev)
+{
+       if (ids) {
+               while (ids->device) {
+                       if (ids->device == dev->id)
+                               return ids;
+                       ids++;
+               }
+       }
+
+       return NULL;
+}
+
+static int mcb_match(struct device *dev, struct device_driver *drv)
+{
+       struct mcb_driver *mdrv = to_mcb_driver(drv);
+       struct mcb_device *mdev = to_mcb_device(dev);
+       const struct mcb_device_id *found_id;
+
+       found_id = mcb_match_id(mdrv->id_table, mdev);
+       if (found_id)
+               return 1;
+
+       return 0;
+}
+
+static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct mcb_device *mdev = to_mcb_device(dev);
+       int ret;
+
+       ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
+       if (ret)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int mcb_probe(struct device *dev)
+{
+       struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
+       struct mcb_device *mdev = to_mcb_device(dev);
+       const struct mcb_device_id *found_id;
+
+       found_id = mcb_match_id(mdrv->id_table, mdev);
+       if (!found_id)
+               return -ENODEV;
+
+       return mdrv->probe(mdev, found_id);
+}
+
+static int mcb_remove(struct device *dev)
+{
+       struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
+       struct mcb_device *mdev = to_mcb_device(dev);
+
+       mdrv->remove(mdev);
+
+       put_device(&mdev->dev);
+
+       return 0;
+}
+
+static void mcb_shutdown(struct device *dev)
+{
+       struct mcb_device *mdev = to_mcb_device(dev);
+       struct mcb_driver *mdrv = mdev->driver;
+
+       if (mdrv && mdrv->shutdown)
+               mdrv->shutdown(mdev);
+}
+
+static struct bus_type mcb_bus_type = {
+       .name = "mcb",
+       .match = mcb_match,
+       .uevent = mcb_uevent,
+       .probe = mcb_probe,
+       .remove = mcb_remove,
+       .shutdown = mcb_shutdown,
+};
+
+/**
+ * __mcb_register_driver() - Register a @mcb_driver at the system
+ * @drv: The @mcb_driver
+ * @owner: The @mcb_driver's module
+ * @mod_name: The name of the @mcb_driver's module
+ *
+ * Register a @mcb_driver at the system. Perform some sanity checks, if
+ * the .probe and .remove methods are provided by the driver.
+ */
+int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
+                       const char *mod_name)
+{
+       if (!drv->probe || !drv->remove)
+               return -EINVAL;
+
+       drv->driver.owner = owner;
+       drv->driver.bus = &mcb_bus_type;
+       drv->driver.mod_name = mod_name;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__mcb_register_driver);
+
+/**
+ * mcb_unregister_driver() - Unregister a @mcb_driver from the system
+ * @drv: The @mcb_driver
+ *
+ * Unregister a @mcb_driver from the system.
+ */
+void mcb_unregister_driver(struct mcb_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(mcb_unregister_driver);
+
+static void mcb_release_dev(struct device *dev)
+{
+       struct mcb_device *mdev = to_mcb_device(dev);
+
+       mcb_bus_put(mdev->bus);
+       kfree(mdev);
+}
+
+/**
+ * mcb_device_register() - Register a mcb_device
+ * @bus: The @mcb_bus of the device
+ * @dev: The @mcb_device
+ *
+ * Register a specific @mcb_device at a @mcb_bus and the system itself.
+ */
+int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
+{
+       int ret;
+       int device_id;
+
+       device_initialize(&dev->dev);
+       dev->dev.bus = &mcb_bus_type;
+       dev->dev.parent = bus->dev.parent;
+       dev->dev.release = mcb_release_dev;
+
+       device_id = dev->id;
+       dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
+               bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
+
+       ret = device_add(&dev->dev);
+       if (ret < 0) {
+               pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
+                       device_id, bus->bus_nr, ret);
+               goto out;
+       }
+
+       return 0;
+
+out:
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mcb_device_register);
+
+/**
+ * mcb_alloc_bus() - Allocate a new @mcb_bus
+ *
+ * Allocate a new @mcb_bus.
+ */
+struct mcb_bus *mcb_alloc_bus(void)
+{
+       struct mcb_bus *bus;
+       int bus_nr;
+
+       bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
+       if (!bus)
+               return NULL;
+
+       bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
+       if (bus_nr < 0) {
+               kfree(bus);
+               return ERR_PTR(bus_nr);
+       }
+
+       INIT_LIST_HEAD(&bus->children);
+       bus->bus_nr = bus_nr;
+
+       return bus;
+}
+EXPORT_SYMBOL_GPL(mcb_alloc_bus);
+
+static int __mcb_devices_unregister(struct device *dev, void *data)
+{
+       device_unregister(dev);
+       return 0;
+}
+
+static void mcb_devices_unregister(struct mcb_bus *bus)
+{
+       bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
+}
+/**
+ * mcb_release_bus() - Free a @mcb_bus
+ * @bus: The @mcb_bus to release
+ *
+ * Release an allocated @mcb_bus from the system.
+ */
+void mcb_release_bus(struct mcb_bus *bus)
+{
+       mcb_devices_unregister(bus);
+
+       ida_simple_remove(&mcb_ida, bus->bus_nr);
+
+       kfree(bus);
+}
+EXPORT_SYMBOL_GPL(mcb_release_bus);
+
+/**
+ * mcb_bus_put() - Increment refcnt
+ * @bus: The @mcb_bus
+ *
+ * Get a @mcb_bus' ref
+ */
+struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
+{
+       if (bus)
+               get_device(&bus->dev);
+
+       return bus;
+}
+EXPORT_SYMBOL_GPL(mcb_bus_get);
+
+/**
+ * mcb_bus_put() - Decrement refcnt
+ * @bus: The @mcb_bus
+ *
+ * Release a @mcb_bus' ref
+ */
+void mcb_bus_put(struct mcb_bus *bus)
+{
+       if (bus)
+               put_device(&bus->dev);
+}
+EXPORT_SYMBOL_GPL(mcb_bus_put);
+
+/**
+ * mcb_alloc_dev() - Allocate a device
+ * @bus: The @mcb_bus the device is part of
+ *
+ * Allocate a @mcb_device and add bus.
+ */
+struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
+{
+       struct mcb_device *dev;
+
+       dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       INIT_LIST_HEAD(&dev->bus_list);
+       dev->bus = bus;
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(mcb_alloc_dev);
+
+/**
+ * mcb_free_dev() - Free @mcb_device
+ * @dev: The device to free
+ *
+ * Free a @mcb_device
+ */
+void mcb_free_dev(struct mcb_device *dev)
+{
+       kfree(dev);
+}
+EXPORT_SYMBOL_GPL(mcb_free_dev);
+
+static int __mcb_bus_add_devices(struct device *dev, void *data)
+{
+       struct mcb_device *mdev = to_mcb_device(dev);
+       int retval;
+
+       if (mdev->is_added)
+               return 0;
+
+       retval = device_attach(dev);
+       if (retval < 0)
+               dev_err(dev, "Error adding device (%d)\n", retval);
+
+       mdev->is_added = true;
+
+       return 0;
+}
+
+static int __mcb_bus_add_child(struct device *dev, void *data)
+{
+       struct mcb_device *mdev = to_mcb_device(dev);
+       struct mcb_bus *child;
+
+       BUG_ON(!mdev->is_added);
+       child = mdev->subordinate;
+
+       if (child)
+               mcb_bus_add_devices(child);
+
+       return 0;
+}
+
+/**
+ * mcb_bus_add_devices() - Add devices in the bus' internal device list
+ * @bus: The @mcb_bus we add the devices
+ *
+ * Add devices in the bus' internal device list to the system.
+ */
+void mcb_bus_add_devices(const struct mcb_bus *bus)
+{
+       bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
+       bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
+
+}
+EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
+
+/**
+ * mcb_request_mem() - Request memory
+ * @dev: The @mcb_device the memory is for
+ * @name: The name for the memory reference.
+ *
+ * Request memory for a @mcb_device. If @name is NULL the driver name will
+ * be used.
+ */
+struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
+{
+       struct resource *mem;
+       u32 size;
+
+       if (!name)
+               name = dev->dev.driver->name;
+
+       size = resource_size(&dev->mem);
+
+       mem = request_mem_region(dev->mem.start, size, name);
+       if (!mem)
+               return ERR_PTR(-EBUSY);
+
+       return mem;
+}
+EXPORT_SYMBOL_GPL(mcb_request_mem);
+
+/**
+ * mcb_release_mem() - Release memory requested by device
+ * @dev: The @mcb_device that requested the memory
+ *
+ * Release memory that was prior requested via @mcb_request_mem().
+ */
+void mcb_release_mem(struct resource *mem)
+{
+       u32 size;
+
+       size = resource_size(mem);
+       release_mem_region(mem->start, size);
+}
+EXPORT_SYMBOL_GPL(mcb_release_mem);
+
+/**
+ * mcb_get_irq() - Get device's IRQ number
+ * @dev: The @mcb_device the IRQ is for
+ *
+ * Get the IRQ number of a given @mcb_device.
+ */
+int mcb_get_irq(struct mcb_device *dev)
+{
+       struct resource *irq = &dev->irq;
+
+       return irq->start;
+}
+EXPORT_SYMBOL_GPL(mcb_get_irq);
+
+static int mcb_init(void)
+{
+       return bus_register(&mcb_bus_type);
+}
+
+static void mcb_exit(void)
+{
+       bus_unregister(&mcb_bus_type);
+}
+
+/* mcb must be initialized after PCI but before the chameleon drivers.
+ * That means we must use some initcall between subsys_initcall and
+ * device_initcall.
+ */
+fs_initcall(mcb_init);
+module_exit(mcb_exit);
+
+MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mcb/mcb-internal.h b/drivers/mcb/mcb-internal.h
new file mode 100644 (file)
index 0000000..f956ef2
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __MCB_INTERNAL
+#define __MCB_INTERNAL
+
+#include <linux/types.h>
+
+#define PCI_VENDOR_ID_MEN              0x1a88
+#define PCI_DEVICE_ID_MEN_CHAMELEON    0x4d45
+#define CHAMELEON_FILENAME_LEN         12
+#define CHAMELEONV2_MAGIC              0xabce
+
+enum chameleon_descriptor_type {
+       CHAMELEON_DTYPE_GENERAL = 0x0,
+       CHAMELEON_DTYPE_BRIDGE = 0x1,
+       CHAMELEON_DTYPE_CPU = 0x2,
+       CHAMELEON_DTYPE_BAR = 0x3,
+       CHAMELEON_DTYPE_END = 0xf,
+};
+
+enum chameleon_bus_type {
+       CHAMELEON_BUS_WISHBONE,
+       CHAMELEON_BUS_AVALON,
+       CHAMELEON_BUS_LPC,
+       CHAMELEON_BUS_ISA,
+};
+
+/**
+ * struct chameleon_fpga_header
+ *
+ * @revision:  Revison of Chameleon table in FPGA
+ * @model:     Chameleon table model ASCII char
+ * @minor:     Revision minor
+ * @bus_type:  Bus type (usually %CHAMELEON_BUS_WISHBONE)
+ * @magic:     Chameleon header magic number (0xabce for version 2)
+ * @reserved:  Reserved
+ * @filename:  Filename of FPGA bitstream
+ */
+struct chameleon_fpga_header {
+       u8 revision;
+       char model;
+       u8 minor;
+       u8 bus_type;
+       u16 magic;
+       u16 reserved;
+       /* This one has no '\0' at the end!!! */
+       char filename[CHAMELEON_FILENAME_LEN];
+} __packed;
+#define HEADER_MAGIC_OFFSET 0x4
+
+/**
+ * struct chameleon_gdd - Chameleon General Device Descriptor
+ *
+ * @irq:       the position in the FPGA's IRQ controller vector
+ * @rev:       the revision of the variant's implementation
+ * @var:       the variant of the IP core
+ * @dev:       the device  the IP core is
+ * @dtype:     device descriptor type
+ * @bar:       BAR offset that must be added to module offset
+ * @inst:      the instance number of the device, 0 is first instance
+ * @group:     the group the device belongs to (0 = no group)
+ * @reserved:  reserved
+ * @offset:    beginning of the address window of desired module
+ * @size:      size of the module's address window
+ */
+struct chameleon_gdd {
+       __le32 reg1;
+       __le32 reg2;
+       __le32 offset;
+       __le32 size;
+
+} __packed;
+
+/* GDD Register 1 fields */
+#define GDD_IRQ(x) ((x) & 0x1f)
+#define GDD_REV(x) (((x) >> 5) & 0x3f)
+#define GDD_VAR(x) (((x) >> 11) & 0x3f)
+#define GDD_DEV(x) (((x) >> 18) & 0x3ff)
+#define GDD_DTY(x) (((x) >> 28) & 0xf)
+
+/* GDD Register 2 fields */
+#define GDD_BAR(x) ((x) & 0x7)
+#define GDD_INS(x) (((x) >> 3) & 0x3f)
+#define GDD_GRP(x) (((x) >> 9) & 0x3f)
+
+/**
+ * struct chameleon_bdd - Chameleon Bridge Device Descriptor
+ *
+ * @irq:       the position in the FPGA's IRQ controller vector
+ * @rev:       the revision of the variant's implementation
+ * @var:       the variant of the IP core
+ * @dev:       the device  the IP core is
+ * @dtype:     device descriptor type
+ * @bar:       BAR offset that must be added to module offset
+ * @inst:      the instance number of the device, 0 is first instance
+ * @dbar:      destination bar from the bus _behind_ the bridge
+ * @chamoff:   offset within the BAR of the source bus
+ * @offset:
+ * @size:
+ */
+struct chameleon_bdd {
+       unsigned int irq:6;
+       unsigned int rev:6;
+       unsigned int var:6;
+       unsigned int dev:10;
+       unsigned int dtype:4;
+       unsigned int bar:3;
+       unsigned int inst:6;
+       unsigned int dbar:3;
+       unsigned int group:6;
+       unsigned int reserved:14;
+       u32 chamoff;
+       u32 offset;
+       u32 size;
+} __packed;
+
+int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+                         void __iomem *base);
+
+#endif
diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c
new file mode 100644 (file)
index 0000000..d1278b5
--- /dev/null
@@ -0,0 +1,159 @@
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/mcb.h>
+
+#include "mcb-internal.h"
+
+struct mcb_parse_priv {
+       phys_addr_t mapbase;
+       void __iomem *base;
+};
+
+#define for_each_chameleon_cell(dtype, p)      \
+       for ((dtype) = get_next_dtype((p));     \
+            (dtype) != CHAMELEON_DTYPE_END;    \
+            (dtype) = get_next_dtype((p)))
+
+static inline uint32_t get_next_dtype(void __iomem *p)
+{
+       uint32_t dtype;
+
+       dtype = readl(p);
+       return dtype >> 28;
+}
+
+static int chameleon_parse_bdd(struct mcb_bus *bus,
+                       phys_addr_t mapbase,
+                       void __iomem *base)
+{
+       return 0;
+}
+
+static int chameleon_parse_gdd(struct mcb_bus *bus,
+                       phys_addr_t mapbase,
+                       void __iomem *base)
+{
+       struct chameleon_gdd __iomem *gdd =
+               (struct chameleon_gdd __iomem *) base;
+       struct mcb_device *mdev;
+       u32 offset;
+       u32 size;
+       int ret;
+       __le32 reg1;
+       __le32 reg2;
+
+       mdev = mcb_alloc_dev(bus);
+       if (!mdev)
+               return -ENOMEM;
+
+       reg1 = readl(&gdd->reg1);
+       reg2 = readl(&gdd->reg2);
+       offset = readl(&gdd->offset);
+       size = readl(&gdd->size);
+
+       mdev->id = GDD_DEV(reg1);
+       mdev->rev = GDD_REV(reg1);
+       mdev->var = GDD_VAR(reg1);
+       mdev->bar = GDD_BAR(reg1);
+       mdev->group = GDD_GRP(reg2);
+       mdev->inst = GDD_INS(reg2);
+
+       pr_debug("Found a 16z%03d\n", mdev->id);
+
+       mdev->irq.start = GDD_IRQ(reg1);
+       mdev->irq.end = GDD_IRQ(reg1);
+       mdev->irq.flags = IORESOURCE_IRQ;
+
+       mdev->mem.start = mapbase + offset;
+       mdev->mem.end = mdev->mem.start + size - 1;
+       mdev->mem.flags = IORESOURCE_MEM;
+
+       mdev->is_added = false;
+
+       ret = mcb_device_register(bus, mdev);
+       if (ret < 0)
+               goto err;
+
+       return 0;
+
+err:
+       mcb_free_dev(mdev);
+
+       return ret;
+}
+
+int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+                       void __iomem *base)
+{
+       char __iomem *p = base;
+       struct chameleon_fpga_header *header;
+       uint32_t dtype;
+       int num_cells = 0;
+       int ret = 0;
+       u32 hsize;
+
+       hsize = sizeof(struct chameleon_fpga_header);
+
+       header = kzalloc(hsize, GFP_KERNEL);
+       if (!header)
+               return -ENOMEM;
+
+       /* Extract header information */
+       memcpy_fromio(header, p, hsize);
+       /* We only support chameleon v2 at the moment */
+       header->magic = le16_to_cpu(header->magic);
+       if (header->magic != CHAMELEONV2_MAGIC) {
+               pr_err("Unsupported chameleon version 0x%x\n",
+                               header->magic);
+               kfree(header);
+               return -ENODEV;
+       }
+       p += hsize;
+
+       pr_debug("header->revision = %d\n", header->revision);
+       pr_debug("header->model = 0x%x ('%c')\n", header->model,
+               header->model);
+       pr_debug("header->minor = %d\n", header->minor);
+       pr_debug("header->bus_type = 0x%x\n", header->bus_type);
+
+
+       pr_debug("header->magic = 0x%x\n", header->magic);
+       pr_debug("header->filename = \"%.*s\"\n", CHAMELEON_FILENAME_LEN,
+               header->filename);
+
+       for_each_chameleon_cell(dtype, p) {
+               switch (dtype) {
+               case CHAMELEON_DTYPE_GENERAL:
+                       ret = chameleon_parse_gdd(bus, mapbase, p);
+                       if (ret < 0)
+                               goto out;
+                       p += sizeof(struct chameleon_gdd);
+                       break;
+               case CHAMELEON_DTYPE_BRIDGE:
+                       chameleon_parse_bdd(bus, mapbase, p);
+                       p += sizeof(struct chameleon_bdd);
+                       break;
+               case CHAMELEON_DTYPE_END:
+                       break;
+               default:
+                       pr_err("Invalid chameleon descriptor type 0x%x\n",
+                               dtype);
+                       return -EINVAL;
+               }
+               num_cells++;
+       }
+
+       if (num_cells == 0)
+               num_cells = -EINVAL;
+
+       kfree(header);
+       return num_cells;
+
+out:
+       kfree(header);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(chameleon_parse_cells);
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
new file mode 100644 (file)
index 0000000..99c742c
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/mcb.h>
+
+#include "mcb-internal.h"
+
+struct priv {
+       struct mcb_bus *bus;
+       void __iomem *base;
+};
+
+static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct priv *priv;
+       phys_addr_t mapbase;
+       int ret;
+       int num_cells;
+       unsigned long flags;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to enable PCI device\n");
+               return -ENODEV;
+       }
+
+       mapbase = pci_resource_start(pdev, 0);
+       if (!mapbase) {
+               dev_err(&pdev->dev, "No PCI resource\n");
+               goto err_start;
+       }
+
+       ret = pci_request_region(pdev, 0, KBUILD_MODNAME);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to request PCI BARs\n");
+               goto err_start;
+       }
+
+       priv->base = pci_iomap(pdev, 0, 0);
+       if (!priv->base) {
+               dev_err(&pdev->dev, "Cannot ioremap\n");
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       flags = pci_resource_flags(pdev, 0);
+       if (flags & IORESOURCE_IO) {
+               ret = -ENOTSUPP;
+               dev_err(&pdev->dev,
+                       "IO mapped PCI devices are not supported\n");
+               goto err_ioremap;
+       }
+
+       pci_set_drvdata(pdev, priv);
+
+       priv->bus = mcb_alloc_bus();
+
+       ret = chameleon_parse_cells(priv->bus, mapbase, priv->base);
+       if (ret < 0)
+               goto err_drvdata;
+       num_cells = ret;
+
+       dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
+
+       mcb_bus_add_devices(priv->bus);
+
+err_drvdata:
+       pci_iounmap(pdev, priv->base);
+err_ioremap:
+       pci_release_region(pdev, 0);
+err_start:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void mcb_pci_remove(struct pci_dev *pdev)
+{
+       struct priv *priv = pci_get_drvdata(pdev);
+
+       mcb_release_bus(priv->bus);
+}
+
+static const struct pci_device_id mcb_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },
+       { 0 },
+};
+MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);
+
+static struct pci_driver mcb_pci_driver = {
+       .name = "mcb-pci",
+       .id_table = mcb_pci_tbl,
+       .probe = mcb_pci_probe,
+       .remove = mcb_pci_remove,
+};
+
+module_pci_driver(mcb_pci_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MCB over PCI support");
index 9a06fe8837666036fe04afbde6d5e2adf8de6256..95ad936e60482477c1f87c0aa654fded90d06ba5 100644 (file)
@@ -254,16 +254,6 @@ config DM_THIN_PROVISIONING
        ---help---
          Provides thin provisioning and snapshots that share a data store.
 
-config DM_DEBUG_BLOCK_STACK_TRACING
-       boolean "Keep stack trace of persistent data block lock holders"
-       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
-       select STACKTRACE
-       ---help---
-         Enable this for messages that may help debug problems with the
-         block manager locking used by thin provisioning and caching.
-
-         If unsure, say N.
-
 config DM_CACHE
        tristate "Cache target (EXPERIMENTAL)"
        depends on BLK_DEV_DM
index 1e018e986610a57ef9f82a818aa1f70a8c364e30..0e385e40909e74fcde4da4ee5d785149101ad9cb 100644 (file)
@@ -872,7 +872,7 @@ static void mq_destroy(struct dm_cache_policy *p)
 {
        struct mq_policy *mq = to_mq_policy(p);
 
-       kfree(mq->table);
+       vfree(mq->table);
        epool_exit(&mq->cache_pool);
        epool_exit(&mq->pre_cache_pool);
        kfree(mq);
@@ -1245,7 +1245,7 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
 
        mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
        mq->hash_bits = ffs(mq->nr_buckets) - 1;
-       mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL);
+       mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
        if (!mq->table)
                goto bad_alloc_table;
 
index 1af70145fab9bcee990dd54c08224f9e16924851..074b9c8e4cf0840dd0d64014776dc297c2d82da6 100644 (file)
@@ -979,12 +979,13 @@ static void issue_copy_real(struct dm_cache_migration *mg)
        int r;
        struct dm_io_region o_region, c_region;
        struct cache *cache = mg->cache;
+       sector_t cblock = from_cblock(mg->cblock);
 
        o_region.bdev = cache->origin_dev->bdev;
        o_region.count = cache->sectors_per_block;
 
        c_region.bdev = cache->cache_dev->bdev;
-       c_region.sector = from_cblock(mg->cblock) * cache->sectors_per_block;
+       c_region.sector = cblock * cache->sectors_per_block;
        c_region.count = cache->sectors_per_block;
 
        if (mg->writeback || mg->demote) {
@@ -2464,20 +2465,18 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
        bool discarded_block;
        struct dm_bio_prison_cell *cell;
        struct policy_result lookup_result;
-       struct per_bio_data *pb;
+       struct per_bio_data *pb = init_per_bio_data(bio, pb_data_size);
 
-       if (from_oblock(block) > from_oblock(cache->origin_blocks)) {
+       if (unlikely(from_oblock(block) >= from_oblock(cache->origin_blocks))) {
                /*
                 * This can only occur if the io goes to a partial block at
                 * the end of the origin device.  We don't cache these.
                 * Just remap to the origin and carry on.
                 */
-               remap_to_origin_clear_discard(cache, bio, block);
+               remap_to_origin(cache, bio);
                return DM_MAPIO_REMAPPED;
        }
 
-       pb = init_per_bio_data(bio, pb_data_size);
-
        if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
                defer_bio(cache, bio);
                return DM_MAPIO_SUBMITTED;
index 08d9a207259afdd6fc5ef92afeb403357c1e8a1c..b428c0ae63d5d1e3c173cd0afe9b04072f786415 100644 (file)
@@ -66,7 +66,7 @@ static int dm_ulog_sendto_server(struct dm_ulog_request *tfr)
        msg->seq = tfr->seq;
        msg->len = sizeof(struct dm_ulog_request) + tfr->data_size;
 
-       r = cn_netlink_send(msg, 0, gfp_any());
+       r = cn_netlink_send(msg, 0, 0, gfp_any());
 
        return r;
 }
index afc3d017de4c6a479f418df9197a62677539752d..d6e88178d22cff0e88fb8b21cb20558f51e8d6a1 100644 (file)
@@ -546,6 +546,9 @@ static int read_exceptions(struct pstore *ps,
                r = insert_exceptions(ps, area, callback, callback_context,
                                      &full);
 
+               if (!full)
+                       memcpy(ps->area, area, ps->store->chunk_size << SECTOR_SHIFT);
+
                dm_bufio_release(bp);
 
                dm_bufio_forget(client, chunk);
index baa87ff12816382245c520a9a29ed2171d3d4d6a..fb9efc829182d4cce55c9c8cfac1e850e65abe79 100644 (file)
@@ -76,7 +76,7 @@
 
 #define THIN_SUPERBLOCK_MAGIC 27022010
 #define THIN_SUPERBLOCK_LOCATION 0
-#define THIN_VERSION 1
+#define THIN_VERSION 2
 #define THIN_METADATA_CACHE_SIZE 64
 #define SECTOR_TO_BLOCK_SHIFT 3
 
@@ -1755,3 +1755,38 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
 
        return r;
 }
+
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
+{
+       int r;
+       struct dm_block *sblock;
+       struct thin_disk_superblock *disk_super;
+
+       down_write(&pmd->root_lock);
+       pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
+
+       r = superblock_lock(pmd, &sblock);
+       if (r) {
+               DMERR("couldn't read superblock");
+               goto out;
+       }
+
+       disk_super = dm_block_data(sblock);
+       disk_super->flags = cpu_to_le32(pmd->flags);
+
+       dm_bm_unlock(sblock);
+out:
+       up_write(&pmd->root_lock);
+       return r;
+}
+
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
+{
+       bool needs_check;
+
+       down_read(&pmd->root_lock);
+       needs_check = pmd->flags & THIN_METADATA_NEEDS_CHECK_FLAG;
+       up_read(&pmd->root_lock);
+
+       return needs_check;
+}
index 82ea384d36ff9869b10864bc7e7d7f89d2bf3a4f..e3c857db195a7453d192f5f55cfb766a046a789a 100644 (file)
 
 /*----------------------------------------------------------------*/
 
+/*
+ * Thin metadata superblock flags.
+ */
+#define THIN_METADATA_NEEDS_CHECK_FLAG (1 << 0)
+
 struct dm_pool_metadata;
 struct dm_thin_device;
 
@@ -202,6 +207,12 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
                                        dm_sm_threshold_fn fn,
                                        void *context);
 
+/*
+ * Updates the superblock immediately.
+ */
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd);
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+
 /*----------------------------------------------------------------*/
 
 #endif
index 7e84baccf0ad6c90f7a3f62ec084007003319b21..be70d38745f7a7f5da51bd4ba83a29afe851b238 100644 (file)
@@ -130,10 +130,11 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
 struct dm_thin_new_mapping;
 
 /*
- * The pool runs in 3 modes.  Ordered in degraded order for comparisons.
+ * The pool runs in 4 modes.  Ordered in degraded order for comparisons.
  */
 enum pool_mode {
        PM_WRITE,               /* metadata may be changed */
+       PM_OUT_OF_DATA_SPACE,   /* metadata may be changed, though data may not be allocated */
        PM_READ_ONLY,           /* metadata may not be changed */
        PM_FAIL,                /* all I/O fails */
 };
@@ -198,7 +199,6 @@ struct pool {
 };
 
 static enum pool_mode get_pool_mode(struct pool *pool);
-static void out_of_data_space(struct pool *pool);
 static void metadata_operation_failed(struct pool *pool, const char *op, int r);
 
 /*
@@ -226,6 +226,7 @@ struct thin_c {
 
        struct pool *pool;
        struct dm_thin_device *td;
+       bool requeue_mode:1;
 };
 
 /*----------------------------------------------------------------*/
@@ -369,14 +370,18 @@ struct dm_thin_endio_hook {
        struct dm_thin_new_mapping *overwrite_mapping;
 };
 
-static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
+static void requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 {
        struct bio *bio;
        struct bio_list bios;
+       unsigned long flags;
 
        bio_list_init(&bios);
+
+       spin_lock_irqsave(&tc->pool->lock, flags);
        bio_list_merge(&bios, master);
        bio_list_init(master);
+       spin_unlock_irqrestore(&tc->pool->lock, flags);
 
        while ((bio = bio_list_pop(&bios))) {
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -391,12 +396,26 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 static void requeue_io(struct thin_c *tc)
 {
        struct pool *pool = tc->pool;
+
+       requeue_bio_list(tc, &pool->deferred_bios);
+       requeue_bio_list(tc, &pool->retry_on_resume_list);
+}
+
+static void error_retry_list(struct pool *pool)
+{
+       struct bio *bio;
        unsigned long flags;
+       struct bio_list bios;
+
+       bio_list_init(&bios);
 
        spin_lock_irqsave(&pool->lock, flags);
-       __requeue_bio_list(tc, &pool->deferred_bios);
-       __requeue_bio_list(tc, &pool->retry_on_resume_list);
+       bio_list_merge(&bios, &pool->retry_on_resume_list);
+       bio_list_init(&pool->retry_on_resume_list);
        spin_unlock_irqrestore(&pool->lock, flags);
+
+       while ((bio = bio_list_pop(&bios)))
+               bio_io_error(bio);
 }
 
 /*
@@ -925,13 +944,15 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
        }
 }
 
+static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
+
 static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
 {
        int r;
        dm_block_t free_blocks;
        struct pool *pool = tc->pool;
 
-       if (get_pool_mode(pool) != PM_WRITE)
+       if (WARN_ON(get_pool_mode(pool) != PM_WRITE))
                return -EINVAL;
 
        r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
@@ -958,7 +979,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                }
 
                if (!free_blocks) {
-                       out_of_data_space(pool);
+                       set_pool_mode(pool, PM_OUT_OF_DATA_SPACE);
                        return -ENOSPC;
                }
        }
@@ -988,15 +1009,32 @@ static void retry_on_resume(struct bio *bio)
        spin_unlock_irqrestore(&pool->lock, flags);
 }
 
-static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+static bool should_error_unserviceable_bio(struct pool *pool)
 {
-       /*
-        * When pool is read-only, no cell locking is needed because
-        * nothing is changing.
-        */
-       WARN_ON_ONCE(get_pool_mode(pool) != PM_READ_ONLY);
+       enum pool_mode m = get_pool_mode(pool);
+
+       switch (m) {
+       case PM_WRITE:
+               /* Shouldn't get here */
+               DMERR_LIMIT("bio unserviceable, yet pool is in PM_WRITE mode");
+               return true;
+
+       case PM_OUT_OF_DATA_SPACE:
+               return pool->pf.error_if_no_space;
 
-       if (pool->pf.error_if_no_space)
+       case PM_READ_ONLY:
+       case PM_FAIL:
+               return true;
+       default:
+               /* Shouldn't get here */
+               DMERR_LIMIT("bio unserviceable, yet pool has an unknown mode");
+               return true;
+       }
+}
+
+static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+{
+       if (should_error_unserviceable_bio(pool))
                bio_io_error(bio);
        else
                retry_on_resume(bio);
@@ -1007,11 +1045,20 @@ static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *c
        struct bio *bio;
        struct bio_list bios;
 
+       if (should_error_unserviceable_bio(pool)) {
+               cell_error(pool, cell);
+               return;
+       }
+
        bio_list_init(&bios);
        cell_release(pool, cell, &bios);
 
-       while ((bio = bio_list_pop(&bios)))
-               handle_unserviceable_bio(pool, bio);
+       if (should_error_unserviceable_bio(pool))
+               while ((bio = bio_list_pop(&bios)))
+                       bio_io_error(bio);
+       else
+               while ((bio = bio_list_pop(&bios)))
+                       retry_on_resume(bio);
 }
 
 static void process_discard(struct thin_c *tc, struct bio *bio)
@@ -1296,6 +1343,11 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
        }
 }
 
+static void process_bio_success(struct thin_c *tc, struct bio *bio)
+{
+       bio_endio(bio, 0);
+}
+
 static void process_bio_fail(struct thin_c *tc, struct bio *bio)
 {
        bio_io_error(bio);
@@ -1328,6 +1380,11 @@ static void process_deferred_bios(struct pool *pool)
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
                struct thin_c *tc = h->tc;
 
+               if (tc->requeue_mode) {
+                       bio_endio(bio, DM_ENDIO_REQUEUE);
+                       continue;
+               }
+
                /*
                 * If we've got no free new_mapping structs, and processing
                 * this bio might require one, we pause until there are some
@@ -1394,51 +1451,134 @@ static void do_waker(struct work_struct *ws)
 
 /*----------------------------------------------------------------*/
 
+struct noflush_work {
+       struct work_struct worker;
+       struct thin_c *tc;
+
+       atomic_t complete;
+       wait_queue_head_t wait;
+};
+
+static void complete_noflush_work(struct noflush_work *w)
+{
+       atomic_set(&w->complete, 1);
+       wake_up(&w->wait);
+}
+
+static void do_noflush_start(struct work_struct *ws)
+{
+       struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+       w->tc->requeue_mode = true;
+       requeue_io(w->tc);
+       complete_noflush_work(w);
+}
+
+static void do_noflush_stop(struct work_struct *ws)
+{
+       struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+       w->tc->requeue_mode = false;
+       complete_noflush_work(w);
+}
+
+static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
+{
+       struct noflush_work w;
+
+       INIT_WORK(&w.worker, fn);
+       w.tc = tc;
+       atomic_set(&w.complete, 0);
+       init_waitqueue_head(&w.wait);
+
+       queue_work(tc->pool->wq, &w.worker);
+
+       wait_event(w.wait, atomic_read(&w.complete));
+}
+
+/*----------------------------------------------------------------*/
+
 static enum pool_mode get_pool_mode(struct pool *pool)
 {
        return pool->pf.mode;
 }
 
+static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode)
+{
+       dm_table_event(pool->ti->table);
+       DMINFO("%s: switching pool to %s mode",
+              dm_device_name(pool->pool_md), new_mode);
+}
+
 static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
 {
-       int r;
-       enum pool_mode old_mode = pool->pf.mode;
+       struct pool_c *pt = pool->ti->private;
+       bool needs_check = dm_pool_metadata_needs_check(pool->pmd);
+       enum pool_mode old_mode = get_pool_mode(pool);
+
+       /*
+        * Never allow the pool to transition to PM_WRITE mode if user
+        * intervention is required to verify metadata and data consistency.
+        */
+       if (new_mode == PM_WRITE && needs_check) {
+               DMERR("%s: unable to switch pool to write mode until repaired.",
+                     dm_device_name(pool->pool_md));
+               if (old_mode != new_mode)
+                       new_mode = old_mode;
+               else
+                       new_mode = PM_READ_ONLY;
+       }
+       /*
+        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
+        * not going to recover without a thin_repair.  So we never let the
+        * pool move out of the old mode.
+        */
+       if (old_mode == PM_FAIL)
+               new_mode = old_mode;
 
        switch (new_mode) {
        case PM_FAIL:
                if (old_mode != new_mode)
-                       DMERR("%s: switching pool to failure mode",
-                             dm_device_name(pool->pool_md));
+                       notify_of_pool_mode_change(pool, "failure");
                dm_pool_metadata_read_only(pool->pmd);
                pool->process_bio = process_bio_fail;
                pool->process_discard = process_bio_fail;
                pool->process_prepared_mapping = process_prepared_mapping_fail;
                pool->process_prepared_discard = process_prepared_discard_fail;
+
+               error_retry_list(pool);
                break;
 
        case PM_READ_ONLY:
                if (old_mode != new_mode)
-                       DMERR("%s: switching pool to read-only mode",
-                             dm_device_name(pool->pool_md));
-               r = dm_pool_abort_metadata(pool->pmd);
-               if (r) {
-                       DMERR("%s: aborting transaction failed",
-                             dm_device_name(pool->pool_md));
-                       new_mode = PM_FAIL;
-                       set_pool_mode(pool, new_mode);
-               } else {
-                       dm_pool_metadata_read_only(pool->pmd);
-                       pool->process_bio = process_bio_read_only;
-                       pool->process_discard = process_discard;
-                       pool->process_prepared_mapping = process_prepared_mapping_fail;
-                       pool->process_prepared_discard = process_prepared_discard_passdown;
-               }
+                       notify_of_pool_mode_change(pool, "read-only");
+               dm_pool_metadata_read_only(pool->pmd);
+               pool->process_bio = process_bio_read_only;
+               pool->process_discard = process_bio_success;
+               pool->process_prepared_mapping = process_prepared_mapping_fail;
+               pool->process_prepared_discard = process_prepared_discard_passdown;
+
+               error_retry_list(pool);
+               break;
+
+       case PM_OUT_OF_DATA_SPACE:
+               /*
+                * Ideally we'd never hit this state; the low water mark
+                * would trigger userland to extend the pool before we
+                * completely run out of data space.  However, many small
+                * IOs to unprovisioned space can consume data space at an
+                * alarming rate.  Adjust your low water mark if you're
+                * frequently seeing this mode.
+                */
+               if (old_mode != new_mode)
+                       notify_of_pool_mode_change(pool, "out-of-data-space");
+               pool->process_bio = process_bio_read_only;
+               pool->process_discard = process_discard;
+               pool->process_prepared_mapping = process_prepared_mapping;
+               pool->process_prepared_discard = process_prepared_discard_passdown;
                break;
 
        case PM_WRITE:
                if (old_mode != new_mode)
-                       DMINFO("%s: switching pool to write mode",
-                              dm_device_name(pool->pool_md));
+                       notify_of_pool_mode_change(pool, "write");
                dm_pool_metadata_read_write(pool->pmd);
                pool->process_bio = process_bio;
                pool->process_discard = process_discard;
@@ -1448,32 +1588,35 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
        }
 
        pool->pf.mode = new_mode;
+       /*
+        * The pool mode may have changed, sync it so bind_control_target()
+        * doesn't cause an unexpected mode transition on resume.
+        */
+       pt->adjusted_pf.mode = new_mode;
 }
 
-/*
- * Rather than calling set_pool_mode directly, use these which describe the
- * reason for mode degradation.
- */
-static void out_of_data_space(struct pool *pool)
+static void abort_transaction(struct pool *pool)
 {
-       DMERR_LIMIT("%s: no free data space available.",
-                   dm_device_name(pool->pool_md));
-       set_pool_mode(pool, PM_READ_ONLY);
+       const char *dev_name = dm_device_name(pool->pool_md);
+
+       DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
+       if (dm_pool_abort_metadata(pool->pmd)) {
+               DMERR("%s: failed to abort metadata transaction", dev_name);
+               set_pool_mode(pool, PM_FAIL);
+       }
+
+       if (dm_pool_metadata_set_needs_check(pool->pmd)) {
+               DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+               set_pool_mode(pool, PM_FAIL);
+       }
 }
 
 static void metadata_operation_failed(struct pool *pool, const char *op, int r)
 {
-       dm_block_t free_blocks;
-
        DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
                    dm_device_name(pool->pool_md), op, r);
 
-       if (r == -ENOSPC &&
-           !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
-           !free_blocks)
-               DMERR_LIMIT("%s: no free metadata space available.",
-                           dm_device_name(pool->pool_md));
-
+       abort_transaction(pool);
        set_pool_mode(pool, PM_READ_ONLY);
 }
 
@@ -1524,6 +1667,11 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
 
        thin_hook_bio(tc, bio);
 
+       if (tc->requeue_mode) {
+               bio_endio(bio, DM_ENDIO_REQUEUE);
+               return DM_MAPIO_SUBMITTED;
+       }
+
        if (get_pool_mode(tc->pool) == PM_FAIL) {
                bio_io_error(bio);
                return DM_MAPIO_SUBMITTED;
@@ -1687,7 +1835,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        /*
         * We want to make sure that a pool in PM_FAIL mode is never upgraded.
         */
-       enum pool_mode old_mode = pool->pf.mode;
+       enum pool_mode old_mode = get_pool_mode(pool);
        enum pool_mode new_mode = pt->adjusted_pf.mode;
 
        /*
@@ -1701,16 +1849,6 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        pool->pf = pt->adjusted_pf;
        pool->low_water_blocks = pt->low_water_blocks;
 
-       /*
-        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
-        * not going to recover without a thin_repair.  So we never let the
-        * pool move out of the old mode.  On the other hand a PM_READ_ONLY
-        * may have been due to a lack of metadata or data space, and may
-        * now work (ie. if the underlying devices have been resized).
-        */
-       if (old_mode == PM_FAIL)
-               new_mode = old_mode;
-
        set_pool_mode(pool, new_mode);
 
        return 0;
@@ -2253,6 +2391,12 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
                return -EINVAL;
 
        } else if (data_size > sb_data_size) {
+               if (dm_pool_metadata_needs_check(pool->pmd)) {
+                       DMERR("%s: unable to grow the data device until repaired.",
+                             dm_device_name(pool->pool_md));
+                       return 0;
+               }
+
                if (sb_data_size)
                        DMINFO("%s: growing the data device from %llu to %llu blocks",
                               dm_device_name(pool->pool_md),
@@ -2294,6 +2438,12 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
                return -EINVAL;
 
        } else if (metadata_dev_size > sb_metadata_dev_size) {
+               if (dm_pool_metadata_needs_check(pool->pmd)) {
+                       DMERR("%s: unable to grow the metadata device until repaired.",
+                             dm_device_name(pool->pool_md));
+                       return 0;
+               }
+
                warn_if_metadata_device_too_big(pool->md_dev);
                DMINFO("%s: growing the metadata device from %llu to %llu blocks",
                       dm_device_name(pool->pool_md),
@@ -2681,7 +2831,9 @@ static void pool_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("- ");
 
-               if (pool->pf.mode == PM_READ_ONLY)
+               if (pool->pf.mode == PM_OUT_OF_DATA_SPACE)
+                       DMEMIT("out_of_data_space ");
+               else if (pool->pf.mode == PM_READ_ONLY)
                        DMEMIT("ro ");
                else
                        DMEMIT("rw ");
@@ -2795,7 +2947,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2997,10 +3149,23 @@ static int thin_endio(struct dm_target *ti, struct bio *bio, int err)
        return 0;
 }
 
-static void thin_postsuspend(struct dm_target *ti)
+static void thin_presuspend(struct dm_target *ti)
 {
+       struct thin_c *tc = ti->private;
+
        if (dm_noflush_suspending(ti))
-               requeue_io((struct thin_c *)ti->private);
+               noflush_work(tc, do_noflush_start);
+}
+
+static void thin_postsuspend(struct dm_target *ti)
+{
+       struct thin_c *tc = ti->private;
+
+       /*
+        * The dm_noflush_suspending flag has been cleared by now, so
+        * unfortunately we must always run this.
+        */
+       noflush_work(tc, do_noflush_stop);
 }
 
 /*
@@ -3085,12 +3250,13 @@ static int thin_iterate_devices(struct dm_target *ti,
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
        .map = thin_map,
        .end_io = thin_endio,
+       .presuspend = thin_presuspend,
        .postsuspend = thin_postsuspend,
        .status = thin_status,
        .iterate_devices = thin_iterate_devices,
index 19b268795415b4a1eaf519001511275774a7f96e..0c2dec7aec20fd798d45b24d92156b3f85f4aae0 100644 (file)
@@ -6,3 +6,13 @@ config DM_PERSISTENT_DATA
        ---help---
         Library providing immutable on-disk data structure support for
         device-mapper targets such as the thin provisioning target.
+
+config DM_DEBUG_BLOCK_STACK_TRACING
+       boolean "Keep stack trace of persistent data block lock holders"
+       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
+       select STACKTRACE
+       ---help---
+        Enable this for messages that may help debug problems with the
+        block manager locking used by thin provisioning and caching.
+
+        If unsure, say N.
index e9bdd462f4f51a7cdcf917c6abbac85a80f58eaf..786b689bdfc7fe0c42d9a651a2369ffadcdc2382 100644 (file)
@@ -91,6 +91,69 @@ struct block_op {
        dm_block_t block;
 };
 
+struct bop_ring_buffer {
+       unsigned begin;
+       unsigned end;
+       struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
+};
+
+static void brb_init(struct bop_ring_buffer *brb)
+{
+       brb->begin = 0;
+       brb->end = 0;
+}
+
+static bool brb_empty(struct bop_ring_buffer *brb)
+{
+       return brb->begin == brb->end;
+}
+
+static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
+{
+       unsigned r = old + 1;
+       return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r;
+}
+
+static int brb_push(struct bop_ring_buffer *brb,
+                   enum block_op_type type, dm_block_t b)
+{
+       struct block_op *bop;
+       unsigned next = brb_next(brb, brb->end);
+
+       /*
+        * We don't allow the last bop to be filled, this way we can
+        * differentiate between full and empty.
+        */
+       if (next == brb->begin)
+               return -ENOMEM;
+
+       bop = brb->bops + brb->end;
+       bop->type = type;
+       bop->block = b;
+
+       brb->end = next;
+
+       return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+{
+       struct block_op *bop;
+
+       if (brb_empty(brb))
+               return -ENODATA;
+
+       bop = brb->bops + brb->begin;
+       result->type = bop->type;
+       result->block = bop->block;
+
+       brb->begin = brb_next(brb, brb->begin);
+
+       return 0;
+}
+
+/*----------------------------------------------------------------*/
+
 struct sm_metadata {
        struct dm_space_map sm;
 
@@ -101,25 +164,20 @@ struct sm_metadata {
 
        unsigned recursion_count;
        unsigned allocated_this_transaction;
-       unsigned nr_uncommitted;
-       struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS];
+       struct bop_ring_buffer uncommitted;
 
        struct threshold threshold;
 };
 
 static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
 {
-       struct block_op *op;
+       int r = brb_push(&smm->uncommitted, type, b);
 
-       if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) {
+       if (r) {
                DMERR("too many recursive allocations");
                return -ENOMEM;
        }
 
-       op = smm->uncommitted + smm->nr_uncommitted++;
-       op->type = type;
-       op->block = b;
-
        return 0;
 }
 
@@ -158,11 +216,17 @@ static int out(struct sm_metadata *smm)
                return -ENOMEM;
        }
 
-       if (smm->recursion_count == 1 && smm->nr_uncommitted) {
-               while (smm->nr_uncommitted && !r) {
-                       smm->nr_uncommitted--;
-                       r = commit_bop(smm, smm->uncommitted +
-                                      smm->nr_uncommitted);
+       if (smm->recursion_count == 1) {
+               while (!brb_empty(&smm->uncommitted)) {
+                       struct block_op bop;
+
+                       r = brb_pop(&smm->uncommitted, &bop);
+                       if (r) {
+                               DMERR("bug in bop ring buffer");
+                               break;
+                       }
+
+                       r = commit_bop(smm, &bop);
                        if (r)
                                break;
                }
@@ -217,7 +281,8 @@ static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
 static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
                                 uint32_t *result)
 {
-       int r, i;
+       int r;
+       unsigned i;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        unsigned adjustment = 0;
 
@@ -225,8 +290,10 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
         * We may have some uncommitted adjustments to add.  This list
         * should always be really short.
         */
-       for (i = 0; i < smm->nr_uncommitted; i++) {
-               struct block_op *op = smm->uncommitted + i;
+       for (i = smm->uncommitted.begin;
+            i != smm->uncommitted.end;
+            i = brb_next(&smm->uncommitted, i)) {
+               struct block_op *op = smm->uncommitted.bops + i;
 
                if (op->block != b)
                        continue;
@@ -254,7 +321,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
 static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
                                              dm_block_t b, int *result)
 {
-       int r, i, adjustment = 0;
+       int r, adjustment = 0;
+       unsigned i;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        uint32_t rc;
 
@@ -262,8 +330,11 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
         * We may have some uncommitted adjustments to add.  This list
         * should always be really short.
         */
-       for (i = 0; i < smm->nr_uncommitted; i++) {
-               struct block_op *op = smm->uncommitted + i;
+       for (i = smm->uncommitted.begin;
+            i != smm->uncommitted.end;
+            i = brb_next(&smm->uncommitted, i)) {
+
+               struct block_op *op = smm->uncommitted.bops + i;
 
                if (op->block != b)
                        continue;
@@ -671,7 +742,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        smm->begin = superblock + 1;
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
-       smm->nr_uncommitted = 0;
+       brb_init(&smm->uncommitted);
        threshold_init(&smm->threshold);
 
        memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
@@ -715,7 +786,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm,
        smm->begin = 0;
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
-       smm->nr_uncommitted = 0;
+       brb_init(&smm->uncommitted);
        threshold_init(&smm->threshold);
 
        memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
index b2c8c3439fea88ca441c435cfcb4d04387d997db..ea272bcb38df14e086f226fe024ec17e0ef98574 100644 (file)
@@ -145,11 +145,12 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev)
        /* This is a no-op for us.  We'll use the cx->instance */
 
        /* (2) Create a card instance */
-       ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
-                             SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
-                             THIS_MODULE, 0, &sc);
+       ret = snd_card_new(&cx->pci_dev->dev,
+                          SNDRV_DEFAULT_IDX1, /* use first available id */
+                          SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+                          THIS_MODULE, 0, &sc);
        if (ret) {
-               CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+               CX18_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
                              __func__, ret);
                goto err_exit;
        }
index c6c9bd58f8be87426ed63200cfc729428e7b417b..554798dcedd09b3a1ad86961b2fd5fde691df254 100644 (file)
@@ -489,7 +489,8 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
                return NULL;
        }
 
-       err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+       err = snd_card_new(&dev->pci->dev,
+                          SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);
        if (err < 0)
                goto error;
@@ -500,8 +501,6 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
        chip->card = card;
        spin_lock_init(&chip->lock);
 
-       snd_card_set_dev(card, &dev->pci->dev);
-
        err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");
        if (err < 0)
                goto error;
index b1e08c3e55cd5561d286700f470adcaf3e182776..2dd5bcaa7e53c4b80868b24f15683e5d07580819 100644 (file)
@@ -645,8 +645,9 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
                return -ENOENT;
        }
 
-       err = snd_card_create(index[devno], id[devno], THIS_MODULE,
-                       sizeof(struct cx25821_audio_dev), &card);
+       err = snd_card_new(&dev->pci->dev, index[devno], id[devno],
+                          THIS_MODULE,
+                          sizeof(struct cx25821_audio_dev), &card);
        if (err < 0) {
                pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
                        __func__);
@@ -682,8 +683,6 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
                goto error;
        }
 
-       snd_card_set_dev(card, &chip->pci->dev);
-
        strcpy(card->shortname, "cx25821");
        sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name,
                chip->iobase, chip->irq);
index d014206e71762799ad007ce676af13cef333566a..a72579a9f67f15d8c2e1640f57719c32787fc00a 100644 (file)
@@ -852,8 +852,6 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
        chip->irq = pci->irq;
        synchronize_irq(chip->irq);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        *core_ptr = core;
 
@@ -876,8 +874,8 @@ static int cx88_audio_initdev(struct pci_dev *pci,
                return (-ENOENT);
        }
 
-       err = snd_card_create(index[devno], id[devno], THIS_MODULE,
-                             sizeof(snd_cx88_card_t), &card);
+       err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,
+                          sizeof(snd_cx88_card_t), &card);
        if (err < 0)
                return err;
 
index e970cface70edfaea231213ddafd983d379630f4..39b52929755aca482839c01f46f4fd2251183bd6 100644 (file)
@@ -145,11 +145,12 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev)
        /* This is a no-op for us.  We'll use the itv->instance */
 
        /* (2) Create a card instance */
-       ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
-                             SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
-                             THIS_MODULE, 0, &sc);
+       ret = snd_card_new(&itv->pdev->dev,
+                          SNDRV_DEFAULT_IDX1, /* use first available id */
+                          SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+                          THIS_MODULE, 0, &sc);
        if (ret) {
-               IVTV_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+               IVTV_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
                              __func__, ret);
                goto err_exit;
        }
index dd67c8a400cc5d02f20b33967d27c9698846355b..e04a4d5d66722192a9b6e1452d51ba822a803c55 100644 (file)
@@ -1072,8 +1072,8 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
        if (!enable[devnum])
                return -ENODEV;
 
-       err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
-                             sizeof(snd_card_saa7134_t), &card);
+       err = snd_card_new(&dev->pci->dev, index[devnum], id[devnum],
+                          THIS_MODULE, sizeof(snd_card_saa7134_t), &card);
        if (err < 0)
                return err;
 
@@ -1115,8 +1115,6 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
        if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
                goto __nodev;
 
-       snd_card_set_dev(card, &chip->pci->dev);
-
        /* End of "creation" */
 
        strcpy(card->shortname, "SAA7134");
index 81a1d971d797e449e0fc2a08c8f5d7511b5ae6c5..9b925874d392de05a7c44e3192aa8953e68c5a27 100644 (file)
@@ -665,8 +665,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
        cx231xx_info("cx231xx-audio.c: probing for cx231xx "
                     "non standard usbaudio\n");
 
-       err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE,
-                             0, &card);
+       err = snd_card_new(&dev->udev->dev, index[devnr], "Cx231xx Audio",
+                          THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -682,7 +682,6 @@ static int cx231xx_audio_init(struct cx231xx *dev)
        pcm->info_flags = 0;
        pcm->private_data = dev;
        strcpy(pcm->name, "Conexant cx231xx Capture");
-       snd_card_set_dev(card, &dev->udev->dev);
        strcpy(card->driver, "Cx231xx-Audio");
        strcpy(card->shortname, "Cx231xx Audio");
        strcpy(card->longname, "Conexant cx231xx Audio");
index 05e9bd11a3ff016128e6c9dd05e1086cd454ce0e..1a28897af1831d1ebfc8e101a25e71e5732ba1a3 100644 (file)
@@ -900,8 +900,8 @@ static int em28xx_audio_init(struct em28xx *dev)
        printk(KERN_INFO
               "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
 
-       err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
-                             &card);
+       err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio",
+                          THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -918,7 +918,6 @@ static int em28xx_audio_init(struct em28xx *dev)
        pcm->private_data = dev;
        strcpy(pcm->name, "Empia 28xx Capture");
 
-       snd_card_set_dev(card, &dev->udev->dev);
        strcpy(card->driver, "Em28xx-Audio");
        strcpy(card->shortname, "Em28xx Audio");
        strcpy(card->longname, "Empia Em28xx Audio");
index c8583c262c3d0b6f055cdf73a77e7d78037e2929..c46c8be896029534f2b08228eee825247398995d 100644 (file)
@@ -98,13 +98,11 @@ int stk1160_ac97_register(struct stk1160 *dev)
         * Just want a card to access ac96 controls,
         * the actual capture interface will be handled by snd-usb-audio
         */
-       rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                             THIS_MODULE, 0, &card);
+       rc = snd_card_new(dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                         THIS_MODULE, 0, &card);
        if (rc < 0)
                return rc;
 
-       snd_card_set_dev(card, dev->dev);
-
        /* TODO: I'm not sure where should I get these names :-( */
        snprintf(card->shortname, sizeof(card->shortname),
                 "stk1160-mixer");
index 3f3e141f70fb963547074f47a867e79ff4664e49..dd8fe100590ff88d6d202c7ecc112bb469e2bfac 100644 (file)
@@ -300,7 +300,8 @@ int poseidon_audio_init(struct poseidon *p)
        struct snd_pcm *pcm;
        int ret;
 
-       ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
+       ret = snd_card_new(&p->interface->dev, -1, "Telegent",
+                          THIS_MODULE, 0, &card);
        if (ret != 0)
                return ret;
 
index 813c1ec5360884274f5d3e31e66f9d38d91d0753..3239cd62e4529e57d1af2fbf074fffd0539bc2d9 100644 (file)
@@ -431,7 +431,8 @@ static int tm6000_audio_init(struct tm6000_core *dev)
        if (!enable[devnr])
                return -ENOENT;
 
-       rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+       rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000",
+                         THIS_MODULE, 0, &card);
        if (rc < 0) {
                snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
                return rc;
@@ -445,7 +446,6 @@ static int tm6000_audio_init(struct tm6000_core *dev)
                le16_to_cpu(dev->udev->descriptor.idVendor),
                le16_to_cpu(dev->udev->descriptor.idProduct));
        snd_component_add(card, component);
-       snd_card_set_dev(card, &dev->udev->dev);
 
        chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
        if (!chip) {
index 29a11db365bc5e6bae120a28bb92914f6b4ca990..c59e9c96e86d131033d702c72468b08cb71bd4db 100644 (file)
@@ -7,6 +7,17 @@ menuconfig MEMORY
 
 if MEMORY
 
+config TI_AEMIF
+       tristate "Texas Instruments AEMIF driver"
+       depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
+       help
+         This driver is for the AEMIF module available in Texas Instruments
+         SoCs. AEMIF stands for Asynchronous External Memory Interface and
+         is intended to provide a glue-less interface to a variety of
+         asynchronuous memory devices like ASRAM, NOR and NAND memory. A total
+         of 256M bytes of any of these memories can be accessed at a given
+         time via four chip selects with 64M byte access per chip select.
+
 config TI_EMIF
        tristate "Texas Instruments EMIF driver"
        depends on ARCH_OMAP2PLUS
@@ -50,4 +61,8 @@ config TEGRA30_MC
          analysis, especially for IOMMU/SMMU(System Memory Management
          Unit) module.
 
+config FSL_IFC
+       bool
+       depends on FSL_SOC
+
 endif
index 969d923dad93399b8d672f6077941c1dea0e3b3e..71160a2b7313613bd7b366222a413ba92e7bd471 100644 (file)
@@ -5,7 +5,9 @@
 ifeq ($(CONFIG_DDR),y)
 obj-$(CONFIG_OF)               += of_memory.o
 endif
+obj-$(CONFIG_TI_AEMIF)         += ti-aemif.o
 obj-$(CONFIG_TI_EMIF)          += emif.o
+obj-$(CONFIG_FSL_IFC)          += fsl_ifc.o
 obj-$(CONFIG_MVEBU_DEVBUS)     += mvebu-devbus.o
 obj-$(CONFIG_TEGRA20_MC)       += tegra20-mc.o
 obj-$(CONFIG_TEGRA30_MC)       += tegra30-mc.o
diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
new file mode 100644 (file)
index 0000000..3d5d792
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Freescale Integrated Flash Controller
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_ifc.h>
+#include <asm/prom.h>
+
+struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
+EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
+
+/*
+ * convert_ifc_address - convert the base address
+ * @addr_base: base address of the memory bank
+ */
+unsigned int convert_ifc_address(phys_addr_t addr_base)
+{
+       return addr_base & CSPR_BA;
+}
+EXPORT_SYMBOL(convert_ifc_address);
+
+/*
+ * fsl_ifc_find - find IFC bank
+ * @addr_base: base address of the memory bank
+ *
+ * This function walks IFC banks comparing "Base address" field of the CSPR
+ * registers with the supplied addr_base argument. When bases match this
+ * function returns bank number (starting with 0), otherwise it returns
+ * appropriate errno value.
+ */
+int fsl_ifc_find(phys_addr_t addr_base)
+{
+       int i = 0;
+
+       if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+               return -ENODEV;
+
+       for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) {
+               u32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
+               if (cspr & CSPR_V && (cspr & CSPR_BA) ==
+                               convert_ifc_address(addr_base))
+                       return i;
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(fsl_ifc_find);
+
+static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
+{
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+       /*
+        * Clear all the common status and event registers
+        */
+       if (in_be32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
+               out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
+
+       /* enable all error and events */
+       out_be32(&ifc->cm_evter_en, IFC_CM_EVTER_EN_CSEREN);
+
+       /* enable all error and event interrupts */
+       out_be32(&ifc->cm_evter_intr_en, IFC_CM_EVTER_INTR_EN_CSERIREN);
+       out_be32(&ifc->cm_erattr0, 0x0);
+       out_be32(&ifc->cm_erattr1, 0x0);
+
+       return 0;
+}
+
+static int fsl_ifc_ctrl_remove(struct platform_device *dev)
+{
+       struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
+
+       free_irq(ctrl->nand_irq, ctrl);
+       free_irq(ctrl->irq, ctrl);
+
+       irq_dispose_mapping(ctrl->nand_irq);
+       irq_dispose_mapping(ctrl->irq);
+
+       iounmap(ctrl->regs);
+
+       dev_set_drvdata(&dev->dev, NULL);
+       kfree(ctrl);
+
+       return 0;
+}
+
+/*
+ * NAND events are split between an operational interrupt which only
+ * receives OPC, and an error interrupt that receives everything else,
+ * including non-NAND errors.  Whichever interrupt gets to it first
+ * records the status and wakes the wait queue.
+ */
+static DEFINE_SPINLOCK(nand_irq_lock);
+
+static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
+{
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+       unsigned long flags;
+       u32 stat;
+
+       spin_lock_irqsave(&nand_irq_lock, flags);
+
+       stat = in_be32(&ifc->ifc_nand.nand_evter_stat);
+       if (stat) {
+               out_be32(&ifc->ifc_nand.nand_evter_stat, stat);
+               ctrl->nand_stat = stat;
+               wake_up(&ctrl->nand_wait);
+       }
+
+       spin_unlock_irqrestore(&nand_irq_lock, flags);
+
+       return stat;
+}
+
+static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
+{
+       struct fsl_ifc_ctrl *ctrl = data;
+
+       if (check_nand_stat(ctrl))
+               return IRQ_HANDLED;
+
+       return IRQ_NONE;
+}
+
+/*
+ * NOTE: This interrupt is used to report ifc events of various kinds,
+ * such as transaction errors on the chipselects.
+ */
+static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
+{
+       struct fsl_ifc_ctrl *ctrl = data;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+       u32 err_axiid, err_srcid, status, cs_err, err_addr;
+       irqreturn_t ret = IRQ_NONE;
+
+       /* read for chip select error */
+       cs_err = in_be32(&ifc->cm_evter_stat);
+       if (cs_err) {
+               dev_err(ctrl->dev, "transaction sent to IFC is not mapped to"
+                               "any memory bank 0x%08X\n", cs_err);
+               /* clear the chip select error */
+               out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
+
+               /* read error attribute registers print the error information */
+               status = in_be32(&ifc->cm_erattr0);
+               err_addr = in_be32(&ifc->cm_erattr1);
+
+               if (status & IFC_CM_ERATTR0_ERTYP_READ)
+                       dev_err(ctrl->dev, "Read transaction error"
+                               "CM_ERATTR0 0x%08X\n", status);
+               else
+                       dev_err(ctrl->dev, "Write transaction error"
+                               "CM_ERATTR0 0x%08X\n", status);
+
+               err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
+                                       IFC_CM_ERATTR0_ERAID_SHIFT;
+               dev_err(ctrl->dev, "AXI ID of the error"
+                                       "transaction 0x%08X\n", err_axiid);
+
+               err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
+                                       IFC_CM_ERATTR0_ESRCID_SHIFT;
+               dev_err(ctrl->dev, "SRC ID of the error"
+                                       "transaction 0x%08X\n", err_srcid);
+
+               dev_err(ctrl->dev, "Transaction Address corresponding to error"
+                                       "ERADDR 0x%08X\n", err_addr);
+
+               ret = IRQ_HANDLED;
+       }
+
+       if (check_nand_stat(ctrl))
+               ret = IRQ_HANDLED;
+
+       return ret;
+}
+
+/*
+ * fsl_ifc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only.  The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+static int fsl_ifc_ctrl_probe(struct platform_device *dev)
+{
+       int ret = 0;
+
+
+       dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
+
+       fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
+       if (!fsl_ifc_ctrl_dev)
+               return -ENOMEM;
+
+       dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
+
+       /* IOMAP the entire IFC region */
+       fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
+       if (!fsl_ifc_ctrl_dev->regs) {
+               dev_err(&dev->dev, "failed to get memory region\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* get the Controller level irq */
+       fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+       if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
+               dev_err(&dev->dev, "failed to get irq resource "
+                                                       "for IFC\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* get the nand machine irq */
+       fsl_ifc_ctrl_dev->nand_irq =
+                       irq_of_parse_and_map(dev->dev.of_node, 1);
+
+       fsl_ifc_ctrl_dev->dev = &dev->dev;
+
+       ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
+       if (ret < 0)
+               goto err;
+
+       init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
+
+       ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
+                         "fsl-ifc", fsl_ifc_ctrl_dev);
+       if (ret != 0) {
+               dev_err(&dev->dev, "failed to install irq (%d)\n",
+                       fsl_ifc_ctrl_dev->irq);
+               goto err_irq;
+       }
+
+       if (fsl_ifc_ctrl_dev->nand_irq) {
+               ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,
+                               0, "fsl-ifc-nand", fsl_ifc_ctrl_dev);
+               if (ret != 0) {
+                       dev_err(&dev->dev, "failed to install irq (%d)\n",
+                               fsl_ifc_ctrl_dev->nand_irq);
+                       goto err_nandirq;
+               }
+       }
+
+       return 0;
+
+err_nandirq:
+       free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
+       irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
+err_irq:
+       free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
+       irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
+err:
+       return ret;
+}
+
+static const struct of_device_id fsl_ifc_match[] = {
+       {
+               .compatible = "fsl,ifc",
+       },
+       {},
+};
+
+static struct platform_driver fsl_ifc_ctrl_driver = {
+       .driver = {
+               .name   = "fsl-ifc",
+               .of_match_table = fsl_ifc_match,
+       },
+       .probe       = fsl_ifc_ctrl_probe,
+       .remove      = fsl_ifc_ctrl_remove,
+};
+
+static int __init fsl_ifc_init(void)
+{
+       return platform_driver_register(&fsl_ifc_ctrl_driver);
+}
+subsys_initcall(fsl_ifc_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
new file mode 100644 (file)
index 0000000..d3df760
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * TI AEMIF driver
+ *
+ * Copyright (C) 2010 - 2013 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * Authors:
+ * Murali Karicheri <m-karicheri2@ti.com>
+ * Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define TA_SHIFT       2
+#define RHOLD_SHIFT    4
+#define RSTROBE_SHIFT  7
+#define RSETUP_SHIFT   13
+#define WHOLD_SHIFT    17
+#define WSTROBE_SHIFT  20
+#define WSETUP_SHIFT   26
+#define EW_SHIFT       30
+#define SS_SHIFT       31
+
+#define TA(x)          ((x) << TA_SHIFT)
+#define RHOLD(x)       ((x) << RHOLD_SHIFT)
+#define RSTROBE(x)     ((x) << RSTROBE_SHIFT)
+#define RSETUP(x)      ((x) << RSETUP_SHIFT)
+#define WHOLD(x)       ((x) << WHOLD_SHIFT)
+#define WSTROBE(x)     ((x) << WSTROBE_SHIFT)
+#define WSETUP(x)      ((x) << WSETUP_SHIFT)
+#define EW(x)          ((x) << EW_SHIFT)
+#define SS(x)          ((x) << SS_SHIFT)
+
+#define ASIZE_MAX      0x1
+#define TA_MAX         0x3
+#define RHOLD_MAX      0x7
+#define RSTROBE_MAX    0x3f
+#define RSETUP_MAX     0xf
+#define WHOLD_MAX      0x7
+#define WSTROBE_MAX    0x3f
+#define WSETUP_MAX     0xf
+#define EW_MAX         0x1
+#define SS_MAX         0x1
+#define NUM_CS         4
+
+#define TA_VAL(x)      (((x) & TA(TA_MAX)) >> TA_SHIFT)
+#define RHOLD_VAL(x)   (((x) & RHOLD(RHOLD_MAX)) >> RHOLD_SHIFT)
+#define RSTROBE_VAL(x) (((x) & RSTROBE(RSTROBE_MAX)) >> RSTROBE_SHIFT)
+#define RSETUP_VAL(x)  (((x) & RSETUP(RSETUP_MAX)) >> RSETUP_SHIFT)
+#define WHOLD_VAL(x)   (((x) & WHOLD(WHOLD_MAX)) >> WHOLD_SHIFT)
+#define WSTROBE_VAL(x) (((x) & WSTROBE(WSTROBE_MAX)) >> WSTROBE_SHIFT)
+#define WSETUP_VAL(x)  (((x) & WSETUP(WSETUP_MAX)) >> WSETUP_SHIFT)
+#define EW_VAL(x)      (((x) & EW(EW_MAX)) >> EW_SHIFT)
+#define SS_VAL(x)      (((x) & SS(SS_MAX)) >> SS_SHIFT)
+
+#define NRCSR_OFFSET   0x00
+#define AWCCR_OFFSET   0x04
+#define A1CR_OFFSET    0x10
+
+#define ACR_ASIZE_MASK 0x3
+#define ACR_EW_MASK    BIT(30)
+#define ACR_SS_MASK    BIT(31)
+#define ASIZE_16BIT    1
+
+#define CONFIG_MASK    (TA(TA_MAX) | \
+                               RHOLD(RHOLD_MAX) | \
+                               RSTROBE(RSTROBE_MAX) |  \
+                               RSETUP(RSETUP_MAX) | \
+                               WHOLD(WHOLD_MAX) | \
+                               WSTROBE(WSTROBE_MAX) | \
+                               WSETUP(WSETUP_MAX) | \
+                               EW(EW_MAX) | SS(SS_MAX) | \
+                               ASIZE_MAX)
+
+/**
+ * struct aemif_cs_data: structure to hold cs parameters
+ * @cs: chip-select number
+ * @wstrobe: write strobe width, ns
+ * @rstrobe: read strobe width, ns
+ * @wsetup: write setup width, ns
+ * @whold: write hold width, ns
+ * @rsetup: read setup width, ns
+ * @rhold: read hold width, ns
+ * @ta: minimum turn around time, ns
+ * @enable_ss: enable/disable select strobe mode
+ * @enable_ew: enable/disable extended wait mode
+ * @asize: width of the asynchronous device's data bus
+ */
+struct aemif_cs_data {
+       u8      cs;
+       u16     wstrobe;
+       u16     rstrobe;
+       u8      wsetup;
+       u8      whold;
+       u8      rsetup;
+       u8      rhold;
+       u8      ta;
+       u8      enable_ss;
+       u8      enable_ew;
+       u8      asize;
+};
+
+/**
+ * struct aemif_device: structure to hold device data
+ * @base: base address of AEMIF registers
+ * @clk: source clock
+ * @clk_rate: clock's rate in kHz
+ * @num_cs: number of assigned chip-selects
+ * @cs_offset: start number of cs nodes
+ * @cs_data: array of chip-select settings
+ */
+struct aemif_device {
+       void __iomem *base;
+       struct clk *clk;
+       unsigned long clk_rate;
+       u8 num_cs;
+       int cs_offset;
+       struct aemif_cs_data cs_data[NUM_CS];
+};
+
+/**
+ * aemif_calc_rate - calculate timing data.
+ * @pdev: platform device to calculate for
+ * @wanted: The cycle time needed in nanoseconds.
+ * @clk: The input clock rate in kHz.
+ * @max: The maximum divider value that can be programmed.
+ *
+ * On success, returns the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers, else negative errno.
+ */
+static int aemif_calc_rate(struct platform_device *pdev, int wanted,
+                          unsigned long clk, int max)
+{
+       int result;
+
+       result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
+
+       dev_dbg(&pdev->dev, "%s: result %d from %ld, %d\n", __func__, result,
+               clk, wanted);
+
+       /* It is generally OK to have a more relaxed timing than requested... */
+       if (result < 0)
+               result = 0;
+
+       /* ... But configuring tighter timings is not an option. */
+       else if (result > max)
+               result = -EINVAL;
+
+       return result;
+}
+
+/**
+ * aemif_config_abus - configure async bus parameters
+ * @pdev: platform device to configure for
+ * @csnum: aemif chip select number
+ *
+ * This function programs the given timing values (in real clock) into the
+ * AEMIF registers taking the AEMIF clock into account.
+ *
+ * This function does not use any locking while programming the AEMIF
+ * because it is expected that there is only one user of a given
+ * chip-select.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int aemif_config_abus(struct platform_device *pdev, int csnum)
+{
+       struct aemif_device *aemif = platform_get_drvdata(pdev);
+       struct aemif_cs_data *data = &aemif->cs_data[csnum];
+       int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+       unsigned long clk_rate = aemif->clk_rate;
+       unsigned offset;
+       u32 set, val;
+
+       offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
+
+       ta      = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
+       rhold   = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
+       rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
+       rsetup  = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
+       whold   = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
+       wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
+       wsetup  = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
+
+       if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+           whold < 0 || wstrobe < 0 || wsetup < 0) {
+               dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
+               WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+
+       set |= (data->asize & ACR_ASIZE_MASK);
+       if (data->enable_ew)
+               set |= ACR_EW_MASK;
+       if (data->enable_ss)
+               set |= ACR_SS_MASK;
+
+       val = readl(aemif->base + offset);
+       val &= ~CONFIG_MASK;
+       val |= set;
+       writel(val, aemif->base + offset);
+
+       return 0;
+}
+
+static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
+{
+       return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
+}
+
+/**
+ * aemif_get_hw_params - function to read hw register values
+ * @pdev: platform device to read for
+ * @csnum: aemif chip select number
+ *
+ * This function reads the defaults from the registers and update
+ * the timing values. Required for get/set commands and also for
+ * the case when driver needs to use defaults in hardware.
+ */
+static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
+{
+       struct aemif_device *aemif = platform_get_drvdata(pdev);
+       struct aemif_cs_data *data = &aemif->cs_data[csnum];
+       unsigned long clk_rate = aemif->clk_rate;
+       u32 val, offset;
+
+       offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
+       val = readl(aemif->base + offset);
+
+       data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
+       data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
+       data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
+       data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
+       data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
+       data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
+       data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
+       data->enable_ew = EW_VAL(val);
+       data->enable_ss = SS_VAL(val);
+       data->asize = val & ASIZE_MAX;
+}
+
+/**
+ * of_aemif_parse_abus_config - parse CS configuration from DT
+ * @pdev: platform device to parse for
+ * @np: device node ptr
+ *
+ * This function update the emif async bus configuration based on the values
+ * configured in a cs device binding node.
+ */
+static int of_aemif_parse_abus_config(struct platform_device *pdev,
+                                     struct device_node *np)
+{
+       struct aemif_device *aemif = platform_get_drvdata(pdev);
+       struct aemif_cs_data *data;
+       u32 cs;
+       u32 val;
+
+       if (of_property_read_u32(np, "ti,cs-chipselect", &cs)) {
+               dev_dbg(&pdev->dev, "cs property is required");
+               return -EINVAL;
+       }
+
+       if (cs - aemif->cs_offset >= NUM_CS || cs < aemif->cs_offset) {
+               dev_dbg(&pdev->dev, "cs number is incorrect %d", cs);
+               return -EINVAL;
+       }
+
+       if (aemif->num_cs >= NUM_CS) {
+               dev_dbg(&pdev->dev, "cs count is more than %d", NUM_CS);
+               return -EINVAL;
+       }
+
+       data = &aemif->cs_data[aemif->num_cs];
+       data->cs = cs;
+
+       /* read the current value in the hw register */
+       aemif_get_hw_params(pdev, aemif->num_cs++);
+
+       /* override the values from device node */
+       if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
+               data->ta = val;
+
+       if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
+               data->rhold = val;
+
+       if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
+               data->rstrobe = val;
+
+       if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
+               data->rsetup = val;
+
+       if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
+               data->whold = val;
+
+       if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
+               data->wstrobe = val;
+
+       if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
+               data->wsetup = val;
+
+       if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
+               if (val == 16)
+                       data->asize = 1;
+       data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
+       data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
+       return 0;
+}
+
+static const struct of_device_id aemif_of_match[] = {
+       { .compatible = "ti,davinci-aemif", },
+       { .compatible = "ti,da850-aemif", },
+       {},
+};
+
+static int aemif_probe(struct platform_device *pdev)
+{
+       int i;
+       int ret = -ENODEV;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct device_node *child_np;
+       struct aemif_device *aemif;
+
+       if (np == NULL)
+               return 0;
+
+       aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL);
+       if (!aemif)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, aemif);
+
+       aemif->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(aemif->clk)) {
+               dev_err(dev, "cannot get clock 'aemif'\n");
+               return PTR_ERR(aemif->clk);
+       }
+
+       clk_prepare_enable(aemif->clk);
+       aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC;
+
+       if (of_device_is_compatible(np, "ti,da850-aemif"))
+               aemif->cs_offset = 2;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       aemif->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(aemif->base)) {
+               ret = PTR_ERR(aemif->base);
+               goto error;
+       }
+
+       /*
+        * For every controller device node, there is a cs device node that
+        * describe the bus configuration parameters. This functions iterate
+        * over these nodes and update the cs data array.
+        */
+       for_each_available_child_of_node(np, child_np) {
+               ret = of_aemif_parse_abus_config(pdev, child_np);
+               if (ret < 0)
+                       goto error;
+       }
+
+       for (i = 0; i < aemif->num_cs; i++) {
+               ret = aemif_config_abus(pdev, i);
+               if (ret < 0) {
+                       dev_err(dev, "Error configuring chip select %d\n",
+                               aemif->cs_data[i].cs);
+                       goto error;
+               }
+       }
+
+       /*
+        * Create a child devices explicitly from here to
+        * guarantee that the child will be probed after the AEMIF timing
+        * parameters are set.
+        */
+       for_each_available_child_of_node(np, child_np) {
+               ret = of_platform_populate(child_np, NULL, NULL, dev);
+               if (ret < 0)
+                       goto error;
+       }
+
+       return 0;
+error:
+       clk_disable_unprepare(aemif->clk);
+       return ret;
+}
+
+static int aemif_remove(struct platform_device *pdev)
+{
+       struct aemif_device *aemif = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(aemif->clk);
+       return 0;
+}
+
+static struct platform_driver aemif_driver = {
+       .probe = aemif_probe,
+       .remove = aemif_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(aemif_of_match),
+       },
+};
+
+module_platform_driver(aemif_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments AEMIF driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
index a8c08f332da04c596cf1ae3aa33c2a09f1a4f892..92752fb5b2d3d8b41364261a99eb44938e33be32 100644 (file)
@@ -652,6 +652,44 @@ static int i2o_iop_activate(struct i2o_controller *c)
        return i2o_hrt_get(c);
 };
 
+static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
+{
+       i2o_status_block *sb = c->status_block.virt;
+       struct resource *res = &c->mem_resource;
+       resource_size_t size, align;
+       int err;
+
+       res->name = c->pdev->bus->name;
+       res->flags = flags;
+       res->start = 0;
+       res->end = 0;
+       osm_info("%s: requires private memory resources.\n", c->name);
+
+       if (flags & IORESOURCE_MEM) {
+               size = sb->desired_mem_size;
+               align = 1 << 20;        /* unspecified, use 1Mb and play safe */
+       } else {
+               size = sb->desired_io_size;
+               align = 1 << 12;        /* unspecified, use 4Kb and play safe */
+       }
+
+       err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
+                                    NULL, NULL);
+       if (err < 0)
+               return;
+
+       if (flags & IORESOURCE_MEM) {
+               c->mem_alloc = 1;
+               sb->current_mem_size = resource_size(res);
+               sb->current_mem_base = res->start;
+       } else if (flags & IORESOURCE_IO) {
+               c->io_alloc = 1;
+               sb->current_io_size = resource_size(res);
+               sb->current_io_base = res->start;
+       }
+       osm_info("%s: allocated PCI space %pR\n", c->name, res);
+}
+
 /**
  *     i2o_iop_systab_set - Set the I2O System Table of the specified IOP
  *     @c: I2O controller to which the system table should be send
@@ -665,52 +703,13 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
        struct i2o_message *msg;
        i2o_status_block *sb = c->status_block.virt;
        struct device *dev = &c->pdev->dev;
-       struct resource *root;
        int rc;
 
-       if (sb->current_mem_size < sb->desired_mem_size) {
-               struct resource *res = &c->mem_resource;
-               res->name = c->pdev->bus->name;
-               res->flags = IORESOURCE_MEM;
-               res->start = 0;
-               res->end = 0;
-               osm_info("%s: requires private memory resources.\n", c->name);
-               root = pci_find_parent_resource(c->pdev, res);
-               if (root == NULL)
-                       osm_warn("%s: Can't find parent resource!\n", c->name);
-               if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20,     /* Unspecified, so use 1Mb and play safe */
-                                             NULL, NULL) >= 0) {
-                       c->mem_alloc = 1;
-                       sb->current_mem_size = resource_size(res);
-                       sb->current_mem_base = res->start;
-                       osm_info("%s: allocated %llu bytes of PCI memory at "
-                               "0x%016llX.\n", c->name,
-                               (unsigned long long)resource_size(res),
-                               (unsigned long long)res->start);
-               }
-       }
+       if (sb->current_mem_size < sb->desired_mem_size)
+               i2o_res_alloc(c, IORESOURCE_MEM);
 
-       if (sb->current_io_size < sb->desired_io_size) {
-               struct resource *res = &c->io_resource;
-               res->name = c->pdev->bus->name;
-               res->flags = IORESOURCE_IO;
-               res->start = 0;
-               res->end = 0;
-               osm_info("%s: requires private memory resources.\n", c->name);
-               root = pci_find_parent_resource(c->pdev, res);
-               if (root == NULL)
-                       osm_warn("%s: Can't find parent resource!\n", c->name);
-               if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20,        /* Unspecified, so use 1Mb and play safe */
-                                             NULL, NULL) >= 0) {
-                       c->io_alloc = 1;
-                       sb->current_io_size = resource_size(res);
-                       sb->current_mem_base = res->start;
-                       osm_info("%s: allocated %llu bytes of PCI I/O at "
-                               "0x%016llX.\n", c->name,
-                               (unsigned long long)resource_size(res),
-                               (unsigned long long)res->start);
-               }
-       }
+       if (sb->current_io_size < sb->desired_io_size)
+               i2o_res_alloc(c, IORESOURCE_IO);
 
        msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
        if (IS_ERR(msg))
index a45aab9f6bb135e64c0f0a420f75ed2508e17e92..1c3ae57082ed7bc1a2dcd8583a507875f3b7d92b 100644 (file)
@@ -251,8 +251,6 @@ static int arizona_apply_hardware_patch(struct arizona* arizona)
        unsigned int fll, sysclk;
        int ret, err;
 
-       regcache_cache_bypass(arizona->regmap, true);
-
        /* Cache existing FLL and SYSCLK settings */
        ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll);
        if (ret != 0) {
@@ -322,8 +320,6 @@ err_fll:
                        err);
        }
 
-       regcache_cache_bypass(arizona->regmap, false);
-
        if (ret != 0)
                return ret;
        else
index 714e2135210ec2ddc989efcd44f3e800b80f5bcf..281a827472754ad9b79939e67eb11820d70e3eaa 100644 (file)
@@ -26,7 +26,9 @@
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/irq.h>
 #include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mpa01.h>
 #include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
 #include <linux/mfd/samsung/s5m8763.h>
 #include <linux/mfd/samsung/s5m8767.h>
 #include <linux/regmap.h>
@@ -69,18 +71,53 @@ static const struct mfd_cell s2mps11_devs[] = {
        }
 };
 
+static const struct mfd_cell s2mps14_devs[] = {
+       {
+               .name = "s2mps14-pmic",
+       }, {
+               .name = "s2mps14-rtc",
+       }, {
+               .name = "s2mps14-clk",
+       }
+};
+
+static const struct mfd_cell s2mpa01_devs[] = {
+       {
+               .name = "s2mpa01-pmic",
+       },
+};
+
 #ifdef CONFIG_OF
 static struct of_device_id sec_dt_match[] = {
        {       .compatible = "samsung,s5m8767-pmic",
                .data = (void *)S5M8767X,
-       },
-       {       .compatible = "samsung,s2mps11-pmic",
+       }, {
+               .compatible = "samsung,s2mps11-pmic",
                .data = (void *)S2MPS11X,
+       }, {
+               .compatible = "samsung,s2mps14-pmic",
+               .data = (void *)S2MPS14X,
+       }, {
+               .compatible = "samsung,s2mpa01-pmic",
+               .data = (void *)S2MPA01,
+       }, {
+               /* Sentinel */
        },
-       {},
 };
 #endif
 
+static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case S2MPA01_REG_INT1M:
+       case S2MPA01_REG_INT2M:
+       case S2MPA01_REG_INT3M:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static bool s2mps11_volatile(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -111,6 +148,15 @@ static const struct regmap_config sec_regmap_config = {
        .val_bits = 8,
 };
 
+static const struct regmap_config s2mpa01_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S2MPA01_REG_LDO_OVCB4,
+       .volatile_reg = s2mpa01_volatile,
+       .cache_type = REGCACHE_FLAT,
+};
+
 static const struct regmap_config s2mps11_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -120,6 +166,15 @@ static const struct regmap_config s2mps11_regmap_config = {
        .cache_type = REGCACHE_FLAT,
 };
 
+static const struct regmap_config s2mps14_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S2MPS14_REG_LDODSCH3,
+       .volatile_reg = s2mps11_volatile,
+       .cache_type = REGCACHE_FLAT,
+};
+
 static const struct regmap_config s5m8763_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -138,9 +193,18 @@ static const struct regmap_config s5m8767_regmap_config = {
        .cache_type = REGCACHE_FLAT,
 };
 
-static const struct regmap_config sec_rtc_regmap_config = {
+static const struct regmap_config s5m_rtc_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = SEC_RTC_REG_MAX,
+};
+
+static const struct regmap_config s2mps14_rtc_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
+
+       .max_register = S2MPS_RTC_REG_MAX,
 };
 
 #ifdef CONFIG_OF
@@ -180,24 +244,24 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
 }
 #endif
 
-static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c,
                                                const struct i2c_device_id *id)
 {
 #ifdef CONFIG_OF
        if (i2c->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(sec_dt_match, i2c->dev.of_node);
-               return (int)match->data;
+               return (unsigned long)match->data;
        }
 #endif
-       return (int)id->driver_data;
+       return id->driver_data;
 }
 
 static int sec_pmic_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
-       const struct regmap_config *regmap;
+       const struct regmap_config *regmap, *regmap_rtc;
        struct sec_pmic_dev *sec_pmic;
        int ret;
 
@@ -229,17 +293,34 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        }
 
        switch (sec_pmic->device_type) {
+       case S2MPA01:
+               regmap = &s2mpa01_regmap_config;
+               break;
        case S2MPS11X:
                regmap = &s2mps11_regmap_config;
+               /*
+                * The rtc-s5m driver does not support S2MPS11 and there
+                * is no mfd_cell for S2MPS11 RTC device.
+                * However we must pass something to devm_regmap_init_i2c()
+                * so use S5M-like regmap config even though it wouldn't work.
+                */
+               regmap_rtc = &s5m_rtc_regmap_config;
+               break;
+       case S2MPS14X:
+               regmap = &s2mps14_regmap_config;
+               regmap_rtc = &s2mps14_rtc_regmap_config;
                break;
        case S5M8763X:
                regmap = &s5m8763_regmap_config;
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        case S5M8767X:
                regmap = &s5m8767_regmap_config;
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        default:
                regmap = &sec_regmap_config;
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        }
 
@@ -252,10 +333,13 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        }
 
        sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+       if (!sec_pmic->rtc) {
+               dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
 
-       sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc,
-                       &sec_rtc_regmap_config);
+       sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
        if (IS_ERR(sec_pmic->regmap_rtc)) {
                ret = PTR_ERR(sec_pmic->regmap_rtc);
                dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
@@ -283,10 +367,18 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
                                      ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL);
                break;
+       case S2MPA01:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs,
+                                     ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL);
+               break;
        case S2MPS11X:
                ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
                                      ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL);
                break;
+       case S2MPS14X:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs,
+                                     ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL);
+               break;
        default:
                /* If this happens the probe function is problem */
                BUG();
index 4de494f51d401b3d85544633621091d9e7cceff6..64e7913aadc6cf3fbe68389edd8ba986e7a1ec8c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sec-irq.c
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
  *              http://www.samsung.com
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -19,6 +19,7 @@
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/irq.h>
 #include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
 #include <linux/mfd/samsung/s5m8763.h>
 #include <linux/mfd/samsung/s5m8767.h>
 
@@ -59,13 +60,13 @@ static const struct regmap_irq s2mps11_irqs[] = {
                .reg_offset = 1,
                .mask = S2MPS11_IRQ_RTC60S_MASK,
        },
-       [S2MPS11_IRQ_RTCA1] = {
+       [S2MPS11_IRQ_RTCA0] = {
                .reg_offset = 1,
-               .mask = S2MPS11_IRQ_RTCA1_MASK,
+               .mask = S2MPS11_IRQ_RTCA0_MASK,
        },
-       [S2MPS11_IRQ_RTCA2] = {
+       [S2MPS11_IRQ_RTCA1] = {
                .reg_offset = 1,
-               .mask = S2MPS11_IRQ_RTCA2_MASK,
+               .mask = S2MPS11_IRQ_RTCA1_MASK,
        },
        [S2MPS11_IRQ_SMPL] = {
                .reg_offset = 1,
@@ -89,6 +90,76 @@ static const struct regmap_irq s2mps11_irqs[] = {
        },
 };
 
+static const struct regmap_irq s2mps14_irqs[] = {
+       [S2MPS14_IRQ_PWRONF] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_PWRONF_MASK,
+       },
+       [S2MPS14_IRQ_PWRONR] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_PWRONR_MASK,
+       },
+       [S2MPS14_IRQ_JIGONBF] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_JIGONBF_MASK,
+       },
+       [S2MPS14_IRQ_JIGONBR] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_JIGONBR_MASK,
+       },
+       [S2MPS14_IRQ_ACOKBF] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_ACOKBF_MASK,
+       },
+       [S2MPS14_IRQ_ACOKBR] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_ACOKBR_MASK,
+       },
+       [S2MPS14_IRQ_PWRON1S] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_PWRON1S_MASK,
+       },
+       [S2MPS14_IRQ_MRB] = {
+               .reg_offset = 0,
+               .mask = S2MPS11_IRQ_MRB_MASK,
+       },
+       [S2MPS14_IRQ_RTC60S] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_RTC60S_MASK,
+       },
+       [S2MPS14_IRQ_RTCA1] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_RTCA1_MASK,
+       },
+       [S2MPS14_IRQ_RTCA0] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_RTCA0_MASK,
+       },
+       [S2MPS14_IRQ_SMPL] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_SMPL_MASK,
+       },
+       [S2MPS14_IRQ_RTC1S] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_RTC1S_MASK,
+       },
+       [S2MPS14_IRQ_WTSR] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_WTSR_MASK,
+       },
+       [S2MPS14_IRQ_INT120C] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_INT120C_MASK,
+       },
+       [S2MPS14_IRQ_INT140C] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_INT140C_MASK,
+       },
+       [S2MPS14_IRQ_TSD] = {
+               .reg_offset = 2,
+               .mask = S2MPS14_IRQ_TSD_MASK,
+       },
+};
 
 static const struct regmap_irq s5m8767_irqs[] = {
        [S5M8767_IRQ_PWRR] = {
@@ -246,6 +317,16 @@ static const struct regmap_irq_chip s2mps11_irq_chip = {
        .ack_base = S2MPS11_REG_INT1,
 };
 
+static const struct regmap_irq_chip s2mps14_irq_chip = {
+       .name = "s2mps14",
+       .irqs = s2mps14_irqs,
+       .num_irqs = ARRAY_SIZE(s2mps14_irqs),
+       .num_regs = 3,
+       .status_base = S2MPS14_REG_INT1,
+       .mask_base = S2MPS14_REG_INT1M,
+       .ack_base = S2MPS14_REG_INT1,
+};
+
 static const struct regmap_irq_chip s5m8767_irq_chip = {
        .name = "s5m8767",
        .irqs = s5m8767_irqs,
@@ -297,6 +378,12 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
                                  sec_pmic->irq_base, &s2mps11_irq_chip,
                                  &sec_pmic->irq_data);
                break;
+       case S2MPS14X:
+               ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq,
+                                 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                 sec_pmic->irq_base, &s2mps14_irq_chip,
+                                 &sec_pmic->irq_data);
+               break;
        default:
                dev_err(sec_pmic->dev, "Unknown device type %d\n",
                        sec_pmic->device_type);
index 1e9a4b2102f9d89c9549e3d226cf7ef0c91866ef..bffc584e4a4355f25f565ae6d0aa77244e556238 100644 (file)
@@ -80,8 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = {
 int wm5102_patch(struct arizona *arizona)
 {
        const struct reg_default *wm5102_patch;
-       int ret = 0;
-       int i, patch_size;
+       int patch_size;
 
        switch (arizona->rev) {
        case 0:
@@ -92,21 +91,9 @@ int wm5102_patch(struct arizona *arizona)
                patch_size = ARRAY_SIZE(wm5102_revb_patch);
        }
 
-       regcache_cache_bypass(arizona->regmap, true);
-
-       for (i = 0; i < patch_size; i++) {
-               ret = regmap_write(arizona->regmap, wm5102_patch[i].reg,
-                                  wm5102_patch[i].def);
-               if (ret != 0) {
-                       dev_err(arizona->dev, "Failed to write %x = %x: %d\n",
-                               wm5102_patch[i].reg, wm5102_patch[i].def, ret);
-                       goto out;
-               }
-       }
-
-out:
-       regcache_cache_bypass(arizona->regmap, false);
-       return ret;
+       return regmap_multi_reg_write_bypassed(arizona->regmap,
+                                              wm5102_patch,
+                                              patch_size);
 }
 
 static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = {
index 6cb388e8fb7d5ae9fa6783f5b2fad8337ddfef22..809afebe0dad4f4adadee901bcde042bbbba2cf2 100644 (file)
@@ -235,7 +235,7 @@ config SGI_XP
 
 config CS5535_MFGPT
        tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
-       depends on PCI && X86 && MFD_CS5535
+       depends on MFD_CS5535
        default n
        help
          This driver provides access to MFGPT functionality for other
index d3eee113baeba58a1bf2d9aae893c1e8ceed75b2..a43053daad0ec6698e39475f02499b955a12f66a 100644 (file)
@@ -72,7 +72,6 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 
index 0c6e037153d2231a3ff3859babcd5b8958e3ce7f..c6cc3dc8ae1fcfb55e3fc7f15873af1c635c5bbe 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
index 5be808406edcfc4bf08780647c86b322bddea9bb..22de13727641c76dcec8246244385a45d7907818 100644 (file)
@@ -150,6 +150,12 @@ static int ssc_probe(struct platform_device *pdev)
                return -ENODEV;
        ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat;
 
+       if (pdev->dev.of_node) {
+               struct device_node *np = pdev->dev.of_node;
+               ssc->clk_from_rk_pin =
+                       of_property_read_bool(np, "atmel,clk-from-rk-pin");
+       }
+
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ssc->regs = devm_ioremap_resource(&pdev->dev, regs);
        if (IS_ERR(ssc->regs))
index 820e53d0048fa16e248ee41ce5b89987935fa9ac..9b313f7810f5207d02ceb63fe864b7eba1b9637d 100644 (file)
@@ -47,7 +47,6 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #include "bmp085.h"
index 9e2b985293fc08cf30bef9a9455fcade1eb095cb..14d90eae605bcea74c7d5f1d02b5700de93957dc 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/poll.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/kref.h>
 #include <linux/io.h>
index 154b02e5094f3202a528656045f6d1ac210fc883..6a672f9ef522c7fe2a477f3fcc7e1001abf5996d 100644 (file)
@@ -32,7 +32,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/string.h>
 #include <linux/list.h>
index 4f3bca1003a175d2eb0ea7fdf423cd8dfa70e14d..634f72929e123c342ba6ac812f259048df420e2f 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index f0fa4e8ca124a905844f8f30d705be967d467965..33f8673d23a6d1307c8e4ae800f857eca4bfa7bf 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
index 78e55b501c94816a51b6ed7186c8473815b13689..9ebeacdb8ec4a06381974c8e3137cebe7d5fe41d 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
index e36157d5d3abf0c9d8ed388cad08a2dcbf6e74d8..580ff9df55296ccbb29e18561a98d7756e9c60b6 100644 (file)
@@ -27,7 +27,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
index 9c34e5704304f4e40dd33b4293347e6a2d6afa4f..3f2b625b203291c0724b85cfda06b1db9f804158 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/kobject.h>
@@ -96,7 +95,7 @@ static int sunxi_sid_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id sunxi_sid_of_match[] = {
-       { .compatible = "allwinner,sun4i-sid", .data = (void *)16},
+       { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
        { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
        {/* sentinel */},
 };
index 3bfdc07a7248b9654b8e1854aef2e81ff8e96640..50d2096ea1c74d0e86ce9e7fe637f046a2d01a59 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
index 170bd3daf33699598a794e4a58a9df19a917c279..90520d76633f4c2e92a07d3fdf9150e5b022fa6c 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
index e3183f26216b876cee627c6a980bd1ed6ee35ec5..12c30b486b27c01ab8a741cbb743cbb8dbd58cbc 100644 (file)
@@ -26,7 +26,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
index b7f84dacf822f40641858a329175235e2bfe9546..4a9c50a43afb864ebf76e2ea72e9809e783269a1 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
index 61fbe6acabef87521a6e0fc02e07748dea49492f..0a1565e63c711eaf10f13c78ffa6c97a5ace9574 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
index 036effe9a795ab62338be47c306b7f98aa36e0d7..3ef4627f9cb1552a7585787f6da81cb880c4b784 100644 (file)
@@ -23,7 +23,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/types.h>
index 7c97550240f19db127c56b1eb1322f0fe8de803d..d324f8a97b88d7e981a7c5ea680457ec8f0d9ed0 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/pm_runtime.h>
index 9aa2bd2a71ae4fc268f4831d2c9622e890f48b54..bd06d0cfac45e15a2f1ee21f1e4ab856867e0e98 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/err.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
index 49c7a23f02fc554f3232295ed7a80b90b96bdc16..d66a2f24f6b3dceffbcc3335d502e858520558e2 100644 (file)
@@ -30,6 +30,7 @@
  *
  * See Documentation/fault-injection/provoke-crashes.txt for instructions
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
 #include <linux/fs.h>
@@ -45,6 +46,7 @@
 #include <linux/debugfs.h>
 #include <linux/vmalloc.h>
 #include <linux/mman.h>
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_IDE
 #include <linux/ide.h>
@@ -101,6 +103,7 @@ enum ctype {
        CT_EXEC_USERSPACE,
        CT_ACCESS_USERSPACE,
        CT_WRITE_RO,
+       CT_WRITE_KERN,
 };
 
 static char* cp_name[] = {
@@ -137,6 +140,7 @@ static char* cp_type[] = {
        "EXEC_USERSPACE",
        "ACCESS_USERSPACE",
        "WRITE_RO",
+       "WRITE_KERN",
 };
 
 static struct jprobe lkdtm;
@@ -316,6 +320,13 @@ static void do_nothing(void)
        return;
 }
 
+/* Must immediately follow do_nothing for size calculuations to work out. */
+static void do_overwritten(void)
+{
+       pr_info("do_overwritten wasn't overwritten!\n");
+       return;
+}
+
 static noinline void corrupt_stack(void)
 {
        /* Use default char array length that triggers stack protection. */
@@ -328,7 +339,12 @@ static void execute_location(void *dst)
 {
        void (*func)(void) = dst;
 
+       pr_info("attempting ok execution at %p\n", do_nothing);
+       do_nothing();
+
        memcpy(dst, do_nothing, EXEC_SIZE);
+       flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
+       pr_info("attempting bad execution at %p\n", func);
        func();
 }
 
@@ -337,8 +353,13 @@ static void execute_user_location(void *dst)
        /* Intentionally crossing kernel/user memory boundary. */
        void (*func)(void) = dst;
 
+       pr_info("attempting ok execution at %p\n", do_nothing);
+       do_nothing();
+
        if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE))
                return;
+       flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
+       pr_info("attempting bad execution at %p\n", func);
        func();
 }
 
@@ -463,8 +484,12 @@ static void lkdtm_do_action(enum ctype which)
                }
 
                ptr = (unsigned long *)user_addr;
+
+               pr_info("attempting bad read at %p\n", ptr);
                tmp = *ptr;
                tmp += 0xc0dec0de;
+
+               pr_info("attempting bad write at %p\n", ptr);
                *ptr = tmp;
 
                vm_munmap(user_addr, PAGE_SIZE);
@@ -475,10 +500,28 @@ static void lkdtm_do_action(enum ctype which)
                unsigned long *ptr;
 
                ptr = (unsigned long *)&rodata;
+
+               pr_info("attempting bad write at %p\n", ptr);
                *ptr ^= 0xabcd1234;
 
                break;
        }
+       case CT_WRITE_KERN: {
+               size_t size;
+               unsigned char *ptr;
+
+               size = (unsigned long)do_overwritten -
+                      (unsigned long)do_nothing;
+               ptr = (unsigned char *)do_overwritten;
+
+               pr_info("attempting bad %zu byte write at %p\n", size, ptr);
+               memcpy(ptr, (unsigned char *)do_nothing, size);
+               flush_icache_range((unsigned long)ptr,
+                                  (unsigned long)(ptr + size));
+
+               do_overwritten();
+               break;
+       }
        case CT_NONE:
        default:
                break;
@@ -493,8 +536,8 @@ static void lkdtm_handler(void)
 
        spin_lock_irqsave(&count_lock, flags);
        count--;
-       printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",
-                       cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
+       pr_info("Crash point %s of type %s hit, trigger in %d rounds\n",
+               cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
 
        if (count == 0) {
                do_it = true;
@@ -551,18 +594,18 @@ static int lkdtm_register_cpoint(enum cname which)
                lkdtm.kp.symbol_name = "generic_ide_ioctl";
                lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
 #else
-               printk(KERN_INFO "lkdtm: Crash point not available\n");
+               pr_info("Crash point not available\n");
                return -EINVAL;
 #endif
                break;
        default:
-               printk(KERN_INFO "lkdtm: Invalid Crash Point\n");
+               pr_info("Invalid Crash Point\n");
                return -EINVAL;
        }
 
        cpoint = which;
        if ((ret = register_jprobe(&lkdtm)) < 0) {
-               printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
+               pr_info("Couldn't register jprobe\n");
                cpoint = CN_INVALID;
        }
 
@@ -709,8 +752,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
        if (type == CT_NONE)
                return -EINVAL;
 
-       printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
-                       cp_type_to_str(type));
+       pr_info("Performing direct entry %s\n", cp_type_to_str(type));
        lkdtm_do_action(type);
        *off += count;
 
@@ -772,7 +814,7 @@ static int __init lkdtm_module_init(void)
        /* Register debugfs interface */
        lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
        if (!lkdtm_debugfs_root) {
-               printk(KERN_ERR "lkdtm: creating root dir failed\n");
+               pr_err("creating root dir failed\n");
                return -ENODEV;
        }
 
@@ -787,28 +829,26 @@ static int __init lkdtm_module_init(void)
                de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
                                NULL, &cur->fops);
                if (de == NULL) {
-                       printk(KERN_ERR "lkdtm: could not create %s\n",
-                                       cur->name);
+                       pr_err("could not create %s\n", cur->name);
                        goto out_err;
                }
        }
 
        if (lkdtm_parse_commandline() == -EINVAL) {
-               printk(KERN_INFO "lkdtm: Invalid command\n");
+               pr_info("Invalid command\n");
                goto out_err;
        }
 
        if (cpoint != CN_INVALID && cptype != CT_NONE) {
                ret = lkdtm_register_cpoint(cpoint);
                if (ret < 0) {
-                       printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
-                                       cpoint);
+                       pr_info("Invalid crash point %d\n", cpoint);
                        goto out_err;
                }
-               printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n",
-                               cpoint_name, cpoint_type);
+               pr_info("Crash point %s of type %s registered\n",
+                       cpoint_name, cpoint_type);
        } else {
-               printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n");
+               pr_info("No crash points registered, enable through debugfs\n");
        }
 
        return 0;
@@ -823,7 +863,7 @@ static void __exit lkdtm_module_exit(void)
        debugfs_remove_recursive(lkdtm_debugfs_root);
 
        unregister_jprobe(&lkdtm);
-       printk(KERN_INFO "lkdtm: Crash point unregistered\n");
+       pr_info("Crash point unregistered\n");
 }
 
 module_init(lkdtm_module_init);
index c76fa31e9bf6926aac9cc181846d383f1325c8da..d23384dde73b97e3abf7ee166c1a13ef3fb83249 100644 (file)
@@ -34,3 +34,12 @@ config INTEL_MEI_ME
          82Q33 Express
          82X38/X48 Express
 
+config INTEL_MEI_TXE
+       tristate "Intel Trusted Execution Environment with ME Interface"
+       select INTEL_MEI
+       depends on X86 && PCI && WATCHDOG_CORE
+       help
+         MEI Support for Trusted Execution Environment device on Intel SoCs
+
+         Supported SoCs:
+         Intel Bay Trail
index 08698a466268a50aa55427aca15ad9ef2e9b2242..8ebc6cda1373d6c7e543d785064559720bbf0391 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Makefile - Intel Management Engine Interface (Intel MEI) Linux driver
-# Copyright (c) 2010-2011, Intel Corporation.
+# Copyright (c) 2010-2014, Intel Corporation.
 #
 obj-$(CONFIG_INTEL_MEI) += mei.o
 mei-objs := init.o
@@ -17,3 +17,7 @@ mei-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
 mei-me-objs := pci-me.o
 mei-me-objs += hw-me.o
+
+obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o
+mei-txe-objs := pci-txe.o
+mei-txe-objs += hw-txe.o
index 2fad8443282913f65601c408bc37a2e9f990efdf..b8deb345548057b86d2bac1cfe4e478fecc07d21 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/fcntl.h>
 #include <linux/aio.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/ioctl.h>
 #include <linux/cdev.h>
 #include <linux/list.h>
@@ -35,7 +34,6 @@
 
 #include "mei_dev.h"
 #include "hbm.h"
-#include "hw-me.h"
 #include "client.h"
 
 const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
@@ -79,10 +77,9 @@ int mei_amthif_host_init(struct mei_device *dev)
 
        i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
        if (i < 0) {
-               ret = i;
                dev_info(&dev->pdev->dev,
-                       "amthif: failed to find the client %d\n", ret);
-               return ret;
+                       "amthif: failed to find the client %d\n", i);
+               return -ENOTTY;
        }
 
        cl->me_client_id = dev->me_clients[i].client_id;
@@ -116,14 +113,11 @@ int mei_amthif_host_init(struct mei_device *dev)
 
        cl->state = MEI_FILE_CONNECTING;
 
-       if (mei_hbm_cl_connect_req(dev, cl)) {
-               dev_dbg(&dev->pdev->dev, "amthif: Failed to connect to ME client\n");
-               cl->state = MEI_FILE_DISCONNECTED;
-               cl->host_client_id = 0;
-       } else {
-               cl->timer_count = MEI_CONNECT_TIMEOUT;
-       }
-       return 0;
+       ret = mei_cl_connect(cl, NULL);
+
+       dev->iamthif_state = MEI_IAMTHIF_IDLE;
+
+       return ret;
 }
 
 /**
@@ -137,14 +131,12 @@ int mei_amthif_host_init(struct mei_device *dev)
 struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
                                                struct file *file)
 {
-       struct mei_cl_cb *pos = NULL;
-       struct mei_cl_cb *next = NULL;
+       struct mei_cl_cb *cb;
 
-       list_for_each_entry_safe(pos, next,
-                               &dev->amthif_rd_complete_list.list, list) {
-               if (pos->cl && pos->cl == &dev->iamthif_cl &&
-                       pos->file_object == file)
-                       return pos;
+       list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
+               if (cb->cl && cb->cl == &dev->iamthif_cl &&
+                       cb->file_object == file)
+                       return cb;
        }
        return NULL;
 }
@@ -180,14 +172,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
        /* Only possible if we are in timeout */
        if (!cl || cl != &dev->iamthif_cl) {
                dev_dbg(&dev->pdev->dev, "bad file ext.\n");
-               return -ETIMEDOUT;
+               return -ETIME;
        }
 
        i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
-
        if (i < 0) {
                dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
-               return -ENODEV;
+               return -ENOTTY;
        }
        dev_dbg(&dev->pdev->dev, "checking amthif data\n");
        cb = mei_amthif_find_read_list_entry(dev, file);
@@ -228,7 +219,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
                        dev_dbg(&dev->pdev->dev, "amthif Time out\n");
                        /* 15 sec for the message has expired */
                        list_del(&cb->list);
-                       rets = -ETIMEDOUT;
+                       rets = -ETIME;
                        goto free;
                }
        }
@@ -253,9 +244,10 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
         * the buf_idx may point beyond */
        length = min_t(size_t, length, (cb->buf_idx - *offset));
 
-       if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
+       if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+               dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
                rets = -EFAULT;
-       else {
+       else {
                rets = length;
                if ((*offset + length) < cb->buf_idx) {
                        *offset += length;
@@ -302,9 +294,8 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
        if (ret < 0)
                return ret;
 
-       if (ret && dev->hbuf_is_ready) {
+       if (ret && mei_hbuf_acquire(dev)) {
                ret = 0;
-               dev->hbuf_is_ready = false;
                if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
                        mei_hdr.length = mei_hbuf_max_len(dev);
                        mei_hdr.msg_complete = 0;
@@ -336,10 +327,6 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
                        list_add_tail(&cb->list, &dev->write_list.list);
                }
        } else {
-               if (!dev->hbuf_is_ready)
-                       dev_dbg(&dev->pdev->dev, "host buffer is not empty");
-
-               dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
                list_add_tail(&cb->list, &dev->write_list.list);
        }
        return 0;
@@ -365,7 +352,7 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
        if (ret)
                return ret;
 
-       cb->fop_type = MEI_FOP_IOCTL;
+       cb->fop_type = MEI_FOP_WRITE;
 
        if (!list_empty(&dev->amthif_cmd_list.list) ||
            dev->iamthif_state != MEI_IAMTHIF_IDLE) {
@@ -447,23 +434,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 
 
 /**
- * mei_amthif_irq_write_completed - processes completed iamthif operation.
+ * mei_amthif_irq_write - write iamthif command in irq thread context.
  *
  * @dev: the device structure.
- * @slots: free slots.
  * @cb_pos: callback block.
  * @cl: private data of the file object.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                                 s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                        struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
        struct mei_msg_hdr mei_hdr;
        size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
        u32 msg_slots = mei_data2slots(len);
+       int slots;
        int rets;
 
        rets = mei_cl_flow_ctrl_creds(cl);
@@ -480,13 +467,15 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
        mei_hdr.reserved = 0;
        mei_hdr.internal = 0;
 
-       if (*slots >= msg_slots) {
+       slots = mei_hbuf_empty_slots(dev);
+
+       if (slots >= msg_slots) {
                mei_hdr.length = len;
                mei_hdr.msg_complete = 1;
        /* Split the message only if we can write the whole host buffer */
-       } else if (*slots == dev->hbuf_depth) {
-               msg_slots = *slots;
-               len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+       } else if (slots == dev->hbuf_depth) {
+               msg_slots = slots;
+               len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
                mei_hdr.length = len;
                mei_hdr.msg_complete = 0;
        } else {
@@ -496,7 +485,6 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
 
        dev_dbg(&dev->pdev->dev, MEI_HDR_FMT,  MEI_HDR_PRM(&mei_hdr));
 
-       *slots -=  msg_slots;
        rets = mei_write_message(dev, &mei_hdr,
                        dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
        if (rets) {
index 4bc7d620d695f05c26a558cfe70992a4dae83963..ddc5ac92a200a85d7f83762c7df04b4da90fc15d 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mei_cl_bus.h>
 
 #include "mei_dev.h"
-#include "hw-me.h"
 #include "client.h"
 
 #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
@@ -145,9 +144,9 @@ static struct device_type mei_cl_device_type = {
 static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
                                                uuid_le uuid)
 {
-       struct mei_cl *cl, *next;
+       struct mei_cl *cl;
 
-       list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+       list_for_each_entry(cl, &dev->device_list, device_link) {
                if (!uuid_le_cmp(uuid, cl->device_uuid))
                        return cl;
        }
@@ -524,6 +523,22 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
        schedule_work(&device->event_work);
 }
 
+void mei_cl_bus_remove_devices(struct mei_device *dev)
+{
+       struct mei_cl *cl, *next;
+
+       mutex_lock(&dev->device_lock);
+       list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+               if (cl->device)
+                       mei_cl_remove_device(cl->device);
+
+               list_del(&cl->device_link);
+               mei_cl_unlink(cl);
+               kfree(cl);
+       }
+       mutex_unlock(&dev->device_lock);
+}
+
 int __init mei_cl_bus_init(void)
 {
        return bus_register(&mei_cl_bus_type);
index 89a557972d1b926abe915760366d6602c1efa0cf..8c078b808cd3256caa871900ac3967b765feb78e 100644 (file)
  * mei_me_cl_by_uuid - locate index of me client
  *
  * @dev: mei device
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
  * returns me client index or -ENOENT if not found
  */
 int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
 {
-       int i, res = -ENOENT;
+       int i;
 
        for (i = 0; i < dev->me_clients_num; ++i)
                if (uuid_le_cmp(*uuid,
-                               dev->me_clients[i].props.protocol_name) == 0) {
-                       res = i;
-                       break;
-               }
+                               dev->me_clients[i].props.protocol_name) == 0)
+                       return i;
 
-       return res;
+       return -ENOENT;
 }
 
 
@@ -60,36 +61,78 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
 int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
 {
        int i;
+
        for (i = 0; i < dev->me_clients_num; i++)
                if (dev->me_clients[i].client_id == client_id)
-                       break;
-       if (WARN_ON(dev->me_clients[i].client_id != client_id))
-               return -ENOENT;
+                       return i;
 
-       if (i == dev->me_clients_num)
-               return -ENOENT;
-
-       return i;
+       return -ENOENT;
 }
 
 
 /**
- * mei_io_list_flush - removes list entry belonging to cl.
+ * mei_cl_cmp_id - tells if the clients are the same
  *
- * @list:  An instance of our list structure
- * @cl: host client
+ * @cl1: host client 1
+ * @cl2: host client 2
+ *
+ * returns true  - if the clients has same host and me ids
+ *         false - otherwise
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+                               const struct mei_cl *cl2)
+{
+       return cl1 && cl2 &&
+               (cl1->host_client_id == cl2->host_client_id) &&
+               (cl1->me_client_id == cl2->me_client_id);
+}
+
+/**
+ * mei_io_list_flush - removes cbs belonging to cl.
+ *
+ * @list:  an instance of our list structure
+ * @cl:    host client, can be NULL for flushing the whole list
+ * @free:  whether to free the cbs
  */
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+static void __mei_io_list_flush(struct mei_cl_cb *list,
+                               struct mei_cl *cl, bool free)
 {
        struct mei_cl_cb *cb;
        struct mei_cl_cb *next;
 
+       /* enable removing everything if no cl is specified */
        list_for_each_entry_safe(cb, next, &list->list, list) {
-               if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
+               if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
                        list_del(&cb->list);
+                       if (free)
+                               mei_io_cb_free(cb);
+               }
        }
 }
 
+/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list:  An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+       __mei_io_list_flush(list, cl, false);
+}
+
+
+/**
+ * mei_io_list_free - removes cb belonging to cl and free them
+ *
+ * @list:  An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+       __mei_io_list_flush(list, cl, true);
+}
+
 /**
  * mei_io_cb_free - free mei_cb_private related memory
  *
@@ -196,8 +239,8 @@ int mei_cl_flush_queues(struct mei_cl *cl)
 
        cl_dbg(dev, cl, "remove list entry belonging to cl\n");
        mei_io_list_flush(&cl->dev->read_list, cl);
-       mei_io_list_flush(&cl->dev->write_list, cl);
-       mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+       mei_io_list_free(&cl->dev->write_list, cl);
+       mei_io_list_free(&cl->dev->write_waiting_list, cl);
        mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
        mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
        mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
@@ -254,10 +297,9 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
 struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
 {
        struct mei_device *dev = cl->dev;
-       struct mei_cl_cb *cb = NULL;
-       struct mei_cl_cb *next = NULL;
+       struct mei_cl_cb *cb;
 
-       list_for_each_entry_safe(cb, next, &dev->read_list.list, list)
+       list_for_each_entry(cb, &dev->read_list.list, list)
                if (mei_cl_cmp_id(cl, cb->cl))
                        return cb;
        return NULL;
@@ -375,6 +417,23 @@ void mei_host_client_init(struct work_struct *work)
        mutex_unlock(&dev->device_lock);
 }
 
+/**
+ * mei_hbuf_acquire: try to acquire host buffer
+ *
+ * @dev: the device structure
+ * returns true if host buffer was acquired
+ */
+bool mei_hbuf_acquire(struct mei_device *dev)
+{
+       if (!dev->hbuf_is_ready) {
+               dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
+               return false;
+       }
+
+       dev->hbuf_is_ready = false;
+
+       return true;
+}
 
 /**
  * mei_cl_disconnect - disconnect host client from the me one
@@ -406,8 +465,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
                return -ENOMEM;
 
        cb->fop_type = MEI_FOP_CLOSE;
-       if (dev->hbuf_is_ready) {
-               dev->hbuf_is_ready = false;
+       if (mei_hbuf_acquire(dev)) {
                if (mei_hbm_cl_disconnect_req(dev, cl)) {
                        rets = -ENODEV;
                        cl_err(dev, cl, "failed to disconnect.\n");
@@ -461,17 +519,17 @@ free:
 bool mei_cl_is_other_connecting(struct mei_cl *cl)
 {
        struct mei_device *dev;
-       struct mei_cl *pos;
-       struct mei_cl *next;
+       struct mei_cl *ocl; /* the other client */
 
        if (WARN_ON(!cl || !cl->dev))
                return false;
 
        dev = cl->dev;
 
-       list_for_each_entry_safe(pos, next, &dev->file_list, link) {
-               if ((pos->state == MEI_FILE_CONNECTING) &&
-                   (pos != cl) && cl->me_client_id == pos->me_client_id)
+       list_for_each_entry(ocl, &dev->file_list, link) {
+               if (ocl->state == MEI_FILE_CONNECTING &&
+                   ocl != cl &&
+                   cl->me_client_id == ocl->me_client_id)
                        return true;
 
        }
@@ -505,11 +563,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
                goto out;
        }
 
-       cb->fop_type = MEI_FOP_IOCTL;
-
-       if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
-               dev->hbuf_is_ready = false;
+       cb->fop_type = MEI_FOP_CONNECT;
 
+       /* run hbuf acquire last so we don't have to undo */
+       if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
                if (mei_hbm_cl_connect_req(dev, cl)) {
                        rets = -ENODEV;
                        goto out;
@@ -521,18 +578,19 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
        }
 
        mutex_unlock(&dev->device_lock);
-       rets = wait_event_timeout(dev->wait_recvd_msg,
-                                (cl->state == MEI_FILE_CONNECTED ||
-                                 cl->state == MEI_FILE_DISCONNECTED),
-                                mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
+       wait_event_timeout(dev->wait_recvd_msg,
+                       (cl->state == MEI_FILE_CONNECTED ||
+                        cl->state == MEI_FILE_DISCONNECTED),
+                       mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
        mutex_lock(&dev->device_lock);
 
        if (cl->state != MEI_FILE_CONNECTED) {
-               rets = -EFAULT;
+               /* something went really wrong */
+               if (!cl->status)
+                       cl->status = -EFAULT;
 
                mei_io_list_flush(&dev->ctrl_rd_list, cl);
                mei_io_list_flush(&dev->ctrl_wr_list, cl);
-               goto out;
        }
 
        rets = cl->status;
@@ -554,7 +612,8 @@ out:
 int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 {
        struct mei_device *dev;
-       int i;
+       struct mei_me_client *me_cl;
+       int id;
 
        if (WARN_ON(!cl || !cl->dev))
                return -EINVAL;
@@ -567,19 +626,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
        if (cl->mei_flow_ctrl_creds > 0)
                return 1;
 
-       for (i = 0; i < dev->me_clients_num; i++) {
-               struct mei_me_client  *me_cl = &dev->me_clients[i];
-               if (me_cl->client_id == cl->me_client_id) {
-                       if (me_cl->mei_flow_ctrl_creds) {
-                               if (WARN_ON(me_cl->props.single_recv_buf == 0))
-                                       return -EINVAL;
-                               return 1;
-                       } else {
-                               return 0;
-                       }
-               }
+       id = mei_me_cl_by_id(dev, cl->me_client_id);
+       if (id < 0) {
+               cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+               return id;
        }
-       return -ENOENT;
+
+       me_cl = &dev->me_clients[id];
+       if (me_cl->mei_flow_ctrl_creds) {
+               if (WARN_ON(me_cl->props.single_recv_buf == 0))
+                       return -EINVAL;
+               return 1;
+       }
+       return 0;
 }
 
 /**
@@ -595,32 +654,31 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 {
        struct mei_device *dev;
-       int i;
+       struct mei_me_client *me_cl;
+       int id;
 
        if (WARN_ON(!cl || !cl->dev))
                return -EINVAL;
 
        dev = cl->dev;
 
-       if (!dev->me_clients_num)
-               return -ENOENT;
+       id = mei_me_cl_by_id(dev, cl->me_client_id);
+       if (id < 0) {
+               cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+               return id;
+       }
 
-       for (i = 0; i < dev->me_clients_num; i++) {
-               struct mei_me_client  *me_cl = &dev->me_clients[i];
-               if (me_cl->client_id == cl->me_client_id) {
-                       if (me_cl->props.single_recv_buf != 0) {
-                               if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
-                                       return -EINVAL;
-                               dev->me_clients[i].mei_flow_ctrl_creds--;
-                       } else {
-                               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
-                                       return -EINVAL;
-                               cl->mei_flow_ctrl_creds--;
-                       }
-                       return 0;
-               }
+       me_cl = &dev->me_clients[id];
+       if (me_cl->props.single_recv_buf != 0) {
+               if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+                       return -EINVAL;
+               me_cl->mei_flow_ctrl_creds--;
+       } else {
+               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+                       return -EINVAL;
+               cl->mei_flow_ctrl_creds--;
        }
-       return -ENOENT;
+       return 0;
 }
 
 /**
@@ -652,7 +710,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
        i = mei_me_cl_by_id(dev, cl->me_client_id);
        if (i < 0) {
                cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
-               return  -ENODEV;
+               return  -ENOTTY;
        }
 
        cb = mei_io_cb_init(cl, NULL);
@@ -666,8 +724,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
                goto err;
 
        cb->fop_type = MEI_FOP_READ;
-       if (dev->hbuf_is_ready) {
-               dev->hbuf_is_ready = false;
+       if (mei_hbuf_acquire(dev)) {
                if (mei_hbm_cl_flow_control_req(dev, cl)) {
                        cl_err(dev, cl, "flow control send failed\n");
                        rets = -ENODEV;
@@ -687,27 +744,26 @@ err:
 }
 
 /**
- * mei_cl_irq_write_complete - write a message to device
+ * mei_cl_irq_write - write a message to device
  *     from the interrupt thread context
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise error.
  */
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                                    s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                    struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev;
        struct mei_msg_data *buf;
        struct mei_msg_hdr mei_hdr;
        size_t len;
        u32 msg_slots;
+       int slots;
        int rets;
 
-
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
 
@@ -724,6 +780,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
                return 0;
        }
 
+       slots = mei_hbuf_empty_slots(dev);
        len = buf->size - cb->buf_idx;
        msg_slots = mei_data2slots(len);
 
@@ -732,13 +789,13 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
        mei_hdr.reserved = 0;
        mei_hdr.internal = cb->internal;
 
-       if (*slots >= msg_slots) {
+       if (slots >= msg_slots) {
                mei_hdr.length = len;
                mei_hdr.msg_complete = 1;
        /* Split the message only if we can write the whole host buffer */
-       } else if (*slots == dev->hbuf_depth) {
-               msg_slots = *slots;
-               len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+       } else if (slots == dev->hbuf_depth) {
+               msg_slots = slots;
+               len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
                mei_hdr.length = len;
                mei_hdr.msg_complete = 0;
        } else {
@@ -749,7 +806,6 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
        cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
                        cb->request_buffer.size, cb->buf_idx);
 
-       *slots -=  msg_slots;
        rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
        if (rets) {
                cl->status = rets;
@@ -802,21 +858,29 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 
 
        cb->fop_type = MEI_FOP_WRITE;
+       cb->buf_idx = 0;
+       cl->writing_state = MEI_IDLE;
+
+       mei_hdr.host_addr = cl->host_client_id;
+       mei_hdr.me_addr = cl->me_client_id;
+       mei_hdr.reserved = 0;
+       mei_hdr.msg_complete = 0;
+       mei_hdr.internal = cb->internal;
 
        rets = mei_cl_flow_ctrl_creds(cl);
        if (rets < 0)
                goto err;
 
-       /* Host buffer is not ready, we queue the request */
-       if (rets == 0 || !dev->hbuf_is_ready) {
-               cb->buf_idx = 0;
-               /* unseting complete will enqueue the cb for write */
-               mei_hdr.msg_complete = 0;
+       if (rets == 0) {
+               cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
+               rets = buf->size;
+               goto out;
+       }
+       if (!mei_hbuf_acquire(dev)) {
+               cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
                rets = buf->size;
                goto out;
        }
-
-       dev->hbuf_is_ready = false;
 
        /* Check for a maximum length */
        if (buf->size > mei_hbuf_max_len(dev)) {
@@ -827,12 +891,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
                mei_hdr.msg_complete = 1;
        }
 
-       mei_hdr.host_addr = cl->host_client_id;
-       mei_hdr.me_addr = cl->me_client_id;
-       mei_hdr.reserved = 0;
-       mei_hdr.internal = cb->internal;
-
-
        rets = mei_write_message(dev, &mei_hdr, buf->data);
        if (rets)
                goto err;
@@ -840,13 +898,12 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
        cl->writing_state = MEI_WRITING;
        cb->buf_idx = mei_hdr.length;
 
-       rets = buf->size;
 out:
        if (mei_hdr.msg_complete) {
-               if (mei_cl_flow_ctrl_reduce(cl)) {
-                       rets = -ENODEV;
+               rets = mei_cl_flow_ctrl_reduce(cl);
+               if (rets < 0)
                        goto err;
-               }
+
                list_add_tail(&cb->list, &dev->write_waiting_list.list);
        } else {
                list_add_tail(&cb->list, &dev->write_list.list);
@@ -856,15 +913,18 @@ out:
        if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
 
                mutex_unlock(&dev->device_lock);
-               if (wait_event_interruptible(cl->tx_wait,
-                       cl->writing_state == MEI_WRITE_COMPLETE)) {
-                               if (signal_pending(current))
-                                       rets = -EINTR;
-                               else
-                                       rets = -ERESTARTSYS;
-               }
+               rets = wait_event_interruptible(cl->tx_wait,
+                               cl->writing_state == MEI_WRITE_COMPLETE);
                mutex_lock(&dev->device_lock);
+               /* wait_event_interruptible returns -ERESTARTSYS */
+               if (rets) {
+                       if (signal_pending(current))
+                               rets = -EINTR;
+                       goto err;
+               }
        }
+
+       rets = buf->size;
 err:
        return rets;
 }
@@ -905,9 +965,9 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 
 void mei_cl_all_disconnect(struct mei_device *dev)
 {
-       struct mei_cl *cl, *next;
+       struct mei_cl *cl;
 
-       list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+       list_for_each_entry(cl, &dev->file_list, link) {
                cl->state = MEI_FILE_DISCONNECTED;
                cl->mei_flow_ctrl_creds = 0;
                cl->timer_count = 0;
@@ -922,8 +982,8 @@ void mei_cl_all_disconnect(struct mei_device *dev)
  */
 void mei_cl_all_wakeup(struct mei_device *dev)
 {
-       struct mei_cl *cl, *next;
-       list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+       struct mei_cl *cl;
+       list_for_each_entry(cl, &dev->file_list, link) {
                if (waitqueue_active(&cl->rx_wait)) {
                        cl_dbg(dev, cl, "Waking up reading client!\n");
                        wake_up_interruptible(&cl->rx_wait);
@@ -942,20 +1002,8 @@ void mei_cl_all_wakeup(struct mei_device *dev)
  */
 void mei_cl_all_write_clear(struct mei_device *dev)
 {
-       struct mei_cl_cb *cb, *next;
-       struct list_head *list;
-
-       list = &dev->write_list.list;
-       list_for_each_entry_safe(cb, next, list, list) {
-               list_del(&cb->list);
-               mei_io_cb_free(cb);
-       }
-
-       list = &dev->write_waiting_list.list;
-       list_for_each_entry_safe(cb, next, list, list) {
-               list_del(&cb->list);
-               mei_io_cb_free(cb);
-       }
+       mei_io_list_free(&dev->write_list, NULL);
+       mei_io_list_free(&dev->write_waiting_list, NULL);
 }
 
 
index c8396e582f1c697d296834cb62f19442998b59be..96d5de0389f9471e1ff7cb8ca4843d64ded0c7f9 100644 (file)
@@ -45,8 +45,6 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
 {
        INIT_LIST_HEAD(&list->list);
 }
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
-
 /*
  * MEI Host Client Functions
  */
@@ -61,22 +59,6 @@ int mei_cl_unlink(struct mei_cl *cl);
 int mei_cl_flush_queues(struct mei_cl *cl);
 struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
 
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true  - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
-                               const struct mei_cl *cl2)
-{
-       return cl1 && cl2 &&
-               (cl1->host_client_id == cl2->host_client_id) &&
-               (cl1->me_client_id == cl2->me_client_id);
-}
-
 
 int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
 
@@ -86,15 +68,15 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
  */
 static inline bool mei_cl_is_connected(struct mei_cl *cl)
 {
-       return (cl->dev &&
+       return  cl->dev &&
                cl->dev->dev_state == MEI_DEV_ENABLED &&
-               cl->state == MEI_FILE_CONNECTED);
+               cl->state == MEI_FILE_CONNECTED;
 }
 static inline bool mei_cl_is_transitioning(struct mei_cl *cl)
 {
-       return (MEI_FILE_INITIALIZING == cl->state ||
+       return  MEI_FILE_INITIALIZING == cl->state ||
                MEI_FILE_DISCONNECTED == cl->state ||
-               MEI_FILE_DISCONNECTING == cl->state);
+               MEI_FILE_DISCONNECTING == cl->state;
 }
 
 bool mei_cl_is_other_connecting(struct mei_cl *cl);
@@ -102,8 +84,8 @@ int mei_cl_disconnect(struct mei_cl *cl);
 int mei_cl_connect(struct mei_cl *cl, struct file *file);
 int mei_cl_read_start(struct mei_cl *cl, size_t length);
 int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                               s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                    struct mei_cl_cb *cmpl_list);
 
 void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 
index a3ae154444b2e81d60066ef4a1aefe70f7b51cc4..ced5b777c70fde3926df4c8e5ae2329d326e185c 100644 (file)
@@ -75,6 +75,54 @@ static const struct file_operations mei_dbgfs_fops_meclients = {
        .llseek = generic_file_llseek,
 };
 
+static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
+                                       size_t cnt, loff_t *ppos)
+{
+       struct mei_device *dev = fp->private_data;
+       struct mei_cl *cl;
+       const size_t bufsz = 1024;
+       char *buf;
+       int i = 0;
+       int pos = 0;
+       int ret;
+
+       if (!dev)
+               return -ENODEV;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if  (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "  |me|host|state|rd|wr|\n");
+
+       mutex_lock(&dev->device_lock);
+
+       /*  if the driver is not enabled the list won't b consitent */
+       if (dev->dev_state != MEI_DEV_ENABLED)
+               goto out;
+
+       list_for_each_entry(cl, &dev->file_list, link) {
+
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "%2d|%2d|%4d|%5d|%2d|%2d|\n",
+                       i, cl->me_client_id, cl->host_client_id, cl->state,
+                       cl->reading_state, cl->writing_state);
+               i++;
+       }
+out:
+       mutex_unlock(&dev->device_lock);
+       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_active = {
+       .open = simple_open,
+       .read = mei_dbgfs_read_active,
+       .llseek = generic_file_llseek,
+};
+
 static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
                                        size_t cnt, loff_t *ppos)
 {
@@ -128,6 +176,12 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
                dev_err(&dev->pdev->dev, "meclients: registration failed\n");
                goto err;
        }
+       f = debugfs_create_file("active", S_IRUSR, dir,
+                               dev, &mei_dbgfs_fops_active);
+       if (!f) {
+               dev_err(&dev->pdev->dev, "meclients: registration failed\n");
+               goto err;
+       }
        f = debugfs_create_file("devstate", S_IRUSR, dir,
                                dev, &mei_dbgfs_fops_devstate);
        if (!f) {
index 28cd74c073b99e572161e668dba5082ac2c3cabf..4960288e543a2657fbf80689eef5003b93f83428 100644 (file)
 
 #include "mei_dev.h"
 #include "hbm.h"
-#include "hw-me.h"
+#include "client.h"
+
+static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
+{
+#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
+       switch (status) {
+       MEI_CL_CS(SUCCESS);
+       MEI_CL_CS(NOT_FOUND);
+       MEI_CL_CS(ALREADY_STARTED);
+       MEI_CL_CS(OUT_OF_RESOURCES);
+       MEI_CL_CS(MESSAGE_SMALL);
+       default: return "unknown";
+       }
+#undef MEI_CL_CCS
+}
+
+/**
+ * mei_cl_conn_status_to_errno - convert client connect response
+ * status to error code
+ *
+ * @status: client connect response status
+ *
+ * returns corresponding error code
+ */
+static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
+{
+       switch (status) {
+       case MEI_CL_CONN_SUCCESS:          return 0;
+       case MEI_CL_CONN_NOT_FOUND:        return -ENOTTY;
+       case MEI_CL_CONN_ALREADY_STARTED:  return -EBUSY;
+       case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
+       case MEI_CL_CONN_MESSAGE_SMALL:    return -EINVAL;
+       default:                           return -EINVAL;
+       }
+}
 
 /**
  * mei_hbm_me_cl_allocate - allocates storage for me clients
@@ -99,33 +133,6 @@ bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
 }
 
 
-/**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
-               struct hbm_client_connect_response *rs)
-{
-       if (mei_hbm_cl_addr_equal(cl, rs)) {
-               if (!rs->status) {
-                       cl->state = MEI_FILE_CONNECTED;
-                       cl->status = 0;
-
-               } else {
-                       cl->state = MEI_FILE_DISCONNECTED;
-                       cl->status = -ENODEV;
-               }
-               cl->timer_count = 0;
-
-               return true;
-       }
-       return false;
-}
-
 /**
  * mei_hbm_idle - set hbm to idle state
  *
@@ -147,13 +154,13 @@ int mei_hbm_start_wait(struct mei_device *dev)
        ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
                        dev->hbm_state == MEI_HBM_IDLE ||
                        dev->hbm_state >= MEI_HBM_STARTED,
-                       mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+                       mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
        mutex_lock(&dev->device_lock);
 
        if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
                dev->hbm_state = MEI_HBM_IDLE;
                dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
-               return -ETIMEDOUT;
+               return -ETIME;
        }
        return 0;
 }
@@ -283,17 +290,18 @@ static int mei_hbm_prop_req(struct mei_device *dev)
 }
 
 /**
- * mei_hbm_stop_req_prepare - prepare stop request message
+ * mei_hbm_stop_req - send stop request message
  *
  * @dev - mei device
- * @mei_hdr - mei message header
- * @data - hbm message body buffer
+ * @cl: client info
+ *
+ * This function returns -EIO on write failure
  */
-static void mei_hbm_stop_req_prepare(struct mei_device *dev,
-               struct mei_msg_hdr *mei_hdr, unsigned char *data)
+static int mei_hbm_stop_req(struct mei_device *dev)
 {
+       struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
        struct hbm_host_stop_request *req =
-                       (struct hbm_host_stop_request *)data;
+                       (struct hbm_host_stop_request *)dev->wr_msg.data;
        const size_t len = sizeof(struct hbm_host_stop_request);
 
        mei_hbm_hdr(mei_hdr, len);
@@ -301,6 +309,8 @@ static void mei_hbm_stop_req_prepare(struct mei_device *dev,
        memset(req, 0, len);
        req->hbm_cmd = HOST_STOP_REQ_CMD;
        req->reason = DRIVER_STOP_REQUEST;
+
+       return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
 }
 
 /**
@@ -319,8 +329,7 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
        mei_hbm_hdr(mei_hdr, len);
        mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
 
-       dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
-               cl->host_client_id, cl->me_client_id);
+       cl_dbg(dev, cl, "sending flow control\n");
 
        return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
 }
@@ -330,27 +339,34 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
  *
  * @dev: the device structure
  * @flow: flow control.
+ *
+ * return 0 on success, < 0 otherwise
  */
-static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
+static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
                                  struct hbm_flow_control *flow)
 {
-       struct mei_me_client *client;
-       int i;
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               client = &dev->me_clients[i];
-               if (client && flow->me_addr == client->client_id) {
-                       if (client->props.single_recv_buf) {
-                               client->mei_flow_ctrl_creds++;
-                               dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
-                                   flow->me_addr);
-                               dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
-                                   client->mei_flow_ctrl_creds);
-                       } else {
-                               BUG();  /* error in flow control */
-                       }
-               }
+       struct mei_me_client *me_cl;
+       int id;
+
+       id = mei_me_cl_by_id(dev, flow->me_addr);
+       if (id < 0) {
+               dev_err(&dev->pdev->dev, "no such me client %d\n",
+                       flow->me_addr);
+               return id;
        }
+
+       me_cl = &dev->me_clients[id];
+       if (me_cl->props.single_recv_buf) {
+               me_cl->mei_flow_ctrl_creds++;
+               dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+                   flow->me_addr);
+               dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+                   me_cl->mei_flow_ctrl_creds);
+       } else {
+               BUG();  /* error in flow control */
+       }
+
+       return 0;
 }
 
 /**
@@ -362,8 +378,7 @@ static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
 static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
                struct hbm_flow_control *flow_control)
 {
-       struct mei_cl *cl = NULL;
-       struct mei_cl *next = NULL;
+       struct mei_cl *cl;
 
        if (!flow_control->host_addr) {
                /* single receive buffer */
@@ -372,7 +387,7 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
        }
 
        /* normal connection */
-       list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+       list_for_each_entry(cl, &dev->file_list, link) {
                if (mei_hbm_cl_addr_equal(cl, flow_control)) {
                        cl->mei_flow_ctrl_creds++;
                        dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
@@ -404,6 +419,25 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
        return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
 }
 
+/**
+ * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
+ *
+ * @dev: the device structure
+ * @cl: a client to disconnect from
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
+{
+       struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+       const size_t len = sizeof(struct hbm_client_connect_response);
+
+       mei_hbm_hdr(mei_hdr, len);
+       mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, dev->wr_msg.data, len);
+
+       return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
 /**
  * mei_hbm_cl_disconnect_res - disconnect response from ME
  *
@@ -414,29 +448,23 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
                struct hbm_client_connect_response *rs)
 {
        struct mei_cl *cl;
-       struct mei_cl_cb *pos = NULL, *next = NULL;
-
-       dev_dbg(&dev->pdev->dev,
-                       "disconnect_response:\n"
-                       "ME Client = %d\n"
-                       "Host Client = %d\n"
-                       "Status = %d\n",
-                       rs->me_addr,
-                       rs->host_addr,
-                       rs->status);
-
-       list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
-               cl = pos->cl;
-
-               if (!cl) {
-                       list_del(&pos->list);
+       struct mei_cl_cb *cb, *next;
+
+       dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
+                       rs->me_addr, rs->host_addr, rs->status);
+
+       list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
+               cl = cb->cl;
+
+               /* this should not happen */
+               if (WARN_ON(!cl)) {
+                       list_del(&cb->list);
                        return;
                }
 
-               dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
                if (mei_hbm_cl_addr_equal(cl, rs)) {
-                       list_del(&pos->list);
-                       if (!rs->status)
+                       list_del(&cb->list);
+                       if (rs->status == MEI_CL_DISCONN_SUCCESS)
                                cl->state = MEI_FILE_DISCONNECTED;
 
                        cl->status = 0;
@@ -476,46 +504,41 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
 {
 
        struct mei_cl *cl;
-       struct mei_cl_cb *pos = NULL, *next = NULL;
+       struct mei_cl_cb *cb, *next;
 
-       dev_dbg(&dev->pdev->dev,
-                       "connect_response:\n"
-                       "ME Client = %d\n"
-                       "Host Client = %d\n"
-                       "Status = %d\n",
-                       rs->me_addr,
-                       rs->host_addr,
-                       rs->status);
+       dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
+                       rs->me_addr, rs->host_addr,
+                       mei_cl_conn_status_str(rs->status));
 
-       /* if WD or iamthif client treat specially */
+       cl = NULL;
 
-       if (is_treat_specially_client(&dev->wd_cl, rs)) {
-               dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
-               mei_watchdog_register(dev);
+       list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
 
-               return;
-       }
+               cl = cb->cl;
+               /* this should not happen */
+               if (WARN_ON(!cl)) {
+                       list_del_init(&cb->list);
+                       continue;
+               }
 
-       if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
-               dev->iamthif_state = MEI_IAMTHIF_IDLE;
-               return;
-       }
-       list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
+               if (cb->fop_type !=  MEI_FOP_CONNECT)
+                       continue;
 
-               cl = pos->cl;
-               if (!cl) {
-                       list_del(&pos->list);
-                       return;
-               }
-               if (pos->fop_type == MEI_FOP_IOCTL) {
-                       if (is_treat_specially_client(cl, rs)) {
-                               list_del(&pos->list);
-                               cl->status = 0;
-                               cl->timer_count = 0;
-                               break;
-                       }
+               if (mei_hbm_cl_addr_equal(cl, rs)) {
+                       list_del(&cb->list);
+                       break;
                }
        }
+
+       if (!cl)
+               return;
+
+       cl->timer_count = 0;
+       if (rs->status == MEI_CL_CONN_SUCCESS)
+               cl->state = MEI_FILE_CONNECTED;
+       else
+               cl->state = MEI_FILE_DISCONNECTED;
+       cl->status = mei_cl_conn_status_to_errno(rs->status);
 }
 
 
@@ -525,32 +548,34 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
  *
  * @dev: the device structure.
  * @disconnect_req: disconnect request bus message from the me
+ *
+ * returns -ENOMEM on allocation failure
  */
-static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
+static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
                struct hbm_client_connect_request *disconnect_req)
 {
-       struct mei_cl *cl, *next;
-       const size_t len = sizeof(struct hbm_client_connect_response);
+       struct mei_cl *cl;
+       struct mei_cl_cb *cb;
 
-       list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+       list_for_each_entry(cl, &dev->file_list, link) {
                if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
                        dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
                                        disconnect_req->host_addr,
                                        disconnect_req->me_addr);
                        cl->state = MEI_FILE_DISCONNECTED;
                        cl->timer_count = 0;
-                       if (cl == &dev->wd_cl)
-                               dev->wd_pending = false;
-                       else if (cl == &dev->iamthif_cl)
-                               dev->iamthif_timer = 0;
-
-                       /* prepare disconnect response */
-                       mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
-                       mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
-                                        dev->wr_ext_msg.data, len);
+
+                       cb = mei_io_cb_init(cl, NULL);
+                       if (!cb)
+                               return -ENOMEM;
+                       cb->fop_type = MEI_FOP_DISCONNECT_RSP;
+                       cl_dbg(dev, cl, "add disconnect response as first\n");
+                       list_add(&cb->list, &dev->ctrl_wr_list.list);
+
                        break;
                }
        }
+       return 0;
 }
 
 
@@ -629,10 +654,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                        dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
 
                        dev->hbm_state = MEI_HBM_STOPPED;
-                       mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
-                                               dev->wr_msg.data);
-                       if (mei_write_message(dev, &dev->wr_msg.hdr,
-                                       dev->wr_msg.data)) {
+                       if (mei_hbm_stop_req(dev)) {
                                dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
                                return -EIO;
                        }
@@ -778,10 +800,11 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 
        case ME_STOP_REQ_CMD:
                dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
-
                dev->hbm_state = MEI_HBM_STOPPED;
-               mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
-                                       dev->wr_ext_msg.data);
+               if (mei_hbm_stop_req(dev)) {
+                       dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
+                       return -EIO;
+               }
                break;
        default:
                BUG();
index 5f92188a5cd7323653026dc5c4f57cdedb3c107e..20e8782711c0c5f53e8e43c97b0c32476b3d27c8 100644 (file)
@@ -54,6 +54,7 @@ int mei_hbm_start_req(struct mei_device *dev);
 int mei_hbm_start_wait(struct mei_device *dev);
 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl);
 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
 bool mei_hbm_version_is_supported(struct mei_device *dev);
 
index 6f656c053b144a44b20b798e75e16f3efab49f7f..8dbdaaef1af57dcbd63f60bd1088ea39d8d80596 100644 (file)
 #include <linux/interrupt.h>
 
 #include "mei_dev.h"
-#include "hw-me.h"
-
 #include "hbm.h"
 
+#include "hw-me.h"
+#include "hw-me-regs.h"
 
 /**
  * mei_me_reg_read - Reads 32bit data from the mei device
@@ -240,11 +240,11 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
        mutex_unlock(&dev->device_lock);
        err = wait_event_interruptible_timeout(dev->wait_hw_ready,
                        dev->recvd_hw_ready,
-                       mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+                       mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
        mutex_lock(&dev->device_lock);
        if (!err && !dev->recvd_hw_ready) {
                if (!err)
-                       err = -ETIMEDOUT;
+                       err = -ETIME;
                dev_err(&dev->pdev->dev,
                        "wait hw ready failed. status = %d\n", err);
                return err;
@@ -303,7 +303,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
  *
  * @dev: the device structure
  *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ * returns -EOVERFLOW if overflow, otherwise empty slots count
  */
 static int mei_me_hbuf_empty_slots(struct mei_device *dev)
 {
@@ -326,7 +326,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
 
 
 /**
- * mei_write_message - writes a message to mei device.
+ * mei_me_write_message - writes a message to mei device.
  *
  * @dev: the device structure
  * @header: mei HECI header of message
@@ -354,7 +354,7 @@ static int mei_me_write_message(struct mei_device *dev,
 
        dw_cnt = mei_data2slots(length);
        if (empty_slots < 0 || dw_cnt > empty_slots)
-               return -EIO;
+               return -EMSGSIZE;
 
        mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
 
@@ -381,7 +381,7 @@ static int mei_me_write_message(struct mei_device *dev,
  *
  * @dev: the device structure
  *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ * returns -EOVERFLOW if overflow, otherwise filled slots count
  */
 static int mei_me_count_full_read_slots(struct mei_device *dev)
 {
@@ -505,17 +505,25 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
        /* check slots available for reading */
        slots = mei_count_full_read_slots(dev);
        while (slots > 0) {
-               /* we have urgent data to send so break the read */
-               if (dev->wr_ext_msg.hdr.length)
-                       break;
                dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
                rets = mei_irq_read_handler(dev, &complete_list, &slots);
+               /* There is a race between ME write and interrupt delivery:
+                * Not all data is always available immediately after the
+                * interrupt, so try to read again on the next interrupt.
+                */
+               if (rets == -ENODATA)
+                       break;
+
                if (rets && dev->dev_state != MEI_DEV_RESETTING) {
+                       dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n",
+                                               rets);
                        schedule_work(&dev->reset_work);
                        goto end;
                }
        }
 
+       dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+
        rets = mei_irq_write_handler(dev, &complete_list);
 
        dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
index 80bd829fbd9ac4f39332a5053cecbce31ff485da..893d5119fa9bb6eec02d6b82f4452611f4637f7b 100644 (file)
@@ -20,6 +20,7 @@
 #define _MEI_INTERFACE_H_
 
 #include <linux/mei.h>
+#include <linux/irqreturn.h>
 #include "mei_dev.h"
 #include "client.h"
 
diff --git a/drivers/misc/mei/hw-txe-regs.h b/drivers/misc/mei/hw-txe-regs.h
new file mode 100644 (file)
index 0000000..7283c24
--- /dev/null
@@ -0,0 +1,294 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING
+ *
+ * Contact Information:
+ *     Intel Corporation.
+ *     linux-mei@linux.intel.com
+ *     http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef _MEI_HW_TXE_REGS_H_
+#define _MEI_HW_TXE_REGS_H_
+
+#include "hw.h"
+
+#define SEC_ALIVENESS_TIMER_TIMEOUT        (5 * MSEC_PER_SEC)
+#define SEC_ALIVENESS_WAIT_TIMEOUT         (1 * MSEC_PER_SEC)
+#define SEC_RESET_WAIT_TIMEOUT             (1 * MSEC_PER_SEC)
+#define SEC_READY_WAIT_TIMEOUT             (5 * MSEC_PER_SEC)
+#define START_MESSAGE_RESPONSE_WAIT_TIMEOUT (5 * MSEC_PER_SEC)
+#define RESET_CANCEL_WAIT_TIMEOUT          (1 * MSEC_PER_SEC)
+
+enum {
+       SEC_BAR,
+       BRIDGE_BAR,
+
+       NUM_OF_MEM_BARS
+};
+
+/* SeC FW Status Register
+ *
+ * FW uses this register in order to report its status to host.
+ * This register resides in PCI-E config space.
+ */
+#define PCI_CFG_TXE_FW_STS0   0x40
+#  define PCI_CFG_TXE_FW_STS0_WRK_ST_MSK    0x0000000F
+#  define PCI_CFG_TXE_FW_STS0_OP_ST_MSK     0x000001C0
+#  define PCI_CFG_TXE_FW_STS0_FW_INIT_CMPLT 0x00000200
+#  define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK  0x0000F000
+#  define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK   0x000F0000
+#  define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK   0x00F00000
+
+
+#define IPC_BASE_ADDR  0x80400 /* SeC IPC Base Address */
+
+/* IPC Input Doorbell Register */
+#define SEC_IPC_INPUT_DOORBELL_REG       (0x0000 + IPC_BASE_ADDR)
+
+/* IPC Input Status Register
+ * This register indicates whether or not processing of
+ * the most recent command has been completed by the SEC
+ * New commands and payloads should not be written by the Host
+ * until this indicates that the previous command has been processed.
+ */
+#define SEC_IPC_INPUT_STATUS_REG         (0x0008 + IPC_BASE_ADDR)
+#  define SEC_IPC_INPUT_STATUS_RDY    BIT(0)
+
+/* IPC Host Interrupt Status Register */
+#define SEC_IPC_HOST_INT_STATUS_REG      (0x0010 + IPC_BASE_ADDR)
+#define   SEC_IPC_HOST_INT_STATUS_OUT_DB             BIT(0)
+#define   SEC_IPC_HOST_INT_STATUS_IN_RDY             BIT(1)
+#define   SEC_IPC_HOST_INT_STATUS_HDCP_M0_RCVD       BIT(5)
+#define   SEC_IPC_HOST_INT_STATUS_ILL_MEM_ACCESS     BIT(17)
+#define   SEC_IPC_HOST_INT_STATUS_AES_HKEY_ERR       BIT(18)
+#define   SEC_IPC_HOST_INT_STATUS_DES_HKEY_ERR       BIT(19)
+#define   SEC_IPC_HOST_INT_STATUS_TMRMTB_OVERFLOW    BIT(21)
+
+/* Convenient mask for pending interrupts */
+#define   SEC_IPC_HOST_INT_STATUS_PENDING \
+               (SEC_IPC_HOST_INT_STATUS_OUT_DB| \
+               SEC_IPC_HOST_INT_STATUS_IN_RDY)
+
+/* IPC Host Interrupt Mask Register */
+#define SEC_IPC_HOST_INT_MASK_REG        (0x0014 + IPC_BASE_ADDR)
+
+#  define SEC_IPC_HOST_INT_MASK_OUT_DB BIT(0) /* Output Doorbell Int Mask */
+#  define SEC_IPC_HOST_INT_MASK_IN_RDY BIT(1) /* Input Ready Int Mask */
+
+/* IPC Input Payload RAM */
+#define SEC_IPC_INPUT_PAYLOAD_REG        (0x0100 + IPC_BASE_ADDR)
+/* IPC Shared Payload RAM */
+#define IPC_SHARED_PAYLOAD_REG           (0x0200 + IPC_BASE_ADDR)
+
+/* SeC Address Translation Table Entry 2 - Ctrl
+ *
+ * This register resides also in SeC's PCI-E Memory space.
+ */
+#define SATT2_CTRL_REG                   0x1040
+#  define SATT2_CTRL_VALID_MSK            BIT(0)
+#  define SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT 8
+#  define SATT2_CTRL_BRIDGE_HOST_EN_MSK   BIT(12)
+
+/* SATT Table Entry 2 SAP Base Address Register */
+#define SATT2_SAP_BA_REG                 0x1044
+/* SATT Table Entry 2 SAP Size Register. */
+#define SATT2_SAP_SIZE_REG               0x1048
+ /* SATT Table Entry 2 SAP Bridge Address - LSB Register */
+#define SATT2_BRG_BA_LSB_REG             0x104C
+
+/* Host High-level Interrupt Status Register */
+#define HHISR_REG                        0x2020
+/* Host High-level Interrupt Enable Register
+ *
+ * Resides in PCI memory space. This is the top hierarchy for
+ * interrupts from SeC to host, aggregating both interrupts that
+ * arrive through HICR registers as well as interrupts
+ * that arrive via IPC.
+ */
+#define HHIER_REG                        0x2024
+#define   IPC_HHIER_SEC        BIT(0)
+#define   IPC_HHIER_BRIDGE     BIT(1)
+#define   IPC_HHIER_MSK        (IPC_HHIER_SEC | IPC_HHIER_BRIDGE)
+
+/* Host High-level Interrupt Mask Register.
+ *
+ * Resides in PCI memory space.
+ * This is the top hierarchy for masking interrupts from SeC to host.
+ */
+#define HHIMR_REG                        0x2028
+#define   IPC_HHIMR_SEC       BIT(0)
+#define   IPC_HHIMR_BRIDGE    BIT(1)
+
+/* Host High-level IRQ Status Register */
+#define HHIRQSR_REG                      0x202C
+
+/* Host Interrupt Cause Register 0 - SeC IPC Readiness
+ *
+ * This register is both an ICR to Host from PCI Memory Space
+ * and it is also exposed in the SeC memory space.
+ * This register is used by SeC's IPC driver in order
+ * to synchronize with host about IPC interface state.
+ */
+#define HICR_SEC_IPC_READINESS_REG       0x2040
+#define   HICR_SEC_IPC_READINESS_HOST_RDY  BIT(0)
+#define   HICR_SEC_IPC_READINESS_SEC_RDY   BIT(1)
+#define   HICR_SEC_IPC_READINESS_SYS_RDY     \
+         (HICR_SEC_IPC_READINESS_HOST_RDY | \
+          HICR_SEC_IPC_READINESS_SEC_RDY)
+#define   HICR_SEC_IPC_READINESS_RDY_CLR   BIT(2)
+
+/* Host Interrupt Cause Register 1 - Aliveness Response */
+/* This register is both an ICR to Host from PCI Memory Space
+ * and it is also exposed in the SeC memory space.
+ * The register may be used by SeC to ACK a host request for aliveness.
+ */
+#define HICR_HOST_ALIVENESS_RESP_REG     0x2044
+#define   HICR_HOST_ALIVENESS_RESP_ACK    BIT(0)
+
+/* Host Interrupt Cause Register 2 - SeC IPC Output Doorbell */
+#define HICR_SEC_IPC_OUTPUT_DOORBELL_REG 0x2048
+
+/* Host Interrupt Status Register.
+ *
+ * Resides in PCI memory space.
+ * This is the main register involved in generating interrupts
+ * from SeC to host via HICRs.
+ * The interrupt generation rules are as follows:
+ * An interrupt will be generated whenever for any i,
+ * there is a transition from a state where at least one of
+ * the following conditions did not hold, to a state where
+ * ALL the following conditions hold:
+ * A) HISR.INT[i]_STS == 1.
+ * B) HIER.INT[i]_EN == 1.
+ */
+#define HISR_REG                         0x2060
+#define   HISR_INT_0_STS      BIT(0)
+#define   HISR_INT_1_STS      BIT(1)
+#define   HISR_INT_2_STS      BIT(2)
+#define   HISR_INT_3_STS      BIT(3)
+#define   HISR_INT_4_STS      BIT(4)
+#define   HISR_INT_5_STS      BIT(5)
+#define   HISR_INT_6_STS      BIT(6)
+#define   HISR_INT_7_STS      BIT(7)
+#define   HISR_INT_STS_MSK \
+       (HISR_INT_0_STS | HISR_INT_1_STS | HISR_INT_2_STS)
+
+/* Host Interrupt Enable Register. Resides in PCI memory space. */
+#define HIER_REG                         0x2064
+#define   HIER_INT_0_EN      BIT(0)
+#define   HIER_INT_1_EN      BIT(1)
+#define   HIER_INT_2_EN      BIT(2)
+#define   HIER_INT_3_EN      BIT(3)
+#define   HIER_INT_4_EN      BIT(4)
+#define   HIER_INT_5_EN      BIT(5)
+#define   HIER_INT_6_EN      BIT(6)
+#define   HIER_INT_7_EN      BIT(7)
+
+#define   HIER_INT_EN_MSK \
+        (HIER_INT_0_EN | HIER_INT_1_EN | HIER_INT_2_EN)
+
+
+/* SEC Memory Space IPC output payload.
+ *
+ * This register is part of the output payload which SEC provides to host.
+ */
+#define BRIDGE_IPC_OUTPUT_PAYLOAD_REG    0x20C0
+
+/* SeC Interrupt Cause Register - Host Aliveness Request
+ * This register is both an ICR to SeC and it is also exposed
+ * in the host-visible PCI memory space.
+ * The register is used by host to request SeC aliveness.
+ */
+#define SICR_HOST_ALIVENESS_REQ_REG      0x214C
+#define   SICR_HOST_ALIVENESS_REQ_REQUESTED    BIT(0)
+
+
+/* SeC Interrupt Cause Register - Host IPC Readiness
+ *
+ * This register is both an ICR to SeC and it is also exposed
+ * in the host-visible PCI memory space.
+ * This register is used by the host's SeC driver uses in order
+ * to synchronize with SeC about IPC interface state.
+ */
+#define SICR_HOST_IPC_READINESS_REQ_REG  0x2150
+
+
+#define SICR_HOST_IPC_READINESS_HOST_RDY  BIT(0)
+#define SICR_HOST_IPC_READINESS_SEC_RDY   BIT(1)
+#define SICR_HOST_IPC_READINESS_SYS_RDY     \
+       (SICR_HOST_IPC_READINESS_HOST_RDY | \
+        SICR_HOST_IPC_READINESS_SEC_RDY)
+#define SICR_HOST_IPC_READINESS_RDY_CLR   BIT(2)
+
+/* SeC Interrupt Cause Register - SeC IPC Output Status
+ *
+ * This register indicates whether or not processing of the most recent
+ * command has been completed by the Host.
+ * New commands and payloads should not be written by SeC until this
+ * register indicates that the previous command has been processed.
+ */
+#define SICR_SEC_IPC_OUTPUT_STATUS_REG   0x2154
+#  define SEC_IPC_OUTPUT_STATUS_RDY BIT(0)
+
+
+
+/*  MEI IPC Message payload size 64 bytes */
+#define PAYLOAD_SIZE        64
+
+/* MAX size for SATT range 32MB */
+#define SATT_RANGE_MAX     (32 << 20)
+
+
+#endif /* _MEI_HW_TXE_REGS_H_ */
+
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
new file mode 100644 (file)
index 0000000..f60182a
--- /dev/null
@@ -0,0 +1,1107 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/irqreturn.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw-txe.h"
+#include "client.h"
+#include "hbm.h"
+
+/**
+ * mei_txe_reg_read - Reads 32bit data from the device
+ *
+ * @base_addr: registers base address
+ * @offset: register offset
+ *
+ */
+static inline u32 mei_txe_reg_read(void __iomem *base_addr,
+                                       unsigned long offset)
+{
+       return ioread32(base_addr + offset);
+}
+
+/**
+ * mei_txe_reg_write - Writes 32bit data to the device
+ *
+ * @base_addr: registers base address
+ * @offset: register offset
+ * @value: the value to write
+ */
+static inline void mei_txe_reg_write(void __iomem *base_addr,
+                               unsigned long offset, u32 value)
+{
+       iowrite32(value, base_addr + offset);
+}
+
+/**
+ * mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ *
+ * Doesn't check for aliveness while Reads 32bit data from the SeC BAR
+ */
+static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
+                               unsigned long offset)
+{
+       return mei_txe_reg_read(hw->mem_addr[SEC_BAR], offset);
+}
+
+/**
+ * mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ *
+ * Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
+ */
+static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
+                               unsigned long offset)
+{
+       WARN(!hw->aliveness, "sec read: aliveness not asserted\n");
+       return mei_txe_sec_reg_read_silent(hw, offset);
+}
+/**
+ * mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
+ *   doesn't check for aliveness
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ * @value: value to write
+ *
+ * Doesn't check for aliveness while writes 32bit data from to the SeC BAR
+ */
+static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
+                               unsigned long offset, u32 value)
+{
+       mei_txe_reg_write(hw->mem_addr[SEC_BAR], offset, value);
+}
+
+/**
+ * mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ * @value: value to write
+ *
+ * Writes 32bit data from the SeC BAR and shout loud if aliveness is not set
+ */
+static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
+                               unsigned long offset, u32 value)
+{
+       WARN(!hw->aliveness, "sec write: aliveness not asserted\n");
+       mei_txe_sec_reg_write_silent(hw, offset, value);
+}
+/**
+ * mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
+ *
+ * @hw: the device structure
+ * @offset: offset from which to read the data
+ *
+ */
+static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
+                               unsigned long offset)
+{
+       return mei_txe_reg_read(hw->mem_addr[BRIDGE_BAR], offset);
+}
+
+/**
+ * mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
+ *
+ * @hw: the device structure
+ * @offset: offset from which to write the data
+ * @value: the byte to write
+ */
+static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
+                               unsigned long offset, u32 value)
+{
+       mei_txe_reg_write(hw->mem_addr[BRIDGE_BAR], offset, value);
+}
+
+/**
+ * mei_txe_aliveness_set - request for aliveness change
+ *
+ * @dev: the device structure
+ * @req: requested aliveness value
+ *
+ * Request for aliveness change and returns true if the change is
+ *   really needed and false if aliveness is already
+ *   in the requested state
+ * Requires device lock to be held
+ */
+static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
+{
+
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       bool do_req = hw->aliveness != req;
+
+       dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
+                               hw->aliveness, req);
+       if (do_req) {
+               hw->recvd_aliveness = false;
+               mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
+       }
+       return do_req;
+}
+
+
+/**
+ * mei_txe_aliveness_req_get - get aliveness requested register value
+ *
+ * @dev: the device structure
+ *
+ * Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
+ * from HICR_HOST_ALIVENESS_REQ register value
+ */
+static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 reg;
+       reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);
+       return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED;
+}
+
+/**
+ * mei_txe_aliveness_get - get aliveness response register value
+ * @dev: the device structure
+ *
+ * Extract HICR_HOST_ALIVENESS_RESP_ACK bit
+ * from HICR_HOST_ALIVENESS_RESP register value
+ */
+static u32 mei_txe_aliveness_get(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 reg;
+       reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG);
+       return reg & HICR_HOST_ALIVENESS_RESP_ACK;
+}
+
+/**
+ * mei_txe_aliveness_poll - waits for aliveness to settle
+ *
+ * @dev: the device structure
+ * @expected: expected aliveness value
+ *
+ * Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
+ * returns > 0 if the expected value was received, -ETIME otherwise
+ */
+static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       int t = 0;
+
+       do {
+               hw->aliveness = mei_txe_aliveness_get(dev);
+               if (hw->aliveness == expected) {
+                       dev_dbg(&dev->pdev->dev,
+                               "aliveness settled after %d msecs\n", t);
+                       return t;
+               }
+               mutex_unlock(&dev->device_lock);
+               msleep(MSEC_PER_SEC / 5);
+               mutex_lock(&dev->device_lock);
+               t += MSEC_PER_SEC / 5;
+       } while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
+
+       dev_err(&dev->pdev->dev, "aliveness timed out\n");
+       return -ETIME;
+}
+
+/**
+ * mei_txe_aliveness_wait - waits for aliveness to settle
+ *
+ * @dev: the device structure
+ * @expected: expected aliveness value
+ *
+ * Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
+ * returns returns 0 on success and < 0 otherwise
+ */
+static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       const unsigned long timeout =
+                       msecs_to_jiffies(SEC_ALIVENESS_WAIT_TIMEOUT);
+       long err;
+       int ret;
+
+       hw->aliveness = mei_txe_aliveness_get(dev);
+       if (hw->aliveness == expected)
+               return 0;
+
+       mutex_unlock(&dev->device_lock);
+       err = wait_event_timeout(hw->wait_aliveness,
+                       hw->recvd_aliveness, timeout);
+       mutex_lock(&dev->device_lock);
+
+       hw->aliveness = mei_txe_aliveness_get(dev);
+       ret = hw->aliveness == expected ? 0 : -ETIME;
+
+       if (ret)
+               dev_err(&dev->pdev->dev, "aliveness timed out");
+       else
+               dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n",
+                               jiffies_to_msecs(timeout - err));
+       hw->recvd_aliveness = false;
+       return ret;
+}
+
+/**
+ * mei_txe_aliveness_set_sync - sets an wait for aliveness to complete
+ *
+ * @dev: the device structure
+ *
+ * returns returns 0 on success and < 0 otherwise
+ */
+int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
+{
+       if (mei_txe_aliveness_set(dev, req))
+               return mei_txe_aliveness_wait(dev, req);
+       return 0;
+}
+
+/**
+ * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 hintmsk;
+       /* Enable the SEC_IPC_HOST_INT_MASK_IN_RDY interrupt */
+       hintmsk = mei_txe_sec_reg_read(hw, SEC_IPC_HOST_INT_MASK_REG);
+       hintmsk |= SEC_IPC_HOST_INT_MASK_IN_RDY;
+       mei_txe_sec_reg_write(hw, SEC_IPC_HOST_INT_MASK_REG, hintmsk);
+}
+
+/**
+ * mei_txe_input_doorbell_set
+ *   - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
+ * @dev: the device structure
+ */
+static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
+{
+       /* Clear the interrupt cause */
+       clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause);
+       mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_DOORBELL_REG, 1);
+}
+
+/**
+ * mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
+{
+       mei_txe_br_reg_write(hw,
+                       SICR_SEC_IPC_OUTPUT_STATUS_REG,
+                       SEC_IPC_OUTPUT_STATUS_RDY);
+}
+
+/**
+ * mei_txe_is_input_ready - check if TXE is ready for receiving data
+ *
+ * @dev: the device structure
+ */
+static bool mei_txe_is_input_ready(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 status;
+       status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG);
+       return !!(SEC_IPC_INPUT_STATUS_RDY & status);
+}
+
+/**
+ * mei_txe_intr_clear - clear all interrupts
+ *
+ * @dev: the device structure
+ */
+static inline void mei_txe_intr_clear(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG,
+               SEC_IPC_HOST_INT_STATUS_PENDING);
+       mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK);
+       mei_txe_br_reg_write(hw, HHISR_REG, IPC_HHIER_MSK);
+}
+
+/**
+ * mei_txe_intr_disable - disable all interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_intr_disable(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       mei_txe_br_reg_write(hw, HHIER_REG, 0);
+       mei_txe_br_reg_write(hw, HIER_REG, 0);
+}
+/**
+ * mei_txe_intr_disable - enable all interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_intr_enable(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK);
+       mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
+}
+
+/**
+ * mei_txe_pending_interrupts - check if there are pending interrupts
+ *     only Aliveness, Input ready, and output doorbell are of relevance
+ *
+ * @dev: the device structure
+ *
+ * Checks if there are pending interrupts
+ * only Aliveness, Readiness, Input ready, and Output doorbell are relevant
+ */
+static bool mei_txe_pending_interrupts(struct mei_device *dev)
+{
+
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       bool ret = (hw->intr_cause & (TXE_INTR_READINESS |
+                                     TXE_INTR_ALIVENESS |
+                                     TXE_INTR_IN_READY  |
+                                     TXE_INTR_OUT_DB));
+
+       if (ret) {
+               dev_dbg(&dev->pdev->dev,
+                       "Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n",
+                       !!(hw->intr_cause & TXE_INTR_IN_READY),
+                       !!(hw->intr_cause & TXE_INTR_READINESS),
+                       !!(hw->intr_cause & TXE_INTR_ALIVENESS),
+                       !!(hw->intr_cause & TXE_INTR_OUT_DB));
+       }
+       return ret;
+}
+
+/**
+ * mei_txe_input_payload_write - write a dword to the host buffer
+ *     at offset idx
+ *
+ * @dev: the device structure
+ * @idx: index in the host buffer
+ * @value: value
+ */
+static void mei_txe_input_payload_write(struct mei_device *dev,
+                       unsigned long idx, u32 value)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG +
+                       (idx * sizeof(u32)), value);
+}
+
+/**
+ * mei_txe_out_data_read - read dword from the device buffer
+ *     at offset idx
+ *
+ * @dev: the device structure
+ * @idx: index in the device buffer
+ *
+ * returns register value at index
+ */
+static u32 mei_txe_out_data_read(const struct mei_device *dev,
+                                       unsigned long idx)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       return mei_txe_br_reg_read(hw,
+               BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32)));
+}
+
+/* Readiness */
+
+/**
+ * mei_txe_readiness_set_host_rdy
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_readiness_set_host_rdy(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       mei_txe_br_reg_write(hw,
+               SICR_HOST_IPC_READINESS_REQ_REG,
+               SICR_HOST_IPC_READINESS_HOST_RDY);
+}
+
+/**
+ * mei_txe_readiness_clear
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_readiness_clear(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG,
+                               SICR_HOST_IPC_READINESS_RDY_CLR);
+}
+/**
+ * mei_txe_readiness_get - Reads and returns
+ *     the HICR_SEC_IPC_READINESS register value
+ *
+ * @dev: the device structure
+ */
+static u32 mei_txe_readiness_get(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+}
+
+
+/**
+ * mei_txe_readiness_is_sec_rdy - check readiness
+ *  for HICR_SEC_IPC_READINESS_SEC_RDY
+ *
+ * @readiness - cached readiness state
+ */
+static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
+{
+       return !!(readiness & HICR_SEC_IPC_READINESS_SEC_RDY);
+}
+
+/**
+ * mei_txe_hw_is_ready - check if the hw is ready
+ *
+ * @dev: the device structure
+ */
+static bool mei_txe_hw_is_ready(struct mei_device *dev)
+{
+       u32 readiness =  mei_txe_readiness_get(dev);
+       return mei_txe_readiness_is_sec_rdy(readiness);
+}
+
+/**
+ * mei_txe_host_is_ready - check if the host is ready
+ *
+ * @dev: the device structure
+ */
+static inline bool mei_txe_host_is_ready(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+       return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY);
+}
+
+/**
+ * mei_txe_readiness_wait - wait till readiness settles
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success and -ETIME on timeout
+ */
+static int mei_txe_readiness_wait(struct mei_device *dev)
+{
+       if (mei_txe_hw_is_ready(dev))
+               return 0;
+
+       mutex_unlock(&dev->device_lock);
+       wait_event_timeout(dev->wait_hw_ready, dev->recvd_hw_ready,
+                       msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT));
+       mutex_lock(&dev->device_lock);
+       if (!dev->recvd_hw_ready) {
+               dev_err(&dev->pdev->dev, "wait for readiness failed\n");
+               return -ETIME;
+       }
+
+       dev->recvd_hw_ready = false;
+       return 0;
+}
+
+/**
+ *  mei_txe_hw_config - configure hardware at the start of the devices
+ *
+ * @dev: the device structure
+ *
+ * Configure hardware at the start of the device should be done only
+ *   once at the device probe time
+ */
+static void mei_txe_hw_config(struct mei_device *dev)
+{
+
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       /* Doesn't change in runtime */
+       dev->hbuf_depth = PAYLOAD_SIZE / 4;
+
+       hw->aliveness = mei_txe_aliveness_get(dev);
+       hw->readiness = mei_txe_readiness_get(dev);
+
+       dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
+               hw->aliveness, hw->readiness);
+}
+
+
+/**
+ * mei_txe_write - writes a message to device.
+ *
+ * @dev: the device structure
+ * @header: header of message
+ * @buf: message buffer will be written
+ * returns 1 if success, 0 - otherwise.
+ */
+
+static int mei_txe_write(struct mei_device *dev,
+               struct mei_msg_hdr *header, unsigned char *buf)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       unsigned long rem;
+       unsigned long length;
+       int slots = dev->hbuf_depth;
+       u32 *reg_buf = (u32 *)buf;
+       u32 dw_cnt;
+       int i;
+
+       if (WARN_ON(!header || !buf))
+               return -EINVAL;
+
+       length = header->length;
+
+       dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+
+       dw_cnt = mei_data2slots(length);
+       if (dw_cnt > slots)
+               return -EMSGSIZE;
+
+       if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n"))
+               return -EAGAIN;
+
+       /* Enable Input Ready Interrupt. */
+       mei_txe_input_ready_interrupt_enable(dev);
+
+       if (!mei_txe_is_input_ready(dev)) {
+               dev_err(&dev->pdev->dev, "Input is not ready");
+               return -EAGAIN;
+       }
+
+       mei_txe_input_payload_write(dev, 0, *((u32 *)header));
+
+       for (i = 0; i < length / 4; i++)
+               mei_txe_input_payload_write(dev, i + 1, reg_buf[i]);
+
+       rem = length & 0x3;
+       if (rem > 0) {
+               u32 reg = 0;
+               memcpy(&reg, &buf[length - rem], rem);
+               mei_txe_input_payload_write(dev, i + 1, reg);
+       }
+
+       /* after each write the whole buffer is consumed */
+       hw->slots = 0;
+
+       /* Set Input-Doorbell */
+       mei_txe_input_doorbell_set(hw);
+
+       return 0;
+}
+
+/**
+ * mei_txe_hbuf_max_len - mimics the me hbuf circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns the PAYLOAD_SIZE - 4
+ */
+static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
+{
+       return PAYLOAD_SIZE - sizeof(struct mei_msg_hdr);
+}
+
+/**
+ * mei_txe_hbuf_empty_slots - mimics the me hbuf circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns always hbuf_depth
+ */
+static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       return hw->slots;
+}
+
+/**
+ * mei_txe_count_full_read_slots - mimics the me device circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns always buffer size in dwords count
+ */
+static int mei_txe_count_full_read_slots(struct mei_device *dev)
+{
+       /* read buffers has static size */
+       return  PAYLOAD_SIZE / 4;
+}
+
+/**
+ * mei_txe_read_hdr - read message header which is always in 4 first bytes
+ *
+ * @dev: the device structure
+ *
+ * returns mei message header
+ */
+
+static u32 mei_txe_read_hdr(const struct mei_device *dev)
+{
+       return mei_txe_out_data_read(dev, 0);
+}
+/**
+ * mei_txe_read - reads a message from the txe device.
+ *
+ * @dev: the device structure
+ * @buf: message buffer will be written
+ * @len: message size will be read
+ *
+ * returns -EINVAL on error wrong argument and 0 on success
+ */
+static int mei_txe_read(struct mei_device *dev,
+               unsigned char *buf, unsigned long len)
+{
+
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 i;
+       u32 *reg_buf = (u32 *)buf;
+       u32 rem = len & 0x3;
+
+       if (WARN_ON(!buf || !len))
+               return -EINVAL;
+
+       dev_dbg(&dev->pdev->dev,
+               "buffer-length = %lu buf[0]0x%08X\n",
+               len, mei_txe_out_data_read(dev, 0));
+
+       for (i = 0; i < len / 4; i++) {
+               /* skip header: index starts from 1 */
+               u32 reg = mei_txe_out_data_read(dev, i + 1);
+               dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg);
+               *reg_buf++ = reg;
+       }
+
+       if (rem) {
+               u32 reg = mei_txe_out_data_read(dev, i + 1);
+               memcpy(reg_buf, &reg, rem);
+       }
+
+       mei_txe_output_ready_set(hw);
+       return 0;
+}
+
+/**
+ * mei_txe_hw_reset - resets host and fw.
+ *
+ * @dev: the device structure
+ * @intr_enable: if interrupt should be enabled after reset.
+ *
+ * returns 0 on success and < 0 in case of error
+ */
+static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+
+       u32 aliveness_req;
+       /*
+        * read input doorbell to ensure consistency between  Bridge and SeC
+        * return value might be garbage return
+        */
+       (void)mei_txe_sec_reg_read_silent(hw, SEC_IPC_INPUT_DOORBELL_REG);
+
+       aliveness_req = mei_txe_aliveness_req_get(dev);
+       hw->aliveness = mei_txe_aliveness_get(dev);
+
+       /* Disable interrupts in this stage we will poll */
+       mei_txe_intr_disable(dev);
+
+       /*
+        * If Aliveness Request and Aliveness Response are not equal then
+        * wait for them to be equal
+        * Since we might have interrupts disabled - poll for it
+        */
+       if (aliveness_req != hw->aliveness)
+               if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) {
+                       dev_err(&dev->pdev->dev,
+                               "wait for aliveness settle failed ... bailing out\n");
+                       return -EIO;
+               }
+
+       /*
+        * If Aliveness Request and Aliveness Response are set then clear them
+        */
+       if (aliveness_req) {
+               mei_txe_aliveness_set(dev, 0);
+               if (mei_txe_aliveness_poll(dev, 0) < 0) {
+                       dev_err(&dev->pdev->dev,
+                               "wait for aliveness failed ... bailing out\n");
+                       return -EIO;
+               }
+       }
+
+       /*
+        * Set rediness RDY_CLR bit
+        */
+       mei_txe_readiness_clear(dev);
+
+       return 0;
+}
+
+/**
+ * mei_txe_hw_start - start the hardware after reset
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success and < 0 in case of error
+ */
+static int mei_txe_hw_start(struct mei_device *dev)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       int ret;
+
+       u32 hisr;
+
+       /* bring back interrupts */
+       mei_txe_intr_enable(dev);
+
+       ret = mei_txe_readiness_wait(dev);
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev, "wating for readiness failed\n");
+               return ret;
+       }
+
+       /*
+        * If HISR.INT2_STS interrupt status bit is set then clear it.
+        */
+       hisr = mei_txe_br_reg_read(hw, HISR_REG);
+       if (hisr & HISR_INT_2_STS)
+               mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_2_STS);
+
+       /* Clear the interrupt cause of OutputDoorbell */
+       clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause);
+
+       ret = mei_txe_aliveness_set_sync(dev, 1);
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n");
+               return ret;
+       }
+
+       /* enable input ready interrupts:
+        * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK
+        */
+       mei_txe_input_ready_interrupt_enable(dev);
+
+
+       /*  Set the SICR_SEC_IPC_OUTPUT_STATUS.IPC_OUTPUT_READY bit */
+       mei_txe_output_ready_set(hw);
+
+       /* Set bit SICR_HOST_IPC_READINESS.HOST_RDY
+        */
+       mei_txe_readiness_set_host_rdy(dev);
+
+       return 0;
+}
+
+/**
+ * mei_txe_check_and_ack_intrs - translate multi BAR interrupt into
+ *  single bit mask and acknowledge the interrupts
+ *
+ * @dev: the device structure
+ * @do_ack: acknowledge interrupts
+ */
+static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       u32 hisr;
+       u32 hhisr;
+       u32 ipc_isr;
+       u32 aliveness;
+       bool generated;
+
+       /* read interrupt registers */
+       hhisr = mei_txe_br_reg_read(hw, HHISR_REG);
+       generated = (hhisr & IPC_HHIER_MSK);
+       if (!generated)
+               goto out;
+
+       hisr = mei_txe_br_reg_read(hw, HISR_REG);
+
+       aliveness = mei_txe_aliveness_get(dev);
+       if (hhisr & IPC_HHIER_SEC && aliveness)
+               ipc_isr = mei_txe_sec_reg_read_silent(hw,
+                               SEC_IPC_HOST_INT_STATUS_REG);
+       else
+               ipc_isr = 0;
+
+       generated = generated ||
+               (hisr & HISR_INT_STS_MSK) ||
+               (ipc_isr & SEC_IPC_HOST_INT_STATUS_PENDING);
+
+       if (generated && do_ack) {
+               /* Save the interrupt causes */
+               hw->intr_cause |= hisr & HISR_INT_STS_MSK;
+               if (ipc_isr & SEC_IPC_HOST_INT_STATUS_IN_RDY)
+                       hw->intr_cause |= TXE_INTR_IN_READY;
+
+
+               mei_txe_intr_disable(dev);
+               /* Clear the interrupts in hierarchy:
+                * IPC and Bridge, than the High Level */
+               mei_txe_sec_reg_write_silent(hw,
+                       SEC_IPC_HOST_INT_STATUS_REG, ipc_isr);
+               mei_txe_br_reg_write(hw, HISR_REG, hisr);
+               mei_txe_br_reg_write(hw, HHISR_REG, hhisr);
+       }
+
+out:
+       return generated;
+}
+
+/**
+ * mei_txe_irq_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
+{
+       struct mei_device *dev = dev_id;
+
+       if (mei_txe_check_and_ack_intrs(dev, true))
+               return IRQ_WAKE_THREAD;
+       return IRQ_NONE;
+}
+
+
+/**
+ * mei_txe_irq_thread_handler - txe interrupt thread
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
+{
+       struct mei_device *dev = (struct mei_device *) dev_id;
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+       struct mei_cl_cb complete_list;
+       s32 slots;
+       int rets = 0;
+
+       dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
+               mei_txe_br_reg_read(hw, HHISR_REG),
+               mei_txe_br_reg_read(hw, HISR_REG),
+               mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG));
+
+
+       /* initialize our complete list */
+       mutex_lock(&dev->device_lock);
+       mei_io_list_init(&complete_list);
+
+       if (pci_dev_msi_enabled(dev->pdev))
+               mei_txe_check_and_ack_intrs(dev, true);
+
+       /* show irq events */
+       mei_txe_pending_interrupts(dev);
+
+       hw->aliveness = mei_txe_aliveness_get(dev);
+       hw->readiness = mei_txe_readiness_get(dev);
+
+       /* Readiness:
+        * Detection of TXE driver going through reset
+        * or TXE driver resetting the HECI interface.
+        */
+       if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) {
+               dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n");
+
+               /* Check if SeC is going through reset */
+               if (mei_txe_readiness_is_sec_rdy(hw->readiness)) {
+                       dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+                       dev->recvd_hw_ready = true;
+               } else {
+                       dev->recvd_hw_ready = false;
+                       if (dev->dev_state != MEI_DEV_RESETTING) {
+
+                               dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
+                               schedule_work(&dev->reset_work);
+                               goto end;
+
+                       }
+               }
+               wake_up(&dev->wait_hw_ready);
+       }
+
+       /************************************************************/
+       /* Check interrupt cause:
+        * Aliveness: Detection of SeC acknowledge of host request that
+        * it remain alive or host cancellation of that request.
+        */
+
+       if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) {
+               /* Clear the interrupt cause */
+               dev_dbg(&dev->pdev->dev,
+                       "Aliveness Interrupt: Status: %d\n", hw->aliveness);
+               hw->recvd_aliveness = true;
+               if (waitqueue_active(&hw->wait_aliveness))
+                       wake_up(&hw->wait_aliveness);
+       }
+
+
+       /* Output Doorbell:
+        * Detection of SeC having sent output to host
+        */
+       slots = mei_count_full_read_slots(dev);
+       if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) {
+               /* Read from TXE */
+               rets = mei_irq_read_handler(dev, &complete_list, &slots);
+               if (rets && dev->dev_state != MEI_DEV_RESETTING) {
+                       dev_err(&dev->pdev->dev,
+                               "mei_irq_read_handler ret = %d.\n", rets);
+
+                       schedule_work(&dev->reset_work);
+                       goto end;
+               }
+       }
+       /* Input Ready: Detection if host can write to SeC */
+       if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) {
+               dev->hbuf_is_ready = true;
+               hw->slots = dev->hbuf_depth;
+       }
+
+       if (hw->aliveness && dev->hbuf_is_ready) {
+               /* get the real register value */
+               dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+               rets = mei_irq_write_handler(dev, &complete_list);
+               if (rets && rets != -EMSGSIZE)
+                       dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
+                               rets);
+               dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+       }
+
+       mei_irq_compl_handler(dev, &complete_list);
+
+end:
+       dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
+
+       mutex_unlock(&dev->device_lock);
+
+       mei_enable_interrupts(dev);
+       return IRQ_HANDLED;
+}
+
+static const struct mei_hw_ops mei_txe_hw_ops = {
+
+       .host_is_ready = mei_txe_host_is_ready,
+
+       .hw_is_ready = mei_txe_hw_is_ready,
+       .hw_reset = mei_txe_hw_reset,
+       .hw_config = mei_txe_hw_config,
+       .hw_start = mei_txe_hw_start,
+
+       .intr_clear = mei_txe_intr_clear,
+       .intr_enable = mei_txe_intr_enable,
+       .intr_disable = mei_txe_intr_disable,
+
+       .hbuf_free_slots = mei_txe_hbuf_empty_slots,
+       .hbuf_is_ready = mei_txe_is_input_ready,
+       .hbuf_max_len = mei_txe_hbuf_max_len,
+
+       .write = mei_txe_write,
+
+       .rdbuf_full_slots = mei_txe_count_full_read_slots,
+       .read_hdr = mei_txe_read_hdr,
+
+       .read = mei_txe_read,
+
+};
+
+/**
+ * mei_txe_dev_init - allocates and initializes txe hardware specific structure
+ *
+ * @pdev - pci device
+ * returns struct mei_device * on success or NULL;
+ *
+ */
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
+{
+       struct mei_device *dev;
+       struct mei_txe_hw *hw;
+
+       dev = kzalloc(sizeof(struct mei_device) +
+                        sizeof(struct mei_txe_hw), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       mei_device_init(dev);
+
+       hw = to_txe_hw(dev);
+
+       init_waitqueue_head(&hw->wait_aliveness);
+
+       dev->ops = &mei_txe_hw_ops;
+
+       dev->pdev = pdev;
+       return dev;
+}
+
+/**
+ * mei_txe_setup_satt2 - SATT2 configuration for DMA support.
+ *
+ * @dev:   the device structure
+ * @addr:  physical address start of the range
+ * @range: physical range size
+ */
+int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
+{
+       struct mei_txe_hw *hw = to_txe_hw(dev);
+
+       u32 lo32 = lower_32_bits(addr);
+       u32 hi32 = upper_32_bits(addr);
+       u32 ctrl;
+
+       /* SATT is limited to 36 Bits */
+       if (hi32 & ~0xF)
+               return -EINVAL;
+
+       /* SATT has to be 16Byte aligned */
+       if (lo32 & 0xF)
+               return -EINVAL;
+
+       /* SATT range has to be 4Bytes aligned */
+       if (range & 0x4)
+               return -EINVAL;
+
+       /* SATT is limited to 32 MB range*/
+       if (range > SATT_RANGE_MAX)
+               return -EINVAL;
+
+       ctrl = SATT2_CTRL_VALID_MSK;
+       ctrl |= hi32  << SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT;
+
+       mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range);
+       mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32);
+       mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl);
+       dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
+               range, lo32, ctrl);
+
+       return 0;
+}
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
new file mode 100644 (file)
index 0000000..0812d98
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_HW_TXE_H_
+#define _MEI_HW_TXE_H_
+
+#include <linux/irqreturn.h>
+
+#include "hw.h"
+#include "hw-txe-regs.h"
+
+/* Flatten Hierarchy interrupt cause */
+#define TXE_INTR_READINESS_BIT  0 /* HISR_INT_0_STS */
+#define TXE_INTR_READINESS      HISR_INT_0_STS
+#define TXE_INTR_ALIVENESS_BIT  1 /* HISR_INT_1_STS */
+#define TXE_INTR_ALIVENESS      HISR_INT_1_STS
+#define TXE_INTR_OUT_DB_BIT     2 /* HISR_INT_2_STS */
+#define TXE_INTR_OUT_DB         HISR_INT_2_STS
+#define TXE_INTR_IN_READY_BIT   8 /* beyond HISR */
+#define TXE_INTR_IN_READY       BIT(8)
+
+/**
+ * struct mei_txe_hw - txe hardware specifics
+ *
+ * @mem_addr:        SeC and BRIDGE bars
+ * @aliveness:       aliveness (power gating) state of the hardware
+ * @readiness:       readiness state of the hardware
+ * @wait_aliveness:  aliveness wait queue
+ * @recvd_aliveness: aliveness interrupt was recived
+ * @intr_cause:      translated interrupt cause
+ */
+struct mei_txe_hw {
+       void __iomem *mem_addr[NUM_OF_MEM_BARS];
+       u32 aliveness;
+       u32 readiness;
+       u32 slots;
+
+       wait_queue_head_t wait_aliveness;
+       bool recvd_aliveness;
+
+       unsigned long intr_cause;
+};
+
+#define to_txe_hw(dev) (struct mei_txe_hw *)((dev)->hw)
+
+static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw)
+{
+       return container_of((void *)hw, struct mei_device, hw);
+}
+
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
+
+irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id);
+
+int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req);
+
+int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range);
+
+
+#endif /* _MEI_HW_TXE_H_ */
index dd44e33ad2b6a39daa288a4f23132012629c6779..6b476ab49b2e0d538f4097e093bd19377aa74ec4 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Timeouts in Seconds
  */
-#define MEI_INTEROP_TIMEOUT         7  /* Timeout on ready message */
+#define MEI_HW_READY_TIMEOUT        2  /* Timeout on ready message */
 #define MEI_CONNECT_TIMEOUT         3  /* HPS: at least 2 seconds */
 
 #define MEI_CL_CONNECT_TIMEOUT     15  /* HPS: Client Connect Timeout */
 #define MEI_IAMTHIF_STALL_TIMER    12  /* HPS */
 #define MEI_IAMTHIF_READ_TIMER     10  /* HPS */
 
+#define MEI_HBM_TIMEOUT            1   /* 1 second */
 
 /*
  * MEI Version
  */
 #define HBM_MINOR_VERSION                   0
 #define HBM_MAJOR_VERSION                   1
-#define HBM_TIMEOUT                         1  /* 1 second */
 
 /* Host bus message command opcode */
 #define MEI_HBM_CMD_OP_MSK                  0x7f
@@ -89,19 +89,19 @@ enum mei_stop_reason_types {
  * Client Connect Status
  * used by hbm_client_connect_response.status
  */
-enum client_connect_status_types {
-       CCS_SUCCESS = 0x00,
-       CCS_NOT_FOUND = 0x01,
-       CCS_ALREADY_STARTED = 0x02,
-       CCS_OUT_OF_RESOURCES = 0x03,
-       CCS_MESSAGE_SMALL = 0x04
+enum mei_cl_connect_status {
+       MEI_CL_CONN_SUCCESS          = 0x00,
+       MEI_CL_CONN_NOT_FOUND        = 0x01,
+       MEI_CL_CONN_ALREADY_STARTED  = 0x02,
+       MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
+       MEI_CL_CONN_MESSAGE_SMALL    = 0x04
 };
 
 /*
  * Client Disconnect Status
  */
-enum client_disconnect_status_types {
-       CDS_SUCCESS = 0x00
+enum  mei_cl_disconnect_status {
+       MEI_CL_DISCONN_SUCCESS = 0x00
 };
 
 /*
index cdd31c2a2a2bf095e827758e3d71567d80557a5f..4460975c0eefcc97c765dd83fcafc0a3f3290cd3 100644 (file)
@@ -116,7 +116,6 @@ int mei_reset(struct mei_device *dev)
                mei_cl_unlink(&dev->wd_cl);
                mei_cl_unlink(&dev->iamthif_cl);
                mei_amthif_reset_params(dev);
-               memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
        }
 
 
@@ -126,7 +125,6 @@ int mei_reset(struct mei_device *dev)
 
        if (ret) {
                dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
-               dev->dev_state = MEI_DEV_DISABLED;
                return ret;
        }
 
@@ -139,7 +137,6 @@ int mei_reset(struct mei_device *dev)
        ret = mei_hw_start(dev);
        if (ret) {
                dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
-               dev->dev_state = MEI_DEV_DISABLED;
                return ret;
        }
 
@@ -149,7 +146,7 @@ int mei_reset(struct mei_device *dev)
        ret = mei_hbm_start_req(dev);
        if (ret) {
                dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
-               dev->dev_state = MEI_DEV_DISABLED;
+               dev->dev_state = MEI_DEV_RESETTING;
                return ret;
        }
 
@@ -166,6 +163,7 @@ EXPORT_SYMBOL_GPL(mei_reset);
  */
 int mei_start(struct mei_device *dev)
 {
+       int ret;
        mutex_lock(&dev->device_lock);
 
        /* acknowledge interrupt and stop interrupts */
@@ -175,10 +173,18 @@ int mei_start(struct mei_device *dev)
 
        dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
 
-       dev->dev_state = MEI_DEV_INITIALIZING;
        dev->reset_count = 0;
-       mei_reset(dev);
+       do {
+               dev->dev_state = MEI_DEV_INITIALIZING;
+               ret = mei_reset(dev);
+
+               if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
+                       dev_err(&dev->pdev->dev, "reset failed ret = %d", ret);
+                       goto err;
+               }
+       } while (ret);
 
+       /* we cannot start the device w/o hbm start message completed */
        if (dev->dev_state == MEI_DEV_DISABLED) {
                dev_err(&dev->pdev->dev, "reset failed");
                goto err;
@@ -238,27 +244,40 @@ int mei_restart(struct mei_device *dev)
 
        mutex_unlock(&dev->device_lock);
 
-       if (err || dev->dev_state == MEI_DEV_DISABLED)
+       if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
+               dev_err(&dev->pdev->dev, "device disabled = %d\n", err);
                return -ENODEV;
+       }
+
+       /* try to start again */
+       if (err)
+               schedule_work(&dev->reset_work);
+
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(mei_restart);
 
-
 static void mei_reset_work(struct work_struct *work)
 {
        struct mei_device *dev =
                container_of(work, struct mei_device,  reset_work);
+       int ret;
 
        mutex_lock(&dev->device_lock);
 
-       mei_reset(dev);
+       ret = mei_reset(dev);
 
        mutex_unlock(&dev->device_lock);
 
-       if (dev->dev_state == MEI_DEV_DISABLED)
-               dev_err(&dev->pdev->dev, "reset failed");
+       if (dev->dev_state == MEI_DEV_DISABLED) {
+               dev_err(&dev->pdev->dev, "device disabled = %d\n", ret);
+               return;
+       }
+
+       /* retry reset in case of failure */
+       if (ret)
+               schedule_work(&dev->reset_work);
 }
 
 void mei_stop(struct mei_device *dev)
@@ -269,6 +288,8 @@ void mei_stop(struct mei_device *dev)
 
        mei_nfc_host_exit(dev);
 
+       mei_cl_bus_remove_devices(dev);
+
        mutex_lock(&dev->device_lock);
 
        mei_wd_stop(dev);
index f0fbb5179f80cf6960bed4771fd0b12fdadea786..29b5af8efb71f33ad000578f08493128fef69806 100644 (file)
@@ -26,7 +26,6 @@
 
 #include "mei_dev.h"
 #include "hbm.h"
-#include "hw-me.h"
 #include "client.h"
 
 
@@ -160,30 +159,64 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
        return 0;
 }
 
+/**
+ * mei_cl_irq_disconnect_rsp - send disconnection response message
+ *
+ * @cl: client
+ * @cb: callback block.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
+                                    struct mei_cl_cb *cmpl_list)
+{
+       struct mei_device *dev = cl->dev;
+       u32 msg_slots;
+       int slots;
+       int ret;
+
+       slots = mei_hbuf_empty_slots(dev);
+       msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_response));
+
+       if (slots < msg_slots)
+               return -EMSGSIZE;
+
+       ret = mei_hbm_cl_disconnect_rsp(dev, cl);
+
+       cl->state = MEI_FILE_DISCONNECTED;
+       cl->status = 0;
+       list_del(&cb->list);
+       mei_io_cb_free(cb);
+
+       return ret;
+}
+
+
+
 /**
  * mei_cl_irq_close - processes close related operation from
  *     interrupt thread context - send disconnect request
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
-                       s32 *slots, struct mei_cl_cb *cmpl_list)
+                           struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
+       u32 msg_slots;
+       int slots;
 
-       u32 msg_slots =
-               mei_data2slots(sizeof(struct hbm_client_connect_request));
+       msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+       slots = mei_hbuf_empty_slots(dev);
 
-       if (*slots < msg_slots)
+       if (slots < msg_slots)
                return -EMSGSIZE;
 
-       *slots -= msg_slots;
-
        if (mei_hbm_cl_disconnect_req(dev, cl)) {
                cl->status = 0;
                cb->buf_idx = 0;
@@ -207,27 +240,23 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
-                          s32 *slots, struct mei_cl_cb *cmpl_list)
+                          struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
-       u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
-
+       u32 msg_slots;
+       int slots;
        int ret;
 
+       msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+       slots = mei_hbuf_empty_slots(dev);
 
-       if (*slots < msg_slots) {
-               /* return the cancel routine */
-               list_del(&cb->list);
+       if (slots < msg_slots)
                return -EMSGSIZE;
-       }
-
-       *slots -= msg_slots;
 
        ret = mei_hbm_cl_flow_control_req(dev, cl);
        if (ret) {
@@ -244,32 +273,30 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
 
 
 /**
- * mei_cl_irq_ioctl - processes client ioctl related operation from the
- *     interrupt thread context -   send connection request
+ * mei_cl_irq_connect - send connect request in irq_thread context
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
-static int mei_cl_irq_ioctl(struct mei_cl *cl, struct mei_cl_cb *cb,
-                          s32 *slots, struct mei_cl_cb *cmpl_list)
+static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
+                             struct mei_cl_cb *cmpl_list)
 {
        struct mei_device *dev = cl->dev;
+       u32 msg_slots;
+       int slots;
        int ret;
 
-       u32 msg_slots =
-               mei_data2slots(sizeof(struct hbm_client_connect_request));
+       msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+       slots = mei_hbuf_empty_slots(dev);
 
-       if (*slots < msg_slots) {
-               /* return the cancel routine */
-               list_del(&cb->list);
-               return -EMSGSIZE;
-       }
+       if (mei_cl_is_other_connecting(cl))
+               return 0;
 
-       *slots -=  msg_slots;
+       if (slots < msg_slots)
+               return -EMSGSIZE;
 
        cl->state = MEI_FILE_CONNECTING;
 
@@ -323,7 +350,7 @@ int mei_irq_read_handler(struct mei_device *dev,
                dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
                                *slots);
                /* we can't read the message */
-               ret = -ERANGE;
+               ret = -ENODATA;
                goto end;
        }
 
@@ -409,10 +436,10 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
        s32 slots;
        int ret;
 
-       if (!mei_hbuf_is_ready(dev)) {
-               dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
+
+       if (!mei_hbuf_acquire(dev))
                return 0;
-       }
+
        slots = mei_hbuf_empty_slots(dev);
        if (slots <= 0)
                return -EMSGSIZE;
@@ -447,29 +474,16 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 
        if (dev->wd_state == MEI_WD_STOPPING) {
                dev->wd_state = MEI_WD_IDLE;
-               wake_up_interruptible(&dev->wait_stop_wd);
+               wake_up(&dev->wait_stop_wd);
        }
 
-       if (dev->wr_ext_msg.hdr.length) {
-               mei_write_message(dev, &dev->wr_ext_msg.hdr,
-                               dev->wr_ext_msg.data);
-               slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
-               dev->wr_ext_msg.hdr.length = 0;
-       }
-       if (dev->dev_state == MEI_DEV_ENABLED) {
+       if (mei_cl_is_connected(&dev->wd_cl)) {
                if (dev->wd_pending &&
                    mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
-                       if (mei_wd_send(dev))
-                               dev_dbg(&dev->pdev->dev, "wd send failed.\n");
-                       else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
-                               return -ENODEV;
-
+                       ret = mei_wd_send(dev);
+                       if (ret)
+                               return ret;
                        dev->wd_pending = false;
-
-                       if (dev->wd_state == MEI_WD_RUNNING)
-                               slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
-                       else
-                               slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
                }
        }
 
@@ -484,28 +498,31 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
                switch (cb->fop_type) {
                case MEI_FOP_CLOSE:
                        /* send disconnect message */
-                       ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_close(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
 
                        break;
                case MEI_FOP_READ:
                        /* send flow control message */
-                       ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_read(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
 
                        break;
-               case MEI_FOP_IOCTL:
+               case MEI_FOP_CONNECT:
                        /* connect message */
-                       if (mei_cl_is_other_connecting(cl))
-                               continue;
-                       ret = mei_cl_irq_ioctl(cl, cb, &slots, cmpl_list);
+                       ret = mei_cl_irq_connect(cl, cb, cmpl_list);
                        if (ret)
                                return ret;
 
                        break;
-
+               case MEI_FOP_DISCONNECT_RSP:
+                       /* send disconnect resp */
+                       ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);
+                       if (ret)
+                               return ret;
+                       break;
                default:
                        BUG();
                }
@@ -518,11 +535,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
                if (cl == NULL)
                        continue;
                if (cl == &dev->iamthif_cl)
-                       ret = mei_amthif_irq_write_complete(cl, cb,
-                                               &slots, cmpl_list);
+                       ret = mei_amthif_irq_write(cl, cb, cmpl_list);
                else
-                       ret = mei_cl_irq_write_complete(cl, cb,
-                                               &slots, cmpl_list);
+                       ret = mei_cl_irq_write(cl, cb, cmpl_list);
                if (ret)
                        return ret;
        }
@@ -541,8 +556,7 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler);
 void mei_timer(struct work_struct *work)
 {
        unsigned long timeout;
-       struct mei_cl *cl_pos = NULL;
-       struct mei_cl *cl_next = NULL;
+       struct mei_cl *cl;
        struct mei_cl_cb  *cb_pos = NULL;
        struct mei_cl_cb  *cb_next = NULL;
 
@@ -570,9 +584,9 @@ void mei_timer(struct work_struct *work)
                goto out;
 
        /*** connect/disconnect timeouts ***/
-       list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-               if (cl_pos->timer_count) {
-                       if (--cl_pos->timer_count == 0) {
+       list_for_each_entry(cl, &dev->file_list, link) {
+               if (cl->timer_count) {
+                       if (--cl->timer_count == 0) {
                                dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
                                mei_reset(dev);
                                goto out;
@@ -580,6 +594,9 @@ void mei_timer(struct work_struct *work)
                }
        }
 
+       if (!mei_cl_is_connected(&dev->iamthif_cl))
+               goto out;
+
        if (dev->iamthif_stall_timer) {
                if (--dev->iamthif_stall_timer == 0) {
                        dev_err(&dev->pdev->dev, "timer: amthif  hanged.\n");
@@ -619,10 +636,10 @@ void mei_timer(struct work_struct *work)
                        list_for_each_entry_safe(cb_pos, cb_next,
                                &dev->amthif_rd_complete_list.list, list) {
 
-                               cl_pos = cb_pos->file_object->private_data;
+                               cl = cb_pos->file_object->private_data;
 
                                /* Finding the AMTHI entry. */
-                               if (cl_pos == &dev->iamthif_cl)
+                               if (cl == &dev->iamthif_cl)
                                        list_del(&cb_pos->list);
                        }
                        mei_io_cb_free(dev->iamthif_current_cb);
index 5424f8ff3f7f7d2653f1089517e67b790cec03d5..b35594dbf52f49bf034e94254b85d70d0a019756 100644 (file)
@@ -13,9 +13,6 @@
  * more details.
  *
  */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
@@ -40,7 +37,6 @@
 #include <linux/mei.h>
 
 #include "mei_dev.h"
-#include "hw-me.h"
 #include "client.h"
 
 /**
@@ -129,17 +125,11 @@ static int mei_release(struct inode *inode, struct file *file)
        }
        if (cl->state == MEI_FILE_CONNECTED) {
                cl->state = MEI_FILE_DISCONNECTING;
-               dev_dbg(&dev->pdev->dev,
-                       "disconnecting client host client = %d, "
-                   "ME client = %d\n",
-                   cl->host_client_id,
-                   cl->me_client_id);
+               cl_dbg(dev, cl, "disconnecting\n");
                rets = mei_cl_disconnect(cl);
        }
        mei_cl_flush_queues(cl);
-       dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
-           cl->host_client_id,
-           cl->me_client_id);
+       cl_dbg(dev, cl, "removing\n");
 
        mei_cl_unlink(cl);
 
@@ -284,6 +274,7 @@ copy_buffer:
        length = min_t(size_t, length, cb->buf_idx - *offset);
 
        if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+               dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
                rets = -EFAULT;
                goto free;
        }
@@ -340,7 +331,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 
        id = mei_me_cl_by_id(dev, cl->me_client_id);
        if (id < 0) {
-               rets = -ENODEV;
+               rets = -ENOTTY;
                goto out;
        }
 
@@ -404,7 +395,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 
        rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
        if (rets) {
-               dev_err(&dev->pdev->dev, "failed to copy data from userland\n");
+               dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
                rets = -EFAULT;
                goto out;
        }
@@ -471,7 +462,7 @@ static int mei_ioctl_connect_client(struct file *file,
        if (i < 0 || dev->me_clients[i].props.fixed_address) {
                dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
                                &data->in_client_uuid);
-               rets = -ENODEV;
+               rets = -ENOTTY;
                goto end;
        }
 
@@ -569,7 +560,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
        dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
        if (copy_from_user(connect_data, (char __user *)data,
                                sizeof(struct mei_connect_client_data))) {
-               dev_err(&dev->pdev->dev, "failed to copy data from userland\n");
+               dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
                rets = -EFAULT;
                goto out;
        }
index f7de95b4cdd907ebfbf241b46f73d95cdc9cb3d7..94a516716d226b0ec448a468c8b17545af0842cc 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/mei_cl_bus.h>
 
 #include "hw.h"
-#include "hw-me-regs.h"
 #include "hbm.h"
 
 /*
@@ -130,16 +129,18 @@ enum mei_wd_states {
 
 /**
  * enum mei_cb_file_ops  - file operation associated with the callback
- * @MEI_FOP_READ   - read
- * @MEI_FOP_WRITE  - write
- * @MEI_FOP_IOCTL  - ioctl
- * @MEI_FOP_OPEN   - open
- * @MEI_FOP_CLOSE  - close
+ * @MEI_FOP_READ      - read
+ * @MEI_FOP_WRITE     - write
+ * @MEI_FOP_CONNECT   - connect
+ * @MEI_FOP_DISCONNECT_RSP - disconnect response
+ * @MEI_FOP_OPEN      - open
+ * @MEI_FOP_CLOSE     - close
  */
 enum mei_cb_file_ops {
        MEI_FOP_READ = 0,
        MEI_FOP_WRITE,
-       MEI_FOP_IOCTL,
+       MEI_FOP_CONNECT,
+       MEI_FOP_DISCONNECT_RSP,
        MEI_FOP_OPEN,
        MEI_FOP_CLOSE
 };
@@ -236,20 +237,20 @@ struct mei_cl {
  */
 struct mei_hw_ops {
 
-       bool (*host_is_ready) (struct mei_device *dev);
+       bool (*host_is_ready)(struct mei_device *dev);
 
-       bool (*hw_is_ready) (struct mei_device *dev);
-       int (*hw_reset) (struct mei_device *dev, bool enable);
-       int  (*hw_start) (struct mei_device *dev);
-       void (*hw_config) (struct mei_device *dev);
+       bool (*hw_is_ready)(struct mei_device *dev);
+       int (*hw_reset)(struct mei_device *dev, bool enable);
+       int (*hw_start)(struct mei_device *dev);
+       void (*hw_config)(struct mei_device *dev);
 
-       void (*intr_clear) (struct mei_device *dev);
-       void (*intr_enable) (struct mei_device *dev);
-       void (*intr_disable) (struct mei_device *dev);
+       void (*intr_clear)(struct mei_device *dev);
+       void (*intr_enable)(struct mei_device *dev);
+       void (*intr_disable)(struct mei_device *dev);
 
-       int (*hbuf_free_slots) (struct mei_device *dev);
-       bool (*hbuf_is_ready) (struct mei_device *dev);
-       size_t (*hbuf_max_len) (const struct mei_device *dev);
+       int (*hbuf_free_slots)(struct mei_device *dev);
+       bool (*hbuf_is_ready)(struct mei_device *dev);
+       size_t (*hbuf_max_len)(const struct mei_device *dev);
 
        int (*write)(struct mei_device *dev,
                     struct mei_msg_hdr *hdr,
@@ -258,7 +259,7 @@ struct mei_hw_ops {
        int (*rdbuf_full_slots)(struct mei_device *dev);
 
        u32 (*read_hdr)(const struct mei_device *dev);
-       int (*read) (struct mei_device *dev,
+       int (*read)(struct mei_device *dev,
                     unsigned char *buf, unsigned long len);
 };
 
@@ -294,6 +295,7 @@ int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
 int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
 int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 void mei_cl_bus_rx_event(struct mei_cl *cl);
+void mei_cl_bus_remove_devices(struct mei_device *dev);
 int mei_cl_bus_init(void);
 void mei_cl_bus_exit(void);
 
@@ -339,7 +341,6 @@ struct mei_cl_device {
  * @hbuf_depth - depth of hardware host/write buffer is slots
  * @hbuf_is_ready - query if the host host/write buffer is ready
  * @wr_msg - the buffer for hbm control messages
- * @wr_ext_msg - the buffer for hbm control responses (set in read cycle)
  */
 struct mei_device {
        struct pci_dev *pdev;   /* pointer to pci device struct */
@@ -394,11 +395,6 @@ struct mei_device {
                unsigned char data[128];
        } wr_msg;
 
-       struct {
-               struct mei_msg_hdr hdr;
-               unsigned char data[4];  /* All HBM messages are 4 bytes */
-       } wr_ext_msg;           /* for control responses */
-
        struct hbm_version version;
 
        struct mei_me_client *me_clients; /* Note: memory has to be allocated */
@@ -518,8 +514,8 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 
 void mei_amthif_run_next_cmd(struct mei_device *dev);
 
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-                                 s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+                       struct mei_cl_cb *cmpl_list);
 
 void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
 int mei_amthif_irq_read_msg(struct mei_device *dev,
@@ -546,7 +542,7 @@ int mei_wd_host_init(struct mei_device *dev);
  *   once we got connection to the WD Client
  * @dev - mei device
  */
-void mei_watchdog_register(struct mei_device *dev);
+int mei_watchdog_register(struct mei_device *dev);
 /*
  * mei_watchdog_unregister  - Unregistering watchdog interface
  * @dev - mei device
@@ -633,6 +629,8 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
        return dev->ops->rdbuf_full_slots(dev);
 }
 
+bool mei_hbuf_acquire(struct mei_device *dev);
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 int mei_dbgfs_register(struct mei_device *dev, const char *name);
 void mei_dbgfs_deregister(struct mei_device *dev);
index a58320c0c049c7342ca3d912e4f427bd487381de..3095fc514a65f3a44868587e6adae91b0eef5612 100644 (file)
@@ -364,7 +364,7 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
        if (!wait_event_interruptible_timeout(ndev->send_wq,
                                ndev->recv_req_id == ndev->req_id, HZ)) {
                dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
-               err = -ETIMEDOUT;
+               err = -ETIME;
        } else {
                ndev->req_id++;
        }
@@ -502,7 +502,7 @@ int mei_nfc_host_init(struct mei_device *dev)
        i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
        if (i < 0) {
                dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
-               ret = -ENOENT;
+               ret = -ENOTTY;
                goto err;
        }
 
@@ -520,7 +520,7 @@ int mei_nfc_host_init(struct mei_device *dev)
        i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
        if (i < 0) {
                dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
-               ret = -ENOENT;
+               ret = -ENOTTY;
                goto err;
        }
 
@@ -552,13 +552,7 @@ err:
 void mei_nfc_host_exit(struct mei_device *dev)
 {
        struct mei_nfc_dev *ndev = &nfc_dev;
-
        cancel_work_sync(&ndev->init_work);
+}
 
-       mutex_lock(&dev->device_lock);
-       if (ndev->cl && ndev->cl->device)
-               mei_cl_remove_device(ndev->cl->device);
 
-       mei_nfc_free(ndev);
-       mutex_unlock(&dev->device_lock);
-}
index ddadd08956f46bc3af94e93cc146c50b76cde196..1c8fd3a3e135d2611d5fb9741ed4b78381f8e4a3 100644 (file)
@@ -13,9 +13,6 @@
  * more details.
  *
  */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
@@ -27,7 +24,6 @@
 #include <linux/aio.h>
 #include <linux/pci.h>
 #include <linux/poll.h>
-#include <linux/init.h>
 #include <linux/ioctl.h>
 #include <linux/cdev.h>
 #include <linux/sched.h>
 #include <linux/mei.h>
 
 #include "mei_dev.h"
-#include "hw-me.h"
 #include "client.h"
+#include "hw-me-regs.h"
+#include "hw-me.h"
 
 /* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
+static const struct pci_device_id mei_me_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
@@ -270,7 +267,7 @@ static void mei_me_remove(struct pci_dev *pdev)
 
 
 }
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int mei_me_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
@@ -330,11 +327,12 @@ static int mei_me_pci_resume(struct device *device)
 
        return 0;
 }
+
 static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
 #define MEI_ME_PM_OPS  (&mei_me_pm_ops)
 #else
 #define MEI_ME_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 /*
  *  PCI driver structure
  */
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
new file mode 100644 (file)
index 0000000..ad3adb0
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mei.h>
+
+
+#include "mei_dev.h"
+#include "hw-txe.h"
+
+static const struct pci_device_id mei_txe_pci_tbl[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */
+       {0, }
+};
+MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
+
+
+static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
+{
+       int i;
+       for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
+               if (hw->mem_addr[i]) {
+                       pci_iounmap(pdev, hw->mem_addr[i]);
+                       hw->mem_addr[i] = NULL;
+               }
+       }
+}
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in mei_txe_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct mei_device *dev;
+       struct mei_txe_hw *hw;
+       int err;
+       int i;
+
+       /* enable pci dev */
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable pci device.\n");
+               goto end;
+       }
+       /* set PCI host mastering  */
+       pci_set_master(pdev);
+       /* pci request regions for mei driver */
+       err = pci_request_regions(pdev, KBUILD_MODNAME);
+       if (err) {
+               dev_err(&pdev->dev, "failed to get pci regions.\n");
+               goto disable_device;
+       }
+
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (err) {
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (err) {
+                       dev_err(&pdev->dev, "No suitable DMA available.\n");
+                       goto release_regions;
+               }
+       }
+
+       /* allocates and initializes the mei dev structure */
+       dev = mei_txe_dev_init(pdev);
+       if (!dev) {
+               err = -ENOMEM;
+               goto release_regions;
+       }
+       hw = to_txe_hw(dev);
+
+       /* mapping  IO device memory */
+       for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
+               hw->mem_addr[i] = pci_iomap(pdev, i, 0);
+               if (!hw->mem_addr[i]) {
+                       dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
+                       err = -ENOMEM;
+                       goto free_device;
+               }
+       }
+
+
+       pci_enable_msi(pdev);
+
+       /* clear spurious interrupts */
+       mei_clear_interrupts(dev);
+
+       /* request and enable interrupt  */
+       if (pci_dev_msi_enabled(pdev))
+               err = request_threaded_irq(pdev->irq,
+                       NULL,
+                       mei_txe_irq_thread_handler,
+                       IRQF_ONESHOT, KBUILD_MODNAME, dev);
+       else
+               err = request_threaded_irq(pdev->irq,
+                       mei_txe_irq_quick_handler,
+                       mei_txe_irq_thread_handler,
+                       IRQF_SHARED, KBUILD_MODNAME, dev);
+       if (err) {
+               dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
+                       pdev->irq);
+               goto free_device;
+       }
+
+       if (mei_start(dev)) {
+               dev_err(&pdev->dev, "init hw failure.\n");
+               err = -ENODEV;
+               goto release_irq;
+       }
+
+       err = mei_register(dev);
+       if (err)
+               goto release_irq;
+
+       pci_set_drvdata(pdev, dev);
+
+       return 0;
+
+release_irq:
+
+       mei_cancel_work(dev);
+
+       /* disable interrupts */
+       mei_disable_interrupts(dev);
+
+       free_irq(pdev->irq, dev);
+       pci_disable_msi(pdev);
+
+free_device:
+       mei_txe_pci_iounmap(pdev, hw);
+
+       kfree(dev);
+release_regions:
+       pci_release_regions(pdev);
+disable_device:
+       pci_disable_device(pdev);
+end:
+       dev_err(&pdev->dev, "initialization failed.\n");
+       return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void mei_txe_remove(struct pci_dev *pdev)
+{
+       struct mei_device *dev;
+       struct mei_txe_hw *hw;
+
+       dev = pci_get_drvdata(pdev);
+       if (!dev) {
+               dev_err(&pdev->dev, "mei: dev =NULL\n");
+               return;
+       }
+
+       hw = to_txe_hw(dev);
+
+       mei_stop(dev);
+
+       /* disable interrupts */
+       mei_disable_interrupts(dev);
+       free_irq(pdev->irq, dev);
+       pci_disable_msi(pdev);
+
+       pci_set_drvdata(pdev, NULL);
+
+       mei_txe_pci_iounmap(pdev, hw);
+
+       mei_deregister(dev);
+
+       kfree(dev);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+
+#ifdef CONFIG_PM_SLEEP
+static int mei_txe_pci_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct mei_device *dev = pci_get_drvdata(pdev);
+
+       if (!dev)
+               return -ENODEV;
+
+       dev_dbg(&pdev->dev, "suspend\n");
+
+       mei_stop(dev);
+
+       mei_disable_interrupts(dev);
+
+       free_irq(pdev->irq, dev);
+       pci_disable_msi(pdev);
+
+       return 0;
+}
+
+static int mei_txe_pci_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct mei_device *dev;
+       int err;
+
+       dev = pci_get_drvdata(pdev);
+       if (!dev)
+               return -ENODEV;
+
+       pci_enable_msi(pdev);
+
+       mei_clear_interrupts(dev);
+
+       /* request and enable interrupt */
+       if (pci_dev_msi_enabled(pdev))
+               err = request_threaded_irq(pdev->irq,
+                       NULL,
+                       mei_txe_irq_thread_handler,
+                       IRQF_ONESHOT, KBUILD_MODNAME, dev);
+       else
+               err = request_threaded_irq(pdev->irq,
+                       mei_txe_irq_quick_handler,
+                       mei_txe_irq_thread_handler,
+                       IRQF_SHARED, KBUILD_MODNAME, dev);
+       if (err) {
+               dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+                               pdev->irq);
+               return err;
+       }
+
+       err = mei_restart(dev);
+
+       return err;
+}
+
+static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops,
+                        mei_txe_pci_suspend,
+                        mei_txe_pci_resume);
+
+#define MEI_TXE_PM_OPS (&mei_txe_pm_ops)
+#else
+#define MEI_TXE_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+/*
+ *  PCI driver structure
+ */
+static struct pci_driver mei_txe_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = mei_txe_pci_tbl,
+       .probe = mei_txe_probe,
+       .remove = mei_txe_remove,
+       .shutdown = mei_txe_remove,
+       .driver.pm = MEI_TXE_PM_OPS,
+};
+
+module_pci_driver(mei_txe_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
+MODULE_LICENSE("GPL v2");
index f70945ed96f6f82ab6f6f62d5485cea9fa39ea16..ebf1cbc198fd342d85541ae713f045867c52eaaa 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "mei_dev.h"
 #include "hbm.h"
-#include "hw-me.h"
 #include "client.h"
 
 static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
@@ -53,7 +52,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
  *
  * @dev: the device structure
  *
- * returns -ENENT if wd client cannot be found
+ * returns -ENOTTY if wd client cannot be found
  *         -EIO if write has failed
  *         0 on success
  */
@@ -73,7 +72,7 @@ int mei_wd_host_init(struct mei_device *dev)
        id = mei_me_cl_by_uuid(dev, &mei_wd_guid);
        if (id < 0) {
                dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
-               return id;
+               return -ENOTTY;
        }
 
        cl->me_client_id = dev->me_clients[id].client_id;
@@ -87,15 +86,20 @@ int mei_wd_host_init(struct mei_device *dev)
 
        cl->state = MEI_FILE_CONNECTING;
 
-       if (mei_hbm_cl_connect_req(dev, cl)) {
-               dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
-               cl->state = MEI_FILE_DISCONNECTED;
-               cl->host_client_id = 0;
-               return -EIO;
+       ret = mei_cl_connect(cl, NULL);
+
+       if (ret) {
+               dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret);
+               mei_cl_unlink(cl);
+               return ret;
        }
-       cl->timer_count = MEI_CONNECT_TIMEOUT;
 
-       return 0;
+       ret = mei_watchdog_register(dev);
+       if (ret) {
+               mei_cl_disconnect(cl);
+               mei_cl_unlink(cl);
+       }
+       return ret;
 }
 
 /**
@@ -106,13 +110,16 @@ int mei_wd_host_init(struct mei_device *dev)
  * returns 0 if success,
  *     -EIO when message send fails
  *     -EINVAL when invalid message is to be sent
+ *     -ENODEV on flow control failure
  */
 int mei_wd_send(struct mei_device *dev)
 {
+       struct mei_cl *cl = &dev->wd_cl;
        struct mei_msg_hdr hdr;
+       int ret;
 
-       hdr.host_addr = dev->wd_cl.host_client_id;
-       hdr.me_addr = dev->wd_cl.me_client_id;
+       hdr.host_addr = cl->host_client_id;
+       hdr.me_addr = cl->me_client_id;
        hdr.msg_complete = 1;
        hdr.reserved = 0;
        hdr.internal = 0;
@@ -121,10 +128,24 @@ int mei_wd_send(struct mei_device *dev)
                hdr.length = MEI_WD_START_MSG_SIZE;
        else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
                hdr.length = MEI_WD_STOP_MSG_SIZE;
-       else
+       else {
+               dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");
                return -EINVAL;
+       }
 
-       return mei_write_message(dev, &hdr, dev->wd_data);
+       ret = mei_write_message(dev, &hdr, dev->wd_data);
+       if (ret) {
+               dev_err(&dev->pdev->dev, "wd: write message failed\n");
+               return ret;
+       }
+
+       ret = mei_cl_flow_ctrl_reduce(cl);
+       if (ret) {
+               dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n");
+               return ret;
+       }
+
+       return 0;
 }
 
 /**
@@ -133,9 +154,11 @@ int mei_wd_send(struct mei_device *dev)
  * @dev: the device structure
  * @preserve: indicate if to keep the timeout value
  *
- * returns 0 if success,
- *     -EIO when message send fails
+ * returns 0 if success
+ * on error:
+ *     -EIO    when message send fails
  *     -EINVAL when invalid message is to be sent
+ *     -ETIME  on message timeout
  */
 int mei_wd_stop(struct mei_device *dev)
 {
@@ -151,20 +174,12 @@ int mei_wd_stop(struct mei_device *dev)
 
        ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
        if (ret < 0)
-               goto out;
-
-       if (ret && dev->hbuf_is_ready) {
-               ret = 0;
-               dev->hbuf_is_ready = false;
-
-               if (!mei_wd_send(dev)) {
-                       ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
-                       if (ret)
-                               goto out;
-               } else {
-                       dev_err(&dev->pdev->dev, "wd: send stop failed\n");
-               }
+               goto err;
 
+       if (ret && mei_hbuf_acquire(dev)) {
+               ret = mei_wd_send(dev);
+               if (ret)
+                       goto err;
                dev->wd_pending = false;
        } else {
                dev->wd_pending = true;
@@ -172,21 +187,21 @@ int mei_wd_stop(struct mei_device *dev)
 
        mutex_unlock(&dev->device_lock);
 
-       ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
-                                       dev->wd_state == MEI_WD_IDLE,
-                                       msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
+       ret = wait_event_timeout(dev->wait_stop_wd,
+                               dev->wd_state == MEI_WD_IDLE,
+                               msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
        mutex_lock(&dev->device_lock);
-       if (dev->wd_state == MEI_WD_IDLE) {
-               dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
-               ret = 0;
-       } else {
-               if (!ret)
-                       ret = -ETIMEDOUT;
+       if (dev->wd_state != MEI_WD_IDLE) {
+               /* timeout */
+               ret = -ETIME;
                dev_warn(&dev->pdev->dev,
                        "wd: stop failed to complete ret=%d.\n", ret);
+               goto err;
        }
-
-out:
+       dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n",
+                       MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
+       return 0;
+err:
        return ret;
 }
 
@@ -260,8 +275,8 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
  */
 static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 {
-       int ret = 0;
        struct mei_device *dev;
+       int ret;
 
        dev = watchdog_get_drvdata(wd_dev);
        if (!dev)
@@ -277,25 +292,18 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 
        dev->wd_state = MEI_WD_RUNNING;
 
+       ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
+       if (ret < 0)
+               goto end;
        /* Check if we can send the ping to HW*/
-       if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
+       if (ret && mei_hbuf_acquire(dev)) {
 
-               dev->hbuf_is_ready = false;
                dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
 
-               if (mei_wd_send(dev)) {
-                       dev_err(&dev->pdev->dev, "wd: send failed.\n");
-                       ret = -EIO;
+               ret = mei_wd_send(dev);
+               if (ret)
                        goto end;
-               }
-
-               if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
-                       dev_err(&dev->pdev->dev,
-                               "wd: mei_cl_flow_ctrl_reduce() failed.\n");
-                       ret = -EIO;
-                       goto end;
-               }
-
+               dev->wd_pending = false;
        } else {
                dev->wd_pending = true;
        }
@@ -363,17 +371,25 @@ static struct watchdog_device amt_wd_dev = {
 };
 
 
-void mei_watchdog_register(struct mei_device *dev)
+int mei_watchdog_register(struct mei_device *dev)
 {
-       if (watchdog_register_device(&amt_wd_dev)) {
-               dev_err(&dev->pdev->dev,
-                       "wd: unable to register watchdog device.\n");
-               return;
+
+       int ret;
+
+       /* unlock to perserve correct locking order */
+       mutex_unlock(&dev->device_lock);
+       ret = watchdog_register_device(&amt_wd_dev);
+       mutex_lock(&dev->device_lock);
+       if (ret) {
+               dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n",
+                       ret);
+               return ret;
        }
 
        dev_dbg(&dev->pdev->dev,
                "wd: successfully register watchdog interface.\n");
        watchdog_set_drvdata(&amt_wd_dev, dev);
+       return 0;
 }
 
 void mei_watchdog_unregister(struct mei_device *dev)
index 347b9b3b791620767c23ca6a93ccd5121784da53..306f502be95e2b2d7449c0f042eec14d8bbe6959 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/io.h>
+#include <linux/irqreturn.h>
 
 /**
  * struct mic_intr_info - Contains h/w specific interrupt sources info
index 1a6edce2ecde56fc65dbeaaa6a4ead627478a73e..0398c696d25758fa9fe36d1a15fd97cad75b27da 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/cdev.h>
 #include <linux/idr.h>
 #include <linux/notifier.h>
+#include <linux/irqreturn.h>
 
 #include "mic_intr.h"
 
index f9c29bc918bc05c4b5394ddd472fbc3b839aec67..dbc5afde13928dba672ec0add3d93bbee54dd34a 100644 (file)
@@ -194,7 +194,7 @@ static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev)
        for (i = 0; i < MIC_MIN_MSIX; i++)
                mdev->irq_info.msix_entries[i].entry = i;
 
-       rc = pci_enable_msix(pdev, mdev->irq_info.msix_entries,
+       rc = pci_enable_msix_exact(pdev, mdev->irq_info.msix_entries,
                MIC_MIN_MSIX);
        if (rc) {
                dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc);
index a5925f7f17f6a564cab6296dd2333fb5ae08d92e..956597321d2a39e2599ac7eb19f7071df3b7945e 100644 (file)
@@ -636,6 +636,7 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
        u8 mac[ETH_ALEN];
        ssize_t rom_size;
        struct pch_phub_reg *chip = dev_get_drvdata(dev);
+       int ret;
 
        if (!mac_pton(buf, mac))
                return -EINVAL;
@@ -644,8 +645,10 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
        if (!chip->pch_phub_extrom_base_address)
                return -ENOMEM;
 
-       pch_phub_write_gbe_mac_addr(chip, mac);
+       ret = pch_phub_write_gbe_mac_addr(chip, mac);
        pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address);
+       if (ret)
+               return ret;
 
        return count;
 }
index b9e2000969f025894be4bcae2c6950d699ded3a9..95c894482fddf443d4516ffad39c54adda5be754 100644 (file)
@@ -240,7 +240,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
 
        nid = cpu_to_node(cpu);
        page = alloc_pages_exact_node(nid,
-                                     GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                                     GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                      pg_order);
        if (page == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
index afe66571ce0b7bfde98f05a1a75175f250482fa5..21181fa243dfd8705f10e113f4293c990b231c37 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -36,14 +39,35 @@ struct sram_dev {
        struct clk *clk;
 };
 
+struct sram_reserve {
+       struct list_head list;
+       u32 start;
+       u32 size;
+};
+
+static int sram_reserve_cmp(void *priv, struct list_head *a,
+                                       struct list_head *b)
+{
+       struct sram_reserve *ra = list_entry(a, struct sram_reserve, list);
+       struct sram_reserve *rb = list_entry(b, struct sram_reserve, list);
+
+       return ra->start - rb->start;
+}
+
 static int sram_probe(struct platform_device *pdev)
 {
        void __iomem *virt_base;
        struct sram_dev *sram;
        struct resource *res;
-       unsigned long size;
+       struct device_node *np = pdev->dev.of_node, *child;
+       unsigned long size, cur_start, cur_size;
+       struct sram_reserve *rblocks, *block;
+       struct list_head reserve_list;
+       unsigned int nblocks;
        int ret;
 
+       INIT_LIST_HEAD(&reserve_list);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        virt_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(virt_base))
@@ -65,19 +89,106 @@ static int sram_probe(struct platform_device *pdev)
        if (!sram->pool)
                return -ENOMEM;
 
-       ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
-                               res->start, size, -1);
-       if (ret < 0) {
-               if (sram->clk)
-                       clk_disable_unprepare(sram->clk);
-               return ret;
+       /*
+        * We need an additional block to mark the end of the memory region
+        * after the reserved blocks from the dt are processed.
+        */
+       nblocks = (np) ? of_get_available_child_count(np) + 1 : 1;
+       rblocks = kmalloc((nblocks) * sizeof(*rblocks), GFP_KERNEL);
+       if (!rblocks) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       block = &rblocks[0];
+       for_each_available_child_of_node(np, child) {
+               struct resource child_res;
+
+               ret = of_address_to_resource(child, 0, &child_res);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "could not get address for node %s\n",
+                               child->full_name);
+                       goto err_chunks;
+               }
+
+               if (child_res.start < res->start || child_res.end > res->end) {
+                       dev_err(&pdev->dev,
+                               "reserved block %s outside the sram area\n",
+                               child->full_name);
+                       ret = -EINVAL;
+                       goto err_chunks;
+               }
+
+               block->start = child_res.start - res->start;
+               block->size = resource_size(&child_res);
+               list_add_tail(&block->list, &reserve_list);
+
+               dev_dbg(&pdev->dev, "found reserved block 0x%x-0x%x\n",
+                       block->start,
+                       block->start + block->size);
+
+               block++;
+       }
+
+       /* the last chunk marks the end of the region */
+       rblocks[nblocks - 1].start = size;
+       rblocks[nblocks - 1].size = 0;
+       list_add_tail(&rblocks[nblocks - 1].list, &reserve_list);
+
+       list_sort(NULL, &reserve_list, sram_reserve_cmp);
+
+       cur_start = 0;
+
+       list_for_each_entry(block, &reserve_list, list) {
+               /* can only happen if sections overlap */
+               if (block->start < cur_start) {
+                       dev_err(&pdev->dev,
+                               "block at 0x%x starts after current offset 0x%lx\n",
+                               block->start, cur_start);
+                       ret = -EINVAL;
+                       goto err_chunks;
+               }
+
+               /* current start is in a reserved block, so continue after it */
+               if (block->start == cur_start) {
+                       cur_start = block->start + block->size;
+                       continue;
+               }
+
+               /*
+                * allocate the space between the current starting
+                * address and the following reserved block, or the
+                * end of the region.
+                */
+               cur_size = block->start - cur_start;
+
+               dev_dbg(&pdev->dev, "adding chunk 0x%lx-0x%lx\n",
+                       cur_start, cur_start + cur_size);
+               ret = gen_pool_add_virt(sram->pool,
+                               (unsigned long)virt_base + cur_start,
+                               res->start + cur_start, cur_size, -1);
+               if (ret < 0)
+                       goto err_chunks;
+
+               /* next allocation after this reserved block */
+               cur_start = block->start + block->size;
        }
 
+       kfree(rblocks);
+
        platform_set_drvdata(pdev, sram);
 
        dev_dbg(&pdev->dev, "SRAM pool: %ld KiB @ 0x%p\n", size / 1024, virt_base);
 
        return 0;
+
+err_chunks:
+       kfree(rblocks);
+err_alloc:
+       if (sram->clk)
+               clk_disable_unprepare(sram->clk);
+       return ret;
 }
 
 static int sram_remove(struct platform_device *pdev)
@@ -87,8 +198,6 @@ static int sram_remove(struct platform_device *pdev)
        if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
                dev_dbg(&pdev->dev, "removed while SRAM allocated\n");
 
-       gen_pool_destroy(sram->pool);
-
        if (sram->clk)
                clk_disable_unprepare(sram->clk);
 
index 3aed525e55b48bee7303715c55dea5f162f23752..1972d57aadb30b9aa69304a9513f251864dd589e 100644 (file)
@@ -22,7 +22,6 @@
 #define pr_fmt(fmt)    "(stc): " fmt
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/tty.h>
 
 #include <linux/seq_file.h>
index 83da711ce9f13688660192f55fac62571961ec93..cb0289b44a179150a4cc267fceb2b69fef379779 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/spi/spi.h>
 #include <linux/of.h>
 
index 5bc10fa193de16e682e5bcc540193bd157e37b50..b00335652e52ac45087a65510f0c82a799920879 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
index d35cda06b5e866c98fe722fa7bc1e49a00a1de24..e0d5017785e5f4caa1c8b06fae0366adef9e9b2d 100644 (file)
@@ -383,11 +383,12 @@ static int vmci_enable_msix(struct pci_dev *pdev,
                vmci_dev->msix_entries[i].vector = i;
        }
 
-       result = pci_enable_msix(pdev, vmci_dev->msix_entries, VMCI_MAX_INTRS);
+       result = pci_enable_msix_exact(pdev,
+                                      vmci_dev->msix_entries, VMCI_MAX_INTRS);
        if (result == 0)
                vmci_dev->exclusive_vectors = true;
-       else if (result > 0)
-               result = pci_enable_msix(pdev, vmci_dev->msix_entries, 1);
+       else if (result == -ENOSPC)
+               result = pci_enable_msix_exact(pdev, vmci_dev->msix_entries, 1);
 
        return result;
 }
index 55cd110a49c4009451b0ca4b35144c8631b8c7d1..c204b7d1532c0f1c910b25a7435d3f12c8435732 100644 (file)
@@ -2607,7 +2607,7 @@ int dw_mci_probe(struct dw_mci *host)
 
        tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
        host->card_workqueue = alloc_workqueue("dw-mci-card",
-                       WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
+                       WQ_MEM_RECLAIM, 1);
        if (!host->card_workqueue) {
                ret = -ENOMEM;
                goto err_dmaunmap;
index 90ff447bf0437707fe763133532fbb6b89bae7b7..a4bee41ad5cb3c191748a04409c81ad5414dd1f4 100644 (file)
@@ -428,6 +428,7 @@ config MTD_NAND_FSL_IFC
        tristate "NAND support for Freescale IFC controller"
        depends on MTD_NAND && FSL_SOC
        select FSL_IFC
+       select MEMORY
        help
          Various Freescale chips e.g P1010, include a NAND Flash machine
          with built-in hardware ECC capabilities.
index 90ca7e75d6f038e4cefb365ee2a436eac4ac8cc2..50d9161c4faf49959174f603efe69db4ed969334 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand_ecc.h>
-#include <asm/fsl_ifc.h>
+#include <linux/fsl_ifc.h>
 
 #define FSL_IFC_V1_1_0 0x01010000
 #define ERR_BYTE               0xFF /* Value returned for read
index d72783dd7b962f798f1256067e3d4d9f5a1c5366..c0670237e7a2ebb1c4b845735ac38c591465e815 100644 (file)
@@ -897,7 +897,7 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
                if (!flctl->qos_request) {
                        ret = dev_pm_qos_add_request(&flctl->pdev->dev,
                                                        &flctl->pm_qos,
-                                                       DEV_PM_QOS_LATENCY,
+                                                       DEV_PM_QOS_RESUME_LATENCY,
                                                        100);
                        if (ret < 0)
                                dev_err(&flctl->pdev->dev,
index 6d20fbde8d43502ca6a211c2cd0b83615ea051a0..dcde56057fe14f7bb64a8221db03b2d72a22d842 100644 (file)
@@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg)
  */
 static inline void __disable_port(struct port *port)
 {
-       bond_set_slave_inactive_flags(port->slave);
+       bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
 }
 
 /**
@@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port)
        struct slave *slave = port->slave;
 
        if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
-               bond_set_slave_active_flags(slave);
+               bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
 }
 
 /**
@@ -2062,6 +2062,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        struct list_head *iter;
        struct slave *slave;
        struct port *port;
+       bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
        read_lock(&bond->lock);
        rcu_read_lock();
@@ -2119,8 +2120,19 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        }
 
 re_arm:
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               if (slave->should_notify) {
+                       should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+                       break;
+               }
+       }
        rcu_read_unlock();
        read_unlock(&bond->lock);
+
+       if (should_notify_rtnl && rtnl_trylock()) {
+               bond_slave_state_notify(bond);
+               rtnl_unlock();
+       }
        queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
 }
 
index a2c47476804dc388406e05b4c425c4be59089add..e8f133e926aae720d09d76117bd0c84dcc90d775 100644 (file)
@@ -730,7 +730,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
                        client_info->ntt = 0;
                }
 
-               if (!vlan_get_tag(skb, &client_info->vlan_id))
+               if (vlan_get_tag(skb, &client_info->vlan_id))
                        client_info->vlan_id = 0;
 
                if (!client_info->assigned) {
index 1c6104d3501d4df22e95beab7b60be63548dcc53..e5628fc725c3fc3885b7deac79074caa41edbae4 100644 (file)
@@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
        if (bond_is_lb(bond)) {
                bond_alb_handle_active_change(bond, new_active);
                if (old_active)
-                       bond_set_slave_inactive_flags(old_active);
+                       bond_set_slave_inactive_flags(old_active,
+                                                     BOND_SLAVE_NOTIFY_NOW);
                if (new_active)
-                       bond_set_slave_active_flags(new_active);
+                       bond_set_slave_active_flags(new_active,
+                                                   BOND_SLAVE_NOTIFY_NOW);
        } else {
                rcu_assign_pointer(bond->curr_active_slave, new_active);
        }
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
                if (old_active)
-                       bond_set_slave_inactive_flags(old_active);
+                       bond_set_slave_inactive_flags(old_active,
+                                                     BOND_SLAVE_NOTIFY_NOW);
 
                if (new_active) {
                        bool should_notify_peers = false;
 
-                       bond_set_slave_active_flags(new_active);
+                       bond_set_slave_active_flags(new_active,
+                                                   BOND_SLAVE_NOTIFY_NOW);
 
                        if (bond->params.fail_over_mac)
                                bond_do_fail_over_mac(bond, new_active,
@@ -1193,6 +1197,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                return -EBUSY;
        }
 
+       if (bond_dev == slave_dev) {
+               pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name);
+               return -EPERM;
+       }
+
        /* vlan challenged mutual exclusion */
        /* no need to lock since we're protected by rtnl_lock */
        if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
@@ -1463,14 +1472,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        switch (bond->params.mode) {
        case BOND_MODE_ACTIVEBACKUP:
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave,
+                                             BOND_SLAVE_NOTIFY_NOW);
                break;
        case BOND_MODE_8023AD:
                /* in 802.3ad mode, the internal mechanism
                 * will activate the slaves in the selected
                 * aggregator
                 */
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
                /* if this is the first slave */
                if (!prev_slave) {
                        SLAVE_AD_INFO(new_slave).id = 1;
@@ -1488,7 +1498,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        case BOND_MODE_TLB:
        case BOND_MODE_ALB:
                bond_set_active_slave(new_slave);
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
                break;
        default:
                pr_debug("This slave is always active in trunk mode\n");
@@ -1654,9 +1664,6 @@ static int __bond_release_one(struct net_device *bond_dev,
                return -EINVAL;
        }
 
-       /* release the slave from its bond */
-       bond->slave_cnt--;
-
        bond_sysfs_slave_del(slave);
 
        bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -1738,6 +1745,7 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        unblock_netpoll_tx();
        synchronize_rcu();
+       bond->slave_cnt--;
 
        if (!bond_has_slaves(bond)) {
                call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -2015,7 +2023,8 @@ static void bond_miimon_commit(struct bonding *bond)
 
                        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
                            bond->params.mode == BOND_MODE_8023AD)
-                               bond_set_slave_inactive_flags(slave);
+                               bond_set_slave_inactive_flags(slave,
+                                                             BOND_SLAVE_NOTIFY_NOW);
 
                        pr_info("%s: link status definitely down for interface %s, disabling it\n",
                                bond->dev->name, slave->dev->name);
@@ -2562,7 +2571,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                slave->link = BOND_LINK_UP;
                                if (bond->current_arp_slave) {
                                        bond_set_slave_inactive_flags(
-                                               bond->current_arp_slave);
+                                               bond->current_arp_slave,
+                                               BOND_SLAVE_NOTIFY_NOW);
                                        bond->current_arp_slave = NULL;
                                }
 
@@ -2582,7 +2592,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                slave->link_failure_count++;
 
                        slave->link = BOND_LINK_DOWN;
-                       bond_set_slave_inactive_flags(slave);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_NOW);
 
                        pr_info("%s: link status definitely down for interface %s, disabling it\n",
                                bond->dev->name, slave->dev->name);
@@ -2615,17 +2626,17 @@ do_failover:
 
 /*
  * Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with rcu_read_lock hold.
  */
 static bool bond_ab_arp_probe(struct bonding *bond)
 {
        struct slave *slave, *before = NULL, *new_slave = NULL,
-                    *curr_arp_slave, *curr_active_slave;
+                    *curr_arp_slave = rcu_dereference(bond->current_arp_slave),
+                    *curr_active_slave = rcu_dereference(bond->curr_active_slave);
        struct list_head *iter;
        bool found = false;
-
-       rcu_read_lock();
-       curr_arp_slave = rcu_dereference(bond->current_arp_slave);
-       curr_active_slave = rcu_dereference(bond->curr_active_slave);
+       bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
        if (curr_arp_slave && curr_active_slave)
                pr_info("PROBE: c_arp %s && cas %s BAD\n",
@@ -2634,32 +2645,23 @@ static bool bond_ab_arp_probe(struct bonding *bond)
 
        if (curr_active_slave) {
                bond_arp_send_all(bond, curr_active_slave);
-               rcu_read_unlock();
-               return true;
+               return should_notify_rtnl;
        }
-       rcu_read_unlock();
 
        /* if we don't have a curr_active_slave, search for the next available
         * backup slave from the current_arp_slave and make it the candidate
         * for becoming the curr_active_slave
         */
 
-       if (!rtnl_trylock())
-               return false;
-       /* curr_arp_slave might have gone away */
-       curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave);
-
        if (!curr_arp_slave) {
-               curr_arp_slave = bond_first_slave(bond);
-               if (!curr_arp_slave) {
-                       rtnl_unlock();
-                       return true;
-               }
+               curr_arp_slave = bond_first_slave_rcu(bond);
+               if (!curr_arp_slave)
+                       return should_notify_rtnl;
        }
 
-       bond_set_slave_inactive_flags(curr_arp_slave);
+       bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
 
-       bond_for_each_slave(bond, slave, iter) {
+       bond_for_each_slave_rcu(bond, slave, iter) {
                if (!found && !before && IS_UP(slave->dev))
                        before = slave;
 
@@ -2677,7 +2679,8 @@ static bool bond_ab_arp_probe(struct bonding *bond)
                        if (slave->link_failure_count < UINT_MAX)
                                slave->link_failure_count++;
 
-                       bond_set_slave_inactive_flags(slave);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_LATER);
 
                        pr_info("%s: backup interface %s is now down.\n",
                                bond->dev->name, slave->dev->name);
@@ -2689,26 +2692,31 @@ static bool bond_ab_arp_probe(struct bonding *bond)
        if (!new_slave && before)
                new_slave = before;
 
-       if (!new_slave) {
-               rtnl_unlock();
-               return true;
-       }
+       if (!new_slave)
+               goto check_state;
 
        new_slave->link = BOND_LINK_BACK;
-       bond_set_slave_active_flags(new_slave);
+       bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
        bond_arp_send_all(bond, new_slave);
        new_slave->jiffies = jiffies;
        rcu_assign_pointer(bond->current_arp_slave, new_slave);
-       rtnl_unlock();
 
-       return true;
+check_state:
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               if (slave->should_notify) {
+                       should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+                       break;
+               }
+       }
+       return should_notify_rtnl;
 }
 
 static void bond_activebackup_arp_mon(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            arp_work.work);
-       bool should_notify_peers = false, should_commit = false;
+       bool should_notify_peers = false;
+       bool should_notify_rtnl = false;
        int delta_in_ticks;
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2717,11 +2725,12 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                goto re_arm;
 
        rcu_read_lock();
+
        should_notify_peers = bond_should_notify_peers(bond);
-       should_commit = bond_ab_arp_inspect(bond);
-       rcu_read_unlock();
 
-       if (should_commit) {
+       if (bond_ab_arp_inspect(bond)) {
+               rcu_read_unlock();
+
                /* Race avoidance with bond_close flush of workqueue */
                if (!rtnl_trylock()) {
                        delta_in_ticks = 1;
@@ -2730,23 +2739,28 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                }
 
                bond_ab_arp_commit(bond);
+
                rtnl_unlock();
+               rcu_read_lock();
        }
 
-       if (!bond_ab_arp_probe(bond)) {
-               /* rtnl locking failed, re-arm */
-               delta_in_ticks = 1;
-               should_notify_peers = false;
-       }
+       should_notify_rtnl = bond_ab_arp_probe(bond);
+       rcu_read_unlock();
 
 re_arm:
        if (bond->params.arp_interval)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 
-       if (should_notify_peers) {
+       if (should_notify_peers || should_notify_rtnl) {
                if (!rtnl_trylock())
                        return;
-               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
+
+               if (should_notify_peers)
+                       call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
+                                                bond->dev);
+               if (should_notify_rtnl)
+                       bond_slave_state_notify(bond);
+
                rtnl_unlock();
        }
 }
@@ -3046,9 +3060,11 @@ static int bond_open(struct net_device *bond_dev)
                bond_for_each_slave(bond, slave, iter) {
                        if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                && (slave != bond->curr_active_slave)) {
-                               bond_set_slave_inactive_flags(slave);
+                               bond_set_slave_inactive_flags(slave,
+                                                             BOND_SLAVE_NOTIFY_NOW);
                        } else {
-                               bond_set_slave_active_flags(slave);
+                               bond_set_slave_active_flags(slave,
+                                                           BOND_SLAVE_NOTIFY_NOW);
                        }
                }
                read_unlock(&bond->curr_slave_lock);
index c378784327172a327bfc55a8cc4ee8737db93b43..298c26509095cdd6a6306aa954fe79b1ba46622b 100644 (file)
@@ -121,6 +121,7 @@ static struct bond_opt_value bond_resend_igmp_tbl[] = {
 static struct bond_opt_value bond_lp_interval_tbl[] = {
        { "minval",  1,       BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
        { "maxval",  INT_MAX, BOND_VALFLAG_MAX},
+       { NULL,      -1,      0},
 };
 
 static struct bond_option bond_opts[] = {
index 86ccfb9f71cc4dd8c843f40f5eee38b7c0c033ab..2b0fdec695f78fbf77d9cb7c9cd43cb5b7adb30b 100644 (file)
@@ -195,7 +195,8 @@ struct slave {
        s8     new_link;
        u8     backup:1,   /* indicates backup slave. Value corresponds with
                              BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
-              inactive:1; /* indicates inactive slave */
+              inactive:1, /* indicates inactive slave */
+              should_notify:1; /* indicateds whether the state changed */
        u8     duplex;
        u32    original_mtu;
        u32    link_failure_count;
@@ -303,6 +304,24 @@ static inline void bond_set_backup_slave(struct slave *slave)
        }
 }
 
+static inline void bond_set_slave_state(struct slave *slave,
+                                       int slave_state, bool notify)
+{
+       if (slave->backup == slave_state)
+               return;
+
+       slave->backup = slave_state;
+       if (notify) {
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+               slave->should_notify = 0;
+       } else {
+               if (slave->should_notify)
+                       slave->should_notify = 0;
+               else
+                       slave->should_notify = 1;
+       }
+}
+
 static inline void bond_slave_state_change(struct bonding *bond)
 {
        struct list_head *iter;
@@ -316,6 +335,19 @@ static inline void bond_slave_state_change(struct bonding *bond)
        }
 }
 
+static inline void bond_slave_state_notify(struct bonding *bond)
+{
+       struct list_head *iter;
+       struct slave *tmp;
+
+       bond_for_each_slave(bond, tmp, iter) {
+               if (tmp->should_notify) {
+                       rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_KERNEL);
+                       tmp->should_notify = 0;
+               }
+       }
+}
+
 static inline int bond_slave_state(struct slave *slave)
 {
        return slave->backup;
@@ -343,6 +375,9 @@ static inline bool bond_is_active_slave(struct slave *slave)
 #define BOND_ARP_VALIDATE_ALL          (BOND_ARP_VALIDATE_ACTIVE | \
                                         BOND_ARP_VALIDATE_BACKUP)
 
+#define BOND_SLAVE_NOTIFY_NOW          true
+#define BOND_SLAVE_NOTIFY_LATER                false
+
 static inline int slave_do_arp_validate(struct bonding *bond,
                                        struct slave *slave)
 {
@@ -394,17 +429,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
 }
 #endif
 
-static inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave,
+                                                bool notify)
 {
        if (!bond_is_lb(slave->bond))
-               bond_set_backup_slave(slave);
+               bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
        if (!slave->bond->params.all_slaves_active)
                slave->inactive = 1;
 }
 
-static inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave,
+                                              bool notify)
 {
-       bond_set_active_slave(slave);
+       bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
        slave->inactive = 0;
 }
 
index 320bef2dba427f266511330bc11b1a4097368520..61376abdab395cd941f9a118c46e9912e17f4452 100644 (file)
 
 #define FLEXCAN_MB_CODE_MASK           (0xf0ffffff)
 
+#define FLEXCAN_TIMEOUT_US             (50)
+
 /*
  * FLEXCAN hardware feature flags
  *
@@ -262,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
 }
 #endif
 
+static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
+{
+       if (!priv->reg_xceiver)
+               return 0;
+
+       return regulator_enable(priv->reg_xceiver);
+}
+
+static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
+{
+       if (!priv->reg_xceiver)
+               return 0;
+
+       return regulator_disable(priv->reg_xceiver);
+}
+
 static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
                                              u32 reg_esr)
 {
@@ -269,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
                (reg_esr & FLEXCAN_ESR_ERR_BUS);
 }
 
-static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+static int flexcan_chip_enable(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
        u32 reg;
 
        reg = flexcan_read(&regs->mcr);
        reg &= ~FLEXCAN_MCR_MDIS;
        flexcan_write(reg, &regs->mcr);
 
-       udelay(10);
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
-static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+static int flexcan_chip_disable(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
        u32 reg;
 
        reg = flexcan_read(&regs->mcr);
        reg |= FLEXCAN_MCR_MDIS;
        flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               usleep_range(10, 20);
+
+       if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_freeze(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+       u32 reg;
+
+       reg = flexcan_read(&regs->mcr);
+       reg |= FLEXCAN_MCR_HALT;
+       flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               usleep_range(100, 200);
+
+       if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+       u32 reg;
+
+       reg = flexcan_read(&regs->mcr);
+       reg &= ~FLEXCAN_MCR_HALT;
+       flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_softreset(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+       flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
 static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -709,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev)
        u32 reg_mcr, reg_ctrl;
 
        /* enable module */
-       flexcan_chip_enable(priv);
+       err = flexcan_chip_enable(priv);
+       if (err)
+               return err;
 
        /* soft reset */
-       flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
-       udelay(10);
-
-       reg_mcr = flexcan_read(&regs->mcr);
-       if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
-               netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
-                          reg_mcr);
-               err = -ENODEV;
-               goto out;
-       }
+       err = flexcan_chip_softreset(priv);
+       if (err)
+               goto out_chip_disable;
 
        flexcan_set_bittiming(dev);
 
@@ -788,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
                flexcan_write(0x0, &regs->rxfgmask);
 
-       if (priv->reg_xceiver)  {
-               err = regulator_enable(priv->reg_xceiver);
-               if (err)
-                       goto out;
-       }
+       err = flexcan_transceiver_enable(priv);
+       if (err)
+               goto out_chip_disable;
 
        /* synchronize with the can bus */
-       reg_mcr = flexcan_read(&regs->mcr);
-       reg_mcr &= ~FLEXCAN_MCR_HALT;
-       flexcan_write(reg_mcr, &regs->mcr);
+       err = flexcan_chip_unfreeze(priv);
+       if (err)
+               goto out_transceiver_disable;
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
@@ -810,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
 
        return 0;
 
- out:
+ out_transceiver_disable:
+       flexcan_transceiver_disable(priv);
+ out_chip_disable:
        flexcan_chip_disable(priv);
        return err;
 }
@@ -825,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
 {
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
-       u32 reg;
+
+       /* freeze + disable module */
+       flexcan_chip_freeze(priv);
+       flexcan_chip_disable(priv);
 
        /* Disable all interrupts */
        flexcan_write(0, &regs->imask1);
+       flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+                     &regs->ctrl);
 
-       /* Disable + halt module */
-       reg = flexcan_read(&regs->mcr);
-       reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
-       flexcan_write(reg, &regs->mcr);
-
-       if (priv->reg_xceiver)
-               regulator_disable(priv->reg_xceiver);
+       flexcan_transceiver_disable(priv);
        priv->can.state = CAN_STATE_STOPPED;
 
        return;
@@ -866,7 +947,7 @@ static int flexcan_open(struct net_device *dev)
        /* start chip and queuing */
        err = flexcan_chip_start(dev);
        if (err)
-               goto out_close;
+               goto out_free_irq;
 
        can_led_event(dev, CAN_LED_EVENT_OPEN);
 
@@ -875,6 +956,8 @@ static int flexcan_open(struct net_device *dev)
 
        return 0;
 
+ out_free_irq:
+       free_irq(dev->irq, dev);
  out_close:
        close_candev(dev);
  out_disable_per:
@@ -945,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev)
                goto out_disable_ipg;
 
        /* select "bus clock", chip must be disabled */
-       flexcan_chip_disable(priv);
+       err = flexcan_chip_disable(priv);
+       if (err)
+               goto out_disable_per;
        reg = flexcan_read(&regs->ctrl);
        reg |= FLEXCAN_CTRL_CLK_SRC;
        flexcan_write(reg, &regs->ctrl);
 
-       flexcan_chip_enable(priv);
+       err = flexcan_chip_enable(priv);
+       if (err)
+               goto out_chip_disable;
 
        /* set freeze, halt and activate FIFO, restrict register access */
        reg = flexcan_read(&regs->mcr);
@@ -967,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev)
        if (!(reg & FLEXCAN_MCR_FEN)) {
                netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
                err = -ENODEV;
-               goto out_disable_per;
+               goto out_chip_disable;
        }
 
        err = register_candev(dev);
 
- out_disable_per:
        /* disable core and turn off clocks */
+ out_chip_disable:
        flexcan_chip_disable(priv);
+ out_disable_per:
        clk_disable_unprepare(priv->clk_per);
  out_disable_ipg:
        clk_disable_unprepare(priv->clk_ipg);
@@ -1104,9 +1192,10 @@ static int flexcan_probe(struct platform_device *pdev)
 static int flexcan_remove(struct platform_device *pdev)
 {
        struct net_device *dev = platform_get_drvdata(pdev);
+       struct flexcan_priv *priv = netdev_priv(dev);
 
        unregister_flexcandev(dev);
-
+       netif_napi_del(&priv->napi);
        free_candev(dev);
 
        return 0;
@@ -1117,8 +1206,11 @@ static int flexcan_suspend(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
 
-       flexcan_chip_disable(priv);
+       err = flexcan_chip_disable(priv);
+       if (err)
+               return err;
 
        if (netif_running(dev)) {
                netif_stop_queue(dev);
@@ -1139,9 +1231,7 @@ static int flexcan_resume(struct device *device)
                netif_device_attach(dev);
                netif_start_queue(dev);
        }
-       flexcan_chip_enable(priv);
-
-       return 0;
+       return flexcan_chip_enable(priv);
 }
 #endif /* CONFIG_PM_SLEEP */
 
index 2e45f6ec1bf076de4eaf07b9380466b01eff41b2..380d24922049d97beeedd523e04e9ba9f8033bc5 100644 (file)
@@ -1248,19 +1248,13 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * shared register for the high 32 bits, so only a single, aligned,
         * 4 GB physical address range can be used for descriptors.
         */
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
-           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+       if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
                dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
        } else {
-               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = dma_set_coherent_mask(&pdev->dev,
-                                                   DMA_BIT_MASK(32));
-                       if (err) {
-                               dev_err(&pdev->dev,
-                                       "No usable DMA config, aborting\n");
-                               goto out_pci_disable;
-                       }
+                       dev_err(&pdev->dev, "No usable DMA config, aborting\n");
+                       goto out_pci_disable;
                }
        }
 
index d5c2d3e912e57e1aae51b4bc265a95420f89822b..422aab27ea1bb7b3e9f52e7d44ba6d157a1c2647 100644 (file)
@@ -2436,7 +2436,7 @@ err_reset:
 err_register:
 err_sw_init:
 err_eeprom:
-       iounmap(adapter->hw.hw_addr);
+       pci_iounmap(pdev, adapter->hw.hw_addr);
 err_init_netdev:
 err_ioremap:
        free_netdev(netdev);
@@ -2474,7 +2474,7 @@ static void atl1e_remove(struct pci_dev *pdev)
        unregister_netdev(netdev);
        atl1e_free_ring_resources(adapter);
        atl1e_force_ps(&adapter->hw);
-       iounmap(adapter->hw.hw_addr);
+       pci_iounmap(pdev, adapter->hw.hw_addr);
        pci_release_regions(pdev);
        free_netdev(netdev);
        pci_disable_device(pdev);
index 1f7b5aa114fae3ee3adf589af58e5def31fc84d7..8a7bf7dad89823fadaa7b98f74ae08fe6a56838b 100644 (file)
@@ -1484,6 +1484,10 @@ static int b44_open(struct net_device *dev)
        add_timer(&bp->timer);
 
        b44_enable_ints(bp);
+
+       if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+               phy_start(bp->phydev);
+
        netif_start_queue(dev);
 out:
        return err;
@@ -1646,6 +1650,9 @@ static int b44_close(struct net_device *dev)
 
        netif_stop_queue(dev);
 
+       if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+               phy_stop(bp->phydev);
+
        napi_disable(&bp->napi);
 
        del_timer_sync(&bp->timer);
@@ -2222,7 +2229,12 @@ static void b44_adjust_link(struct net_device *dev)
        }
 
        if (status_changed) {
-               b44_check_phy(bp);
+               u32 val = br32(bp, B44_TX_CTRL);
+               if (bp->flags & B44_FLAG_FULL_DUPLEX)
+                       val |= TX_CTRL_DUPLEX;
+               else
+                       val &= ~TX_CTRL_DUPLEX;
+               bw32(bp, B44_TX_CTRL, val);
                phy_print_status(phydev);
        }
 }
index cda25ac45b475ad7c173a78191f232ea7a252882..6c9e1c9bdeb8cbe06ae1788bd7ecb628e2ea4564 100644 (file)
@@ -2507,6 +2507,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
 
        bp->fw_wr_seq++;
        msg_data |= bp->fw_wr_seq;
+       bp->fw_last_msg = msg_data;
 
        bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
 
@@ -4000,8 +4001,23 @@ bnx2_setup_wol(struct bnx2 *bp)
                        wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
        }
 
-       if (!(bp->flags & BNX2_FLAG_NO_WOL))
-               bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
+       if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
+               u32 val;
+
+               wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
+               if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
+                       bnx2_fw_sync(bp, wol_msg, 1, 0);
+                       return;
+               }
+               /* Tell firmware not to power down the PHY yet, otherwise
+                * the chip will take a long time to respond to MMIO reads.
+                */
+               val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
+               bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
+                             val | BNX2_PORT_FEATURE_ASF_ENABLED);
+               bnx2_fw_sync(bp, wol_msg, 1, 0);
+               bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
+       }
 
 }
 
@@ -4033,9 +4049,22 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
 
                        if (bp->wol)
                                pci_set_power_state(bp->pdev, PCI_D3hot);
-               } else {
-                       pci_set_power_state(bp->pdev, PCI_D3hot);
+                       break;
+
+               }
+               if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
+                       u32 val;
+
+                       /* Tell firmware not to power down the PHY yet,
+                        * otherwise the other port may not respond to
+                        * MMIO reads.
+                        */
+                       val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+                       val &= ~BNX2_CONDITION_PM_STATE_MASK;
+                       val |= BNX2_CONDITION_PM_STATE_UNPREP;
+                       bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
                }
+               pci_set_power_state(bp->pdev, PCI_D3hot);
 
                /* No more memory access after this point until
                 * device is brought back to D0.
index f1cf2c44e7ed549519fe2eaf860d0d01302b032d..e341bc366fa5f1d003a9355516a8ebdd81811ac8 100644 (file)
@@ -6900,6 +6900,7 @@ struct bnx2 {
 
        u16                     fw_wr_seq;
        u16                     fw_drv_pulse_wr_seq;
+       u32                     fw_last_msg;
 
        int                     rx_max_ring;
        int                     rx_ring_size;
@@ -7406,6 +7407,10 @@ struct bnx2_rv2p_fw_file {
 #define BNX2_CONDITION_MFW_RUN_NCSI             0x00006000
 #define BNX2_CONDITION_MFW_RUN_NONE             0x0000e000
 #define BNX2_CONDITION_MFW_RUN_MASK             0x0000e000
+#define BNX2_CONDITION_PM_STATE_MASK            0x00030000
+#define BNX2_CONDITION_PM_STATE_FULL            0x00030000
+#define BNX2_CONDITION_PM_STATE_PREP            0x00020000
+#define BNX2_CONDITION_PM_STATE_UNPREP          0x00010000
 
 #define BNX2_BC_STATE_DEBUG_CMD                        0x1dc
 #define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE      0x42440000
index 66c0df78c3ff9685c495626c6301fc85c6aac345..dbcff509dc3f6d62cf48c729563196de8c4c7904 100644 (file)
@@ -3875,7 +3875,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                     xmit_type);
                }
 
-               /* Add the macs to the parsing BD this is a vf */
+               /* Add the macs to the parsing BD if this is a vf or if
+                * Tx Switching is enabled.
+                */
                if (IS_VF(bp)) {
                        /* override GRE parameters in BD */
                        bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
@@ -3883,6 +3885,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                              &pbd_e2->data.mac_addr.src_lo,
                                              eth->h_source);
 
+                       bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
+                                             &pbd_e2->data.mac_addr.dst_mid,
+                                             &pbd_e2->data.mac_addr.dst_lo,
+                                             eth->h_dest);
+               } else if (bp->flags & TX_SWITCHING) {
                        bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
                                              &pbd_e2->data.mac_addr.dst_mid,
                                              &pbd_e2->data.mac_addr.dst_lo,
index fcf9105a5476123c0e5d4e7a4095f05d6c95774e..09f3fefcbf9ce405839e6f5893174a79dc91c5b8 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -342,7 +342,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
        while (retry < 3) {
                rc = 0;
                rcu_read_lock();
-               ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
+               ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
                if (ulp_ops)
                        rc = ulp_ops->iscsi_nl_send_msg(
                                cp->ulp_handle[CNIC_ULP_ISCSI],
@@ -726,7 +726,7 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
 
        for (i = 0; i < dma->num_pages; i++) {
                if (dma->pg_arr[i]) {
-                       dma_free_coherent(&dev->pcidev->dev, BNX2_PAGE_SIZE,
+                       dma_free_coherent(&dev->pcidev->dev, CNIC_PAGE_SIZE,
                                          dma->pg_arr[i], dma->pg_map_arr[i]);
                        dma->pg_arr[i] = NULL;
                }
@@ -785,7 +785,7 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
 
        for (i = 0; i < pages; i++) {
                dma->pg_arr[i] = dma_alloc_coherent(&dev->pcidev->dev,
-                                                   BNX2_PAGE_SIZE,
+                                                   CNIC_PAGE_SIZE,
                                                    &dma->pg_map_arr[i],
                                                    GFP_ATOMIC);
                if (dma->pg_arr[i] == NULL)
@@ -794,8 +794,8 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
        if (!use_pg_tbl)
                return 0;
 
-       dma->pgtbl_size = ((pages * 8) + BNX2_PAGE_SIZE - 1) &
-                         ~(BNX2_PAGE_SIZE - 1);
+       dma->pgtbl_size = ((pages * 8) + CNIC_PAGE_SIZE - 1) &
+                         ~(CNIC_PAGE_SIZE - 1);
        dma->pgtbl = dma_alloc_coherent(&dev->pcidev->dev, dma->pgtbl_size,
                                        &dma->pgtbl_map, GFP_ATOMIC);
        if (dma->pgtbl == NULL)
@@ -900,8 +900,8 @@ static int cnic_alloc_context(struct cnic_dev *dev)
        if (BNX2_CHIP(cp) == BNX2_CHIP_5709) {
                int i, k, arr_size;
 
-               cp->ctx_blk_size = BNX2_PAGE_SIZE;
-               cp->cids_per_blk = BNX2_PAGE_SIZE / 128;
+               cp->ctx_blk_size = CNIC_PAGE_SIZE;
+               cp->cids_per_blk = CNIC_PAGE_SIZE / 128;
                arr_size = BNX2_MAX_CID / cp->cids_per_blk *
                           sizeof(struct cnic_ctx);
                cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
@@ -933,7 +933,7 @@ static int cnic_alloc_context(struct cnic_dev *dev)
                for (i = 0; i < cp->ctx_blks; i++) {
                        cp->ctx_arr[i].ctx =
                                dma_alloc_coherent(&dev->pcidev->dev,
-                                                  BNX2_PAGE_SIZE,
+                                                  CNIC_PAGE_SIZE,
                                                   &cp->ctx_arr[i].mapping,
                                                   GFP_KERNEL);
                        if (cp->ctx_arr[i].ctx == NULL)
@@ -1013,7 +1013,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
        if (udev->l2_ring)
                return 0;
 
-       udev->l2_ring_size = pages * BNX2_PAGE_SIZE;
+       udev->l2_ring_size = pages * CNIC_PAGE_SIZE;
        udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
                                           &udev->l2_ring_map,
                                           GFP_KERNEL | __GFP_COMP);
@@ -1021,7 +1021,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
                return -ENOMEM;
 
        udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
-       udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+       udev->l2_buf_size = CNIC_PAGE_ALIGN(udev->l2_buf_size);
        udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
                                          &udev->l2_buf_map,
                                          GFP_KERNEL | __GFP_COMP);
@@ -1102,7 +1102,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
                uinfo->mem[0].size = MB_GET_CID_ADDR(TX_TSS_CID +
                                                     TX_MAX_TSS_RINGS + 1);
                uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
-                                       PAGE_MASK;
+                                       CNIC_PAGE_MASK;
                if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
                        uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
                else
@@ -1113,7 +1113,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
                uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0);
 
                uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
-                       PAGE_MASK;
+                       CNIC_PAGE_MASK;
                uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
 
                uinfo->name = "bnx2x_cnic";
@@ -1267,14 +1267,14 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
        for (i = MAX_ISCSI_TBL_SZ; i < cp->max_cid_space; i++)
                cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_FCOE;
 
-       pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
-               PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
+               CNIC_PAGE_SIZE;
 
        ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
        if (ret)
                return -ENOMEM;
 
-       n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
+       n = CNIC_PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
        for (i = 0, j = 0; i < cp->max_cid_space; i++) {
                long off = CNIC_KWQ16_DATA_SIZE * (i % n);
 
@@ -1296,7 +1296,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
                        goto error;
        }
 
-       pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / CNIC_PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
        if (ret)
                goto error;
@@ -1466,8 +1466,8 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
        cp->r2tq_size = cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS *
                        BNX2X_ISCSI_R2TQE_SIZE;
        cp->hq_size = cp->num_ccells * BNX2X_ISCSI_HQ_BD_SIZE;
-       pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
-       hq_bds = pages * (PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
+       pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
+       hq_bds = pages * (CNIC_PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
        cp->num_cqs = req1->num_cqs;
 
        if (!dev->max_iscsi_conn)
@@ -1477,9 +1477,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
        CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(pfid),
                  req1->rq_num_wqes);
        CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
-                TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
                  TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1489,9 +1489,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
                  USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfid),
                  req1->rq_buffer_size);
        CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_USTRORM_INTMEM +
-                USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_USTRORM_INTMEM +
                  USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1504,9 +1504,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
 
        /* init Xstorm RAM */
        CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
-                XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
                  XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1519,9 +1519,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
 
        /* init Cstorm RAM */
        CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
-                CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
                  CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1623,18 +1623,18 @@ static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
        }
 
        ctx->cid = cid;
-       pages = PAGE_ALIGN(cp->task_array_size) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->task_array_size) / CNIC_PAGE_SIZE;
 
        ret = cnic_alloc_dma(dev, &iscsi->task_array_info, pages, 1);
        if (ret)
                goto error;
 
-       pages = PAGE_ALIGN(cp->r2tq_size) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->r2tq_size) / CNIC_PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &iscsi->r2tq_info, pages, 1);
        if (ret)
                goto error;
 
-       pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &iscsi->hq_info, pages, 1);
        if (ret)
                goto error;
@@ -1760,7 +1760,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
        ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
        /* TSTORM requires the base address of RQ DB & not PTE */
        ictx->tstorm_st_context.iscsi.rq_db_phy_addr.lo =
-               req2->rq_page_table_addr_lo & PAGE_MASK;
+               req2->rq_page_table_addr_lo & CNIC_PAGE_MASK;
        ictx->tstorm_st_context.iscsi.rq_db_phy_addr.hi =
                req2->rq_page_table_addr_hi;
        ictx->tstorm_st_context.iscsi.iscsi_conn_id = req1->iscsi_conn_id;
@@ -1842,7 +1842,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
        /* CSTORM and USTORM initialization is different, CSTORM requires
         * CQ DB base & not PTE addr */
        ictx->cstorm_st_context.cq_db_base.lo =
-               req1->cq_page_table_addr_lo & PAGE_MASK;
+               req1->cq_page_table_addr_lo & CNIC_PAGE_MASK;
        ictx->cstorm_st_context.cq_db_base.hi = req1->cq_page_table_addr_hi;
        ictx->cstorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
        ictx->cstorm_st_context.cq_proc_en_bit_map = (1 << cp->num_cqs) - 1;
@@ -2911,7 +2911,7 @@ static int cnic_l2_completion(struct cnic_local *cp)
        u16 hw_cons, sw_cons;
        struct cnic_uio_dev *udev = cp->udev;
        union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
-                                       (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+                                       (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
        u32 cmd;
        int comp = 0;
 
@@ -3244,7 +3244,8 @@ static int cnic_copy_ulp_stats(struct cnic_dev *dev, int ulp_type)
        int rc;
 
        mutex_lock(&cnic_lock);
-       ulp_ops = cnic_ulp_tbl_prot(ulp_type);
+       ulp_ops = rcu_dereference_protected(cp->ulp_ops[ulp_type],
+                                           lockdep_is_held(&cnic_lock));
        if (ulp_ops && ulp_ops->cnic_get_stats)
                rc = ulp_ops->cnic_get_stats(cp->ulp_handle[ulp_type]);
        else
@@ -4384,7 +4385,7 @@ static int cnic_setup_5709_context(struct cnic_dev *dev, int valid)
                u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk;
                u32 val;
 
-               memset(cp->ctx_arr[i].ctx, 0, BNX2_PAGE_SIZE);
+               memset(cp->ctx_arr[i].ctx, 0, CNIC_PAGE_SIZE);
 
                CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0,
                        (cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit);
@@ -4628,7 +4629,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
                val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
 
-       rxbd = udev->l2_ring + BNX2_PAGE_SIZE;
+       rxbd = udev->l2_ring + CNIC_PAGE_SIZE;
        for (i = 0; i < BNX2_MAX_RX_DESC_CNT; i++, rxbd++) {
                dma_addr_t buf_map;
                int n = (i % cp->l2_rx_ring_size) + 1;
@@ -4639,11 +4640,11 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
                rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
                rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
        }
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
        rxbd->rx_bd_haddr_hi = val;
 
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
        rxbd->rx_bd_haddr_lo = val;
 
@@ -4709,10 +4710,10 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        val = CNIC_RD(dev, BNX2_MQ_CONFIG);
        val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
-       if (BNX2_PAGE_BITS > 12)
+       if (CNIC_PAGE_BITS > 12)
                val |= (12 - 8)  << 4;
        else
-               val |= (BNX2_PAGE_BITS - 8)  << 4;
+               val |= (CNIC_PAGE_BITS - 8)  << 4;
 
        CNIC_WR(dev, BNX2_MQ_CONFIG, val);
 
@@ -4742,13 +4743,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        /* Initialize the kernel work queue context. */
        val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
-             (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+             (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
        cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val);
 
-       val = (BNX2_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+       val = (CNIC_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
        cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
 
-       val = ((BNX2_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+       val = ((CNIC_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
        cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
 
        val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
@@ -4768,13 +4769,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        /* Initialize the kernel complete queue context. */
        val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
-             (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+             (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
        cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val);
 
-       val = (BNX2_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+       val = (CNIC_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
        cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
 
-       val = ((BNX2_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+       val = ((CNIC_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
        cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
 
        val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32);
@@ -4918,7 +4919,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
        u32 cli = cp->ethdev->iscsi_l2_client_id;
        u32 val;
 
-       memset(txbd, 0, BNX2_PAGE_SIZE);
+       memset(txbd, 0, CNIC_PAGE_SIZE);
 
        buf_map = udev->l2_buf_map;
        for (i = 0; i < BNX2_MAX_TX_DESC_CNT; i += 3, txbd += 3) {
@@ -4978,9 +4979,9 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
        struct bnx2x *bp = netdev_priv(dev->netdev);
        struct cnic_uio_dev *udev = cp->udev;
        struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (udev->l2_ring +
-                               BNX2_PAGE_SIZE);
+                               CNIC_PAGE_SIZE);
        struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *)
-                               (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+                               (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
        struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
        int i;
        u32 cli = cp->ethdev->iscsi_l2_client_id;
@@ -5004,20 +5005,20 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
                rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
        }
 
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
        rxbd->addr_hi = cpu_to_le32(val);
        data->rx.bd_page_base.hi = cpu_to_le32(val);
 
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
        rxbd->addr_lo = cpu_to_le32(val);
        data->rx.bd_page_base.lo = cpu_to_le32(val);
 
        rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
-       val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) >> 32;
+       val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) >> 32;
        rxcqe->addr_hi = cpu_to_le32(val);
        data->rx.cqe_page_base.hi = cpu_to_le32(val);
 
-       val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) & 0xffffffff;
+       val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) & 0xffffffff;
        rxcqe->addr_lo = cpu_to_le32(val);
        data->rx.cqe_page_base.lo = cpu_to_le32(val);
 
@@ -5265,8 +5266,8 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
                msleep(10);
        }
        clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
-       rx_ring = udev->l2_ring + BNX2_PAGE_SIZE;
-       memset(rx_ring, 0, BNX2_PAGE_SIZE);
+       rx_ring = udev->l2_ring + CNIC_PAGE_SIZE;
+       memset(rx_ring, 0, CNIC_PAGE_SIZE);
 }
 
 static int cnic_register_netdev(struct cnic_dev *dev)
index 0d6b13f854d959ab0cdaf101192dfe2c4930c372..d535ae4228b4ccb12d9df6e24f7fed6911e9a6da 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.h: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 95a8e4b11c9fcce45a0f24acea5bd1b86fa53ab9..dcbca6997e8fbcb9d4f38f12acbf8718846bdfbd 100644 (file)
@@ -1,7 +1,7 @@
 
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 8cf6b1926069d2c541b8b6888eced6463b887aa4..5f4d5573a73dbb8252d34ec6419750c3ec06eee1 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic_if.h: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
 
 #include "bnx2x/bnx2x_mfw_req.h"
 
-#define CNIC_MODULE_VERSION    "2.5.19"
-#define CNIC_MODULE_RELDATE    "December 19, 2013"
+#define CNIC_MODULE_VERSION    "2.5.20"
+#define CNIC_MODULE_RELDATE    "March 14, 2014"
 
 #define CNIC_ULP_RDMA          0
 #define CNIC_ULP_ISCSI         1
 #define MAX_CNIC_ULP_TYPE_EXT  3
 #define MAX_CNIC_ULP_TYPE      4
 
+/* Use CPU native page size up to 16K for cnic ring sizes.  */
+#if (PAGE_SHIFT > 14)
+#define CNIC_PAGE_BITS 14
+#else
+#define CNIC_PAGE_BITS PAGE_SHIFT
+#endif
+#define CNIC_PAGE_SIZE (1 << (CNIC_PAGE_BITS))
+#define CNIC_PAGE_ALIGN(addr) ALIGN(addr, CNIC_PAGE_SIZE)
+#define CNIC_PAGE_MASK (~((CNIC_PAGE_SIZE) - 1))
+
 struct kwqe {
        u32 kwqe_op_flag;
 
index 3167ed6593b0410bc0382294a015e3ac06e1ffed..70a225c8df5c846a4d7045f2e7649925a5d8c50c 100644 (file)
@@ -6843,8 +6843,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 
                work_mask |= opaque_key;
 
-               if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
-                   (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+               if (desc->err_vlan & RXD_ERR_MASK) {
                drop_it:
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
@@ -17650,8 +17649,6 @@ static int tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_bufmgr_config(tp);
 
-       features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
-
        /* 5700 B0 chips do not support checksumming correctly due
         * to hardware bugs.
         */
@@ -17683,7 +17680,8 @@ static int tg3_init_one(struct pci_dev *pdev,
                        features |= NETIF_F_TSO_ECN;
        }
 
-       dev->features |= features;
+       dev->features |= features | NETIF_F_HW_VLAN_CTAG_TX |
+                        NETIF_F_HW_VLAN_CTAG_RX;
        dev->vlan_features |= features;
 
        /*
index ef472385bce47dcea87f43e48f202ffabbddf16d..04321e5a356e45a0f7fc642f3817035d983dbd90 100644 (file)
@@ -2608,7 +2608,11 @@ struct tg3_rx_buffer_desc {
 #define RXD_ERR_TOO_SMALL              0x00400000
 #define RXD_ERR_NO_RESOURCES           0x00800000
 #define RXD_ERR_HUGE_FRAME             0x01000000
-#define RXD_ERR_MASK                   0xffff0000
+
+#define RXD_ERR_MASK   (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION |          \
+                        RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE |       \
+                        RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL |         \
+                        RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME)
 
        u32                             reserved;
        u32                             opaque;
index 1803c39590442d497d1cc7f543ef8148ac7e56ec..354ae9792badb329e89b0ab37f59ff78c73efd11 100644 (file)
@@ -1704,7 +1704,7 @@ bfa_flash_sem_get(void __iomem *bar)
        while (!bfa_raw_sem_get(bar)) {
                if (--n <= 0)
                        return BFA_STATUS_BADFLASH;
-               udelay(10000);
+               mdelay(10);
        }
        return BFA_STATUS_OK;
 }
index cf64f3d0b60d91a1de68836523c6304086dc9ece..4ad1187e82fb463e9642fd3e73b2850cf1137a01 100644 (file)
@@ -707,7 +707,8 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                else
                        skb_checksum_none_assert(skb);
 
-               if (flags & BNA_CQ_EF_VLAN)
+               if ((flags & BNA_CQ_EF_VLAN) &&
+                   (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag));
 
                if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type))
@@ -2094,7 +2095,9 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
                rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE;
        }
 
-       rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+       rx_config->vlan_strip_status =
+               (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ?
+               BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED;
 }
 
 static void
@@ -3245,11 +3248,6 @@ bnad_set_rx_mode(struct net_device *netdev)
                        BNA_RXMODE_ALLMULTI;
        bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
 
-       if (bnad->cfg_flags & BNAD_CF_PROMISC)
-               bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
-       else
-               bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
-
        spin_unlock_irqrestore(&bnad->bna_lock, flags);
 }
 
@@ -3374,6 +3372,27 @@ bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
        return 0;
 }
 
+static int bnad_set_features(struct net_device *dev, netdev_features_t features)
+{
+       struct bnad *bnad = netdev_priv(dev);
+       netdev_features_t changed = features ^ dev->features;
+
+       if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+
+               if (features & NETIF_F_HW_VLAN_CTAG_RX)
+                       bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
+               else
+                       bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
+
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void
 bnad_netpoll(struct net_device *netdev)
@@ -3421,6 +3440,7 @@ static const struct net_device_ops bnad_netdev_ops = {
        .ndo_change_mtu         = bnad_change_mtu,
        .ndo_vlan_rx_add_vid    = bnad_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = bnad_vlan_rx_kill_vid,
+       .ndo_set_features       = bnad_set_features,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = bnad_netpoll
 #endif
@@ -3433,14 +3453,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
 
        netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX;
+               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX |
+               NETIF_F_HW_VLAN_CTAG_RX;
 
        netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                NETIF_F_TSO | NETIF_F_TSO6;
 
-       netdev->features |= netdev->hw_features |
-               NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
+       netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
 
        if (using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
index 3190d38e16fbd5d59a8cbc0cca7378a500572402..d0c38e01e99fdc70e802b33dc977e081d1a72f5c 100644 (file)
@@ -632,11 +632,16 @@ static void gem_rx_refill(struct macb *bp)
                                           "Unable to allocate sk_buff\n");
                                break;
                        }
-                       bp->rx_skbuff[entry] = skb;
 
                        /* now fill corresponding descriptor entry */
                        paddr = dma_map_single(&bp->pdev->dev, skb->data,
                                               bp->rx_buffer_size, DMA_FROM_DEVICE);
+                       if (dma_mapping_error(&bp->pdev->dev, paddr)) {
+                               dev_kfree_skb(skb);
+                               break;
+                       }
+
+                       bp->rx_skbuff[entry] = skb;
 
                        if (entry == RX_RING_SIZE - 1)
                                paddr |= MACB_BIT(RX_WRAP);
@@ -725,7 +730,7 @@ static int gem_rx(struct macb *bp, int budget)
                skb_put(skb, len);
                addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, addr));
                dma_unmap_single(&bp->pdev->dev, addr,
-                                len, DMA_FROM_DEVICE);
+                                bp->rx_buffer_size, DMA_FROM_DEVICE);
 
                skb->protocol = eth_type_trans(skb, bp->dev);
                skb_checksum_none_assert(skb);
@@ -1036,11 +1041,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        entry = macb_tx_ring_wrap(bp->tx_head);
-       bp->tx_head++;
        netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
        mapping = dma_map_single(&bp->pdev->dev, skb->data,
                                 len, DMA_TO_DEVICE);
+       if (dma_mapping_error(&bp->pdev->dev, mapping)) {
+               kfree_skb(skb);
+               goto unlock;
+       }
 
+       bp->tx_head++;
        tx_skb = &bp->tx_skb[entry];
        tx_skb->skb = skb;
        tx_skb->mapping = mapping;
@@ -1066,6 +1075,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1)
                netif_stop_queue(dev);
 
+unlock:
        spin_unlock_irqrestore(&bp->lock, flags);
 
        return NETDEV_TX_OK;
index 43ab35fea48d2be9fe6dfcd4d1e9dc10651724be..34e2488767d94d0c6eeaf677ffbfca493d871e54 100644 (file)
@@ -6179,6 +6179,7 @@ static struct pci_driver cxgb4_driver = {
        .id_table = cxgb4_pci_tbl,
        .probe    = init_one,
        .remove   = remove_one,
+       .shutdown = remove_one,
        .err_handler = &cxgb4_eeh,
 };
 
index 8d09615da585671a4d0fa9d00dc9cc6ba80f6517..05529e273050e3718c0ca1e105ce05174fdfe618 100644 (file)
@@ -350,11 +350,13 @@ struct be_drv_stats {
        u32 roce_drops_crc;
 };
 
+/* A vlan-id of 0xFFFF must be used to clear transparent vlan-tagging */
+#define BE_RESET_VLAN_TAG_ID   0xFFFF
+
 struct be_vf_cfg {
        unsigned char mac_addr[ETH_ALEN];
        int if_handle;
        int pmac_id;
-       u16 def_vid;
        u16 vlan_tag;
        u32 tx_rate;
 };
index 04ac9c6a0d3972d4e18ee91a8ce3a8bf2e141cd7..36c80612e21a3ebe6ee52447e9075dc4022f005e 100644 (file)
@@ -913,24 +913,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
        return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
 }
 
-static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
-                                          struct sk_buff *skb,
-                                          bool *skip_hw_vlan)
+static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+                                                 struct sk_buff *skb,
+                                                 bool *skip_hw_vlan)
 {
        struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
        unsigned int eth_hdr_len;
        struct iphdr *ip;
 
-       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
-        * may cause a transmit stall on that port. So the work-around is to
-        * pad short packets (<= 32 bytes) to a 36-byte length.
-        */
-       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
-               if (skb_padto(skb, 36))
-                       goto tx_drop;
-               skb->len = 36;
-       }
-
        /* For padded packets, BE HW modifies tot_len field in IP header
         * incorrecly when VLAN tag is inserted by HW.
         * For padded packets, Lancer computes incorrect checksum.
@@ -959,7 +949,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            vlan_tx_tag_present(skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        /* HW may lockup when VLAN HW tagging is requested on
@@ -981,15 +971,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            be_vlan_tag_tx_chk(adapter, skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        return skb;
 tx_drop:
        dev_kfree_skb_any(skb);
+err:
        return NULL;
 }
 
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+                                          struct sk_buff *skb,
+                                          bool *skip_hw_vlan)
+{
+       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
+        * less may cause a transmit stall on that port. So the work-around is
+        * to pad short packets (<= 32 bytes) to a 36-byte length.
+        */
+       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
+               if (skb_padto(skb, 36))
+                       return NULL;
+               skb->len = 36;
+       }
+
+       if (BEx_chip(adapter) || lancer_chip(adapter)) {
+               skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+               if (!skb)
+                       return NULL;
+       }
+
+       return skb;
+}
+
 static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1157,6 +1171,14 @@ ret:
        return status;
 }
 
+static void be_clear_promisc(struct be_adapter *adapter)
+{
+       adapter->promiscuous = false;
+       adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+
+       be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+}
+
 static void be_set_rx_mode(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1170,9 +1192,7 @@ static void be_set_rx_mode(struct net_device *netdev)
 
        /* BE was previously in promiscuous mode; disable it */
        if (adapter->promiscuous) {
-               adapter->promiscuous = false;
-               be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
-
+               be_clear_promisc(adapter);
                if (adapter->vlans_added)
                        be_vid_config(adapter);
        }
@@ -1287,24 +1307,20 @@ static int be_set_vf_vlan(struct net_device *netdev,
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan) {
-                       /* If this is new value, program it. Else skip. */
-                       vf_cfg->vlan_tag = vlan;
+               if (vf_cfg->vlan_tag != vlan)
                        status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
                                                       vf_cfg->if_handle, 0);
-               }
        } else {
                /* Reset Transparent Vlan Tagging. */
-               vf_cfg->vlan_tag = 0;
-               vlan = vf_cfg->def_vid;
-               status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                              vf_cfg->if_handle, 0);
+               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
+                                              vf + 1, vf_cfg->if_handle, 0);
        }
 
-
-       if (status)
+       if (!status)
+               vf_cfg->vlan_tag = vlan;
+       else
                dev_info(&adapter->pdev->dev,
-                               "VLAN %d config on VF %d failed\n", vlan, vf);
+                        "VLAN %d config on VF %d failed\n", vlan, vf);
        return status;
 }
 
@@ -3013,11 +3029,11 @@ static int be_vf_setup_init(struct be_adapter *adapter)
 
 static int be_vf_setup(struct be_adapter *adapter)
 {
+       struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
-       u16 def_vlan, lnk_speed;
        int status, old_vfs, vf;
-       struct device *dev = &adapter->pdev->dev;
        u32 privileges;
+       u16 lnk_speed;
 
        old_vfs = pci_num_vf(adapter->pdev);
        if (old_vfs) {
@@ -3084,12 +3100,6 @@ static int be_vf_setup(struct be_adapter *adapter)
                if (!status)
                        vf_cfg->tx_rate = lnk_speed;
 
-               status = be_cmd_get_hsw_config(adapter, &def_vlan,
-                                              vf + 1, vf_cfg->if_handle, NULL);
-               if (status)
-                       goto err;
-               vf_cfg->def_vid = def_vlan;
-
                if (!old_vfs)
                        be_cmd_enable_vf(adapter, vf + 1);
        }
index 903362a7b58435878d790b06d9bb2dadbcdede35..03a351300013c82999474fb411731f1487755550 100644 (file)
@@ -389,12 +389,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        netdev_err(ndev, "Tx DMA memory map failed\n");
                return NETDEV_TX_OK;
        }
-       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
-        * it's the last BD of the frame, and to put the CRC on the end.
-        */
-       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
-                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
-       bdp->cbd_sc = status;
 
        if (fep->bufdesc_ex) {
 
@@ -416,6 +410,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                }
        }
 
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        * it's the last BD of the frame, and to put the CRC on the end.
+        */
+       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+       bdp->cbd_sc = status;
+
        bdp_pre = fec_enet_get_prevdesc(bdp, fep);
        if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
            !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
@@ -527,13 +528,6 @@ fec_restart(struct net_device *ndev, int duplex)
        /* Clear any outstanding interrupt. */
        writel(0xffc00000, fep->hwp + FEC_IEVENT);
 
-       /* Setup multicast filter. */
-       set_multicast_list(ndev);
-#ifndef CONFIG_M5272
-       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
-       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
-#endif
-
        /* Set maximum receive buffer size. */
        writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
 
@@ -654,6 +648,13 @@ fec_restart(struct net_device *ndev, int duplex)
 
        writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
+       /* Setup multicast filter. */
+       set_multicast_list(ndev);
+#ifndef CONFIG_M5272
+       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+#endif
+
        if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
                /* enable ENET endian swap */
                ecntl |= (1 << 8);
index 4be9715904616b3f9c1ff2a3bc38d55b58135e58..1fc8334fc181ad6d949ecffa2a289eb899c2a160 100644 (file)
@@ -522,10 +522,21 @@ retry:
        return rc;
 }
 
+static u64 ibmveth_encode_mac_addr(u8 *mac)
+{
+       int i;
+       u64 encoded = 0;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               encoded = (encoded << 8) | mac[i];
+
+       return encoded;
+}
+
 static int ibmveth_open(struct net_device *netdev)
 {
        struct ibmveth_adapter *adapter = netdev_priv(netdev);
-       u64 mac_address = 0;
+       u64 mac_address;
        int rxq_entries = 1;
        unsigned long lpar_rc;
        int rc;
@@ -579,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev)
        adapter->rx_queue.num_slots = rxq_entries;
        adapter->rx_queue.toggle = 1;
 
-       memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
-       mac_address = mac_address >> 16;
+       mac_address = ibmveth_encode_mac_addr(netdev->dev_addr);
 
        rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
                                        adapter->rx_queue.queue_len;
@@ -1183,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                /* add the addresses to the filter table */
                netdev_for_each_mc_addr(ha, netdev) {
                        /* add the multicast address to the filter table */
-                       unsigned long mcast_addr = 0;
-                       memcpy(((char *)&mcast_addr)+2, ha->addr, ETH_ALEN);
+                       u64 mcast_addr;
+                       mcast_addr = ibmveth_encode_mac_addr(ha->addr);
                        lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                                   IbmVethMcastAddFilter,
                                                   mcast_addr);
@@ -1372,9 +1382,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
 
-       adapter->mac_addr = 0;
-       memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN);
-
        netdev->irq = dev->irq;
        netdev->netdev_ops = &ibmveth_netdev_ops;
        netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1383,7 +1390,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        netdev->features |= netdev->hw_features;
 
-       memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+       memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
 
        for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
index 451ba7949e152a66ee87e661e90722496792dfb8..1f37499d43981d260c61cdc1c089d7328a7942c9 100644 (file)
@@ -138,7 +138,6 @@ struct ibmveth_adapter {
     struct napi_struct napi;
     struct net_device_stats stats;
     unsigned int mcastFilterSize;
-    unsigned long mac_addr;
     void * buffer_list_addr;
     void * filter_list_addr;
     dma_addr_t buffer_list_dma;
index f418f4f20f94a0f22524a6d5c1c878c2a40f7146..8d76fca7fde75085da8364a621e97e332f1e23bc 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_mdio.h>
@@ -88,8 +89,9 @@
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
-#define MVNETA_SGMII_SERDES_CFG                         0x24A0
+#define MVNETA_SERDES_CFG                       0x24A0
 #define      MVNETA_SGMII_SERDES_PROTO          0x0cc7
+#define      MVNETA_RGMII_SERDES_PROTO          0x0667
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
 #define      MVNETA_GMAC_MAX_RX_SIZE_MASK        0x7ffc
 #define      MVNETA_GMAC0_PORT_ENABLE            BIT(0)
 #define MVNETA_GMAC_CTRL_2                       0x2c08
-#define      MVNETA_GMAC2_PSC_ENABLE             BIT(3)
+#define      MVNETA_GMAC2_PCS_ENABLE             BIT(3)
 #define      MVNETA_GMAC2_PORT_RGMII             BIT(4)
 #define      MVNETA_GMAC2_PORT_RESET             BIT(6)
 #define MVNETA_GMAC_STATUS                       0x2c10
@@ -710,35 +712,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
        mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
 }
 
-
-
-/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
-static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
-{
-       u32  val;
-
-       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-
-       if (enable)
-               val |= MVNETA_GMAC2_PORT_RGMII;
-       else
-               val &= ~MVNETA_GMAC2_PORT_RGMII;
-
-       mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-}
-
-/* Config SGMII port */
-static void mvneta_port_sgmii_config(struct mvneta_port *pp)
-{
-       u32 val;
-
-       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-       val |= MVNETA_GMAC2_PSC_ENABLE;
-       mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-
-       mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
-}
-
 /* Start the Ethernet port RX and TX activity */
 static void mvneta_port_up(struct mvneta_port *pp)
 {
@@ -2756,12 +2729,15 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
        mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
 
        if (phy_mode == PHY_INTERFACE_MODE_SGMII)
-               mvneta_port_sgmii_config(pp);
+               mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
+       else
+               mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO);
+
+       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 
-       mvneta_gmac_rgmii_set(pp, 1);
+       val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII;
 
        /* Cancel Port Reset */
-       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
        val &= ~MVNETA_GMAC2_PORT_RESET;
        mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 
@@ -2774,6 +2750,7 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
 static int mvneta_probe(struct platform_device *pdev)
 {
        const struct mbus_dram_target_info *dram_target_info;
+       struct resource *res;
        struct device_node *dn = pdev->dev.of_node;
        struct device_node *phy_node;
        u32 phy_addr;
@@ -2838,9 +2815,15 @@ static int mvneta_probe(struct platform_device *pdev)
 
        clk_prepare_enable(pp->clk);
 
-       pp->base = of_iomap(dn, 0);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err = -ENODEV;
+               goto err_clk;
+       }
+
+       pp->base = devm_ioremap_resource(&pdev->dev, res);
        if (pp->base == NULL) {
-               err = -ENOMEM;
+               err = PTR_ERR(pp->base);
                goto err_clk;
        }
 
@@ -2848,7 +2831,7 @@ static int mvneta_probe(struct platform_device *pdev)
        pp->stats = alloc_percpu(struct mvneta_pcpu_stats);
        if (!pp->stats) {
                err = -ENOMEM;
-               goto err_unmap;
+               goto err_clk;
        }
 
        for_each_possible_cpu(cpu) {
@@ -2913,8 +2896,6 @@ err_deinit:
        mvneta_deinit(pp);
 err_free_stats:
        free_percpu(pp->stats);
-err_unmap:
-       iounmap(pp->base);
 err_clk:
        clk_disable_unprepare(pp->clk);
 err_free_irq:
@@ -2934,7 +2915,6 @@ static int mvneta_remove(struct platform_device *pdev)
        mvneta_deinit(pp);
        clk_disable_unprepare(pp->clk);
        free_percpu(pp->stats);
-       iounmap(pp->base);
        irq_dispose_mapping(dev->irq);
        free_netdev(dev);
 
index fad45316200aa0fbcb115e3f6b4ec56a24ca29cd..84a96f70dfb51ea7cecf3c5f0e03daa90f52a880 100644 (file)
@@ -742,6 +742,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
                                err = mlx4_en_uc_steer_add(priv, new_mac,
                                                           &qpn,
                                                           &entry->reg_id);
+                               if (err)
+                                       return err;
+                               if (priv->tunnel_reg_id) {
+                                       mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id);
+                                       priv->tunnel_reg_id = 0;
+                               }
+                               err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn,
+                                                              &priv->tunnel_reg_id);
                                return err;
                        }
                }
@@ -1792,6 +1800,8 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
                mc_list[5] = priv->port;
                mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
                                      mc_list, MLX4_PROT_ETH, mclist->reg_id);
+               if (mclist->tunnel_reg_id)
+                       mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id);
        }
        mlx4_en_clear_list(dev);
        list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
index 91b69ff4b4a20f8f2bd2f6c9405cf6ab60af7f6a..7e2995ecea6f4b3e6d4a2fbadbdfb6876a73e5c8 100644 (file)
@@ -129,13 +129,14 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [0] = "RSS support",
                [1] = "RSS Toeplitz Hash Function support",
                [2] = "RSS XOR Hash Function support",
-               [3] = "Device manage flow steering support",
+               [3] = "Device managed flow steering support",
                [4] = "Automatic MAC reassignment support",
                [5] = "Time stamping support",
                [6] = "VST (control vlan insertion/stripping) support",
                [7] = "FSM (MAC anti-spoofing) support",
                [8] = "Dynamic QP updates support",
-               [9] = "TCP/IP offloads/flow-steering for VXLAN support"
+               [9] = "Device managed flow steering IPoIB support",
+               [10] = "TCP/IP offloads/flow-steering for VXLAN support"
        };
        int i;
 
@@ -859,7 +860,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
 
        /* For guests, disable vxlan tunneling */
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
        field &= 0xf7;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
 
@@ -869,7 +870,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
 
        /* For guests, disable mw type 2 */
-       MLX4_GET(bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+       MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
        bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
        MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
 
@@ -883,7 +884,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        }
 
        /* turn off ipoib managed steering for guests */
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
        field &= ~0x80;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
 
index d711158b0d4b1ab59bb3d1cf8973e8d4936ce853..d413e60071d47cd7e74d86652f5a0fb813cd5eb0 100644 (file)
@@ -150,6 +150,8 @@ struct mlx4_port_config {
        struct pci_dev *pdev;
 };
 
+static atomic_t pf_loading = ATOMIC_INIT(0);
+
 int mlx4_check_port_params(struct mlx4_dev *dev,
                           enum mlx4_port_type *port_type)
 {
@@ -749,7 +751,7 @@ static void mlx4_request_modules(struct mlx4_dev *dev)
                        has_eth_port = true;
        }
 
-       if (has_ib_port)
+       if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
                request_module_nowait(IB_DRV_NAME);
        if (has_eth_port)
                request_module_nowait(EN_DRV_NAME);
@@ -1407,6 +1409,11 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
        u32 slave_read;
        u32 cmd_channel_ver;
 
+       if (atomic_read(&pf_loading)) {
+               mlx4_warn(dev, "PF is not ready. Deferring probe\n");
+               return -EPROBE_DEFER;
+       }
+
        mutex_lock(&priv->cmd.slave_cmd_mutex);
        priv->cmd.max_cmds = 1;
        mlx4_warn(dev, "Sending reset\n");
@@ -2319,7 +2326,11 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
 
                if (num_vfs) {
                        mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", num_vfs);
+
+                       atomic_inc(&pf_loading);
                        err = pci_enable_sriov(pdev, num_vfs);
+                       atomic_dec(&pf_loading);
+
                        if (err) {
                                mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
                                         err);
@@ -2670,7 +2681,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
 
 static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
 {
-       int ret = __mlx4_init_one(pdev, 0);
+       const struct pci_device_id *id;
+       int ret;
+
+       id = pci_match_id(mlx4_pci_table, pdev);
+       ret = __mlx4_init_one(pdev, id->driver_data);
 
        return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
 }
@@ -2684,6 +2699,7 @@ static struct pci_driver mlx4_driver = {
        .name           = DRV_NAME,
        .id_table       = mlx4_pci_table,
        .probe          = mlx4_init_one,
+       .shutdown       = mlx4_remove_one,
        .remove         = mlx4_remove_one,
        .err_handler    = &mlx4_err_handler,
 };
index 6b65f77952153f5dd1ceab2d074e456b2a9567c4..7aec6c833973c3c84c13bc3d02ca34c5a6dfef4e 100644 (file)
@@ -51,8 +51,8 @@
 
 #define DRV_NAME       "mlx4_core"
 #define PFX            DRV_NAME ": "
-#define DRV_VERSION    "1.1"
-#define DRV_RELDATE    "Dec, 2011"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb, 2014"
 
 #define MLX4_FS_UDP_UC_EN              (1 << 1)
 #define MLX4_FS_TCP_UC_EN              (1 << 2)
index 9ca223bc90fc4fe7445a447828028b8a046f6fcb..b57e8c87a34ea8723ae9316747a69a32386429ea 100644 (file)
@@ -57,8 +57,8 @@
 #include "en_port.h"
 
 #define DRV_NAME       "mlx4_en"
-#define DRV_VERSION    "2.0"
-#define DRV_RELDATE    "Dec 2011"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb 2014"
 
 #define MLX4_EN_MSG_LEVEL      (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
 
index a064f06e0cb8a244d183c3c48acb1754349115dd..23b7e2d35a93bb0598ac76b71d75cfc3ea7afff8 100644 (file)
@@ -46,8 +46,8 @@
 #include "mlx5_core.h"
 
 #define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
index 727b546a9eb844c909dd8cd145aacfab014c9f99..e0c92e0e5e1d463f0242088d184394608b243cb6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/eeprom_93cx6.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/spi/spi.h>
 
@@ -83,6 +84,7 @@ union ks8851_tx_hdr {
  * @rc_rxqcr: Cached copy of KS_RXQCR.
  * @eeprom_size: Companion eeprom size in Bytes, 0 if no eeprom
  * @eeprom: 93CX6 EEPROM state for accessing on-board EEPROM.
+ * @vdd_reg:   Optional regulator supplying the chip
  *
  * The @lock ensures that the chip is protected when certain operations are
  * in progress. When the read or write packet transfer is in progress, most
@@ -130,6 +132,7 @@ struct ks8851_net {
        struct spi_transfer     spi_xfer2[2];
 
        struct eeprom_93cx6     eeprom;
+       struct regulator        *vdd_reg;
 };
 
 static int msg_enable;
@@ -1414,6 +1417,21 @@ static int ks8851_probe(struct spi_device *spi)
        ks->spidev = spi;
        ks->tx_space = 6144;
 
+       ks->vdd_reg = regulator_get_optional(&spi->dev, "vdd");
+       if (IS_ERR(ks->vdd_reg)) {
+               ret = PTR_ERR(ks->vdd_reg);
+               if (ret == -EPROBE_DEFER)
+                       goto err_reg;
+       } else {
+               ret = regulator_enable(ks->vdd_reg);
+               if (ret) {
+                       dev_err(&spi->dev, "regulator enable fail: %d\n",
+                               ret);
+                       goto err_reg_en;
+               }
+       }
+
+
        mutex_init(&ks->lock);
        spin_lock_init(&ks->statelock);
 
@@ -1508,8 +1526,14 @@ static int ks8851_probe(struct spi_device *spi)
 err_netdev:
        free_irq(ndev->irq, ks);
 
-err_id:
 err_irq:
+err_id:
+       if (!IS_ERR(ks->vdd_reg))
+               regulator_disable(ks->vdd_reg);
+err_reg_en:
+       if (!IS_ERR(ks->vdd_reg))
+               regulator_put(ks->vdd_reg);
+err_reg:
        free_netdev(ndev);
        return ret;
 }
@@ -1523,6 +1547,10 @@ static int ks8851_remove(struct spi_device *spi)
 
        unregister_netdev(priv->netdev);
        free_irq(spi->irq, priv);
+       if (!IS_ERR(priv->vdd_reg)) {
+               regulator_disable(priv->vdd_reg);
+               regulator_put(priv->vdd_reg);
+       }
        free_netdev(priv->netdev);
 
        return 0;
index 4146664d4d6a43978789081713b858b3f982de0e..27c4f131863bc30618ae5996411122f91685144b 100644 (file)
@@ -340,6 +340,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
                        if (qlcnic_sriov_vf_check(adapter))
                                return -EINVAL;
                        num_msix = 1;
+                       adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
                        adapter->drv_tx_rings = QLCNIC_SINGLE_RING;
                }
        }
index 77f1bce432d2998b3d14b5b6f56c694a877a1ae6..7d4f54912bad526077b145109dc003e532b88d70 100644 (file)
@@ -807,7 +807,7 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio,
            !type->tc_param_valid)
                return;
 
-       if (tc < 0 || (tc > QLC_DCB_MAX_TC))
+       if (tc < 0 || (tc >= QLC_DCB_MAX_TC))
                return;
 
        tc_cfg = &type->tc_cfg[tc];
@@ -843,7 +843,7 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
            !type->tc_param_valid)
                return;
 
-       if (pgid < 0 || pgid > QLC_DCB_MAX_PG)
+       if (pgid < 0 || pgid >= QLC_DCB_MAX_PG)
                return;
 
        pgcfg = &type->pg_cfg[pgid];
index ba78c7481fa3432f32fd7d5a5e7c56b66423b801..1222865cfb7319b4ec085c035c00c862cff6dcd2 100644 (file)
@@ -816,9 +816,10 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)
 
                if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
                        qlcnic_disable_multi_tx(adapter);
+                       adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
 
                        err = qlcnic_enable_msi_legacy(adapter);
-                       if (!err)
+                       if (err)
                                return err;
                }
        }
@@ -3863,7 +3864,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt,
                strcpy(buf, "Tx");
        }
 
-       if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+       if (!QLCNIC_IS_MSI_FAMILY(adapter)) {
                netdev_err(netdev, "No RSS/TSS support in INT-x mode\n");
                return -EINVAL;
        }
index 09acf15c3a564d1482a6e40960c6ef8dafa6f1cc..e5277a632671a1ca23877fb5ca46ab1397ca3cc2 100644 (file)
@@ -13,8 +13,6 @@
 #define QLC_VF_MIN_TX_RATE     100
 #define QLC_VF_MAX_TX_RATE     9999
 #define QLC_MAC_OPCODE_MASK    0x7
-#define QLC_MAC_STAR_ADD       6
-#define QLC_MAC_STAR_DEL       7
 #define QLC_VF_FLOOD_BIT       BIT_16
 #define QLC_FLOOD_MODE         0x5
 
@@ -1206,13 +1204,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
        struct qlcnic_vport *vp = vf->vp;
        u8 op, new_op;
 
-       if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) ||
-           ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) {
-               netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n",
-                          vf->pci_func);
-               return -EINVAL;
-       }
-
        if (!(cmd->req.arg[1] & BIT_8))
                return -EINVAL;
 
index ce2cfddbed504c1b960e32bc87691ff6965a1fce..656c65ddadb4af03ff032f8f2310ebb91a7f0189 100644 (file)
@@ -4765,7 +4765,9 @@ static int qlge_probe(struct pci_dev *pdev,
        ndev->features = ndev->hw_features;
        ndev->vlan_features = ndev->hw_features;
        /* vlan gets same features (except vlan filter) */
-       ndev->vlan_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+       ndev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER |
+                                NETIF_F_HW_VLAN_CTAG_TX |
+                                NETIF_F_HW_VLAN_CTAG_RX);
 
        if (test_bit(QL_DMA64, &qdev->flags))
                ndev->features |= NETIF_F_HIGHDMA;
index 91a67ae8f17b9bffc5bf86405a5788055b583ba0..3ff7bc3e7a23ba419c9957917a9471a939db54f2 100644 (file)
@@ -209,7 +209,7 @@ static const struct {
        [RTL_GIGA_MAC_VER_16] =
                _R("RTL8101e",          RTL_TD_0, NULL, JUMBO_1K, true),
        [RTL_GIGA_MAC_VER_17] =
-               _R("RTL8168b/8111b",    RTL_TD_1, NULL, JUMBO_4K, false),
+               _R("RTL8168b/8111b",    RTL_TD_0, NULL, JUMBO_4K, false),
        [RTL_GIGA_MAC_VER_18] =
                _R("RTL8168cp/8111cp",  RTL_TD_1, NULL, JUMBO_6K, false),
        [RTL_GIGA_MAC_VER_19] =
@@ -7118,6 +7118,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        mutex_init(&tp->wk.mutex);
+       u64_stats_init(&tp->rx_stats.syncp);
+       u64_stats_init(&tp->tx_stats.syncp);
 
        /* Get MAC address */
        for (i = 0; i < ETH_ALEN; i++)
index eb75fbd11a0115c73195f7d820ed051e3f720d71..d7a36829649a7eea1797057e0bb0e5773bc83c0e 100644 (file)
@@ -1668,6 +1668,13 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev)
        struct efx_ptp_data *ptp = efx->ptp_data;
        int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE);
 
+       if (!ptp) {
+               if (net_ratelimit())
+                       netif_warn(efx, drv, efx->net_dev,
+                                  "Received PTP event but PTP not set up\n");
+               return;
+       }
+
        if (!ptp->enabled)
                return;
 
index 72d282bf33a51e8e2cb0036cac6fd03fe19acdf0..c553f6b5a9131f0af16230f59ccd0557fe1116a5 100644 (file)
@@ -151,7 +151,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
                                          sizeof(struct dma_desc)));
 }
 
-const struct stmmac_chain_mode_ops chain_mode_ops = {
+const struct stmmac_mode_ops chain_mode_ops = {
        .init = stmmac_init_dma_chain,
        .is_jumbo_frm = stmmac_is_jumbo_frm,
        .jumbo_frm = stmmac_jumbo_frm,
index 7834a39939464a844fd4fd8bf8ecbc2f9f8847c0..74610f3aca9e5bc8670c49f4a25901c4b4575136 100644 (file)
@@ -419,20 +419,13 @@ struct mii_regs {
        unsigned int data;      /* MII Data */
 };
 
-struct stmmac_ring_mode_ops {
-       unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
-       unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
-       void (*refill_desc3) (void *priv, struct dma_desc *p);
-       void (*init_desc3) (struct dma_desc *p);
-       void (*clean_desc3) (void *priv, struct dma_desc *p);
-       int (*set_16kib_bfsize) (int mtu);
-};
-
-struct stmmac_chain_mode_ops {
+struct stmmac_mode_ops {
        void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
                      unsigned int extend_desc);
        unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
        unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+       int (*set_16kib_bfsize)(int mtu);
+       void (*init_desc3)(struct dma_desc *p);
        void (*refill_desc3) (void *priv, struct dma_desc *p);
        void (*clean_desc3) (void *priv, struct dma_desc *p);
 };
@@ -441,8 +434,7 @@ struct mac_device_info {
        const struct stmmac_ops *mac;
        const struct stmmac_desc_ops *desc;
        const struct stmmac_dma_ops *dma;
-       const struct stmmac_ring_mode_ops *ring;
-       const struct stmmac_chain_mode_ops *chain;
+       const struct stmmac_mode_ops *mode;
        const struct stmmac_hwtimestamp *ptp;
        struct mii_regs mii;    /* MII register Addresses */
        struct mac_link link;
@@ -460,7 +452,7 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
 void stmmac_set_mac(void __iomem *ioaddr, bool enable);
 
 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
-extern const struct stmmac_ring_mode_ops ring_mode_ops;
-extern const struct stmmac_chain_mode_ops chain_mode_ops;
+extern const struct stmmac_mode_ops ring_mode_ops;
+extern const struct stmmac_mode_ops chain_mode_ops;
 
 #endif /* __COMMON_H__ */
index a96c7c2f5f3f220b32df9c0ebad2b197e7ecd45a..650a4be6bce5243e046fcd226719e669f66444e8 100644 (file)
@@ -100,10 +100,9 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
 
-       if (unlikely(priv->plat->has_gmac))
-               /* Fill DES3 in case of RING mode */
-               if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
-                       p->des3 = p->des2 + BUF_SIZE_8KiB;
+       /* Fill DES3 in case of RING mode */
+       if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+               p->des3 = p->des2 + BUF_SIZE_8KiB;
 }
 
 /* In ring mode we need to fill the desc3 because it is used as buffer */
@@ -126,7 +125,7 @@ static int stmmac_set_16kib_bfsize(int mtu)
        return ret;
 }
 
-const struct stmmac_ring_mode_ops ring_mode_ops = {
+const struct stmmac_mode_ops ring_mode_ops = {
        .is_jumbo_frm = stmmac_is_jumbo_frm,
        .jumbo_frm = stmmac_jumbo_frm,
        .refill_desc3 = stmmac_refill_desc3,
index a2e7d2c96e3678c309377d3e4dbb416feb5fbc38..8543e1cfd55edb4a60f5cb543a1e5ea9fc18a097 100644 (file)
@@ -92,8 +92,8 @@ static int tc = TC_DEFAULT;
 module_param(tc, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(tc, "DMA threshold control value");
 
-#define DMA_BUFFER_SIZE        BUF_SIZE_4KiB
-static int buf_sz = DMA_BUFFER_SIZE;
+#define        DEFAULT_BUFSIZE 1536
+static int buf_sz = DEFAULT_BUFSIZE;
 module_param(buf_sz, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(buf_sz, "DMA buffer size");
 
@@ -136,8 +136,8 @@ static void stmmac_verify_args(void)
                dma_rxsize = DMA_RX_SIZE;
        if (unlikely(dma_txsize < 0))
                dma_txsize = DMA_TX_SIZE;
-       if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
-               buf_sz = DMA_BUFFER_SIZE;
+       if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB)))
+               buf_sz = DEFAULT_BUFSIZE;
        if (unlikely(flow_ctrl > 1))
                flow_ctrl = FLOW_AUTO;
        else if (likely(flow_ctrl < 0))
@@ -286,10 +286,25 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
        /* MAC core supports the EEE feature. */
        if (priv->dma_cap.eee) {
+               int tx_lpi_timer = priv->tx_lpi_timer;
+
                /* Check if the PHY supports EEE */
-               if (phy_init_eee(priv->phydev, 1))
+               if (phy_init_eee(priv->phydev, 1)) {
+                       /* To manage at run-time if the EEE cannot be supported
+                        * anymore (for example because the lp caps have been
+                        * changed).
+                        * In that case the driver disable own timers.
+                        */
+                       if (priv->eee_active) {
+                               pr_debug("stmmac: disable EEE\n");
+                               del_timer_sync(&priv->eee_ctrl_timer);
+                               priv->hw->mac->set_eee_timer(priv->ioaddr, 0,
+                                                            tx_lpi_timer);
+                       }
+                       priv->eee_active = 0;
                        goto out;
-
+               }
+               /* Activate the EEE and start timers */
                if (!priv->eee_active) {
                        priv->eee_active = 1;
                        init_timer(&priv->eee_ctrl_timer);
@@ -300,13 +315,13 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
                        priv->hw->mac->set_eee_timer(priv->ioaddr,
                                                     STMMAC_DEFAULT_LIT_LS,
-                                                    priv->tx_lpi_timer);
+                                                    tx_lpi_timer);
                } else
                        /* Set HW EEE according to the speed */
                        priv->hw->mac->set_eee_pls(priv->ioaddr,
                                                   priv->phydev->link);
 
-               pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
+               pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
 
                ret = true;
        }
@@ -886,10 +901,10 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
                ret = BUF_SIZE_8KiB;
        else if (mtu >= BUF_SIZE_2KiB)
                ret = BUF_SIZE_4KiB;
-       else if (mtu >= DMA_BUFFER_SIZE)
+       else if (mtu > DEFAULT_BUFSIZE)
                ret = BUF_SIZE_2KiB;
        else
-               ret = DMA_BUFFER_SIZE;
+               ret = DEFAULT_BUFSIZE;
 
        return ret;
 }
@@ -951,9 +966,9 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
 
        p->des2 = priv->rx_skbuff_dma[i];
 
-       if ((priv->mode == STMMAC_RING_MODE) &&
+       if ((priv->hw->mode->init_desc3) &&
            (priv->dma_buf_sz == BUF_SIZE_16KiB))
-               priv->hw->ring->init_desc3(p);
+               priv->hw->mode->init_desc3(p);
 
        return 0;
 }
@@ -984,11 +999,8 @@ static int init_dma_desc_rings(struct net_device *dev)
        unsigned int bfsize = 0;
        int ret = -ENOMEM;
 
-       /* Set the max buffer size according to the DESC mode
-        * and the MTU. Note that RING mode allows 16KiB bsize.
-        */
-       if (priv->mode == STMMAC_RING_MODE)
-               bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+       if (priv->hw->mode->set_16kib_bfsize)
+               bfsize = priv->hw->mode->set_16kib_bfsize(dev->mtu);
 
        if (bfsize < BUF_SIZE_16KiB)
                bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
@@ -1029,15 +1041,15 @@ static int init_dma_desc_rings(struct net_device *dev)
        /* Setup the chained descriptor addresses */
        if (priv->mode == STMMAC_CHAIN_MODE) {
                if (priv->extend_desc) {
-                       priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy,
-                                             rxsize, 1);
-                       priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy,
-                                             txsize, 1);
+                       priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy,
+                                            rxsize, 1);
+                       priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy,
+                                            txsize, 1);
                } else {
-                       priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy,
-                                             rxsize, 0);
-                       priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy,
-                                             txsize, 0);
+                       priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy,
+                                            rxsize, 0);
+                       priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy,
+                                            txsize, 0);
                }
        }
 
@@ -1288,7 +1300,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
                                         DMA_TO_DEVICE);
                        priv->tx_skbuff_dma[entry] = 0;
                }
-               priv->hw->ring->clean_desc3(priv, p);
+               priv->hw->mode->clean_desc3(priv, p);
 
                if (likely(skb != NULL)) {
                        dev_kfree_skb(skb);
@@ -1705,7 +1717,7 @@ static int stmmac_open(struct net_device *dev)
        priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
        priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
 
-       alloc_dma_desc_resources(priv);
+       ret = alloc_dma_desc_resources(priv);
        if (ret < 0) {
                pr_err("%s: DMA descriptors allocation failed\n", __func__);
                goto dma_desc_error;
@@ -1844,6 +1856,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        int nfrags = skb_shinfo(skb)->nr_frags;
        struct dma_desc *desc, *first;
        unsigned int nopaged_len = skb_headlen(skb);
+       unsigned int enh_desc = priv->plat->enh_desc;
 
        if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
                if (!netif_queue_stopped(dev)) {
@@ -1871,27 +1884,19 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        first = desc;
 
        /* To program the descriptors according to the size of the frame */
-       if (priv->mode == STMMAC_RING_MODE) {
-               is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
-                                                       priv->plat->enh_desc);
-               if (unlikely(is_jumbo))
-                       entry = priv->hw->ring->jumbo_frm(priv, skb,
-                                                         csum_insertion);
-       } else {
-               is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
-                                                        priv->plat->enh_desc);
-               if (unlikely(is_jumbo))
-                       entry = priv->hw->chain->jumbo_frm(priv, skb,
-                                                          csum_insertion);
-       }
+       if (enh_desc)
+               is_jumbo = priv->hw->mode->is_jumbo_frm(skb->len, enh_desc);
+
        if (likely(!is_jumbo)) {
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            nopaged_len, DMA_TO_DEVICE);
                priv->tx_skbuff_dma[entry] = desc->des2;
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
                                                csum_insertion, priv->mode);
-       } else
+       } else {
                desc = first;
+               entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
+       }
 
        for (i = 0; i < nfrags; i++) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2029,7 +2034,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 
                        p->des2 = priv->rx_skbuff_dma[entry];
 
-                       priv->hw->ring->refill_desc3(priv, p);
+                       priv->hw->mode->refill_desc3(priv, p);
 
                        if (netif_msg_rx_status(priv))
                                pr_debug("\trefill entry #%d\n", entry);
@@ -2633,11 +2638,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
 
        /* To use the chained or ring mode */
        if (chain_mode) {
-               priv->hw->chain = &chain_mode_ops;
+               priv->hw->mode = &chain_mode_ops;
                pr_info(" Chain mode enabled\n");
                priv->mode = STMMAC_CHAIN_MODE;
        } else {
-               priv->hw->ring = &ring_mode_ops;
+               priv->hw->mode = &ring_mode_ops;
                pr_info(" Ring mode enabled\n");
                priv->mode = STMMAC_RING_MODE;
        }
index c61bc72b8e9006a2f8cb654421a7aaed50730436..8fb32a80f1c1999a18234a2daec7323affd3917a 100644 (file)
@@ -36,7 +36,7 @@ static const struct of_device_id stmmac_dt_ids[] = {
 #ifdef CONFIG_DWMAC_STI
        { .compatible = "st,stih415-dwmac", .data = &sti_gmac_data},
        { .compatible = "st,stih416-dwmac", .data = &sti_gmac_data},
-       { .compatible = "st,stih127-dwmac", .data = &sti_gmac_data},
+       { .compatible = "st,stid127-dwmac", .data = &sti_gmac_data},
 #endif
        /* SoC specific glue layers should come before generic bindings */
        { .compatible = "st,spear600-gmac"},
index 651087b5c8da57c9f9226925ef33f61372986531..7d6d8ec676c892ebeb633b7f54fcd91cca1267c1 100644 (file)
@@ -1164,11 +1164,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 
 static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
 {
+       u32 slave_port;
+
+       slave_port = cpsw_get_slave_port(priv, slave->slave_num);
+
        if (!slave->phy)
                return;
        phy_stop(slave->phy);
        phy_disconnect(slave->phy);
        slave->phy = NULL;
+       cpsw_ale_control_set(priv->ale, slave_port,
+                            ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
@@ -2223,10 +2229,6 @@ static int cpsw_probe(struct platform_device *pdev)
                goto clean_ale_ret;
        }
 
-       if (cpts_register(&pdev->dev, priv->cpts,
-                         data->cpts_clock_mult, data->cpts_clock_shift))
-               dev_err(priv->dev, "error registering cpts device\n");
-
        cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n",
                    &ss_res->start, ndev->irq);
 
index 364d0c7952c023d0cc60de6cc8d73460b000fbd1..88ef27067bf24a8b2569f533b63ac223d52280fe 100644 (file)
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
        int i;
 
        spin_lock_irqsave(&ctlr->lock, flags);
-       if (ctlr->state != CPDMA_STATE_ACTIVE) {
+       if (ctlr->state == CPDMA_STATE_TEARDOWN) {
                spin_unlock_irqrestore(&ctlr->lock, flags);
                return -EINVAL;
        }
@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
        unsigned                timeout;
 
        spin_lock_irqsave(&chan->lock, flags);
-       if (chan->state != CPDMA_STATE_ACTIVE) {
+       if (chan->state == CPDMA_STATE_TEARDOWN) {
                spin_unlock_irqrestore(&chan->lock, flags);
                return -EINVAL;
        }
index cd9b164a0434acb3a51066b5d0e17262a4bdc0dd..8f0e69ce07ca3e03cfbf4cf1b22c92c9af27beeb 100644 (file)
@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)
        struct device *emac_dev = &ndev->dev;
        u32 cnt;
        struct resource *res;
-       int ret;
+       int q, m, ret;
+       int res_num = 0, irq_num = 0;
        int i = 0;
-       int k = 0;
        struct emac_priv *priv = netdev_priv(ndev);
 
        pm_runtime_get(&priv->pdev->dev);
@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
        }
 
        /* Request IRQ */
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ,
+                                           res_num))) {
+               for (irq_num = res->start; irq_num <= res->end; irq_num++) {
+                       dev_err(emac_dev, "Request IRQ %d\n", irq_num);
+                       if (request_irq(irq_num, emac_irq, 0, ndev->name,
+                                       ndev)) {
+                               dev_err(emac_dev,
+                                       "DaVinci EMAC: request_irq() failed\n");
+                               ret = -EBUSY;
 
-       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
-                                            0, ndev->name, ndev))
                                goto rollback;
+                       }
                }
-               k++;
+               res_num++;
        }
+       /* prepare counters for rollback in case of an error */
+       res_num--;
+       irq_num--;
 
        /* Start/Enable EMAC hardware */
        emac_hw_enable(priv);
@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
 
        return 0;
 
-rollback:
-
-       dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed");
-       ret = -EBUSY;
 err:
+       emac_int_disable(priv);
+       napi_disable(&priv->napi);
+
+rollback:
+       for (q = res_num; q >= 0; q--) {
+               res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q);
+               /* at the first iteration, irq_num is already set to the
+                * right value
+                */
+               if (q != res_num)
+                       irq_num = res->end;
+
+               for (m = irq_num; m >= res->start; m--)
+                       free_irq(m, ndev);
+       }
+       cpdma_ctlr_stop(priv->dma);
        pm_runtime_put(&priv->pdev->dev);
        return ret;
 }
@@ -1659,6 +1680,9 @@ err:
  */
 static int emac_dev_stop(struct net_device *ndev)
 {
+       struct resource *res;
+       int i = 0;
+       int irq_num;
        struct emac_priv *priv = netdev_priv(ndev);
        struct device *emac_dev = &ndev->dev;
 
@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev)
        if (priv->phydev)
                phy_disconnect(priv->phydev);
 
+       /* Free IRQ */
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) {
+               for (irq_num = res->start; irq_num <= res->end; irq_num++)
+                       free_irq(irq_num, priv->ndev);
+               i++;
+       }
+
        if (netif_msg_drv(priv))
                dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name);
 
index ef312bc6b8658deabae28d179c39237564b8ede4..6ac20a6738f4df5862b49aea71955a4a51ee4842 100644 (file)
@@ -923,7 +923,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc) {
                dev_err(&pdev->dev,
                        "32-bit PCI DMA addresses not supported by the card!?\n");
-               goto err_out;
+               goto err_out_pci_disable;
        }
 
        /* sanity check */
@@ -931,7 +931,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
            (pci_resource_len(pdev, 1) < io_size)) {
                rc = -EIO;
                dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
-               goto err_out;
+               goto err_out_pci_disable;
        }
 
        pioaddr = pci_resource_start(pdev, 0);
@@ -942,7 +942,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev = alloc_etherdev(sizeof(struct rhine_private));
        if (!dev) {
                rc = -ENOMEM;
-               goto err_out;
+               goto err_out_pci_disable;
        }
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -1084,6 +1084,8 @@ err_out_free_res:
        pci_release_regions(pdev);
 err_out_free_netdev:
        free_netdev(dev);
+err_out_pci_disable:
+       pci_disable_device(pdev);
 err_out:
        return rc;
 }
index 7141a1937360fabe59070e983c8737701307b48b..d6fce9750b9553b221759f18fd4ec48158af4e73 100644 (file)
@@ -442,6 +442,8 @@ static int netvsc_probe(struct hv_device *dev,
        if (!net)
                return -ENOMEM;
 
+       netif_carrier_off(net);
+
        net_device_ctx = netdev_priv(net);
        net_device_ctx->device_ctx = dev;
        hv_set_drvdata(dev, net);
@@ -473,6 +475,8 @@ static int netvsc_probe(struct hv_device *dev,
                pr_err("Unable to register netdev.\n");
                rndis_filter_device_remove(dev);
                free_netdev(net);
+       } else {
+               schedule_delayed_work(&net_device_ctx->dwork, 0);
        }
 
        return ret;
index 1084e5de3ceb4c805d2ef9e98b90c6d68a9a9991..b54fd257652bb629b8228162712bb557e9023943 100644 (file)
@@ -243,6 +243,22 @@ static int rndis_filter_send_request(struct rndis_device *dev,
        return ret;
 }
 
+static void rndis_set_link_state(struct rndis_device *rdev,
+                                struct rndis_request *request)
+{
+       u32 link_status;
+       struct rndis_query_complete *query_complete;
+
+       query_complete = &request->response_msg.msg.query_complete;
+
+       if (query_complete->status == RNDIS_STATUS_SUCCESS &&
+           query_complete->info_buflen == sizeof(u32)) {
+               memcpy(&link_status, (void *)((unsigned long)query_complete +
+                      query_complete->info_buf_offset), sizeof(u32));
+               rdev->link_state = link_status != 0;
+       }
+}
+
 static void rndis_filter_receive_response(struct rndis_device *dev,
                                       struct rndis_message *resp)
 {
@@ -272,6 +288,10 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
                    sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
                        memcpy(&request->response_msg, resp,
                               resp->msg_len);
+                       if (request->request_msg.ndis_msg_type ==
+                           RNDIS_MSG_QUERY && request->request_msg.msg.
+                           query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
+                               rndis_set_link_state(dev, request);
                } else {
                        netdev_err(ndev,
                                "rndis response buffer overflow "
@@ -620,7 +640,6 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
        ret = rndis_filter_query_device(dev,
                                      RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
                                      &link_status, &size);
-       dev->link_state = (link_status != 0) ? true : false;
 
        return ret;
 }
index ab31544bc25487ac82b1703beef9df6c069e615e..a30258aad139e9ae3491c92211a191f9aea42cc6 100644 (file)
@@ -546,12 +546,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        int rc;
        unsigned long flags;
 
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        if  (lp->irq_busy) {
-               spin_unlock(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                return -EBUSY;
        }
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        might_sleep();
 
@@ -725,10 +725,11 @@ static void at86rf230_irqwork_level(struct work_struct *work)
 static irqreturn_t at86rf230_isr(int irq, void *data)
 {
        struct at86rf230_local *lp = data;
+       unsigned long flags;
 
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        lp->irq_busy = 1;
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        schedule_work(&lp->irqwork);
 
index c14d39bf32d06a6f8d1b42a29b36dcd84b25c8f6..d7b2e947184b549a5034e4a54423ecde9050d721 100644 (file)
@@ -180,7 +180,8 @@ static void ifb_setup(struct net_device *dev)
        dev->tx_queue_len = TX_Q_LIMIT;
 
        dev->features |= IFB_FEATURES;
-       dev->vlan_features |= IFB_FEATURES;
+       dev->vlan_features |= IFB_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX |
+                                              NETIF_F_HW_VLAN_STAG_TX);
 
        dev->flags |= IFF_NOARP;
        dev->flags &= ~IFF_MULTICAST;
index a5d21893670d2692cf73da15113a2f116c3f0352..1831fb7cd0174d9afd6696bf029d37a657b07222 100644 (file)
@@ -506,6 +506,9 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
 static struct lock_class_key macvlan_netdev_xmit_lock_key;
 static struct lock_class_key macvlan_netdev_addr_lock_key;
 
+#define ALWAYS_ON_FEATURES \
+       (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX)
+
 #define MACVLAN_FEATURES \
        (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
@@ -539,7 +542,7 @@ static int macvlan_init(struct net_device *dev)
        dev->state              = (dev->state & ~MACVLAN_STATE_MASK) |
                                  (lowerdev->state & MACVLAN_STATE_MASK);
        dev->features           = lowerdev->features & MACVLAN_FEATURES;
-       dev->features           |= NETIF_F_LLTX;
+       dev->features           |= ALWAYS_ON_FEATURES;
        dev->gso_max_size       = lowerdev->gso_max_size;
        dev->iflink             = lowerdev->ifindex;
        dev->hard_header_len    = lowerdev->hard_header_len;
@@ -699,7 +702,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
        features = netdev_increment_features(vlan->lowerdev->features,
                                             features,
                                             mask);
-       features |= NETIF_F_LLTX;
+       features |= ALWAYS_ON_FEATURES;
 
        return features;
 }
index 19c9eca0ef2638165dc9dc087d87aee934d28348..76d96b9ebcdb94d2e57c3f52d5b49a41e7397ab4 100644 (file)
@@ -164,9 +164,9 @@ static const struct phy_setting settings[] = {
  *   of that setting.  Returns the index of the last setting if
  *   none of the others match.
  */
-static inline int phy_find_setting(int speed, int duplex)
+static inline unsigned int phy_find_setting(int speed, int duplex)
 {
-       int idx = 0;
+       unsigned int idx = 0;
 
        while (idx < ARRAY_SIZE(settings) &&
               (settings[idx].speed != speed || settings[idx].duplex != duplex))
@@ -185,7 +185,7 @@ static inline int phy_find_setting(int speed, int duplex)
  *   the mask in features.  Returns the index of the last setting
  *   if nothing else matches.
  */
-static inline int phy_find_valid(int idx, u32 features)
+static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
 {
        while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
                idx++;
@@ -204,7 +204,7 @@ static inline int phy_find_valid(int idx, u32 features)
 static void phy_sanitize_settings(struct phy_device *phydev)
 {
        u32 features = phydev->supported;
-       int idx;
+       unsigned int idx;
 
        /* Sanitize settings based on PHY capabilities */
        if ((features & SUPPORTED_Autoneg) == 0)
@@ -954,7 +954,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
            (phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
-               int idx, status;
+               int status;
+               unsigned int idx;
 
                /* Read phy status to properly get the right settings */
                status = phy_read_status(phydev);
index 82514e72b3d8b47538cc8c75a8e52f361d1361c8..2f6989b1e0dc801c9adea4d5e145a5dcf4d8ad26 100644 (file)
@@ -683,10 +683,9 @@ EXPORT_SYMBOL(phy_detach);
 int phy_suspend(struct phy_device *phydev)
 {
        struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
-       struct ethtool_wolinfo wol;
+       struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
 
        /* If the device has WOL enabled, we cannot suspend the PHY */
-       wol.cmd = ETHTOOL_GWOL;
        phy_ethtool_get_wol(phydev, &wol);
        if (wol.wolopts)
                return -EBUSY;
@@ -916,6 +915,8 @@ int genphy_read_status(struct phy_device *phydev)
        int err;
        int lpa;
        int lpagb = 0;
+       int common_adv;
+       int common_adv_gb = 0;
 
        /* Update the link, but return if there was an error */
        err = genphy_update_link(phydev);
@@ -937,7 +938,7 @@ int genphy_read_status(struct phy_device *phydev)
 
                        phydev->lp_advertising =
                                mii_stat1000_to_ethtool_lpa_t(lpagb);
-                       lpagb &= adv << 2;
+                       common_adv_gb = lpagb & adv << 2;
                }
 
                lpa = phy_read(phydev, MII_LPA);
@@ -950,25 +951,25 @@ int genphy_read_status(struct phy_device *phydev)
                if (adv < 0)
                        return adv;
 
-               lpa &= adv;
+               common_adv = lpa & adv;
 
                phydev->speed = SPEED_10;
                phydev->duplex = DUPLEX_HALF;
                phydev->pause = 0;
                phydev->asym_pause = 0;
 
-               if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+               if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
                        phydev->speed = SPEED_1000;
 
-                       if (lpagb & LPA_1000FULL)
+                       if (common_adv_gb & LPA_1000FULL)
                                phydev->duplex = DUPLEX_FULL;
-               } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+               } else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
                        phydev->speed = SPEED_100;
 
-                       if (lpa & LPA_100FULL)
+                       if (common_adv & LPA_100FULL)
                                phydev->duplex = DUPLEX_FULL;
                } else
-                       if (lpa & LPA_10FULL)
+                       if (common_adv & LPA_10FULL)
                                phydev->duplex = DUPLEX_FULL;
 
                if (phydev->duplex == DUPLEX_FULL) {
index 8fe9cb7d0f72e9fb7d34307f9a12797772844db1..26f8635b027d3fb44ab12223000badc214098df0 100644 (file)
@@ -1686,7 +1686,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                                   TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
                                   NETIF_F_HW_VLAN_STAG_TX;
                dev->features = dev->hw_features;
-               dev->vlan_features = dev->features;
+               dev->vlan_features = dev->features &
+                                    ~(NETIF_F_HW_VLAN_CTAG_TX |
+                                      NETIF_F_HW_VLAN_STAG_TX);
 
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false);
index 433f0a00c68324e46e60aa04b8e16989fac36701..e2797f1e1b31ee51f82c11d50b23e6bd274d29ab 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_USB_HSO)         += hso.o
 obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
 asix-y := asix_devices.o asix_common.o ax88172a.o
 obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)  += cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
 obj-$(CONFIG_USB_NET_SR9700)   += sr9700.o
index 955df81a43589bc30857b56db94f94886ce9cc30..054e59ca6946446389cd22eb1e851a6b4fad6633 100644 (file)
@@ -1029,20 +1029,12 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = 0x03;
        dev->mii.supports_gmii = 1;
 
-       if (usb_device_no_sg_constraint(dev->udev))
-               dev->can_dma_sg = 1;
-
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                              NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                                 NETIF_F_RXCSUM;
 
-       if (dev->can_dma_sg) {
-               dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
-               dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
-       }
-
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
@@ -1395,6 +1387,19 @@ static const struct driver_info ax88178a_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info dlink_dub1312_info = {
+       .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct driver_info sitecom_info = {
        .description = "Sitecom USB 3.0 to Gigabit Adapter",
        .bind = ax88179_bind,
@@ -1421,6 +1426,19 @@ static const struct driver_info samsung_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info lenovo_info = {
+       .description = "Lenovo OneLinkDock Gigabit LAN",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct usb_device_id products[] = {
 {
        /* ASIX AX88179 10/100/1000 */
@@ -1430,6 +1448,10 @@ static const struct usb_device_id products[] = {
        /* ASIX AX88178A 10/100/1000 */
        USB_DEVICE(0x0b95, 0x178a),
        .driver_info = (unsigned long)&ax88178a_info,
+}, {
+       /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
+       USB_DEVICE(0x2001, 0x4a00),
+       .driver_info = (unsigned long)&dlink_dub1312_info,
 }, {
        /* Sitecom USB 3.0 to Gigabit Adapter */
        USB_DEVICE(0x0df6, 0x0072),
@@ -1438,6 +1460,10 @@ static const struct usb_device_id products[] = {
        /* Samsung USB Ethernet Adapter */
        USB_DEVICE(0x04e8, 0xa100),
        .driver_info = (unsigned long)&samsung_info,
+}, {
+       /* Lenovo OneLinkDock Gigabit LAN */
+       USB_DEVICE(0x17ef, 0x304b),
+       .driver_info = (unsigned long)&lenovo_info,
 },
        { },
 };
index 42e176912c8ea151606883c0b8563e45fa95a447..bd363b27e8540e3bfe2acc6173adcc8a1952f4b7 100644 (file)
@@ -652,6 +652,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* Samsung USB Ethernet Adapters */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index dbff290ed0e4f5ac4752efbe56eeea0fda0c419f..d350d2795e1029cc71f197b2ca863586942d4d3f 100644 (file)
@@ -68,7 +68,6 @@ static struct usb_driver cdc_ncm_driver;
 static int cdc_ncm_setup(struct usbnet *dev)
 {
        struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-       struct usb_cdc_ncm_ntb_parameters ncm_parm;
        u32 val;
        u8 flags;
        u8 iface_no;
@@ -82,22 +81,22 @@ static int cdc_ncm_setup(struct usbnet *dev)
        err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
                              USB_TYPE_CLASS | USB_DIR_IN
                              |USB_RECIP_INTERFACE,
-                             0, iface_no, &ncm_parm,
-                             sizeof(ncm_parm));
+                             0, iface_no, &ctx->ncm_parm,
+                             sizeof(ctx->ncm_parm));
        if (err < 0) {
                dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
                return err; /* GET_NTB_PARAMETERS is required */
        }
 
        /* read correct set of parameters according to device mode */
-       ctx->rx_max = le32_to_cpu(ncm_parm.dwNtbInMaxSize);
-       ctx->tx_max = le32_to_cpu(ncm_parm.dwNtbOutMaxSize);
-       ctx->tx_remainder = le16_to_cpu(ncm_parm.wNdpOutPayloadRemainder);
-       ctx->tx_modulus = le16_to_cpu(ncm_parm.wNdpOutDivisor);
-       ctx->tx_ndp_modulus = le16_to_cpu(ncm_parm.wNdpOutAlignment);
+       ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+       ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+       ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+       ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+       ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
        /* devices prior to NCM Errata shall set this field to zero */
-       ctx->tx_max_datagrams = le16_to_cpu(ncm_parm.wNtbOutMaxDatagrams);
-       ntb_fmt_supported = le16_to_cpu(ncm_parm.bmNtbFormatsSupported);
+       ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
+       ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
 
        /* there are some minor differences in NCM and MBIM defaults */
        if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
@@ -146,7 +145,7 @@ static int cdc_ncm_setup(struct usbnet *dev)
        }
 
        /* inform device about NTB input size changes */
-       if (ctx->rx_max != le32_to_cpu(ncm_parm.dwNtbInMaxSize)) {
+       if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
                __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
 
                err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
@@ -162,14 +161,6 @@ static int cdc_ncm_setup(struct usbnet *dev)
                dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n",
                        CDC_NCM_NTB_MAX_SIZE_TX);
                ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
-
-               /* Adding a pad byte here simplifies the handling in
-                * cdc_ncm_fill_tx_frame, by making tx_max always
-                * represent the real skb max size.
-                */
-               if (ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
-                       ctx->tx_max++;
-
        }
 
        /*
@@ -439,6 +430,10 @@ advance:
                goto error2;
        }
 
+       /* initialize data interface */
+       if (cdc_ncm_setup(dev))
+               goto error2;
+
        /* configure data interface */
        temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
        if (temp) {
@@ -453,12 +448,6 @@ advance:
                goto error2;
        }
 
-       /* initialize data interface */
-       if (cdc_ncm_setup(dev)) {
-               dev_dbg(&intf->dev, "cdc_ncm_setup() failed\n");
-               goto error2;
-       }
-
        usb_set_intfdata(ctx->data, dev);
        usb_set_intfdata(ctx->control, dev);
 
@@ -475,6 +464,15 @@ advance:
        dev->hard_mtu = ctx->tx_max;
        dev->rx_urb_size = ctx->rx_max;
 
+       /* cdc_ncm_setup will override dwNtbOutMaxSize if it is
+        * outside the sane range. Adding a pad byte here if necessary
+        * simplifies the handling in cdc_ncm_fill_tx_frame, making
+        * tx_max always represent the real skb max size.
+        */
+       if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
+           ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
+               ctx->tx_max++;
+
        return 0;
 
 error2:
index d89dbe395ad2929441bec4a3d6cdf96b1ffe8686..adb12f349a61fc58582d2092c49db5a9ceb7b7cf 100644 (file)
@@ -449,9 +449,6 @@ enum rtl8152_flags {
 #define MCU_TYPE_PLA                   0x0100
 #define MCU_TYPE_USB                   0x0000
 
-#define REALTEK_USB_DEVICE(vend, prod) \
-       USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
-
 struct rx_desc {
        __le32 opts1;
 #define RX_LEN_MASK                    0x7fff
@@ -2739,6 +2736,12 @@ static int rtl8152_probe(struct usb_interface *intf,
        struct net_device *netdev;
        int ret;
 
+       if (udev->actconfig->desc.bConfigurationValue != 1) {
+               usb_driver_set_configuration(udev, 1);
+               return -ENODEV;
+       }
+
+       usb_reset_device(udev);
        netdev = alloc_etherdev(sizeof(struct r8152));
        if (!netdev) {
                dev_err(&intf->dev, "Out of memory\n");
@@ -2819,9 +2822,9 @@ static void rtl8152_disconnect(struct usb_interface *intf)
 
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8152_table[] = {
-       {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
-       {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
-       {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
+       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
+       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
+       {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
        {}
 };
 
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
deleted file mode 100644 (file)
index f0a8791..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/usb/usbnet.h>
-
-#define RTL815x_REQT_READ      0xc0
-#define RTL815x_REQT_WRITE     0x40
-#define RTL815x_REQ_GET_REGS   0x05
-#define RTL815x_REQ_SET_REGS   0x05
-
-#define MCU_TYPE_PLA           0x0100
-#define OCP_BASE               0xe86c
-#define BASE_MII               0xa400
-
-#define BYTE_EN_DWORD          0xff
-#define BYTE_EN_WORD           0x33
-#define BYTE_EN_BYTE           0x11
-
-#define R815x_PHY_ID           32
-#define REALTEK_VENDOR_ID      0x0bda
-
-
-static int pla_read_word(struct usb_device *udev, u16 index)
-{
-       int ret;
-       u8 shift = index & 2;
-       __le32 *tmp;
-
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       index &= ~3;
-
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret < 0)
-               goto out2;
-
-       ret = __le32_to_cpu(*tmp);
-       ret >>= (shift * 8);
-       ret &= 0xffff;
-
-out2:
-       kfree(tmp);
-       return ret;
-}
-
-static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
-{
-       __le32 *tmp;
-       u32 mask = 0xffff;
-       u16 byen = BYTE_EN_WORD;
-       u8 shift = index & 2;
-       int ret;
-
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       data &= mask;
-
-       if (shift) {
-               byen <<= shift;
-               mask <<= (shift * 8);
-               data <<= (shift * 8);
-               index &= ~3;
-       }
-
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret < 0)
-               goto out3;
-
-       data |= __le32_to_cpu(*tmp) & ~mask;
-       *tmp = __cpu_to_le32(data);
-
-       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-                             index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
-                             500);
-
-out3:
-       kfree(tmp);
-       return ret;
-}
-
-static int ocp_reg_read(struct usbnet *dev, u16 addr)
-{
-       u16 ocp_base, ocp_index;
-       int ret;
-
-       ocp_base = addr & 0xf000;
-       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
-       if (ret < 0)
-               goto out;
-
-       ocp_index = (addr & 0x0fff) | 0xb000;
-       ret = pla_read_word(dev->udev, ocp_index);
-
-out:
-       return ret;
-}
-
-static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
-{
-       u16 ocp_base, ocp_index;
-       int ret;
-
-       ocp_base = addr & 0xf000;
-       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
-       if (ret < 0)
-               goto out1;
-
-       ocp_index = (addr & 0x0fff) | 0xb000;
-       ret = pla_write_word(dev->udev, ocp_index, data);
-
-out1:
-       return ret;
-}
-
-static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
-{
-       struct usbnet *dev = netdev_priv(netdev);
-       int ret;
-
-       if (phy_id != R815x_PHY_ID)
-               return -EINVAL;
-
-       if (usb_autopm_get_interface(dev->intf) < 0)
-               return -ENODEV;
-
-       ret = ocp_reg_read(dev, BASE_MII + reg * 2);
-
-       usb_autopm_put_interface(dev->intf);
-       return ret;
-}
-
-static
-void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
-{
-       struct usbnet *dev = netdev_priv(netdev);
-
-       if (phy_id != R815x_PHY_ID)
-               return;
-
-       if (usb_autopm_get_interface(dev->intf) < 0)
-               return;
-
-       ocp_reg_write(dev, BASE_MII + reg * 2, val);
-
-       usb_autopm_put_interface(dev->intf);
-}
-
-static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-       int status;
-
-       status = usbnet_cdc_bind(dev, intf);
-       if (status < 0)
-               return status;
-
-       dev->mii.dev = dev->net;
-       dev->mii.mdio_read = r815x_mdio_read;
-       dev->mii.mdio_write = r815x_mdio_write;
-       dev->mii.phy_id_mask = 0x3f;
-       dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = R815x_PHY_ID;
-       dev->mii.supports_gmii = 1;
-
-       return status;
-}
-
-static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-       int status;
-
-       status = usbnet_cdc_bind(dev, intf);
-       if (status < 0)
-               return status;
-
-       dev->mii.dev = dev->net;
-       dev->mii.mdio_read = r815x_mdio_read;
-       dev->mii.mdio_write = r815x_mdio_write;
-       dev->mii.phy_id_mask = 0x3f;
-       dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = R815x_PHY_ID;
-       dev->mii.supports_gmii = 0;
-
-       return status;
-}
-
-static const struct driver_info r8152_info = {
-       .description =  "RTL8152 ECM Device",
-       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       .bind =         r8152_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
-       .manage_power = usbnet_manage_power,
-};
-
-static const struct driver_info r8153_info = {
-       .description =  "RTL8153 ECM Device",
-       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       .bind =         r8153_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
-       .manage_power = usbnet_manage_power,
-};
-
-static const struct usb_device_id products[] = {
-{
-       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &r8152_info,
-},
-
-{
-       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &r8153_info,
-},
-
-       { },            /* END */
-};
-MODULE_DEVICE_TABLE(usb, products);
-
-static struct usb_driver r815x_driver = {
-       .name =         "r815x",
-       .id_table =     products,
-       .probe =        usbnet_probe,
-       .disconnect =   usbnet_disconnect,
-       .suspend =      usbnet_suspend,
-       .resume =       usbnet_resume,
-       .reset_resume = usbnet_resume,
-       .supports_autosuspend = 1,
-       .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(r815x_driver);
-
-MODULE_AUTHOR("Hayes Wang");
-MODULE_DESCRIPTION("Realtek USB ECM device");
-MODULE_LICENSE("GPL");
index dd10d5817d2a975b414dc40bf0f4937b46c263be..f9e96c4275589ebc63b3d87432fe50471c287872 100644 (file)
@@ -752,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
 // precondition: never called in_interrupt
 static void usbnet_terminate_urbs(struct usbnet *dev)
 {
-       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
        DECLARE_WAITQUEUE(wait, current);
        int temp;
 
        /* ensure there are no more active urbs */
-       add_wait_queue(&unlink_wakeup, &wait);
+       add_wait_queue(&dev->wait, &wait);
        set_current_state(TASK_UNINTERRUPTIBLE);
-       dev->wait = &unlink_wakeup;
        temp = unlink_urbs(dev, &dev->txq) +
                unlink_urbs(dev, &dev->rxq);
 
@@ -773,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
                                  "waited for %d urb completions\n", temp);
        }
        set_current_state(TASK_RUNNING);
-       dev->wait = NULL;
-       remove_wait_queue(&unlink_wakeup, &wait);
+       remove_wait_queue(&dev->wait, &wait);
 }
 
 int usbnet_stop (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
        struct driver_info      *info = dev->driver_info;
-       int                     retval;
+       int                     retval, pm;
 
        clear_bit(EVENT_DEV_OPEN, &dev->flags);
        netif_stop_queue (net);
@@ -791,6 +788,8 @@ int usbnet_stop (struct net_device *net)
                   net->stats.rx_packets, net->stats.tx_packets,
                   net->stats.rx_errors, net->stats.tx_errors);
 
+       /* to not race resume */
+       pm = usb_autopm_get_interface(dev->intf);
        /* allow minidriver to stop correctly (wireless devices to turn off
         * radio etc) */
        if (info->stop) {
@@ -817,6 +816,9 @@ int usbnet_stop (struct net_device *net)
        dev->flags = 0;
        del_timer_sync (&dev->delay);
        tasklet_kill (&dev->bh);
+       if (!pm)
+               usb_autopm_put_interface(dev->intf);
+
        if (info->manage_power &&
            !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
                info->manage_power(dev, 0);
@@ -1437,11 +1439,12 @@ static void usbnet_bh (unsigned long param)
        /* restart RX again after disabling due to high error rate */
        clear_bit(EVENT_RX_KILL, &dev->flags);
 
-       // waiting for all pending urbs to complete?
-       if (dev->wait) {
-               if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
-                       wake_up (dev->wait);
-               }
+       /* waiting for all pending urbs to complete?
+        * only then can we forgo submitting anew
+        */
+       if (waitqueue_active(&dev->wait)) {
+               if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
+                       wake_up_all(&dev->wait);
 
        // or are we maybe short a few urbs?
        } else if (netif_running (dev->net) &&
@@ -1580,6 +1583,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        dev->driver_name = name;
        dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
                                | NETIF_MSG_PROBE | NETIF_MSG_LINK);
+       init_waitqueue_head(&dev->wait);
        skb_queue_head_init (&dev->rxq);
        skb_queue_head_init (&dev->txq);
        skb_queue_head_init (&dev->done);
@@ -1791,9 +1795,10 @@ int usbnet_resume (struct usb_interface *intf)
                spin_unlock_irq(&dev->txq.lock);
 
                if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
-                       /* handle remote wakeup ASAP */
-                       if (!dev->wait &&
-                               netif_device_present(dev->net) &&
+                       /* handle remote wakeup ASAP
+                        * we cannot race against stop
+                        */
+                       if (netif_device_present(dev->net) &&
                                !timer_pending(&dev->delay) &&
                                !test_bit(EVENT_RX_HALT, &dev->flags))
                                        rx_alloc_submit(dev, GFP_NOIO);
index 2ec2041b62d4eb215bf23f74ad82ba44332b8d3d..c0e7c64765abd449070a7bce6826a994c674b8c7 100644 (file)
@@ -285,7 +285,11 @@ static void veth_setup(struct net_device *dev)
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->features |= VETH_FEATURES;
-       dev->vlan_features = dev->features;
+       dev->vlan_features = dev->features &
+                            ~(NETIF_F_HW_VLAN_CTAG_TX |
+                              NETIF_F_HW_VLAN_STAG_TX |
+                              NETIF_F_HW_VLAN_CTAG_RX |
+                              NETIF_F_HW_VLAN_STAG_RX);
        dev->destructor = veth_dev_free;
 
        dev->hw_features = VETH_FEATURES;
index d75f8edf4fb370300d13bd22adcfe66e754fb5a2..841b60831df1b2e83c12f55ee5e8fc90874b9475 100644 (file)
@@ -671,8 +671,7 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
                if (err)
                        break;
        } while (rq->vq->num_free);
-       if (unlikely(!virtqueue_kick(rq->vq)))
-               return false;
+       virtqueue_kick(rq->vq);
        return !oom;
 }
 
@@ -877,7 +876,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
        err = xmit_skb(sq, skb);
 
        /* This should not happen! */
-       if (unlikely(err) || unlikely(!virtqueue_kick(sq->vq))) {
+       if (unlikely(err)) {
                dev->stats.tx_fifo_errors++;
                if (net_ratelimit())
                        dev_warn(&dev->dev,
@@ -886,6 +885,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                kfree_skb(skb);
                return NETDEV_TX_OK;
        }
+       virtqueue_kick(sq->vq);
 
        /* Don't wait up for transmitted skbs to be freed. */
        skb_orphan(skb);
@@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        /* If we can receive ANY GSO packets, we must allocate large ones. */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
            virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
-           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
                vi->big_packets = true;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
index 3be786faaaec222f0226b8285dde01e88b147e59..0fa3b44f7342dc0cf979cf69b6b1d6c3444411f3 100644 (file)
@@ -1762,11 +1762,20 @@ vmxnet3_netpoll(struct net_device *netdev)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 
-       if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
-               vmxnet3_disable_all_intrs(adapter);
-
-       vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
-       vmxnet3_enable_all_intrs(adapter);
+       switch (adapter->intr.type) {
+#ifdef CONFIG_PCI_MSI
+       case VMXNET3_IT_MSIX: {
+               int i;
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       vmxnet3_msix_rx(0, &adapter->rx_queue[i]);
+               break;
+       }
+#endif
+       case VMXNET3_IT_MSI:
+       default:
+               vmxnet3_intr(0, adapter->netdev);
+               break;
+       }
 
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
index b0f705c2378f9ac683c526e7f12440eab7b40293..1236812c7be69975487e7956c24d39718997ec2b 100644 (file)
@@ -1318,6 +1318,9 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
 
                neigh_release(n);
 
+               if (reply == NULL)
+                       goto out;
+
                skb_reset_mac_header(reply);
                __skb_pull(reply, skb_network_offset(reply));
                reply->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1339,15 +1342,103 @@ out:
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
+
+static struct sk_buff *vxlan_na_create(struct sk_buff *request,
+       struct neighbour *n, bool isrouter)
+{
+       struct net_device *dev = request->dev;
+       struct sk_buff *reply;
+       struct nd_msg *ns, *na;
+       struct ipv6hdr *pip6;
+       u8 *daddr;
+       int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+       int ns_olen;
+       int i, len;
+
+       if (dev == NULL)
+               return NULL;
+
+       len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+               sizeof(*na) + na_olen + dev->needed_tailroom;
+       reply = alloc_skb(len, GFP_ATOMIC);
+       if (reply == NULL)
+               return NULL;
+
+       reply->protocol = htons(ETH_P_IPV6);
+       reply->dev = dev;
+       skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
+       skb_push(reply, sizeof(struct ethhdr));
+       skb_set_mac_header(reply, 0);
+
+       ns = (struct nd_msg *)skb_transport_header(request);
+
+       daddr = eth_hdr(request)->h_source;
+       ns_olen = request->len - skb_transport_offset(request) - sizeof(*ns);
+       for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
+               if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
+                       daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+                       break;
+               }
+       }
+
+       /* Ethernet header */
+       ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
+       ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
+       eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
+       reply->protocol = htons(ETH_P_IPV6);
+
+       skb_pull(reply, sizeof(struct ethhdr));
+       skb_set_network_header(reply, 0);
+       skb_put(reply, sizeof(struct ipv6hdr));
+
+       /* IPv6 header */
+
+       pip6 = ipv6_hdr(reply);
+       memset(pip6, 0, sizeof(struct ipv6hdr));
+       pip6->version = 6;
+       pip6->priority = ipv6_hdr(request)->priority;
+       pip6->nexthdr = IPPROTO_ICMPV6;
+       pip6->hop_limit = 255;
+       pip6->daddr = ipv6_hdr(request)->saddr;
+       pip6->saddr = *(struct in6_addr *)n->primary_key;
+
+       skb_pull(reply, sizeof(struct ipv6hdr));
+       skb_set_transport_header(reply, 0);
+
+       na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen);
+
+       /* Neighbor Advertisement */
+       memset(na, 0, sizeof(*na)+na_olen);
+       na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+       na->icmph.icmp6_router = isrouter;
+       na->icmph.icmp6_override = 1;
+       na->icmph.icmp6_solicited = 1;
+       na->target = ns->target;
+       ether_addr_copy(&na->opt[2], n->ha);
+       na->opt[0] = ND_OPT_TARGET_LL_ADDR;
+       na->opt[1] = na_olen >> 3;
+
+       na->icmph.icmp6_cksum = csum_ipv6_magic(&pip6->saddr,
+               &pip6->daddr, sizeof(*na)+na_olen, IPPROTO_ICMPV6,
+               csum_partial(na, sizeof(*na)+na_olen, 0));
+
+       pip6->payload_len = htons(sizeof(*na)+na_olen);
+
+       skb_push(reply, sizeof(struct ipv6hdr));
+
+       reply->ip_summed = CHECKSUM_UNNECESSARY;
+
+       return reply;
+}
+
 static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
-       struct neighbour *n;
-       union vxlan_addr ipa;
+       struct nd_msg *msg;
        const struct ipv6hdr *iphdr;
        const struct in6_addr *saddr, *daddr;
-       struct nd_msg *msg;
-       struct inet6_dev *in6_dev = NULL;
+       struct neighbour *n;
+       struct inet6_dev *in6_dev;
 
        in6_dev = __in6_dev_get(dev);
        if (!in6_dev)
@@ -1360,19 +1451,20 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
        saddr = &iphdr->saddr;
        daddr = &iphdr->daddr;
 
-       if (ipv6_addr_loopback(daddr) ||
-           ipv6_addr_is_multicast(daddr))
-               goto out;
-
        msg = (struct nd_msg *)skb_transport_header(skb);
        if (msg->icmph.icmp6_code != 0 ||
            msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
                goto out;
 
-       n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev);
+       if (ipv6_addr_loopback(daddr) ||
+           ipv6_addr_is_multicast(&msg->target))
+               goto out;
+
+       n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, dev);
 
        if (n) {
                struct vxlan_fdb *f;
+               struct sk_buff *reply;
 
                if (!(n->nud_state & NUD_CONNECTED)) {
                        neigh_release(n);
@@ -1386,13 +1478,23 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
                        goto out;
                }
 
-               ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target,
-                                        !!in6_dev->cnf.forwarding,
-                                        true, false, false);
+               reply = vxlan_na_create(skb, n,
+                                       !!(f ? f->flags & NTF_ROUTER : 0));
+
                neigh_release(n);
+
+               if (reply == NULL)
+                       goto out;
+
+               if (netif_rx_ni(reply) == NET_RX_DROP)
+                       dev->stats.rx_dropped++;
+
        } else if (vxlan->flags & VXLAN_F_L3MISS) {
-               ipa.sin6.sin6_addr = *daddr;
-               ipa.sa.sa_family = AF_INET6;
+               union vxlan_addr ipa = {
+                       .sin6.sin6_addr = msg->target,
+                       .sa.sa_family = AF_INET6,
+               };
+
                vxlan_ip_miss(dev, &ipa);
        }
 
index 1cc13569b17b8ed7126a9aae49a2d519c360337b..1b6b4d0cfa97a5df8c2a7e0d631c417377ba17b2 100644 (file)
@@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
        {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
        {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
        {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
@@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
        {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-       {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+       {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},
        {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
 };
 
index 11eab9f01fd89ac9bb8f9b665646051a6386ac0a..9078a6c5a74e3b340266836f7c0151b242ccbc1e 100644 (file)
@@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
 bool ath9k_hw_check_alive(struct ath_hw *ah)
 {
        int count = 50;
-       u32 reg;
+       u32 reg, last_val;
 
        if (AR_SREV_9300(ah))
                return !ath9k_hw_detect_mac_hang(ah);
@@ -1542,9 +1542,14 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
        if (AR_SREV_9285_12_OR_LATER(ah))
                return true;
 
+       last_val = REG_READ(ah, AR_OBS_BUS_1);
        do {
                reg = REG_READ(ah, AR_OBS_BUS_1);
+               if (reg != last_val)
+                       return true;
 
+               udelay(1);
+               last_val = reg;
                if ((reg & 0x7E7FFFEF) == 0x00702400)
                        continue;
 
index a0ebdd000fc20f83dac90401ba017dd1ebf3b570..82e340d3ec60a81cc83d2427bd9280e55ca3af3a 100644 (file)
@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
                        return NULL;
 
                /*
-                * mark descriptor as zero-length and set the 'more'
-                * flag to ensure that both buffers get discarded
+                * Re-check previous descriptor, in case it has been filled
+                * in the mean time.
                 */
-               rs->rs_datalen = 0;
-               rs->rs_more = true;
+               ret = ath9k_hw_rxprocdesc(ah, ds, rs);
+               if (ret == -EINPROGRESS) {
+                       /*
+                        * mark descriptor as zero-length and set the 'more'
+                        * flag to ensure that both buffers get discarded
+                        */
+                       rs->rs_datalen = 0;
+                       rs->rs_more = true;
+               }
        }
 
        list_del(&bf->list);
@@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_hdr *hdr;
        bool discard_current = sc->rx.discard_next;
-       int ret = 0;
 
        /*
         * Discard corrupt descriptors which are marked in
         * ath_get_next_rx_buf().
         */
-       sc->rx.discard_next = rx_stats->rs_more;
        if (discard_current)
-               return -EINVAL;
+               goto corrupt;
+
+       sc->rx.discard_next = false;
 
        /*
         * Discard zero-length packets.
         */
        if (!rx_stats->rs_datalen) {
                RX_STAT_INC(rx_len_err);
-               return -EINVAL;
+               goto corrupt;
        }
 
-        /*
-         * rs_status follows rs_datalen so if rs_datalen is too large
-         * we can take a hint that hardware corrupted it, so ignore
-         * those frames.
-         */
+       /*
+        * rs_status follows rs_datalen so if rs_datalen is too large
+        * we can take a hint that hardware corrupted it, so ignore
+        * those frames.
+        */
        if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
                RX_STAT_INC(rx_len_err);
-               return -EINVAL;
+               goto corrupt;
        }
 
        /* Only use status info from the last fragment */
@@ -1024,10 +1031,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
         * This is different from the other corrupt descriptor
         * condition handled above.
         */
-       if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
-               ret = -EINVAL;
-               goto exit;
-       }
+       if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
+               goto corrupt;
 
        hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
 
@@ -1043,18 +1048,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
                if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
                        RX_STAT_INC(rx_spectral);
 
-               ret = -EINVAL;
-               goto exit;
+               return -EINVAL;
        }
 
        /*
         * everything but the rate is checked here, the rate check is done
         * separately to avoid doing two lookups for a rate for each frame.
         */
-       if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
-               ret = -EINVAL;
-               goto exit;
-       }
+       if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+               return -EINVAL;
 
        if (ath_is_mybeacon(common, hdr)) {
                RX_STAT_INC(rx_beacons);
@@ -1064,15 +1066,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        /*
         * This shouldn't happen, but have a safety check anyway.
         */
-       if (WARN_ON(!ah->curchan)) {
-               ret = -EINVAL;
-               goto exit;
-       }
+       if (WARN_ON(!ah->curchan))
+               return -EINVAL;
 
-       if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
-               ret =-EINVAL;
-               goto exit;
-       }
+       if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+               return -EINVAL;
 
        ath9k_process_rssi(common, hw, rx_stats, rx_status);
 
@@ -1087,9 +1085,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
                sc->rx.num_pkts++;
 #endif
 
-exit:
-       sc->rx.discard_next = false;
-       return ret;
+       return 0;
+
+corrupt:
+       sc->rx.discard_next = rx_stats->rs_more;
+       return -EINVAL;
 }
 
 static void ath9k_rx_skb_postprocess(struct ath_common *common,
index 0a75e2f68c9dc30043e32653d78f67799ab8b771..55897d508a76c7220d041f22c077cef2e435fff4 100644 (file)
@@ -1444,14 +1444,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
        for (tidno = 0, tid = &an->tid[tidno];
             tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
 
-               if (!tid->sched)
-                       continue;
-
                ac = tid->ac;
                txq = ac->txq;
 
                ath_txq_lock(sc, txq);
 
+               if (!tid->sched) {
+                       ath_txq_unlock(sc, txq);
+                       continue;
+               }
+
                buffered = ath_tid_has_buffered(tid);
 
                tid->sched = false;
@@ -2061,7 +2063,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
 
        ATH_TXBUF_RESET(bf);
 
-       if (tid) {
+       if (tid && ieee80211_is_data_present(hdr->frame_control)) {
                fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
                seqno = tid->seq_next;
                hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
@@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                txq->stopped = true;
        }
 
+       if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
+               tid = ath_get_skb_tid(sc, txctl->an, skb);
+
        if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
                ath_txq_unlock(sc, txq);
                txq = sc->tx.uapsdq;
                ath_txq_lock(sc, txq);
        } else if (txctl->an &&
                   ieee80211_is_data_present(hdr->frame_control)) {
-               tid = ath_get_skb_tid(sc, txctl->an, skb);
-
                WARN_ON(tid->ac->txq != txctl->txq);
 
                if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
index 3e991897d7ca4dfe856d06f4027fc0dec5c726f1..ddaa9efd053df3a61e404ca96c60cd82dad3f0f2 100644 (file)
@@ -457,7 +457,6 @@ struct brcmf_sdio {
 
        u8 tx_hdrlen;           /* sdio bus header length for tx packet */
        bool txglom;            /* host tx glomming enable flag */
-       struct sk_buff *txglom_sgpad;   /* scatter-gather padding buffer */
        u16 head_align;         /* buffer pointer alignment */
        u16 sgentry_align;      /* scatter-gather buffer alignment */
 };
@@ -1944,19 +1943,21 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
        if (lastfrm && chain_pad)
                tail_pad += blksize - chain_pad;
        if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
-               pkt_pad = bus->txglom_sgpad;
-               if (pkt_pad == NULL)
-                         brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
+               pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
+                                               bus->head_align);
                if (pkt_pad == NULL)
                        return -ENOMEM;
                ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
-               if (unlikely(ret < 0))
+               if (unlikely(ret < 0)) {
+                       kfree_skb(pkt_pad);
                        return ret;
+               }
                memcpy(pkt_pad->data,
                       pkt->data + pkt->len - tail_chop,
                       tail_chop);
                *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
                skb_trim(pkt, pkt->len - tail_chop);
+               skb_trim(pkt_pad, tail_pad + tail_chop);
                __skb_queue_after(pktq, pkt, pkt_pad);
        } else {
                ntail = pkt->data_len + tail_pad -
@@ -2011,7 +2012,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                        return ret;
                head_pad = (u16)ret;
                if (head_pad)
-                       memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen);
+                       memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
 
                total_len += pkt_next->len;
 
@@ -3486,10 +3487,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
                bus->txglom = false;
                value = 1;
                pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
-               bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
-               if (!bus->txglom_sgpad)
-                       brcmf_err("allocating txglom padding skb failed, reduced performance\n");
-
                err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
                                           &value, sizeof(u32));
                if (err < 0) {
@@ -4053,7 +4050,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
                        brcmf_sdio_chip_detach(&bus->ci);
                }
 
-               brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
                kfree(bus->rxbuf);
                kfree(bus->hdrbuf);
                kfree(bus);
index d36e252d2ccbc0041a5b0c1669fe396c2c18db73..596525528f50504afe3005d98ac0ab47d3e26453 100644 (file)
@@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
 
        if (!sta->ap && sta->u.sta.challenge)
                kfree(sta->u.sta.challenge);
-       del_timer(&sta->timer);
+       del_timer_sync(&sta->timer);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 
        kfree(sta);
index c0d070c5df5ed73e14a64e141d6a7d2f2a3133b6..9cdd91cdf661825604e9ae8c89649213667b0b0e 100644 (file)
@@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
                        sizeof(priv->tid_data[sta_id][tid]));
 
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+       priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
 
        priv->num_stations--;
 
index a6839dfcb82dd75029c1e377bbebb078464a8792..398dd096674cf17bd8112e8e7d06ad4ce57427f0 100644 (file)
@@ -1291,8 +1291,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
        struct iwl_ht_agg *agg;
        struct sk_buff_head reclaimed_skbs;
-       struct ieee80211_tx_info *info;
-       struct ieee80211_hdr *hdr;
        struct sk_buff *skb;
        int sta_id;
        int tid;
@@ -1379,22 +1377,28 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        freed = 0;
 
        skb_queue_walk(&reclaimed_skbs, skb) {
-               hdr = (struct ieee80211_hdr *)skb->data;
+               struct ieee80211_hdr *hdr = (void *)skb->data;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
                if (ieee80211_is_data_qos(hdr->frame_control))
                        freed++;
                else
                        WARN_ON_ONCE(1);
 
-               info = IEEE80211_SKB_CB(skb);
                iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
 
+               memset(&info->status, 0, sizeof(info->status));
+               /* Packet was transmitted successfully, failures come as single
+                * frames because before failing a frame the firmware transmits
+                * it without aggregation at least once.
+                */
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
                if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
                        /* put the rate scaling data there */
                        info = IEEE80211_SKB_CB(skb);
                        memset(&info->status, 0, sizeof(info->status));
-                       info->flags |= IEEE80211_TX_STAT_ACK;
                        info->flags |= IEEE80211_TX_STAT_AMPDU;
                        info->status.ampdu_ack_len = ba_resp->txed_2_done;
                        info->status.ampdu_len = ba_resp->txed;
index 76cde6ce6551dc0a9996a91edc36cad5b40e5588..18a895a949d4520a02af0f34232f6a739a4c4552 100644 (file)
@@ -872,8 +872,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        lockdep_assert_held(&mvm->mutex);
 
-       /* Rssi update while not associated ?! */
-       if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
+       /*
+        * Rssi update while not associated - can happen since the statistics
+        * are handled asynchronously
+        */
+       if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
                return;
 
        /* No BT - reports should be disabled */
index e4ead86f06d69a7ebb99d2ceede388035dd6c89e..2b0ba1fc3c82fb457a897dbb8fe08d528b12d762 100644 (file)
@@ -152,7 +152,7 @@ enum iwl_power_scheme {
        IWL_POWER_SCHEME_LP
 };
 
-#define IWL_CONN_MAX_LISTEN_INTERVAL   70
+#define IWL_CONN_MAX_LISTEN_INTERVAL   10
 #define IWL_UAPSD_AC_INFO              (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
                                         IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
                                         IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
index 4df12fa9d33685b285b489a67897479f8f8dc54a..76ee486039d7a082b9081f835e7b132bf08ecbe5 100644 (file)
@@ -822,16 +822,12 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
        struct sk_buff_head reclaimed_skbs;
        struct iwl_mvm_tid_data *tid_data;
-       struct ieee80211_tx_info *info;
        struct ieee80211_sta *sta;
        struct iwl_mvm_sta *mvmsta;
-       struct ieee80211_hdr *hdr;
        struct sk_buff *skb;
        int sta_id, tid, freed;
-
        /* "flow" corresponds to Tx queue */
        u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
-
        /* "ssn" is start of block-ack Tx window, corresponds to index
         * (in Tx queue's circular buffer) of first TFD/frame in window */
        u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
@@ -888,22 +884,26 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        freed = 0;
 
        skb_queue_walk(&reclaimed_skbs, skb) {
-               hdr = (struct ieee80211_hdr *)skb->data;
+               struct ieee80211_hdr *hdr = (void *)skb->data;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
                if (ieee80211_is_data_qos(hdr->frame_control))
                        freed++;
                else
                        WARN_ON_ONCE(1);
 
-               info = IEEE80211_SKB_CB(skb);
                iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
 
+               memset(&info->status, 0, sizeof(info->status));
+               /* Packet was transmitted successfully, failures come as single
+                * frames because before failing a frame the firmware transmits
+                * it without aggregation at least once.
+                */
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
                if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
                        /* put the rate scaling data there */
-                       info = IEEE80211_SKB_CB(skb);
-                       memset(&info->status, 0, sizeof(info->status));
-                       info->flags |= IEEE80211_TX_STAT_ACK;
                        info->flags |= IEEE80211_TX_STAT_AMPDU;
                        info->status.ampdu_ack_len = ba_notif->txed_2_done;
                        info->status.ampdu_len = ba_notif->txed;
index f47bcbe2945aabf35702cd0319ba322bf073aef7..3872ead75488d6ac485a5cb147a4037988f7ee89 100644 (file)
@@ -359,13 +359,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095A, 0x5112, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5100, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095A, 0x510A, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)},
index 32f75007a825be6c24b6195d35a9f4e31d590961..cb6d189bc3e60fd9bfeb2e3e696caf822ebb9748 100644 (file)
@@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                        id = *pos++;
                        elen = *pos++;
                        left -= 2;
-                       if (elen > left || elen == 0) {
+                       if (elen > left) {
                                lbs_deb_scan("scan response: invalid IE fmt\n");
                                goto done;
                        }
index 5e0eec4d71c7a5d61e4d65b73ca503aaaf54a085..5d9a8084665d5176fc3b54afd62c1b821c7278df 100644 (file)
@@ -189,8 +189,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
                vht_cap->header.len  =
                                cpu_to_le16(sizeof(struct ieee80211_vht_cap));
                memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
-                      (u8 *)bss_desc->bcn_vht_cap +
-                      sizeof(struct ieee_types_header),
+                      (u8 *)bss_desc->bcn_vht_cap,
                       le16_to_cpu(vht_cap->header.len));
 
                mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
index 6261f8c53d44bd7a6ba4f30651bfc8c67da6f4e5..7db1a89fdd9559fda27bf19a17c114e2b4643d56 100644 (file)
@@ -308,8 +308,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
                ht_cap->header.len =
                                cpu_to_le16(sizeof(struct ieee80211_ht_cap));
                memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
-                      (u8 *) bss_desc->bcn_ht_cap +
-                      sizeof(struct ieee_types_header),
+                      (u8 *)bss_desc->bcn_ht_cap,
                       le16_to_cpu(ht_cap->header.len));
 
                mwifiex_fill_cap_info(priv, radio_type, ht_cap);
index 03688aa14e8adb8575163e3a40aeda4a70a32c19..7fe7b53fb17a28d75cb7fa9a6fc315c9f0ddd937 100644 (file)
@@ -1211,6 +1211,12 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                rd_index = card->rxbd_rdptr & reg->rx_mask;
                skb_data = card->rx_buf_list[rd_index];
 
+               /* If skb allocation was failed earlier for Rx packet,
+                * rx_buf_list[rd_index] would have been left with a NULL.
+                */
+               if (!skb_data)
+                       return -ENOMEM;
+
                MWIFIEX_SKB_PACB(skb_data, &buf_pa);
                pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
                                 PCI_DMA_FROMDEVICE);
@@ -1525,6 +1531,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
                if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
                        mwifiex_process_sleep_confirm_resp(adapter, skb->data,
                                                           skb->len);
+                       mwifiex_pcie_enable_host_int(adapter);
+                       if (mwifiex_write_reg(adapter,
+                                             PCIE_CPU_INT_EVENT,
+                                             CPU_INTR_SLEEP_CFM_DONE)) {
+                               dev_warn(adapter->dev,
+                                        "Write register failed\n");
+                               return -1;
+                       }
                        while (reg->sleep_cookie && (count++ < 10) &&
                               mwifiex_pcie_ok_to_access_hw(adapter))
                                usleep_range(50, 60);
@@ -1993,23 +2007,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
                adapter->int_status |= pcie_ireg;
                spin_unlock_irqrestore(&adapter->int_lock, flags);
 
-               if (pcie_ireg & HOST_INTR_CMD_DONE) {
-                       if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
-                           (adapter->ps_state == PS_STATE_SLEEP)) {
-                               mwifiex_pcie_enable_host_int(adapter);
-                               if (mwifiex_write_reg(adapter,
-                                                     PCIE_CPU_INT_EVENT,
-                                                     CPU_INTR_SLEEP_CFM_DONE)
-                                                     ) {
-                                       dev_warn(adapter->dev,
-                                                "Write register failed\n");
-                                       return;
-
-                               }
-                       }
-               } else if (!adapter->pps_uapsd_mode &&
-                          adapter->ps_state == PS_STATE_SLEEP &&
-                          mwifiex_pcie_ok_to_access_hw(adapter)) {
+               if (!adapter->pps_uapsd_mode &&
+                   adapter->ps_state == PS_STATE_SLEEP &&
+                   mwifiex_pcie_ok_to_access_hw(adapter)) {
                                /* Potentially for PCIe we could get other
                                 * interrupts like shared. Don't change power
                                 * state until cookie is set */
index 0a8a26e10f01a421361a5872065954a8ae79c614..668547c2de8464ed93fedc37066ef0fc3c50f320 100644 (file)
@@ -2101,12 +2101,12 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
                         curr_bss->ht_info_offset);
 
        if (curr_bss->bcn_vht_cap)
-               curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
-                                               curr_bss->vht_cap_offset);
+               curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
+                                                curr_bss->vht_cap_offset);
 
        if (curr_bss->bcn_vht_oper)
-               curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
-                                                curr_bss->vht_info_offset);
+               curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
+                                                 curr_bss->vht_info_offset);
 
        if (curr_bss->bcn_bss_co_2040)
                curr_bss->bcn_bss_co_2040 =
index e8ebbd4bc3cd3348b271a6d930781cb799b97300..208748804a55ee56dd1d8d7cbb445e7600525db5 100644 (file)
@@ -22,8 +22,6 @@
 
 #define USB_VERSION    "1.0"
 
-static const char usbdriver_name[] = "usb8xxx";
-
 static struct mwifiex_if_ops usb_ops;
 static struct semaphore add_remove_card_sem;
 static struct usb_card_rec *usb_card;
@@ -527,13 +525,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
                                                   MWIFIEX_BSS_ROLE_ANY),
                                  MWIFIEX_ASYNC_CMD);
 
-#ifdef CONFIG_PM
-       /* Resume handler may be called due to remote wakeup,
-        * force to exit suspend anyway
-        */
-       usb_disable_autosuspend(card->udev);
-#endif /* CONFIG_PM */
-
        return 0;
 }
 
@@ -567,13 +558,12 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
 }
 
 static struct usb_driver mwifiex_usb_driver = {
-       .name = usbdriver_name,
+       .name = "mwifiex_usb",
        .probe = mwifiex_usb_probe,
        .disconnect = mwifiex_usb_disconnect,
        .id_table = mwifiex_usb_table,
        .suspend = mwifiex_usb_suspend,
        .resume = mwifiex_usb_resume,
-       .supports_autosuspend = 1,
 };
 
 static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
index 13eaeed03898288d43abf107090346d513132820..981cf6e7c73be5b65f4a90bb05ef0e9023c592f4 100644 (file)
@@ -559,7 +559,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
        mwifiex_wmm_delete_all_ralist(priv);
        memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
 
-       if (priv->adapter->if_ops.clean_pcie_ring)
+       if (priv->adapter->if_ops.clean_pcie_ring &&
+           !priv->adapter->surprise_removed)
                priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }
index 7f8b5d156c8c91dde72791d439aa5bbc9e66b7cc..41d4a8167dc32f368a8fdf061bea4fe9944fd0f1 100644 (file)
@@ -5460,14 +5460,15 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
 
        rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
-       rt2800_bbp_write(rt2x00dev, 69, 0x0d);
-       rt2800_bbp_write(rt2x00dev, 70, 0x06);
+       rt2800_bbp_write(rt2x00dev, 69, 0x12);
        rt2800_bbp_write(rt2x00dev, 73, 0x13);
        rt2800_bbp_write(rt2x00dev, 75, 0x46);
        rt2800_bbp_write(rt2x00dev, 76, 0x28);
 
        rt2800_bbp_write(rt2x00dev, 77, 0x59);
 
+       rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+
        rt2800_bbp_write(rt2x00dev, 79, 0x13);
        rt2800_bbp_write(rt2x00dev, 80, 0x05);
        rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -5510,7 +5511,6 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_write(rt2x00dev, 134, 0xd0);
                rt2800_bbp_write(rt2x00dev, 135, 0xf6);
-               rt2800_bbp_write(rt2x00dev, 148, 0x84);
        }
 
        rt2800_disable_unused_dac_adc(rt2x00dev);
index caddc1b427a919659200c539552a619af49c5d17..42a2e06512f2f0900ac7f9384b1e247013f2b11d 100644 (file)
@@ -764,7 +764,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
        /*
         * Overwrite TX done handler
         */
-       PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+       INIT_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
 
        return 0;
 }
index 123c4bb50e0a0c2eff220c4509c2ece5aab7b365..cde0eaf99714b4054176bd7a3cad9e850d97abea 100644 (file)
@@ -180,7 +180,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
        wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
 
        /* The actual length doesn't include the target's alignment */
-       skb->len = desc->length  - PLCP_HEADER_LENGTH;
+       skb_trim(skb, desc->length - PLCP_HEADER_LENGTH);
 
        fc = (u16 *)skb->data;
 
index 7669d49a67e2271bebe14e80aaaa9c59312edea2..301cc037fda886f2bc2de48a347a8693eadee178 100644 (file)
@@ -132,8 +132,7 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* If the skb is GSO then we'll also need an extra slot for the
         * metadata.
         */
-       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
-           skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+       if (skb_is_gso(skb))
                min_slots_needed++;
 
        /* If the skb can't possibly fit in the remaining slots
index e5284bca2d90e6e80ec0d682475404e9dc236e33..438d0c09b7e6019b513f8e996f5549bb327463d2 100644 (file)
@@ -240,7 +240,7 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
        struct gnttab_copy *copy_gop;
        struct xenvif_rx_meta *meta;
        unsigned long bytes;
-       int gso_type;
+       int gso_type = XEN_NETIF_GSO_TYPE_NONE;
 
        /* Data must not cross a page boundary. */
        BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
@@ -299,12 +299,12 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                }
 
                /* Leave a gap for the GSO descriptor. */
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
-                       gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
-               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
-                       gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
-               else
-                       gso_type = XEN_NETIF_GSO_TYPE_NONE;
+               if (skb_is_gso(skb)) {
+                       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                               gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+                       else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                               gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
+               }
 
                if (*head && ((1 << gso_type) & vif->gso_mask))
                        vif->rx.req_cons++;
@@ -338,19 +338,15 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        int head = 1;
        int old_meta_prod;
        int gso_type;
-       int gso_size;
 
        old_meta_prod = npo->meta_prod;
 
-       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
-               gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
-               gso_size = skb_shinfo(skb)->gso_size;
-       } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
-               gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
-               gso_size = skb_shinfo(skb)->gso_size;
-       } else {
-               gso_type = XEN_NETIF_GSO_TYPE_NONE;
-               gso_size = 0;
+       gso_type = XEN_NETIF_GSO_TYPE_NONE;
+       if (skb_is_gso(skb)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                       gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                       gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
        }
 
        /* Set up a GSO prefix descriptor, if necessary */
@@ -358,7 +354,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
                meta = npo->meta + npo->meta_prod++;
                meta->gso_type = gso_type;
-               meta->gso_size = gso_size;
+               meta->gso_size = skb_shinfo(skb)->gso_size;
                meta->size = 0;
                meta->id = req->id;
        }
@@ -368,7 +364,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
 
        if ((1 << gso_type) & vif->gso_mask) {
                meta->gso_type = gso_type;
-               meta->gso_size = gso_size;
+               meta->gso_size = skb_shinfo(skb)->gso_size;
        } else {
                meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
                meta->gso_size = 0;
@@ -500,8 +496,9 @@ static void xenvif_rx_action(struct xenvif *vif)
                        size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
                        max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE);
                }
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
-                   skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+               if (skb_is_gso(skb) &&
+                  (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
+                   skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
                        max_slots_needed++;
 
                /* If the skb may not fit then bail out now */
index f9daa9e183f216e7114a1d1b604fe4fc6b6d3861..e30d80033cbc4bb4f93d4e84897ff6fb29417a91 100644 (file)
@@ -907,6 +907,7 @@ static int handle_incoming_queue(struct net_device *dev,
 
                /* Ethernet work: Delayed to here as it peeks the header. */
                skb->protocol = eth_type_trans(skb, dev);
+               skb_reset_network_header(skb);
 
                if (checksum_setup(dev, skb)) {
                        kfree_skb(skb);
index 89e888a78899e2b61281f7007406e5f937cc28a0..1b95a405628f311bf068891f958324f0b5edd0c8 100644 (file)
@@ -903,6 +903,38 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
+/**
+ * of_property_count_elems_of_size - Count the number of elements in a property
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ * @elem_size: size of the individual element
+ *
+ * Search for a property in a device node and count the number of elements of
+ * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
+ * property does not exist or its length does not match a multiple of elem_size
+ * and -ENODATA if the property does not have a value.
+ */
+int of_property_count_elems_of_size(const struct device_node *np,
+                               const char *propname, int elem_size)
+{
+       struct property *prop = of_find_property(np, propname, NULL);
+
+       if (!prop)
+               return -EINVAL;
+       if (!prop->value)
+               return -ENODATA;
+
+       if (prop->length % elem_size != 0) {
+               pr_err("size of %s in node %s is not a multiple of %d\n",
+                      propname, np->full_name, elem_size);
+               return -EINVAL;
+       }
+
+       return prop->length / elem_size;
+}
+EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
+
 /**
  * of_find_property_value_of_size
  *
index 6a83ee1e9178c118dabb6f318e40c447aa7d3d6d..3fa66244ce328c2dfe53812810d4597e09ad3f90 100644 (file)
@@ -905,7 +905,8 @@ int parport_claim_or_block(struct pardevice *dev)
                /* If dev->waiting is clear now, an interrupt
                   gave us the port and we would deadlock if we slept.  */
                if (dev->waiting) {
-                       interruptible_sleep_on (&dev->wait_q);
+                       wait_event_interruptible(dev->wait_q,
+                                                !dev->waiting);
                        if (signal_pending (current)) {
                                return -EINTR;
                        }
index 17d2b07ee67c2db583a650b2ffbada55324faa53..e2501ac6fe84808ad4816ce8bf2cd14d27001b11 100644 (file)
@@ -33,21 +33,15 @@ obj-$(CONFIG_PCI_IOV) += iov.o
 #
 # Some architectures use the generic PCI setup functions
 #
-obj-$(CONFIG_X86) += setup-bus.o
-obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
-obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
-obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o
-obj-$(CONFIG_PARISC) += setup-bus.o
-obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
-obj-$(CONFIG_PPC) += setup-bus.o
-obj-$(CONFIG_FRV) += setup-bus.o
-obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
+obj-$(CONFIG_ALPHA) += setup-irq.o
+obj-$(CONFIG_ARM) += setup-irq.o
+obj-$(CONFIG_UNICORE32) += setup-irq.o
+obj-$(CONFIG_SUPERH) += setup-irq.o
+obj-$(CONFIG_MIPS) += setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
-obj-$(CONFIG_MN10300) += setup-bus.o
-obj-$(CONFIG_MICROBLAZE) += setup-bus.o
-obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
-obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o
-obj-$(CONFIG_M68K) += setup-bus.o setup-irq.o
+obj-$(CONFIG_TILE) += setup-irq.o
+obj-$(CONFIG_SPARC_LEON) += setup-irq.o
+obj-$(CONFIG_M68K) += setup-irq.o
 
 #
 # ACPI Related PCI FW Functions
index 00660cc502c5e0df1da9946281ba2b6fa6d08afc..fb8aed307c2821d70404dbac467fc94d914ed7e0 100644 (file)
@@ -132,7 +132,7 @@ static void pci_clip_resource_to_region(struct pci_bus *bus,
 
 static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
                resource_size_t size, resource_size_t align,
-               resource_size_t min, unsigned int type_mask,
+               resource_size_t min, unsigned long type_mask,
                resource_size_t (*alignf)(void *,
                                          const struct resource *,
                                          resource_size_t,
@@ -144,7 +144,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
        struct resource *r, avail;
        resource_size_t max;
 
-       type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+       type_mask |= IORESOURCE_TYPE_BITS;
 
        pci_bus_for_each_resource(bus, r, i) {
                if (!r)
@@ -162,8 +162,6 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
 
                avail = *r;
                pci_clip_resource_to_region(bus, &avail, region);
-               if (!resource_size(&avail))
-                       continue;
 
                /*
                 * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
@@ -202,7 +200,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
  */
 int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
                resource_size_t size, resource_size_t align,
-               resource_size_t min, unsigned int type_mask,
+               resource_size_t min, unsigned long type_mask,
                resource_size_t (*alignf)(void *,
                                          const struct resource *,
                                          resource_size_t,
index 06ace6248c61d9cb02e8618c52e691b251c02580..47aaf22d814e195f7d397237a59267334ccf5ca2 100644 (file)
@@ -32,11 +32,6 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
        bridge->release_data = release_data;
 }
 
-static bool resource_contains(struct resource *res1, struct resource *res2)
-{
-       return res1->start <= res2->start && res1->end >= res2->end;
-}
-
 void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
                             struct resource *res)
 {
@@ -45,9 +40,6 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
        resource_size_t offset = 0;
 
        list_for_each_entry(window, &bridge->windows, list) {
-               if (resource_type(res) != resource_type(window->res))
-                       continue;
-
                if (resource_contains(window->res, res)) {
                        offset = window->offset;
                        break;
index 47d46c6d84680ba81094de38911a821fb347066e..a6f67ec8882f1f4eab68aad1f64244f55df15738 100644 (file)
@@ -27,7 +27,7 @@ config PCI_TEGRA
 
 config PCI_RCAR_GEN2
        bool "Renesas R-Car Gen2 Internal PCI controller"
-       depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
+       depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
        help
          Say Y here if you want internal PCI support on R-Car Gen2 SoC.
          There are 3 internal PCI controllers available with a single
index e8663a8c3406a0cb73b5c4a2e1f7380e7fc9f898..ee082509b0baa730b90a6c0111673214889604dd 100644 (file)
@@ -424,20 +424,40 @@ static void imx6_pcie_reset_phy(struct pcie_port *pp)
 
 static int imx6_pcie_link_up(struct pcie_port *pp)
 {
-       u32 rc, ltssm, rx_valid;
+       u32 rc, debug_r0, rx_valid;
+       int count = 5;
 
        /*
-        * Test if the PHY reports that the link is up and also that
-        * the link training finished.  It might happen that the PHY
-        * reports the link is already up, but the link training bit
-        * is still set, so make sure to check the training is done
-        * as well here.
+        * Test if the PHY reports that the link is up and also that the LTSSM
+        * training finished. There are three possible states of the link when
+        * this code is called:
+        * 1) The link is DOWN (unlikely)
+        *     The link didn't come up yet for some reason. This usually means
+        *     we have a real problem somewhere. Reset the PHY and exit. This
+        *     state calls for inspection of the DEBUG registers.
+        * 2) The link is UP, but still in LTSSM training
+        *     Wait for the training to finish, which should take a very short
+        *     time. If the training does not finish, we have a problem and we
+        *     need to inspect the DEBUG registers. If the training does finish,
+        *     the link is up and operating correctly.
+        * 3) The link is UP and no longer in LTSSM training
+        *     The link is up and operating correctly.
         */
-       rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
-       if ((rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) &&
-           !(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
-               return 1;
-
+       while (1) {
+               rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+               if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
+                       break;
+               if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
+                       return 1;
+               if (!count--)
+                       break;
+               dev_dbg(pp->dev, "Link is up, but still in training\n");
+               /*
+                * Wait a little bit, then re-check if the link finished
+                * the training.
+                */
+               usleep_range(1000, 2000);
+       }
        /*
         * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
         * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
@@ -446,15 +466,16 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
         * to gen2 is stuck
         */
        pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
-       ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
+       debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
 
        if (rx_valid & 0x01)
                return 0;
 
-       if (ltssm != 0x0d)
+       if ((debug_r0 & 0x3f) != 0x0d)
                return 0;
 
        dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
+       dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc);
 
        imx6_pcie_reset_phy(pp);
 
index 0e79665afd445ebb8e6198a274960978c58c619e..d3d1cfd51e095f058404d96f063df76d227bd652 100644 (file)
@@ -101,7 +101,9 @@ struct mvebu_pcie {
        struct mvebu_pcie_port *ports;
        struct msi_chip *msi;
        struct resource io;
+       char io_name[30];
        struct resource realio;
+       char mem_name[30];
        struct resource mem;
        struct resource busn;
        int nports;
@@ -672,10 +674,30 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
 {
        struct mvebu_pcie *pcie = sys_to_pcie(sys);
        int i;
+       int domain = 0;
 
-       if (resource_size(&pcie->realio) != 0)
+#ifdef CONFIG_PCI_DOMAINS
+       domain = sys->domain;
+#endif
+
+       snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x",
+                domain);
+       pcie->mem.name = pcie->mem_name;
+
+       snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain);
+       pcie->realio.name = pcie->io_name;
+
+       if (request_resource(&iomem_resource, &pcie->mem))
+               return 0;
+
+       if (resource_size(&pcie->realio) != 0) {
+               if (request_resource(&ioport_resource, &pcie->realio)) {
+                       release_resource(&pcie->mem);
+                       return 0;
+               }
                pci_add_resource_offset(&sys->resources, &pcie->realio,
                                        sys->io_offset);
+       }
        pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
        pci_add_resource(&sys->resources, &pcie->busn);
 
@@ -797,7 +819,7 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
 
        for (i = 0; i < nranges; i++) {
                u32 flags = of_read_number(range, 1);
-               u32 slot = of_read_number(range, 2);
+               u32 slot = of_read_number(range + 1, 1);
                u64 cpuaddr = of_read_number(range + na, pna);
                unsigned long rtype;
 
index ceec147baec3560abf5cc07198ab3cc6b1d32d43..fd3e3ab56509125db9e6d25b1b2288eaccda60fd 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 
 /* AHB-PCI Bridge PCI communication registers */
 
 #define RCAR_PCI_INT_ENABLE_REG                (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
 #define RCAR_PCI_INT_STATUS_REG                (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
+#define RCAR_PCI_INT_SIGTABORT         (1 << 0)
+#define RCAR_PCI_INT_SIGRETABORT       (1 << 1)
+#define RCAR_PCI_INT_REMABORT          (1 << 2)
+#define RCAR_PCI_INT_PERR              (1 << 3)
+#define RCAR_PCI_INT_SIGSERR           (1 << 4)
+#define RCAR_PCI_INT_RESERR            (1 << 5)
+#define RCAR_PCI_INT_WIN1ERR           (1 << 12)
+#define RCAR_PCI_INT_WIN2ERR           (1 << 13)
 #define RCAR_PCI_INT_A                 (1 << 16)
 #define RCAR_PCI_INT_B                 (1 << 17)
 #define RCAR_PCI_INT_PME               (1 << 19)
+#define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT         | \
+                               RCAR_PCI_INT_SIGRETABORT        | \
+                               RCAR_PCI_INT_SIGRETABORT        | \
+                               RCAR_PCI_INT_REMABORT           | \
+                               RCAR_PCI_INT_PERR               | \
+                               RCAR_PCI_INT_SIGSERR            | \
+                               RCAR_PCI_INT_RESERR             | \
+                               RCAR_PCI_INT_WIN1ERR            | \
+                               RCAR_PCI_INT_WIN2ERR)
 
 #define RCAR_AHB_BUS_CTR_REG           (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
 #define RCAR_AHB_BUS_MMODE_HTRANS      (1 << 0)
@@ -74,9 +92,6 @@
 
 #define RCAR_PCI_UNIT_REV_REG          (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
 
-/* Number of internal PCI controllers */
-#define RCAR_PCI_NR_CONTROLLERS                3
-
 struct rcar_pci_priv {
        struct device *dev;
        void __iomem *reg;
@@ -84,6 +99,7 @@ struct rcar_pci_priv {
        struct resource mem_res;
        struct resource *cfg_res;
        int irq;
+       unsigned long window_size;
 };
 
 /* PCI configuration space operations */
@@ -102,6 +118,10 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
        if (slot > 2)
                return NULL;
 
+       /* bridge logic only has registers to 0x40 */
+       if (slot == 0x0 && where >= 0x40)
+               return NULL;
+
        val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
                     RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
 
@@ -156,7 +176,7 @@ static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 }
 
 /* PCI interrupt mapping */
-static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_sys_data *sys = dev->bus->sysdata;
        struct rcar_pci_priv *priv = sys->private_data;
@@ -164,8 +184,48 @@ static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return priv->irq;
 }
 
+#ifdef CONFIG_PCI_DEBUG
+/* if debug enabled, then attach an error handler irq to the bridge */
+
+static irqreturn_t rcar_pci_err_irq(int irq, void *pw)
+{
+       struct rcar_pci_priv *priv = pw;
+       u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG);
+
+       if (status & RCAR_PCI_INT_ALLERRORS) {
+               dev_err(priv->dev, "error irq: status %08x\n", status);
+
+               /* clear the error(s) */
+               iowrite32(status & RCAR_PCI_INT_ALLERRORS,
+                         priv->reg + RCAR_PCI_INT_STATUS_REG);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static void rcar_pci_setup_errirq(struct rcar_pci_priv *priv)
+{
+       int ret;
+       u32 val;
+
+       ret = devm_request_irq(priv->dev, priv->irq, rcar_pci_err_irq,
+                              IRQF_SHARED, "error irq", priv);
+       if (ret) {
+               dev_err(priv->dev, "cannot claim IRQ for error handling\n");
+               return;
+       }
+
+       val = ioread32(priv->reg + RCAR_PCI_INT_ENABLE_REG);
+       val |= RCAR_PCI_INT_ALLERRORS;
+       iowrite32(val, priv->reg + RCAR_PCI_INT_ENABLE_REG);
+}
+#else
+static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { }
+#endif
+
 /* PCI host controller setup */
-static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
+static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
 {
        struct rcar_pci_priv *priv = sys->private_data;
        void __iomem *reg = priv->reg;
@@ -183,10 +243,31 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
        iowrite32(val, reg + RCAR_USBCTR_REG);
        udelay(4);
 
-       /* De-assert reset and set PCIAHB window1 size to 1GB */
+       /* De-assert reset and reset PCIAHB window1 size */
        val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
                 RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
-       iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG);
+
+       /* Setup PCIAHB window1 size */
+       switch (priv->window_size) {
+       case SZ_2G:
+               val |= RCAR_USBCTR_PCIAHB_WIN1_2G;
+               break;
+       case SZ_1G:
+               val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
+               break;
+       case SZ_512M:
+               val |= RCAR_USBCTR_PCIAHB_WIN1_512M;
+               break;
+       default:
+               pr_warn("unknown window size %ld - defaulting to 256M\n",
+                       priv->window_size);
+               priv->window_size = SZ_256M;
+               /* fall-through */
+       case SZ_256M:
+               val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
+               break;
+       }
+       iowrite32(val, reg + RCAR_USBCTR_REG);
 
        /* Configure AHB master and slave modes */
        iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
@@ -197,7 +278,7 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
               RCAR_PCI_ARBITER_PCIBP_MODE;
        iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
 
-       /* PCI-AHB mapping: 0x40000000-0x80000000 */
+       /* PCI-AHB mapping: 0x40000000 base */
        iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
                  reg + RCAR_PCIAHB_WIN1_CTR_REG);
 
@@ -224,10 +305,15 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
        iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
                  reg + RCAR_PCI_INT_ENABLE_REG);
 
+       if (priv->irq > 0)
+               rcar_pci_setup_errirq(priv);
+
        /* Add PCI resources */
        pci_add_resource(&sys->resources, &priv->io_res);
        pci_add_resource(&sys->resources, &priv->mem_res);
 
+       /* Setup bus number based on platform device id */
+       sys->busnr = to_platform_device(priv->dev)->id;
        return 1;
 }
 
@@ -236,48 +322,13 @@ static struct pci_ops rcar_pci_ops = {
        .write  = rcar_pci_write_config,
 };
 
-static struct hw_pci rcar_hw_pci __initdata = {
-       .map_irq        = rcar_pci_map_irq,
-       .ops            = &rcar_pci_ops,
-       .setup          = rcar_pci_setup,
-};
-
-static int rcar_pci_count __initdata;
-
-static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
-{
-       void **private_data;
-       int count;
-
-       if (rcar_hw_pci.nr_controllers < rcar_pci_count)
-               goto add_priv;
-
-       /* (Re)allocate private data pointer array if needed */
-       count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
-       private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
-       if (!private_data)
-               return -ENOMEM;
-
-       rcar_pci_count = count;
-       if (rcar_hw_pci.private_data) {
-               memcpy(private_data, rcar_hw_pci.private_data,
-                      rcar_hw_pci.nr_controllers * sizeof(void *));
-               kfree(rcar_hw_pci.private_data);
-       }
-
-       rcar_hw_pci.private_data = private_data;
-
-add_priv:
-       /* Add private data pointer to the array */
-       rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
-       return 0;
-}
-
-static int __init rcar_pci_probe(struct platform_device *pdev)
+static int rcar_pci_probe(struct platform_device *pdev)
 {
        struct resource *cfg_res, *mem_res;
        struct rcar_pci_priv *priv;
        void __iomem *reg;
+       struct hw_pci hw;
+       void *hw_private[1];
 
        cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +359,34 @@ static int __init rcar_pci_probe(struct platform_device *pdev)
        priv->reg = reg;
        priv->dev = &pdev->dev;
 
-       return rcar_pci_add_controller(priv);
+       if (priv->irq < 0) {
+               dev_err(&pdev->dev, "no valid irq found\n");
+               return priv->irq;
+       }
+
+       priv->window_size = SZ_1G;
+
+       hw_private[0] = priv;
+       memset(&hw, 0, sizeof(hw));
+       hw.nr_controllers = ARRAY_SIZE(hw_private);
+       hw.private_data = hw_private;
+       hw.map_irq = rcar_pci_map_irq;
+       hw.ops = &rcar_pci_ops;
+       hw.setup = rcar_pci_setup;
+       pci_common_init_dev(&pdev->dev, &hw);
+       return 0;
 }
 
 static struct platform_driver rcar_pci_driver = {
        .driver = {
                .name = "pci-rcar-gen2",
+               .owner = THIS_MODULE,
+               .suppress_bind_attrs = true,
        },
+       .probe = rcar_pci_probe,
 };
 
-static int __init rcar_pci_init(void)
-{
-       int retval;
-
-       retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe);
-       if (!retval)
-               pci_common_init(&rcar_hw_pci);
-
-       /* Private data pointer array is not needed any more */
-       kfree(rcar_hw_pci.private_data);
-       rcar_hw_pci.private_data = NULL;
-
-       return retval;
-}
-
-subsys_initcall(rcar_pci_init);
+module_platform_driver(rcar_pci_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI");
index 17ce88f79d2b1ed3bbd351726f9d0af68be7d9ba..509a29d84509364b366ef1e130ed5ea37b40a091 100644 (file)
@@ -294,14 +294,12 @@ no_valid_irq:
 static void clear_irq(unsigned int irq)
 {
        unsigned int pos, nvec;
-       struct irq_desc *desc;
        struct msi_desc *msi;
        struct pcie_port *pp;
        struct irq_data *data = irq_get_irq_data(irq);
 
        /* get the port structure */
-       desc = irq_to_desc(irq);
-       msi = irq_desc_get_msi_desc(desc);
+       msi = irq_data_get_msi(data);
        pp = sys_to_pcie(msi->dev->bus->sysdata);
        if (!pp) {
                BUG();
@@ -800,7 +798,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 
        /* setup RC BARs */
        dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
-       dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_1);
+       dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
 
        /* setup interrupt pins */
        dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
index b6162be4df40a2f6a614d983491037dd865b2c8d..2b859249303b8088352995bc23b57c47f7c36472 100644 (file)
@@ -93,7 +93,6 @@ struct acpiphp_slot {
        struct list_head funcs;         /* one slot may have different
                                           objects (i.e. for each function) */
        struct slot *slot;
-       struct mutex crit_sect;
 
        u8              device;         /* pci device# */
        u32             flags;          /* see below */
@@ -117,20 +116,30 @@ struct acpiphp_func {
 };
 
 struct acpiphp_context {
-       acpi_handle handle;
+       struct acpi_hotplug_context hp;
        struct acpiphp_func func;
        struct acpiphp_bridge *bridge;
        unsigned int refcount;
 };
 
+static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp)
+{
+       return container_of(hp, struct acpiphp_context, hp);
+}
+
 static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
 {
        return container_of(func, struct acpiphp_context, func);
 }
 
+static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func)
+{
+       return func_to_context(func)->hp.self;
+}
+
 static inline acpi_handle func_to_handle(struct acpiphp_func *func)
 {
-       return func_to_context(func)->handle;
+       return func_to_acpi_device(func)->handle;
 }
 
 /*
@@ -158,7 +167,6 @@ struct acpiphp_attention_info
 
 #define FUNC_HAS_STA           (0x00000001)
 #define FUNC_HAS_EJ0           (0x00000002)
-#define FUNC_HAS_DCK            (0x00000004)
 
 /* function prototypes */
 
index 7c7a388c85ab3679732f7971552790057abec4f5..bccc27ee10308f4d1ec388db248d1af1ab08aaba 100644 (file)
 
 static LIST_HEAD(bridge_list);
 static DEFINE_MUTEX(bridge_mutex);
-static DEFINE_MUTEX(acpiphp_context_lock);
 
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
+static void acpiphp_post_dock_fixup(struct acpi_device *adev);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event(acpi_handle handle, u32 type, void *data);
+static void hotplug_event(u32 type, struct acpiphp_context *context);
 static void free_bridge(struct kref *kref);
 
-static void acpiphp_context_handler(acpi_handle handle, void *context)
-{
-       /* Intentionally empty. */
-}
-
 /**
  * acpiphp_init_context - Create hotplug context and grab a reference to it.
- * @handle: ACPI object handle to create the context for.
+ * @adev: ACPI device object to create the context for.
  *
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
  */
-static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev)
 {
        struct acpiphp_context *context;
-       acpi_status status;
 
        context = kzalloc(sizeof(*context), GFP_KERNEL);
        if (!context)
                return NULL;
 
-       context->handle = handle;
        context->refcount = 1;
-       status = acpi_attach_data(handle, acpiphp_context_handler, context);
-       if (ACPI_FAILURE(status)) {
-               kfree(context);
-               return NULL;
-       }
+       acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL,
+                           acpiphp_post_dock_fixup);
        return context;
 }
 
 /**
  * acpiphp_get_context - Get hotplug context and grab a reference to it.
- * @handle: ACPI object handle to get the context for.
+ * @adev: ACPI device object to get the context for.
  *
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
  */
-static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev)
 {
-       struct acpiphp_context *context = NULL;
-       acpi_status status;
-       void *data;
+       struct acpiphp_context *context;
 
-       status = acpi_get_data(handle, acpiphp_context_handler, &data);
-       if (ACPI_SUCCESS(status)) {
-               context = data;
-               context->refcount++;
-       }
+       if (!adev->hp)
+               return NULL;
+
+       context = to_acpiphp_context(adev->hp);
+       context->refcount++;
        return context;
 }
 
 /**
  * acpiphp_put_context - Drop a reference to ACPI hotplug context.
- * @handle: ACPI object handle to put the context for.
+ * @context: ACPI hotplug context to drop a reference to.
  *
  * The context object is removed if there are no more references to it.
  *
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
  */
 static void acpiphp_put_context(struct acpiphp_context *context)
 {
@@ -130,7 +118,7 @@ static void acpiphp_put_context(struct acpiphp_context *context)
                return;
 
        WARN_ON(context->bridge);
-       acpi_detach_data(context->handle, acpiphp_context_handler);
+       context->hp.self->hp = NULL;
        kfree(context);
 }
 
@@ -144,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
        kref_put(&bridge->ref, free_bridge);
 }
 
+static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev)
+{
+       struct acpiphp_context *context;
+
+       acpi_lock_hp_context();
+       context = acpiphp_get_context(adev);
+       if (!context || context->func.parent->is_going_away) {
+               acpi_unlock_hp_context();
+               return NULL;
+       }
+       get_bridge(context->func.parent);
+       acpiphp_put_context(context);
+       acpi_unlock_hp_context();
+       return context;
+}
+
+static void acpiphp_let_context_go(struct acpiphp_context *context)
+{
+       put_bridge(context->func.parent);
+}
+
 static void free_bridge(struct kref *kref)
 {
        struct acpiphp_context *context;
@@ -151,7 +160,7 @@ static void free_bridge(struct kref *kref)
        struct acpiphp_slot *slot, *next;
        struct acpiphp_func *func, *tmp;
 
-       mutex_lock(&acpiphp_context_lock);
+       acpi_lock_hp_context();
 
        bridge = container_of(kref, struct acpiphp_bridge, ref);
 
@@ -175,31 +184,32 @@ static void free_bridge(struct kref *kref)
        pci_dev_put(bridge->pci_dev);
        kfree(bridge);
 
-       mutex_unlock(&acpiphp_context_lock);
+       acpi_unlock_hp_context();
 }
 
-/*
- * the _DCK method can do funny things... and sometimes not
- * hah-hah funny.
+/**
+ * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices.
+ * @adev: ACPI device object corresponding to a PCI device.
  *
- * TBD - figure out a way to only call fixups for
- * systems that require them.
+ * TBD - figure out a way to only call fixups for systems that require them.
  */
-static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
+static void acpiphp_post_dock_fixup(struct acpi_device *adev)
 {
-       struct acpiphp_context *context = data;
-       struct pci_bus *bus = context->func.slot->bus;
+       struct acpiphp_context *context = acpiphp_grab_context(adev);
+       struct pci_bus *bus;
        u32 buses;
 
-       if (!bus->self)
+       if (!context)
                return;
 
+       bus = context->func.slot->bus;
+       if (!bus->self)
+               goto out;
+
        /* fixup bad _DCK function that rewrites
         * secondary bridge on slot
         */
-       pci_read_config_dword(bus->self,
-                       PCI_PRIMARY_BUS,
-                       &buses);
+       pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses);
 
        if (((buses >> 8) & 0xff) != bus->busn_res.start) {
                buses = (buses & 0xff000000)
@@ -208,33 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
                        | ((unsigned int)(bus->busn_res.end) << 16);
                pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
        }
-}
-
-static void dock_event(acpi_handle handle, u32 type, void *data)
-{
-       struct acpiphp_context *context;
-
-       mutex_lock(&acpiphp_context_lock);
-       context = acpiphp_get_context(handle);
-       if (!context || WARN_ON(context->handle != handle)
-           || context->func.parent->is_going_away) {
-               mutex_unlock(&acpiphp_context_lock);
-               return;
-       }
-       get_bridge(context->func.parent);
-       acpiphp_put_context(context);
-       mutex_unlock(&acpiphp_context_lock);
-
-       hotplug_event(handle, type, data);
 
-       put_bridge(context->func.parent);
+ out:
+       acpiphp_let_context_go(context);
 }
 
-static const struct acpi_dock_ops acpiphp_dock_ops = {
-       .fixup = post_dock_fixups,
-       .handler = dock_event,
-};
-
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
 static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
 {
@@ -264,26 +252,19 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
        return true;
 }
 
-static void acpiphp_dock_init(void *data)
-{
-       struct acpiphp_context *context = data;
-
-       get_bridge(context->func.parent);
-}
-
-static void acpiphp_dock_release(void *data)
-{
-       struct acpiphp_context *context = data;
-
-       put_bridge(context->func.parent);
-}
-
-/* callback routine to register each ACPI PCI slot object */
-static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
-                                void **rv)
+/**
+ * acpiphp_add_context - Add ACPIPHP context to an ACPI device object.
+ * @handle: ACPI handle of the object to add a context to.
+ * @lvl: Not used.
+ * @data: The object's parent ACPIPHP bridge.
+ * @rv: Not used.
+ */
+static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
+                                      void **rv)
 {
        struct acpiphp_bridge *bridge = data;
        struct acpiphp_context *context;
+       struct acpi_device *adev;
        struct acpiphp_slot *slot;
        struct acpiphp_func *newfunc;
        acpi_status status = AE_OK;
@@ -293,9 +274,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
        struct pci_dev *pdev = bridge->pci_dev;
        u32 val;
 
-       if (pdev && device_is_managed_by_native_pciehp(pdev))
-               return AE_OK;
-
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
        if (ACPI_FAILURE(status)) {
                if (status != AE_NOT_FOUND)
@@ -303,31 +281,34 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
                                "can't evaluate _ADR (%#x)\n", status);
                return AE_OK;
        }
+       if (acpi_bus_get_device(handle, &adev))
+               return AE_OK;
 
        device = (adr >> 16) & 0xffff;
        function = adr & 0xffff;
 
-       mutex_lock(&acpiphp_context_lock);
-       context = acpiphp_init_context(handle);
+       acpi_lock_hp_context();
+       context = acpiphp_init_context(adev);
        if (!context) {
-               mutex_unlock(&acpiphp_context_lock);
+               acpi_unlock_hp_context();
                acpi_handle_err(handle, "No hotplug context\n");
                return AE_NOT_EXIST;
        }
        newfunc = &context->func;
        newfunc->function = function;
        newfunc->parent = bridge;
-       mutex_unlock(&acpiphp_context_lock);
+       acpi_unlock_hp_context();
 
-       if (acpi_has_method(handle, "_EJ0"))
+       /*
+        * If this is a dock device, its _EJ0 should be executed by the dock
+        * notify handler after calling _DCK.
+        */
+       if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0"))
                newfunc->flags = FUNC_HAS_EJ0;
 
        if (acpi_has_method(handle, "_STA"))
                newfunc->flags |= FUNC_HAS_STA;
 
-       if (acpi_has_method(handle, "_DCK"))
-               newfunc->flags |= FUNC_HAS_DCK;
-
        /* search for objects that share the same slot */
        list_for_each_entry(slot, &bridge->slots, node)
                if (slot->device == device)
@@ -335,19 +316,26 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
 
        slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
        if (!slot) {
-               status = AE_NO_MEMORY;
-               goto err;
+               acpi_lock_hp_context();
+               acpiphp_put_context(context);
+               acpi_unlock_hp_context();
+               return AE_NO_MEMORY;
        }
 
        slot->bus = bridge->pci_bus;
        slot->device = device;
        INIT_LIST_HEAD(&slot->funcs);
-       mutex_init(&slot->crit_sect);
 
        list_add_tail(&slot->node, &bridge->slots);
 
-       /* Register slots for ejectable functions only. */
-       if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
+       /*
+        * Expose slots to user space for functions that have _EJ0 or _RMV or
+        * are located in dock stations.  Do not expose them for devices handled
+        * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
+        * expose slots to user space in those cases.
+        */
+       if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
+           && !(pdev && device_is_managed_by_native_pciehp(pdev))) {
                unsigned long long sun;
                int retval;
 
@@ -381,44 +369,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
                                       &val, 60*1000))
                slot->flags |= SLOT_ENABLED;
 
-       if (is_dock_device(handle)) {
-               /* we don't want to call this device's _EJ0
-                * because we want the dock notify handler
-                * to call it after it calls _DCK
-                */
-               newfunc->flags &= ~FUNC_HAS_EJ0;
-               if (register_hotplug_dock_device(handle,
-                       &acpiphp_dock_ops, context,
-                       acpiphp_dock_init, acpiphp_dock_release))
-                       pr_debug("failed to register dock device\n");
-       }
-
-       /* install notify handler */
-       if (!(newfunc->flags & FUNC_HAS_DCK)) {
-               status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-                                                    handle_hotplug_event,
-                                                    context);
-               if (ACPI_FAILURE(status))
-                       acpi_handle_err(handle,
-                                       "failed to install notify handler\n");
-       }
-
        return AE_OK;
-
- err:
-       mutex_lock(&acpiphp_context_lock);
-       acpiphp_put_context(context);
-       mutex_unlock(&acpiphp_context_lock);
-       return status;
 }
 
-static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
+static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev)
 {
        struct acpiphp_context *context;
        struct acpiphp_bridge *bridge = NULL;
 
-       mutex_lock(&acpiphp_context_lock);
-       context = acpiphp_get_context(handle);
+       acpi_lock_hp_context();
+       context = acpiphp_get_context(adev);
        if (context) {
                bridge = context->bridge;
                if (bridge)
@@ -426,7 +386,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 
                acpiphp_put_context(context);
        }
-       mutex_unlock(&acpiphp_context_lock);
+       acpi_unlock_hp_context();
        return bridge;
 }
 
@@ -434,22 +394,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
 {
        struct acpiphp_slot *slot;
        struct acpiphp_func *func;
-       acpi_status status;
 
        list_for_each_entry(slot, &bridge->slots, node) {
                list_for_each_entry(func, &slot->funcs, sibling) {
-                       acpi_handle handle = func_to_handle(func);
-
-                       if (is_dock_device(handle))
-                               unregister_hotplug_dock_device(handle);
+                       struct acpi_device *adev = func_to_acpi_device(func);
 
-                       if (!(func->flags & FUNC_HAS_DCK)) {
-                               status = acpi_remove_notify_handler(handle,
-                                                       ACPI_SYSTEM_NOTIFY,
-                                                       handle_hotplug_event);
-                               if (ACPI_FAILURE(status))
-                                       pr_err("failed to remove notify handler\n");
-                       }
+                       acpi_lock_hp_context();
+                       adev->hp->notify = NULL;
+                       adev->hp->fixup = NULL;
+                       acpi_unlock_hp_context();
                }
                slot->flags |= SLOT_IS_GOING_AWAY;
                if (slot->slot)
@@ -460,9 +413,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
        list_del(&bridge->list);
        mutex_unlock(&bridge_mutex);
 
-       mutex_lock(&acpiphp_context_lock);
+       acpi_lock_hp_context();
        bridge->is_going_away = true;
-       mutex_unlock(&acpiphp_context_lock);
+       acpi_unlock_hp_context();
 }
 
 /**
@@ -471,7 +424,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
  */
 static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
 {
-       struct list_head *tmp;
+       struct pci_bus *tmp;
        unsigned char max, n;
 
        /*
@@ -484,41 +437,14 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
         */
        max = bus->busn_res.start;
 
-       list_for_each(tmp, &bus->children) {
-               n = pci_bus_max_busnr(pci_bus_b(tmp));
+       list_for_each_entry(tmp, &bus->children, node) {
+               n = pci_bus_max_busnr(tmp);
                if (n > max)
                        max = n;
        }
        return max;
 }
 
-/**
- * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
- * @handle: ACPI device object handle to start from.
- */
-static void acpiphp_bus_trim(acpi_handle handle)
-{
-       struct acpi_device *adev = NULL;
-
-       acpi_bus_get_device(handle, &adev);
-       if (adev)
-               acpi_bus_trim(adev);
-}
-
-/**
- * acpiphp_bus_add - Scan ACPI namespace subtree.
- * @handle: ACPI object handle to start the scan from.
- */
-static void acpiphp_bus_add(acpi_handle handle)
-{
-       struct acpi_device *adev = NULL;
-
-       acpi_bus_scan(handle);
-       acpi_bus_get_device(handle, &adev);
-       if (acpi_device_enumerated(adev))
-               acpi_device_set_power(adev, ACPI_STATE_D0);
-}
-
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
@@ -558,9 +484,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
 
-       list_for_each_entry(func, &slot->funcs, sibling)
-               acpiphp_bus_add(func_to_handle(func));
+       list_for_each_entry(func, &slot->funcs, sibling) {
+               struct acpi_device *adev = func_to_acpi_device(func);
 
+               acpi_bus_scan(adev->handle);
+               if (acpi_device_enumerated(adev))
+                       acpi_device_set_power(adev, ACPI_STATE_D0);
+       }
        return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
 }
 
@@ -625,32 +555,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
        }
 }
 
-/* return first device in slot, acquiring a reference on it */
-static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
-{
-       struct pci_bus *bus = slot->bus;
-       struct pci_dev *dev;
-       struct pci_dev *ret = NULL;
-
-       down_read(&pci_bus_sem);
-       list_for_each_entry(dev, &bus->devices, bus_list)
-               if (PCI_SLOT(dev->devfn) == slot->device) {
-                       ret = pci_dev_get(dev);
-                       break;
-               }
-       up_read(&pci_bus_sem);
-
-       return ret;
-}
-
 /**
  * disable_slot - disable a slot
  * @slot: ACPI PHP slot
  */
 static void disable_slot(struct acpiphp_slot *slot)
 {
+       struct pci_bus *bus = slot->bus;
+       struct pci_dev *dev, *prev;
        struct acpiphp_func *func;
-       struct pci_dev *pdev;
 
        /*
         * enable_slot() enumerates all functions in this device via
@@ -658,22 +571,18 @@ static void disable_slot(struct acpiphp_slot *slot)
         * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
         * here.
         */
-       while ((pdev = dev_in_slot(slot))) {
-               pci_stop_and_remove_bus_device(pdev);
-               pci_dev_put(pdev);
-       }
+       list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list)
+               if (PCI_SLOT(dev->devfn) == slot->device)
+                       pci_stop_and_remove_bus_device(dev);
 
        list_for_each_entry(func, &slot->funcs, sibling)
-               acpiphp_bus_trim(func_to_handle(func));
+               acpi_bus_trim(func_to_acpi_device(func));
 
        slot->flags &= (~SLOT_ENABLED);
 }
 
-static bool acpiphp_no_hotplug(acpi_handle handle)
+static bool acpiphp_no_hotplug(struct acpi_device *adev)
 {
-       struct acpi_device *adev = NULL;
-
-       acpi_bus_get_device(handle, &adev);
        return adev && adev->flags.no_hotplug;
 }
 
@@ -682,7 +591,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot)
        struct acpiphp_func *func;
 
        list_for_each_entry(func, &slot->funcs, sibling)
-               if (acpiphp_no_hotplug(func_to_handle(func)))
+               if (acpiphp_no_hotplug(func_to_acpi_device(func)))
                        return true;
 
        return false;
@@ -747,28 +656,25 @@ static inline bool device_status_valid(unsigned int sta)
  */
 static void trim_stale_devices(struct pci_dev *dev)
 {
-       acpi_handle handle = ACPI_HANDLE(&dev->dev);
+       struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
        struct pci_bus *bus = dev->subordinate;
        bool alive = false;
 
-       if (handle) {
+       if (adev) {
                acpi_status status;
                unsigned long long sta;
 
-               status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+               status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
                alive = (ACPI_SUCCESS(status) && device_status_valid(sta))
-                       || acpiphp_no_hotplug(handle);
+                       || acpiphp_no_hotplug(adev);
        }
-       if (!alive) {
-               u32 v;
+       if (!alive)
+               alive = pci_device_is_present(dev);
 
-               /* Check if the device responds. */
-               alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
-       }
        if (!alive) {
                pci_stop_and_remove_bus_device(dev);
-               if (handle)
-                       acpiphp_bus_trim(handle);
+               if (adev)
+                       acpi_bus_trim(adev);
        } else if (bus) {
                struct pci_dev *child, *tmp;
 
@@ -800,7 +706,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                struct pci_bus *bus = slot->bus;
                struct pci_dev *dev, *tmp;
 
-               mutex_lock(&slot->crit_sect);
                if (slot_no_hotplug(slot)) {
                        ; /* do nothing */
                } else if (device_status_valid(get_slot_status(slot))) {
@@ -815,7 +720,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                } else {
                        disable_slot(slot);
                }
-               mutex_unlock(&slot->crit_sect);
        }
 }
 
@@ -855,11 +759,11 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
  * ACPI event handlers
  */
 
-void acpiphp_check_host_bridge(acpi_handle handle)
+void acpiphp_check_host_bridge(struct acpi_device *adev)
 {
        struct acpiphp_bridge *bridge;
 
-       bridge = acpiphp_handle_to_bridge(handle);
+       bridge = acpiphp_dev_to_bridge(adev);
        if (bridge) {
                pci_lock_rescan_remove();
 
@@ -872,73 +776,52 @@ void acpiphp_check_host_bridge(acpi_handle handle)
 
 static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
 
-static void hotplug_event(acpi_handle handle, u32 type, void *data)
+static void hotplug_event(u32 type, struct acpiphp_context *context)
 {
-       struct acpiphp_context *context = data;
+       acpi_handle handle = context->hp.self->handle;
        struct acpiphp_func *func = &context->func;
+       struct acpiphp_slot *slot = func->slot;
        struct acpiphp_bridge *bridge;
-       char objname[64];
-       struct acpi_buffer buffer = { .length = sizeof(objname),
-                                     .pointer = objname };
 
-       mutex_lock(&acpiphp_context_lock);
+       acpi_lock_hp_context();
        bridge = context->bridge;
        if (bridge)
                get_bridge(bridge);
 
-       mutex_unlock(&acpiphp_context_lock);
+       acpi_unlock_hp_context();
 
        pci_lock_rescan_remove();
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
                /* bus re-enumerate */
-               pr_debug("%s: Bus check notify on %s\n", __func__, objname);
-               pr_debug("%s: re-enumerating slots under %s\n",
-                        __func__, objname);
-               if (bridge) {
+               acpi_handle_debug(handle, "Bus check in %s()\n", __func__);
+               if (bridge)
                        acpiphp_check_bridge(bridge);
-               } else {
-                       struct acpiphp_slot *slot = func->slot;
-
-                       if (slot->flags & SLOT_IS_GOING_AWAY)
-                               break;
-
-                       mutex_lock(&slot->crit_sect);
+               else if (!(slot->flags & SLOT_IS_GOING_AWAY))
                        enable_slot(slot);
-                       mutex_unlock(&slot->crit_sect);
-               }
+
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check */
-               pr_debug("%s: Device check notify on %s\n", __func__, objname);
+               acpi_handle_debug(handle, "Device check in %s()\n", __func__);
                if (bridge) {
                        acpiphp_check_bridge(bridge);
-               } else {
-                       struct acpiphp_slot *slot = func->slot;
-                       int ret;
-
-                       if (slot->flags & SLOT_IS_GOING_AWAY)
-                               break;
-
+               } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) {
                        /*
                         * Check if anything has changed in the slot and rescan
                         * from the parent if that's the case.
                         */
-                       mutex_lock(&slot->crit_sect);
-                       ret = acpiphp_rescan_slot(slot);
-                       mutex_unlock(&slot->crit_sect);
-                       if (ret)
+                       if (acpiphp_rescan_slot(slot))
                                acpiphp_check_bridge(func->parent);
                }
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
-               pr_debug("%s: Device eject notify on %s\n", __func__, objname);
-               acpiphp_disable_and_eject_slot(func->slot);
+               acpi_handle_debug(handle, "Eject request in %s()\n", __func__);
+               acpiphp_disable_and_eject_slot(slot);
                break;
        }
 
@@ -947,106 +830,41 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
                put_bridge(bridge);
 }
 
-static void hotplug_event_work(void *data, u32 type)
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type)
 {
-       struct acpiphp_context *context = data;
-       acpi_handle handle = context->handle;
-
-       acpi_scan_lock_acquire();
+       struct acpiphp_context *context;
 
-       hotplug_event(handle, type, context);
+       context = acpiphp_grab_context(adev);
+       if (!context)
+               return -ENODATA;
 
-       acpi_scan_lock_release();
-       acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
-       put_bridge(context->func.parent);
+       hotplug_event(type, context);
+       acpiphp_let_context_go(context);
+       return 0;
 }
 
 /**
- * handle_hotplug_event - handle ACPI hotplug event
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @data: pointer to acpiphp_context structure
+ * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus.
+ * @bus: PCI bus to enumerate the slots for.
  *
- * Handles ACPI event notification on slots.
- */
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
-{
-       struct acpiphp_context *context;
-       u32 ost_code = ACPI_OST_SC_SUCCESS;
-       acpi_status status;
-
-       switch (type) {
-       case ACPI_NOTIFY_BUS_CHECK:
-       case ACPI_NOTIFY_DEVICE_CHECK:
-               break;
-       case ACPI_NOTIFY_EJECT_REQUEST:
-               ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
-               acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-               break;
-
-       case ACPI_NOTIFY_DEVICE_WAKE:
-               return;
-
-       case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-               acpi_handle_err(handle, "Device cannot be configured due "
-                               "to a frequency mismatch\n");
-               goto out;
-
-       case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-               acpi_handle_err(handle, "Device cannot be configured due "
-                               "to a bus mode mismatch\n");
-               goto out;
-
-       case ACPI_NOTIFY_POWER_FAULT:
-               acpi_handle_err(handle, "Device has suffered a power fault\n");
-               goto out;
-
-       default:
-               acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
-               ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
-               goto out;
-       }
-
-       mutex_lock(&acpiphp_context_lock);
-       context = acpiphp_get_context(handle);
-       if (!context || WARN_ON(context->handle != handle)
-           || context->func.parent->is_going_away)
-               goto err_out;
-
-       get_bridge(context->func.parent);
-       acpiphp_put_context(context);
-       status = acpi_hotplug_execute(hotplug_event_work, context, type);
-       if (ACPI_SUCCESS(status)) {
-               mutex_unlock(&acpiphp_context_lock);
-               return;
-       }
-       put_bridge(context->func.parent);
-
- err_out:
-       mutex_unlock(&acpiphp_context_lock);
-       ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-
- out:
-       acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-}
-
-/*
- * Create hotplug slots for the PCI bus.
- * It should always return 0 to avoid skipping following notifiers.
+ * A "slot" is an object associated with a PCI device number.  All functions
+ * (PCI devices) with the same bus and device number belong to the same slot.
  */
 void acpiphp_enumerate_slots(struct pci_bus *bus)
 {
        struct acpiphp_bridge *bridge;
+       struct acpi_device *adev;
        acpi_handle handle;
        acpi_status status;
 
        if (acpiphp_disabled)
                return;
 
-       handle = ACPI_HANDLE(bus->bridge);
-       if (!handle)
+       adev = ACPI_COMPANION(bus->bridge);
+       if (!adev)
                return;
 
+       handle = adev->handle;
        bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
        if (!bridge) {
                acpi_handle_err(handle, "No memory for bridge object\n");
@@ -1074,10 +892,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
                 * parent is going to be handled by pciehp, in which case this
                 * bridge is not interesting to us either.
                 */
-               mutex_lock(&acpiphp_context_lock);
-               context = acpiphp_get_context(handle);
+               acpi_lock_hp_context();
+               context = acpiphp_get_context(adev);
                if (!context) {
-                       mutex_unlock(&acpiphp_context_lock);
+                       acpi_unlock_hp_context();
                        put_device(&bus->dev);
                        pci_dev_put(bridge->pci_dev);
                        kfree(bridge);
@@ -1087,17 +905,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
                context->bridge = bridge;
                /* Get a reference to the parent bridge. */
                get_bridge(context->func.parent);
-               mutex_unlock(&acpiphp_context_lock);
+               acpi_unlock_hp_context();
        }
 
-       /* must be added to the list prior to calling register_slot */
+       /* Must be added to the list prior to calling acpiphp_add_context(). */
        mutex_lock(&bridge_mutex);
        list_add(&bridge->list, &bridge_list);
        mutex_unlock(&bridge_mutex);
 
        /* register all slot objects under this bridge */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
-                                    register_slot, NULL, bridge, NULL);
+                                    acpiphp_add_context, NULL, bridge, NULL);
        if (ACPI_FAILURE(status)) {
                acpi_handle_err(handle, "failed to register slots\n");
                cleanup_bridge(bridge);
@@ -1105,7 +923,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
        }
 }
 
-/* Destroy hotplug slots associated with the PCI bus */
+/**
+ * acpiphp_remove_slots - Remove slot objects associated with a given bus.
+ * @bus: PCI bus to remove the slot objects for.
+ */
 void acpiphp_remove_slots(struct pci_bus *bus)
 {
        struct acpiphp_bridge *bridge;
@@ -1136,13 +957,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
        if (slot->flags & SLOT_IS_GOING_AWAY)
                return -ENODEV;
 
-       mutex_lock(&slot->crit_sect);
        /* configure all functions */
        if (!(slot->flags & SLOT_ENABLED))
                enable_slot(slot);
 
-       mutex_unlock(&slot->crit_sect);
-
        pci_unlock_rescan_remove();
        return 0;
 }
@@ -1158,8 +976,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
        if (slot->flags & SLOT_IS_GOING_AWAY)
                return -ENODEV;
 
-       mutex_lock(&slot->crit_sect);
-
        /* unconfigure all functions */
        disable_slot(slot);
 
@@ -1173,7 +989,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
                        break;
                }
 
-       mutex_unlock(&slot->crit_sect);
        return 0;
 }
 
@@ -1181,9 +996,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
 {
        int ret;
 
+       /*
+        * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in
+        * acpiphp_disable_and_eject_slot() will be synchronized properly.
+        */
+       acpi_scan_lock_acquire();
        pci_lock_rescan_remove();
        ret = acpiphp_disable_and_eject_slot(slot);
        pci_unlock_rescan_remove();
+       acpi_scan_lock_release();
        return ret;
 }
 
index 31273e155e6cd360946f068fe7268d13c7e41c27..037e2612c5bd036df0afb7a56c710439839cf31c 100644 (file)
@@ -920,12 +920,12 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                                bus->max_bus_speed = PCI_SPEED_100MHz_PCIX;
                                break;
                        }
-                       if (bus_cap & 20) {
+                       if (bus_cap & 0x20) {
                                dbg("bus max supports 66MHz PCI-X\n");
                                bus->max_bus_speed = PCI_SPEED_66MHz_PCIX;
                                break;
                        }
-                       if (bus_cap & 10) {
+                       if (bus_cap & 0x10) {
                                dbg("bus max supports 66MHz PCI\n");
                                bus->max_bus_speed = PCI_SPEED_66MHz;
                                break;
index 88b37cad4b35eed91fa48b8fbcecc569744f7a45..8a66866b8cf1ad799de42c2a15075f7549f0ca3a 100644 (file)
@@ -76,6 +76,7 @@ struct slot {
        struct hotplug_slot *hotplug_slot;
        struct delayed_work work;       /* work for button event */
        struct mutex lock;
+       struct mutex hotplug_lock;
        struct workqueue_struct *wq;
 };
 
@@ -109,6 +110,8 @@ struct controller {
 #define INT_BUTTON_PRESS               7
 #define INT_BUTTON_RELEASE             8
 #define INT_BUTTON_CANCEL              9
+#define INT_LINK_UP                    10
+#define INT_LINK_DOWN                  11
 
 #define STATIC_STATE                   0
 #define BLINKINGON_STATE               1
@@ -132,6 +135,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot);
 u8 pciehp_handle_switch_change(struct slot *p_slot);
 u8 pciehp_handle_presence_change(struct slot *p_slot);
 u8 pciehp_handle_power_fault(struct slot *p_slot);
+void pciehp_handle_linkstate_change(struct slot *p_slot);
 int pciehp_configure_device(struct slot *p_slot);
 int pciehp_unconfigure_device(struct slot *p_slot);
 void pciehp_queue_pushbutton_work(struct work_struct *work);
@@ -153,6 +157,7 @@ void pciehp_green_led_on(struct slot *slot);
 void pciehp_green_led_off(struct slot *slot);
 void pciehp_green_led_blink(struct slot *slot);
 int pciehp_check_link_status(struct controller *ctrl);
+bool pciehp_check_link_active(struct controller *ctrl);
 void pciehp_release_ctrl(struct controller *ctrl);
 int pciehp_reset_slot(struct slot *slot, int probe);
 
index eddddd447d0df61074d7a133524f37879ab73741..20fea57d2149c7ecf43e31c6ee16d820415ba85d 100644 (file)
@@ -112,6 +112,7 @@ static struct pcie_port_service_driver __initdata dummy_driver = {
 static int __init select_detection_mode(void)
 {
        struct dummy_slot *slot, *tmp;
+
        if (pcie_port_service_register(&dummy_driver))
                return PCIEHP_DETECT_ACPI;
        pcie_port_service_unregister(&dummy_driver);
index 53b58debc28804e02460e09344be754db435056a..0e0a2fff20a39be57f7c9abc8bb422831c771416 100644 (file)
@@ -108,6 +108,7 @@ static int init_slot(struct controller *ctrl)
        ops = kzalloc(sizeof(*ops), GFP_KERNEL);
        if (!ops)
                goto out;
+
        ops->enable_slot = enable_slot;
        ops->disable_slot = disable_slot;
        ops->get_power_status = get_power_status;
@@ -283,8 +284,11 @@ static int pciehp_probe(struct pcie_device *dev)
        slot = ctrl->slot;
        pciehp_get_adapter_status(slot, &occupied);
        pciehp_get_power_status(slot, &poweron);
-       if (occupied && pciehp_force)
+       if (occupied && pciehp_force) {
+               mutex_lock(&slot->hotplug_lock);
                pciehp_enable_slot(slot);
+               mutex_unlock(&slot->hotplug_lock);
+       }
        /* If empty slot's power status is on, turn power off */
        if (!occupied && poweron && POWER_CTRL(ctrl))
                pciehp_power_off_slot(slot);
@@ -328,10 +332,12 @@ static int pciehp_resume (struct pcie_device *dev)
 
        /* Check if slot is occupied */
        pciehp_get_adapter_status(slot, &status);
+       mutex_lock(&slot->hotplug_lock);
        if (status)
                pciehp_enable_slot(slot);
        else
                pciehp_disable_slot(slot);
+       mutex_unlock(&slot->hotplug_lock);
        return 0;
 }
 #endif /* PM */
index 50628487597deb2fe9de2b7499bc7dc253c7c388..c75e6a678dcc22f19707fc8d77200e1ee307afe6 100644 (file)
@@ -150,6 +150,27 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
        return 1;
 }
 
+void pciehp_handle_linkstate_change(struct slot *p_slot)
+{
+       u32 event_type;
+       struct controller *ctrl = p_slot->ctrl;
+
+       /* Link Status Change */
+       ctrl_dbg(ctrl, "Data Link Layer State change\n");
+
+       if (pciehp_check_link_active(ctrl)) {
+               ctrl_info(ctrl, "slot(%s): Link Up event\n",
+                         slot_name(p_slot));
+               event_type = INT_LINK_UP;
+       } else {
+               ctrl_info(ctrl, "slot(%s): Link Down event\n",
+                         slot_name(p_slot));
+               event_type = INT_LINK_DOWN;
+       }
+
+       queue_interrupt_event(p_slot, event_type);
+}
+
 /* The following routines constitute the bulk of the
    hotplug controller logic
  */
@@ -212,7 +233,8 @@ static int board_added(struct slot *p_slot)
        if (retval) {
                ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
                         pci_domain_nr(parent), parent->number);
-               goto err_exit;
+               if (retval != -EEXIST)
+                       goto err_exit;
        }
 
        pciehp_green_led_on(p_slot);
@@ -255,6 +277,9 @@ static int remove_board(struct slot *p_slot)
 struct power_work_info {
        struct slot *p_slot;
        struct work_struct work;
+       unsigned int req;
+#define DISABLE_REQ 0
+#define ENABLE_REQ  1
 };
 
 /**
@@ -269,30 +294,38 @@ static void pciehp_power_thread(struct work_struct *work)
        struct power_work_info *info =
                container_of(work, struct power_work_info, work);
        struct slot *p_slot = info->p_slot;
+       int ret;
 
-       mutex_lock(&p_slot->lock);
-       switch (p_slot->state) {
-       case POWEROFF_STATE:
-               mutex_unlock(&p_slot->lock);
+       switch (info->req) {
+       case DISABLE_REQ:
                ctrl_dbg(p_slot->ctrl,
                         "Disabling domain:bus:device=%04x:%02x:00\n",
                         pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
                         p_slot->ctrl->pcie->port->subordinate->number);
+               mutex_lock(&p_slot->hotplug_lock);
                pciehp_disable_slot(p_slot);
+               mutex_unlock(&p_slot->hotplug_lock);
                mutex_lock(&p_slot->lock);
                p_slot->state = STATIC_STATE;
-               break;
-       case POWERON_STATE:
                mutex_unlock(&p_slot->lock);
-               if (pciehp_enable_slot(p_slot))
+               break;
+       case ENABLE_REQ:
+               ctrl_dbg(p_slot->ctrl,
+                        "Enabling domain:bus:device=%04x:%02x:00\n",
+                        pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
+                        p_slot->ctrl->pcie->port->subordinate->number);
+               mutex_lock(&p_slot->hotplug_lock);
+               ret = pciehp_enable_slot(p_slot);
+               mutex_unlock(&p_slot->hotplug_lock);
+               if (ret)
                        pciehp_green_led_off(p_slot);
                mutex_lock(&p_slot->lock);
                p_slot->state = STATIC_STATE;
+               mutex_unlock(&p_slot->lock);
                break;
        default:
                break;
        }
-       mutex_unlock(&p_slot->lock);
 
        kfree(info);
 }
@@ -315,9 +348,11 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
        switch (p_slot->state) {
        case BLINKINGOFF_STATE:
                p_slot->state = POWEROFF_STATE;
+               info->req = DISABLE_REQ;
                break;
        case BLINKINGON_STATE:
                p_slot->state = POWERON_STATE;
+               info->req = ENABLE_REQ;
                break;
        default:
                kfree(info);
@@ -364,11 +399,10 @@ static void handle_button_press_event(struct slot *p_slot)
                 */
                ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
                cancel_delayed_work(&p_slot->work);
-               if (p_slot->state == BLINKINGOFF_STATE) {
+               if (p_slot->state == BLINKINGOFF_STATE)
                        pciehp_green_led_on(p_slot);
-               } else {
+               else
                        pciehp_green_led_off(p_slot);
-               }
                pciehp_set_attention_status(p_slot, 0);
                ctrl_info(ctrl, "PCI slot #%s - action canceled "
                          "due to button press\n", slot_name(p_slot));
@@ -407,14 +441,81 @@ static void handle_surprise_event(struct slot *p_slot)
        INIT_WORK(&info->work, pciehp_power_thread);
 
        pciehp_get_adapter_status(p_slot, &getstatus);
-       if (!getstatus)
+       if (!getstatus) {
                p_slot->state = POWEROFF_STATE;
-       else
+               info->req = DISABLE_REQ;
+       } else {
                p_slot->state = POWERON_STATE;
+               info->req = ENABLE_REQ;
+       }
 
        queue_work(p_slot->wq, &info->work);
 }
 
+/*
+ * Note: This function must be called with slot->lock held
+ */
+static void handle_link_event(struct slot *p_slot, u32 event)
+{
+       struct controller *ctrl = p_slot->ctrl;
+       struct power_work_info *info;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
+                        __func__);
+               return;
+       }
+       info->p_slot = p_slot;
+       info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
+       INIT_WORK(&info->work, pciehp_power_thread);
+
+       switch (p_slot->state) {
+       case BLINKINGON_STATE:
+       case BLINKINGOFF_STATE:
+               cancel_delayed_work(&p_slot->work);
+               /* Fall through */
+       case STATIC_STATE:
+               p_slot->state = event == INT_LINK_UP ?
+                   POWERON_STATE : POWEROFF_STATE;
+               queue_work(p_slot->wq, &info->work);
+               break;
+       case POWERON_STATE:
+               if (event == INT_LINK_UP) {
+                       ctrl_info(ctrl,
+                                 "Link Up event ignored on slot(%s): already powering on\n",
+                                 slot_name(p_slot));
+                       kfree(info);
+               } else {
+                       ctrl_info(ctrl,
+                                 "Link Down event queued on slot(%s): currently getting powered on\n",
+                                 slot_name(p_slot));
+                       p_slot->state = POWEROFF_STATE;
+                       queue_work(p_slot->wq, &info->work);
+               }
+               break;
+       case POWEROFF_STATE:
+               if (event == INT_LINK_UP) {
+                       ctrl_info(ctrl,
+                                 "Link Up event queued on slot(%s): currently getting powered off\n",
+                                 slot_name(p_slot));
+                       p_slot->state = POWERON_STATE;
+                       queue_work(p_slot->wq, &info->work);
+               } else {
+                       ctrl_info(ctrl,
+                                 "Link Down event ignored on slot(%s): already powering off\n",
+                                 slot_name(p_slot));
+                       kfree(info);
+               }
+               break;
+       default:
+               ctrl_err(ctrl, "Not a valid state on slot(%s)\n",
+                        slot_name(p_slot));
+               kfree(info);
+               break;
+       }
+}
+
 static void interrupt_event_handler(struct work_struct *work)
 {
        struct event_info *info = container_of(work, struct event_info, work);
@@ -433,12 +534,23 @@ static void interrupt_event_handler(struct work_struct *work)
                pciehp_green_led_off(p_slot);
                break;
        case INT_PRESENCE_ON:
-       case INT_PRESENCE_OFF:
                if (!HP_SUPR_RM(ctrl))
                        break;
+               ctrl_dbg(ctrl, "Surprise Insertion\n");
+               handle_surprise_event(p_slot);
+               break;
+       case INT_PRESENCE_OFF:
+               /*
+                * Regardless of surprise capability, we need to
+                * definitely remove a card that has been pulled out!
+                */
                ctrl_dbg(ctrl, "Surprise Removal\n");
                handle_surprise_event(p_slot);
                break;
+       case INT_LINK_UP:
+       case INT_LINK_DOWN:
+               handle_link_event(p_slot, info->event_type);
+               break;
        default:
                break;
        }
@@ -447,6 +559,9 @@ static void interrupt_event_handler(struct work_struct *work)
        kfree(info);
 }
 
+/*
+ * Note: This function must be called with slot->hotplug_lock held
+ */
 int pciehp_enable_slot(struct slot *p_slot)
 {
        u8 getstatus = 0;
@@ -479,13 +594,15 @@ int pciehp_enable_slot(struct slot *p_slot)
        pciehp_get_latch_status(p_slot, &getstatus);
 
        rc = board_added(p_slot);
-       if (rc) {
+       if (rc)
                pciehp_get_latch_status(p_slot, &getstatus);
-       }
+
        return rc;
 }
 
-
+/*
+ * Note: This function must be called with slot->hotplug_lock held
+ */
 int pciehp_disable_slot(struct slot *p_slot)
 {
        u8 getstatus = 0;
@@ -494,24 +611,6 @@ int pciehp_disable_slot(struct slot *p_slot)
        if (!p_slot->ctrl)
                return 1;
 
-       if (!HP_SUPR_RM(p_slot->ctrl)) {
-               pciehp_get_adapter_status(p_slot, &getstatus);
-               if (!getstatus) {
-                       ctrl_info(ctrl, "No adapter on slot(%s)\n",
-                                 slot_name(p_slot));
-                       return -ENODEV;
-               }
-       }
-
-       if (MRL_SENS(p_slot->ctrl)) {
-               pciehp_get_latch_status(p_slot, &getstatus);
-               if (getstatus) {
-                       ctrl_info(ctrl, "Latch open on slot(%s)\n",
-                                 slot_name(p_slot));
-                       return -ENODEV;
-               }
-       }
-
        if (POWER_CTRL(p_slot->ctrl)) {
                pciehp_get_power_status(p_slot, &getstatus);
                if (!getstatus) {
@@ -536,7 +635,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
        case STATIC_STATE:
                p_slot->state = POWERON_STATE;
                mutex_unlock(&p_slot->lock);
+               mutex_lock(&p_slot->hotplug_lock);
                retval = pciehp_enable_slot(p_slot);
+               mutex_unlock(&p_slot->hotplug_lock);
                mutex_lock(&p_slot->lock);
                p_slot->state = STATIC_STATE;
                break;
index 14acfccb767072bb58b00417413afb55747ac0e5..d7d058fa19a428e5503c919979e5a6e1e5e5e0b2 100644 (file)
@@ -206,7 +206,7 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
        mutex_unlock(&ctrl->ctrl_lock);
 }
 
-static bool check_link_active(struct controller *ctrl)
+bool pciehp_check_link_active(struct controller *ctrl)
 {
        struct pci_dev *pdev = ctrl_dev(ctrl);
        u16 lnk_status;
@@ -225,12 +225,12 @@ static void __pcie_wait_link_active(struct controller *ctrl, bool active)
 {
        int timeout = 1000;
 
-       if (check_link_active(ctrl) == active)
+       if (pciehp_check_link_active(ctrl) == active)
                return;
        while (timeout > 0) {
                msleep(10);
                timeout -= 10;
-               if (check_link_active(ctrl) == active)
+               if (pciehp_check_link_active(ctrl) == active)
                        return;
        }
        ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
@@ -242,11 +242,6 @@ static void pcie_wait_link_active(struct controller *ctrl)
        __pcie_wait_link_active(ctrl, true);
 }
 
-static void pcie_wait_link_not_active(struct controller *ctrl)
-{
-       __pcie_wait_link_active(ctrl, false);
-}
-
 static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
 {
        u32 l;
@@ -332,11 +327,6 @@ static int pciehp_link_enable(struct controller *ctrl)
        return __pciehp_link_set(ctrl, true);
 }
 
-static int pciehp_link_disable(struct controller *ctrl)
-{
-       return __pciehp_link_set(ctrl, false);
-}
-
 void pciehp_get_attention_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
@@ -508,14 +498,6 @@ void pciehp_power_off_slot(struct slot * slot)
 {
        struct controller *ctrl = slot->ctrl;
 
-       /* Disable the link at first */
-       pciehp_link_disable(ctrl);
-       /* wait the link is down */
-       if (ctrl->link_active_reporting)
-               pcie_wait_link_not_active(ctrl);
-       else
-               msleep(1000);
-
        pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
        ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
                 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
@@ -540,7 +522,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
 
                detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
                             PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
-                            PCI_EXP_SLTSTA_CC);
+                            PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
                detected &= ~intr_loc;
                intr_loc |= detected;
                if (!intr_loc)
@@ -579,6 +561,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                ctrl->power_fault_detected = 1;
                pciehp_handle_power_fault(slot);
        }
+
+       if (intr_loc & PCI_EXP_SLTSTA_DLLSC)
+               pciehp_handle_linkstate_change(slot);
+
        return IRQ_HANDLED;
 }
 
@@ -596,9 +582,17 @@ void pcie_enable_notification(struct controller *ctrl)
         * when it is cleared in the interrupt service routine, and
         * next power fault detected interrupt was notified again.
         */
-       cmd = PCI_EXP_SLTCTL_PDCE;
+
+       /*
+        * Always enable link events: thus link-up and link-down shall
+        * always be treated as hotplug and unplug respectively. Enable
+        * presence detect only if Attention Button is not present.
+        */
+       cmd = PCI_EXP_SLTCTL_DLLSCE;
        if (ATTN_BUTTN(ctrl))
                cmd |= PCI_EXP_SLTCTL_ABPE;
+       else
+               cmd |= PCI_EXP_SLTCTL_PDCE;
        if (MRL_SENS(ctrl))
                cmd |= PCI_EXP_SLTCTL_MRLSCE;
        if (!pciehp_poll_mode)
@@ -606,7 +600,8 @@ void pcie_enable_notification(struct controller *ctrl)
 
        mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
                PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
-               PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
+               PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
+               PCI_EXP_SLTCTL_DLLSCE);
 
        pcie_write_cmd(ctrl, cmd, mask);
 }
@@ -624,33 +619,38 @@ static void pcie_disable_notification(struct controller *ctrl)
 
 /*
  * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
- * bus reset of the bridge, but if the slot supports surprise removal we need
- * to disable presence detection around the bus reset and clear any spurious
+ * bus reset of the bridge, but at the same time we want to ensure that it is
+ * not seen as a hot-unplug, followed by the hot-plug of the device. Thus,
+ * disable link state notification and presence detection change notification
+ * momentarily, if we see that they could interfere. Also, clear any spurious
  * events after.
  */
 int pciehp_reset_slot(struct slot *slot, int probe)
 {
        struct controller *ctrl = slot->ctrl;
        struct pci_dev *pdev = ctrl_dev(ctrl);
+       u16 stat_mask = 0, ctrl_mask = 0;
 
        if (probe)
                return 0;
 
-       if (HP_SUPR_RM(ctrl)) {
-               pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
-               if (pciehp_poll_mode)
-                       del_timer_sync(&ctrl->poll_timer);
+       if (!ATTN_BUTTN(ctrl)) {
+               ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
+               stat_mask |= PCI_EXP_SLTSTA_PDC;
        }
+       ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
+       stat_mask |= PCI_EXP_SLTSTA_DLLSC;
+
+       pcie_write_cmd(ctrl, 0, ctrl_mask);
+       if (pciehp_poll_mode)
+               del_timer_sync(&ctrl->poll_timer);
 
        pci_reset_bridge_secondary_bus(ctrl->pcie->port);
 
-       if (HP_SUPR_RM(ctrl)) {
-               pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
-                                          PCI_EXP_SLTSTA_PDC);
-               pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
-               if (pciehp_poll_mode)
-                       int_poll_timeout(ctrl->poll_timer.data);
-       }
+       pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
+       pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask);
+       if (pciehp_poll_mode)
+               int_poll_timeout(ctrl->poll_timer.data);
 
        return 0;
 }
@@ -687,6 +687,7 @@ static int pcie_init_slot(struct controller *ctrl)
 
        slot->ctrl = ctrl;
        mutex_init(&slot->lock);
+       mutex_init(&slot->hotplug_lock);
        INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
        ctrl->slot = slot;
        return 0;
index b07d7cc2d697e8c9ce9152eaca90980e90906015..1b533060ce650778bbdc74e2a676d333c9afe7d7 100644 (file)
@@ -50,7 +50,7 @@ int pciehp_configure_device(struct slot *p_slot)
                         "at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
                         pci_domain_nr(parent), parent->number);
                pci_dev_put(dev);
-               ret = -EINVAL;
+               ret = -EEXIST;
                goto out;
        }
 
index 9dce7c5e2a772231b5a33e480d8888452507efbf..de7a74782f929234d808aef1abac26097f1abfe3 100644 (file)
@@ -170,97 +170,6 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
        pci_dev_put(dev);
 }
 
-static int sriov_migration(struct pci_dev *dev)
-{
-       u16 status;
-       struct pci_sriov *iov = dev->sriov;
-
-       if (!iov->num_VFs)
-               return 0;
-
-       if (!(iov->cap & PCI_SRIOV_CAP_VFM))
-               return 0;
-
-       pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status);
-       if (!(status & PCI_SRIOV_STATUS_VFM))
-               return 0;
-
-       schedule_work(&iov->mtask);
-
-       return 1;
-}
-
-static void sriov_migration_task(struct work_struct *work)
-{
-       int i;
-       u8 state;
-       u16 status;
-       struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask);
-
-       for (i = iov->initial_VFs; i < iov->num_VFs; i++) {
-               state = readb(iov->mstate + i);
-               if (state == PCI_SRIOV_VFM_MI) {
-                       writeb(PCI_SRIOV_VFM_AV, iov->mstate + i);
-                       state = readb(iov->mstate + i);
-                       if (state == PCI_SRIOV_VFM_AV)
-                               virtfn_add(iov->self, i, 1);
-               } else if (state == PCI_SRIOV_VFM_MO) {
-                       virtfn_remove(iov->self, i, 1);
-                       writeb(PCI_SRIOV_VFM_UA, iov->mstate + i);
-                       state = readb(iov->mstate + i);
-                       if (state == PCI_SRIOV_VFM_AV)
-                               virtfn_add(iov->self, i, 0);
-               }
-       }
-
-       pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status);
-       status &= ~PCI_SRIOV_STATUS_VFM;
-       pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status);
-}
-
-static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn)
-{
-       int bir;
-       u32 table;
-       resource_size_t pa;
-       struct pci_sriov *iov = dev->sriov;
-
-       if (nr_virtfn <= iov->initial_VFs)
-               return 0;
-
-       pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table);
-       bir = PCI_SRIOV_VFM_BIR(table);
-       if (bir > PCI_STD_RESOURCE_END)
-               return -EIO;
-
-       table = PCI_SRIOV_VFM_OFFSET(table);
-       if (table + nr_virtfn > pci_resource_len(dev, bir))
-               return -EIO;
-
-       pa = pci_resource_start(dev, bir) + table;
-       iov->mstate = ioremap(pa, nr_virtfn);
-       if (!iov->mstate)
-               return -ENOMEM;
-
-       INIT_WORK(&iov->mtask, sriov_migration_task);
-
-       iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR;
-       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-
-       return 0;
-}
-
-static void sriov_disable_migration(struct pci_dev *dev)
-{
-       struct pci_sriov *iov = dev->sriov;
-
-       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR);
-       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-
-       cancel_work_sync(&iov->mtask);
-       iounmap(iov->mstate);
-}
-
 static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 {
        int rc;
@@ -351,12 +260,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
                        goto failed;
        }
 
-       if (iov->cap & PCI_SRIOV_CAP_VFM) {
-               rc = sriov_enable_migration(dev, nr_virtfn);
-               if (rc)
-                       goto failed;
-       }
-
        kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
        iov->num_VFs = nr_virtfn;
 
@@ -387,9 +290,6 @@ static void sriov_disable(struct pci_dev *dev)
        if (!iov->num_VFs)
                return;
 
-       if (iov->cap & PCI_SRIOV_CAP_VFM)
-               sriov_disable_migration(dev);
-
        for (i = 0; i < iov->num_VFs; i++)
                virtfn_remove(dev, i, 0);
 
@@ -687,25 +587,6 @@ void pci_disable_sriov(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_disable_sriov);
 
-/**
- * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration
- * @dev: the PCI device
- *
- * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not.
- *
- * Physical Function driver is responsible to register IRQ handler using
- * VF Migration Interrupt Message Number, and call this function when the
- * interrupt is generated by the hardware.
- */
-irqreturn_t pci_sriov_migration(struct pci_dev *dev)
-{
-       if (!dev->is_physfn)
-               return IRQ_NONE;
-
-       return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE;
-}
-EXPORT_SYMBOL_GPL(pci_sriov_migration);
-
 /**
  * pci_num_vf - return number of VFs associated with a PF device_release_driver
  * @dev: the PCI device
index 25f0bc6591645707bb3b452bbaa4c28bee0efc59..d911e0c1f359799ef4f110b59b2f68516868d153 100644 (file)
@@ -616,15 +616,11 @@ static int pci_pm_prepare(struct device *dev)
        int error = 0;
 
        /*
-        * PCI devices suspended at run time need to be resumed at this
-        * point, because in general it is necessary to reconfigure them for
-        * system suspend.  Namely, if the device is supposed to wake up the
-        * system from the sleep state, we may need to reconfigure it for this
-        * purpose.  In turn, if the device is not supposed to wake up the
-        * system from the sleep state, we'll have to prevent it from signaling
-        * wake-up.
+        * Devices having power.ignore_children set may still be necessary for
+        * suspending their children in the next phase of device suspend.
         */
-       pm_runtime_resume(dev);
+       if (dev->power.ignore_children)
+               pm_runtime_resume(dev);
 
        if (drv && drv->pm && drv->pm->prepare)
                error = drv->pm->prepare(dev);
@@ -654,6 +650,16 @@ static int pci_pm_suspend(struct device *dev)
                goto Fixup;
        }
 
+       /*
+        * PCI devices suspended at run time need to be resumed at this point,
+        * because in general it is necessary to reconfigure them for system
+        * suspend.  Namely, if the device is supposed to wake up the system
+        * from the sleep state, we may need to reconfigure it for this purpose.
+        * In turn, if the device is not supposed to wake up the system from the
+        * sleep state, we'll have to prevent it from signaling wake-up.
+        */
+       pm_runtime_resume(dev);
+
        pci_dev->state_saved = false;
        if (pm->suspend) {
                pci_power_t prev = pci_dev->current_state;
@@ -808,6 +814,14 @@ static int pci_pm_freeze(struct device *dev)
                return 0;
        }
 
+       /*
+        * This used to be done in pci_pm_prepare() for all devices and some
+        * drivers may depend on it, so do it here.  Ideally, runtime-suspended
+        * devices should not be touched during freeze/thaw transitions,
+        * however.
+        */
+       pm_runtime_resume(dev);
+
        pci_dev->state_saved = false;
        if (pm->freeze) {
                int error;
@@ -915,6 +929,9 @@ static int pci_pm_poweroff(struct device *dev)
                goto Fixup;
        }
 
+       /* The reason to do that is the same as in pci_pm_suspend(). */
+       pm_runtime_resume(dev);
+
        pci_dev->state_saved = false;
        if (pm->poweroff) {
                int error;
index 6b05f6134b68700dc1450b249b1f9bfe7b43bdca..7325d43bf030ce65d5f386f6aeeeb3bfa4d5c482 100644 (file)
@@ -108,12 +108,12 @@ static bool pcie_ari_disabled;
  */
 unsigned char pci_bus_max_busnr(struct pci_bus* bus)
 {
-       struct list_head *tmp;
+       struct pci_bus *tmp;
        unsigned char max, n;
 
        max = bus->busn_res.end;
-       list_for_each(tmp, &bus->children) {
-               n = pci_bus_max_busnr(pci_bus_b(tmp));
+       list_for_each_entry(tmp, &bus->children, node) {
+               n = pci_bus_max_busnr(tmp);
                if(n > max)
                        max = n;
        }
@@ -401,33 +401,40 @@ EXPORT_SYMBOL_GPL(pci_find_ht_capability);
  * @res: child resource record for which parent is sought
  *
  *  For given resource region of given device, return the resource
- *  region of parent bus the given region is contained in or where
- *  it should be allocated from.
+ *  region of parent bus the given region is contained in.
  */
 struct resource *
 pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
 {
        const struct pci_bus *bus = dev->bus;
+       struct resource *r;
        int i;
-       struct resource *best = NULL, *r;
 
        pci_bus_for_each_resource(bus, r, i) {
                if (!r)
                        continue;
-               if (res->start && !(res->start >= r->start && res->end <= r->end))
-                       continue;       /* Not contained */
-               if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
-                       continue;       /* Wrong type */
-               if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
-                       return r;       /* Exact match */
-               /* We can't insert a non-prefetch resource inside a prefetchable parent .. */
-               if (r->flags & IORESOURCE_PREFETCH)
-                       continue;
-               /* .. but we can put a prefetchable resource inside a non-prefetchable one */
-               if (!best)
-                       best = r;
+               if (res->start && resource_contains(r, res)) {
+
+                       /*
+                        * If the window is prefetchable but the BAR is
+                        * not, the allocator made a mistake.
+                        */
+                       if (r->flags & IORESOURCE_PREFETCH &&
+                           !(res->flags & IORESOURCE_PREFETCH))
+                               return NULL;
+
+                       /*
+                        * If we're below a transparent bridge, there may
+                        * be both a positively-decoded aperture and a
+                        * subtractively-decoded region that contain the BAR.
+                        * We want the positively-decoded one, so this depends
+                        * on pci_bus_for_each_resource() giving us those
+                        * first.
+                        */
+                       return r;
+               }
        }
-       return best;
+       return NULL;
 }
 
 /**
@@ -1178,6 +1185,11 @@ int pci_load_and_free_saved_state(struct pci_dev *dev,
 }
 EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
 
+int __weak pcibios_enable_device(struct pci_dev *dev, int bars)
+{
+       return pci_enable_resources(dev, bars);
+}
+
 static int do_pci_enable_device(struct pci_dev *dev, int bars)
 {
        int err;
@@ -1192,6 +1204,9 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
                return err;
        pci_fixup_device(pci_fixup_enable, dev);
 
+       if (dev->msi_enabled || dev->msix_enabled)
+               return 0;
+
        pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
        if (pin) {
                pci_read_config_word(dev, PCI_COMMAND, &cmd);
@@ -1621,29 +1636,27 @@ static void pci_pme_list_scan(struct work_struct *work)
        struct pci_pme_device *pme_dev, *n;
 
        mutex_lock(&pci_pme_list_mutex);
-       if (!list_empty(&pci_pme_list)) {
-               list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
-                       if (pme_dev->dev->pme_poll) {
-                               struct pci_dev *bridge;
-
-                               bridge = pme_dev->dev->bus->self;
-                               /*
-                                * If bridge is in low power state, the
-                                * configuration space of subordinate devices
-                                * may be not accessible
-                                */
-                               if (bridge && bridge->current_state != PCI_D0)
-                                       continue;
-                               pci_pme_wakeup(pme_dev->dev, NULL);
-                       } else {
-                               list_del(&pme_dev->list);
-                               kfree(pme_dev);
-                       }
+       list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
+               if (pme_dev->dev->pme_poll) {
+                       struct pci_dev *bridge;
+
+                       bridge = pme_dev->dev->bus->self;
+                       /*
+                        * If bridge is in low power state, the
+                        * configuration space of subordinate devices
+                        * may be not accessible
+                        */
+                       if (bridge && bridge->current_state != PCI_D0)
+                               continue;
+                       pci_pme_wakeup(pme_dev->dev, NULL);
+               } else {
+                       list_del(&pme_dev->list);
+                       kfree(pme_dev);
                }
-               if (!list_empty(&pci_pme_list))
-                       schedule_delayed_work(&pci_pme_work,
-                                             msecs_to_jiffies(PME_TIMEOUT));
        }
+       if (!list_empty(&pci_pme_list))
+               schedule_delayed_work(&pci_pme_work,
+                                     msecs_to_jiffies(PME_TIMEOUT));
        mutex_unlock(&pci_pme_list_mutex);
 }
 
@@ -2190,21 +2203,18 @@ void pci_request_acs(void)
 }
 
 /**
- * pci_enable_acs - enable ACS if hardware support it
+ * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
  * @dev: the PCI device
  */
-void pci_enable_acs(struct pci_dev *dev)
+static int pci_std_enable_acs(struct pci_dev *dev)
 {
        int pos;
        u16 cap;
        u16 ctrl;
 
-       if (!pci_acs_enable)
-               return;
-
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
        if (!pos)
-               return;
+               return -ENODEV;
 
        pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
        pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
@@ -2222,6 +2232,23 @@ void pci_enable_acs(struct pci_dev *dev)
        ctrl |= (cap & PCI_ACS_UF);
 
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+
+       return 0;
+}
+
+/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+void pci_enable_acs(struct pci_dev *dev)
+{
+       if (!pci_acs_enable)
+               return;
+
+       if (!pci_std_enable_acs(dev))
+               return;
+
+       pci_dev_specific_enable_acs(dev);
 }
 
 static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
@@ -4247,6 +4274,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
                                "Rounding up size of resource #%d to %#llx.\n",
                                i, (unsigned long long)size);
                }
+               r->flags |= IORESOURCE_UNSET;
                r->end = size - 1;
                r->start = 0;
        }
@@ -4260,6 +4288,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
                        r = &dev->resource[i];
                        if (!(r->flags & IORESOURCE_MEM))
                                continue;
+                       r->flags |= IORESOURCE_UNSET;
                        r->end = resource_size(r) - 1;
                        r->start = 0;
                }
index 4df38df224f4d3e61f53a5519ad55d9b2053a567..6bd082299e3190b5676e49d781231f49e5eaa3fc 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef DRIVERS_PCI_H
 #define DRIVERS_PCI_H
 
-#include <linux/workqueue.h>
-
 #define PCI_CFG_SPACE_SIZE     256
 #define PCI_CFG_SPACE_EXP_SIZE 4096
 
@@ -240,8 +238,6 @@ struct pci_sriov {
        struct pci_dev *dev;    /* lowest numbered PF */
        struct pci_dev *self;   /* this PF */
        struct mutex lock;      /* lock for VF bus */
-       struct work_struct mtask; /* VF Migration task */
-       u8 __iomem *mstate;     /* VF Migration State Array */
 };
 
 #ifdef CONFIG_PCI_ATS
index 6e34498ec9f0269387c296e498174ccb29cbe3fb..ef09f5f2fe6c0bc7f0ba84ae06eaa9d46adea4e6 100644 (file)
@@ -252,6 +252,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        /* Address above 32-bit boundary; disable the BAR */
                        pci_write_config_dword(dev, pos, 0);
                        pci_write_config_dword(dev, pos + 4, 0);
+                       res->flags |= IORESOURCE_UNSET;
                        region.start = 0;
                        region.end = sz64;
                        bar_disabled = true;
@@ -731,22 +732,6 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de
        return child;
 }
 
-static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
-{
-       struct pci_bus *parent = child->parent;
-
-       /* Attempts to fix that up are really dangerous unless
-          we're going to re-assign all bus numbers. */
-       if (!pcibios_assign_all_busses())
-               return;
-
-       while (parent->parent && parent->busn_res.end < max) {
-               parent->busn_res.end = max;
-               pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
-               parent = parent->parent;
-       }
-}
-
 /*
  * If it's a bridge, configure it and scan the bus behind it.
  * For CardBus bridges, we don't scan behind as the devices will
@@ -782,7 +767,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
        /* Check if setup is sensible at all */
        if (!pass &&
            (primary != bus->number || secondary <= bus->number ||
-            secondary > subordinate)) {
+            secondary > subordinate || subordinate > bus->busn_res.end)) {
                dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
                         secondary, subordinate);
                broken = 1;
@@ -805,11 +790,10 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
                        goto out;
 
                /*
-                * If we already got to this bus through a different bridge,
-                * don't re-add it. This can happen with the i450NX chipset.
-                *
-                * However, we continue to descend down the hierarchy and
-                * scan remaining child buses.
+                * The bus might already exist for two reasons: Either we are
+                * rescanning the bus or the bus is reachable through more than
+                * one bridge. The second case can happen with the i450NX
+                * chipset.
                 */
                child = pci_find_bus(pci_domain_nr(bus), secondary);
                if (!child) {
@@ -822,17 +806,19 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
                }
 
                cmax = pci_scan_child_bus(child);
-               if (cmax > max)
-                       max = cmax;
-               if (child->busn_res.end > max)
-                       max = child->busn_res.end;
+               if (cmax > subordinate)
+                       dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n",
+                                subordinate, cmax);
+               /* subordinate should equal child->busn_res.end */
+               if (subordinate > max)
+                       max = subordinate;
        } else {
                /*
                 * We need to assign a number to this bus which we always
                 * do in the second pass.
                 */
                if (!pass) {
-                       if (pcibios_assign_all_busses() || broken)
+                       if (pcibios_assign_all_busses() || broken || is_cardbus)
                                /* Temporarily disable forwarding of the
                                   configuration cycles on all bridges in
                                   this bus segment to avoid possible
@@ -844,19 +830,25 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
                        goto out;
                }
 
+               if (max >= bus->busn_res.end) {
+                       dev_warn(&dev->dev, "can't allocate child bus %02x from %pR\n",
+                                max, &bus->busn_res);
+                       goto out;
+               }
+
                /* Clear errors */
                pci_write_config_word(dev, PCI_STATUS, 0xffff);
 
-               /* Prevent assigning a bus number that already exists.
-                * This can happen when a bridge is hot-plugged, so in
-                * this case we only re-scan this bus. */
+               /* The bus will already exist if we are rescanning */
                child = pci_find_bus(pci_domain_nr(bus), max+1);
                if (!child) {
-                       child = pci_add_new_bus(bus, dev, ++max);
+                       child = pci_add_new_bus(bus, dev, max+1);
                        if (!child)
                                goto out;
-                       pci_bus_insert_busn_res(child, max, 0xff);
+                       pci_bus_insert_busn_res(child, max+1,
+                                               bus->busn_res.end);
                }
+               max++;
                buses = (buses & 0xff000000)
                      | ((unsigned int)(child->primary)     <<  0)
                      | ((unsigned int)(child->busn_res.start)   <<  8)
@@ -878,20 +870,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 
                if (!is_cardbus) {
                        child->bridge_ctl = bctl;
-                       /*
-                        * Adjust subordinate busnr in parent buses.
-                        * We do this before scanning for children because
-                        * some devices may not be detected if the bios
-                        * was lazy.
-                        */
-                       pci_fixup_parent_subordinate_busnr(child, max);
-                       /* Now we can scan all subordinate buses... */
                        max = pci_scan_child_bus(child);
-                       /*
-                        * now fix it up again since we have found
-                        * the real value of max.
-                        */
-                       pci_fixup_parent_subordinate_busnr(child, max);
                } else {
                        /*
                         * For CardBus bridges, we leave 4 bus numbers
@@ -922,11 +901,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
                                }
                        }
                        max += i;
-                       pci_fixup_parent_subordinate_busnr(child, max);
                }
                /*
                 * Set the subordinate bus number to its real value.
                 */
+               if (max > bus->busn_res.end) {
+                       dev_warn(&dev->dev, "max busn %02x is outside %pR\n",
+                                max, &bus->busn_res);
+                       max = bus->busn_res.end;
+               }
                pci_bus_update_busn_res_end(child, max);
                pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
        }
@@ -1125,10 +1108,10 @@ int pci_setup_device(struct pci_dev *dev)
                pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
 
                /*
-                *      Do the ugly legacy mode stuff here rather than broken chip
-                *      quirk code. Legacy mode ATA controllers have fixed
-                *      addresses. These are not always echoed in BAR0-3, and
-                *      BAR0-3 in a few cases contain junk!
+                * Do the ugly legacy mode stuff here rather than broken chip
+                * quirk code. Legacy mode ATA controllers have fixed
+                * addresses. These are not always echoed in BAR0-3, and
+                * BAR0-3 in a few cases contain junk!
                 */
                if (class == PCI_CLASS_STORAGE_IDE) {
                        u8 progif;
@@ -1139,11 +1122,15 @@ int pci_setup_device(struct pci_dev *dev)
                                res = &dev->resource[0];
                                res->flags = LEGACY_IO_RESOURCE;
                                pcibios_bus_to_resource(dev->bus, res, &region);
+                               dev_info(&dev->dev, "legacy IDE quirk: reg 0x10: %pR\n",
+                                        res);
                                region.start = 0x3F6;
                                region.end = 0x3F6;
                                res = &dev->resource[1];
                                res->flags = LEGACY_IO_RESOURCE;
                                pcibios_bus_to_resource(dev->bus, res, &region);
+                               dev_info(&dev->dev, "legacy IDE quirk: reg 0x14: %pR\n",
+                                        res);
                        }
                        if ((progif & 4) == 0) {
                                region.start = 0x170;
@@ -1151,11 +1138,15 @@ int pci_setup_device(struct pci_dev *dev)
                                res = &dev->resource[2];
                                res->flags = LEGACY_IO_RESOURCE;
                                pcibios_bus_to_resource(dev->bus, res, &region);
+                               dev_info(&dev->dev, "legacy IDE quirk: reg 0x18: %pR\n",
+                                        res);
                                region.start = 0x376;
                                region.end = 0x376;
                                res = &dev->resource[3];
                                res->flags = LEGACY_IO_RESOURCE;
                                pcibios_bus_to_resource(dev->bus, res, &region);
+                               dev_info(&dev->dev, "legacy IDE quirk: reg 0x1c: %pR\n",
+                                        res);
                        }
                }
                break;
@@ -1835,7 +1826,7 @@ int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
                res->flags |= IORESOURCE_PCI_FIXED;
        }
 
-       conflict = insert_resource_conflict(parent_res, res);
+       conflict = request_resource_conflict(parent_res, res);
 
        if (conflict)
                dev_printk(KERN_DEBUG, &b->dev,
index 5cb726c193de824db34ece33610cc6b3bec86eaa..e7292065a1b13f3281eaebde605db8c2eb556145 100644 (file)
@@ -296,6 +296,7 @@ static void quirk_s3_64M(struct pci_dev *dev)
        struct resource *r = &dev->resource[0];
 
        if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
+               r->flags |= IORESOURCE_UNSET;
                r->start = 0;
                r->end = 0x3ffffff;
        }
@@ -937,6 +938,8 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD,   PCI_DEVICE_ID_AMD_FE_GATE_700C
 static void quirk_dunord(struct pci_dev *dev)
 {
        struct resource *r = &dev->resource [1];
+
+       r->flags |= IORESOURCE_UNSET;
        r->start = 0;
        r->end = 0xffffff;
 }
@@ -1740,6 +1743,7 @@ static void quirk_tc86c001_ide(struct pci_dev *dev)
        struct resource *r = &dev->resource[0];
 
        if (r->start & 0x8) {
+               r->flags |= IORESOURCE_UNSET;
                r->start = 0;
                r->end = 0xf;
        }
@@ -1769,6 +1773,7 @@ static void quirk_plx_pci9050(struct pci_dev *dev)
                        dev_info(&dev->dev,
                                 "Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n",
                                 bar);
+                       r->flags |= IORESOURCE_UNSET;
                        r->start = 0;
                        r->end = 0xff;
                }
@@ -3423,6 +3428,61 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
 #endif
 }
 
+/*
+ * Many Intel PCH root ports do provide ACS-like features to disable peer
+ * transactions and validate bus numbers in requests, but do not provide an
+ * actual PCIe ACS capability.  This is the list of device IDs known to fall
+ * into that category as provided by Intel in Red Hat bugzilla 1037684.
+ */
+static const u16 pci_quirk_intel_pch_acs_ids[] = {
+       /* Ibexpeak PCH */
+       0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49,
+       0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51,
+       /* Cougarpoint PCH */
+       0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17,
+       0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f,
+       /* Pantherpoint PCH */
+       0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17,
+       0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f,
+       /* Lynxpoint-H PCH */
+       0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17,
+       0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f,
+       /* Lynxpoint-LP PCH */
+       0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17,
+       0x9c18, 0x9c19, 0x9c1a, 0x9c1b,
+       /* Wildcat PCH */
+       0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97,
+       0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
+};
+
+static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
+{
+       int i;
+
+       /* Filter out a few obvious non-matches first */
+       if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
+               return false;
+
+       for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++)
+               if (pci_quirk_intel_pch_acs_ids[i] == dev->device)
+                       return true;
+
+       return false;
+}
+
+#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV)
+
+static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+{
+       u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ?
+                   INTEL_PCH_ACS_FLAGS : 0;
+
+       if (!pci_quirk_intel_pch_acs_match(dev))
+               return -ENOTTY;
+
+       return acs_flags & ~flags ? 0 : 1;
+}
+
 static const struct pci_dev_acs_enabled {
        u16 vendor;
        u16 device;
@@ -3434,6 +3494,7 @@ static const struct pci_dev_acs_enabled {
        { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
        { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
        { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
        { 0 }
 };
 
@@ -3461,3 +3522,132 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
 
        return -ENOTTY;
 }
+
+/* Config space offset of Root Complex Base Address register */
+#define INTEL_LPC_RCBA_REG 0xf0
+/* 31:14 RCBA address */
+#define INTEL_LPC_RCBA_MASK 0xffffc000
+/* RCBA Enable */
+#define INTEL_LPC_RCBA_ENABLE (1 << 0)
+
+/* Backbone Scratch Pad Register */
+#define INTEL_BSPR_REG 0x1104
+/* Backbone Peer Non-Posted Disable */
+#define INTEL_BSPR_REG_BPNPD (1 << 8)
+/* Backbone Peer Posted Disable */
+#define INTEL_BSPR_REG_BPPD  (1 << 9)
+
+/* Upstream Peer Decode Configuration Register */
+#define INTEL_UPDCR_REG 0x1114
+/* 5:0 Peer Decode Enable bits */
+#define INTEL_UPDCR_REG_MASK 0x3f
+
+static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev)
+{
+       u32 rcba, bspr, updcr;
+       void __iomem *rcba_mem;
+
+       /*
+        * Read the RCBA register from the LPC (D31:F0).  PCH root ports
+        * are D28:F* and therefore get probed before LPC, thus we can't
+        * use pci_get_slot/pci_read_config_dword here.
+        */
+       pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0),
+                                 INTEL_LPC_RCBA_REG, &rcba);
+       if (!(rcba & INTEL_LPC_RCBA_ENABLE))
+               return -EINVAL;
+
+       rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK,
+                                  PAGE_ALIGN(INTEL_UPDCR_REG));
+       if (!rcba_mem)
+               return -ENOMEM;
+
+       /*
+        * The BSPR can disallow peer cycles, but it's set by soft strap and
+        * therefore read-only.  If both posted and non-posted peer cycles are
+        * disallowed, we're ok.  If either are allowed, then we need to use
+        * the UPDCR to disable peer decodes for each port.  This provides the
+        * PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
+        */
+       bspr = readl(rcba_mem + INTEL_BSPR_REG);
+       bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD;
+       if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) {
+               updcr = readl(rcba_mem + INTEL_UPDCR_REG);
+               if (updcr & INTEL_UPDCR_REG_MASK) {
+                       dev_info(&dev->dev, "Disabling UPDCR peer decodes\n");
+                       updcr &= ~INTEL_UPDCR_REG_MASK;
+                       writel(updcr, rcba_mem + INTEL_UPDCR_REG);
+               }
+       }
+
+       iounmap(rcba_mem);
+       return 0;
+}
+
+/* Miscellaneous Port Configuration register */
+#define INTEL_MPC_REG 0xd8
+/* MPC: Invalid Receive Bus Number Check Enable */
+#define INTEL_MPC_REG_IRBNCE (1 << 26)
+
+static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
+{
+       u32 mpc;
+
+       /*
+        * When enabled, the IRBNCE bit of the MPC register enables the
+        * equivalent of PCI ACS Source Validation (PCI_ACS_SV), which
+        * ensures that requester IDs fall within the bus number range
+        * of the bridge.  Enable if not already.
+        */
+       pci_read_config_dword(dev, INTEL_MPC_REG, &mpc);
+       if (!(mpc & INTEL_MPC_REG_IRBNCE)) {
+               dev_info(&dev->dev, "Enabling MPC IRBNCE\n");
+               mpc |= INTEL_MPC_REG_IRBNCE;
+               pci_write_config_word(dev, INTEL_MPC_REG, mpc);
+       }
+}
+
+static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
+{
+       if (!pci_quirk_intel_pch_acs_match(dev))
+               return -ENOTTY;
+
+       if (pci_quirk_enable_intel_lpc_acs(dev)) {
+               dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n");
+               return 0;
+       }
+
+       pci_quirk_enable_intel_rp_mpc_acs(dev);
+
+       dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK;
+
+       dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n");
+
+       return 0;
+}
+
+static const struct pci_dev_enable_acs {
+       u16 vendor;
+       u16 device;
+       int (*enable_acs)(struct pci_dev *dev);
+} pci_dev_enable_acs[] = {
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
+       { 0 }
+};
+
+void pci_dev_specific_enable_acs(struct pci_dev *dev)
+{
+       const struct pci_dev_enable_acs *i;
+       int ret;
+
+       for (i = pci_dev_enable_acs; i->enable_acs; i++) {
+               if ((i->vendor == dev->vendor ||
+                    i->vendor == (u16)PCI_ANY_ID) &&
+                   (i->device == dev->device ||
+                    i->device == (u16)PCI_ANY_ID)) {
+                       ret = i->enable_acs(dev);
+                       if (ret >= 0)
+                               return;
+               }
+       }
+}
index 5d595724e5f4deee3a3390a65bd85c1914bfaecb..c1839450d4d6cc4d77a5b37e983b7dbecdafe31b 100644 (file)
@@ -197,8 +197,10 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
 void pci_cleanup_rom(struct pci_dev *pdev)
 {
        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+
        if (res->flags & IORESOURCE_ROM_COPY) {
                kfree((void*)(unsigned long)res->start);
+               res->flags |= IORESOURCE_UNSET;
                res->flags &= ~IORESOURCE_ROM_COPY;
                res->start = 0;
                res->end = 0;
index 3ff2ac7c14e235c564b3b8d9c4d11609a4696fe5..4a1b972efe7f2fbb76c33467de665a16004fda37 100644 (file)
@@ -54,14 +54,14 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
 
 static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
 {
-       struct pci_buschild;
-       struct list_head *tmp;
+       struct pci_bus *child;
+       struct pci_bus *tmp;
 
        if(bus->number == busnr)
                return bus;
 
-       list_for_each(tmp, &bus->children) {
-               child = pci_do_find_bus(pci_bus_b(tmp), busnr);
+       list_for_each_entry(tmp, &bus->children, node) {
+               child = pci_do_find_bus(tmp, busnr);
                if(child)
                        return child;
        }
@@ -111,7 +111,7 @@ pci_find_next_bus(const struct pci_bus *from)
        down_read(&pci_bus_sem);
        n = from ? from->node.next : pci_root_buses.next;
        if (n != &pci_root_buses)
-               b = pci_bus_b(n);
+               b = list_entry(n, struct pci_bus, node);
        up_read(&pci_bus_sem);
        return b;
 }
index 5c060b152ce6aaffba7f1bd9844cdeaf1c56d605..7eed671d55861c4ef890b33a68cfbaa2d7ef47e0 100644 (file)
@@ -44,6 +44,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
        if (!res->flags)
                return;
 
+       if (res->flags & IORESOURCE_UNSET)
+               return;
+
        /*
         * Ignore non-moveable resources.  This might be legacy resources for
         * which no functional BAR register exists or another important
@@ -101,11 +104,6 @@ void pci_update_resource(struct pci_dev *dev, int resno)
 
        if (disable)
                pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-       res->flags &= ~IORESOURCE_UNSET;
-       dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
-               resno, res, (unsigned long long)region.start,
-               (unsigned long long)region.end);
 }
 
 int pci_claim_resource(struct pci_dev *dev, int resource)
@@ -113,18 +111,23 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
        struct resource *res = &dev->resource[resource];
        struct resource *root, *conflict;
 
+       if (res->flags & IORESOURCE_UNSET) {
+               dev_info(&dev->dev, "can't claim BAR %d %pR: no address assigned\n",
+                        resource, res);
+               return -EINVAL;
+       }
+
        root = pci_find_parent_resource(dev, res);
        if (!root) {
-               dev_info(&dev->dev, "no compatible bridge window for %pR\n",
-                        res);
+               dev_info(&dev->dev, "can't claim BAR %d %pR: no compatible bridge window\n",
+                        resource, res);
                return -EINVAL;
        }
 
        conflict = request_resource_conflict(root, res);
        if (conflict) {
-               dev_info(&dev->dev,
-                        "address space collision: %pR conflicts with %s %pR\n",
-                        res, conflict->name, conflict);
+               dev_info(&dev->dev, "can't claim BAR %d %pR: address conflict with %s %pR\n",
+                        resource, res, conflict->name, conflict);
                return -EBUSY;
        }
 
@@ -263,6 +266,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
        resource_size_t align, size;
        int ret;
 
+       res->flags |= IORESOURCE_UNSET;
        align = pci_resource_alignment(dev, res);
        if (!align) {
                dev_info(&dev->dev, "BAR %d: can't assign %pR "
@@ -282,6 +286,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
                ret = pci_revert_fw_address(res, dev, resno, size);
 
        if (!ret) {
+               res->flags &= ~IORESOURCE_UNSET;
                res->flags &= ~IORESOURCE_STARTALIGN;
                dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
                if (resno < PCI_BRIDGE_RESOURCES)
@@ -297,6 +302,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
        resource_size_t new_size;
        int ret;
 
+       res->flags |= IORESOURCE_UNSET;
        if (!res->parent) {
                dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR "
                         "\n", resno, res);
@@ -307,6 +313,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
        new_size = resource_size(res) + addsize;
        ret = _pci_assign_resource(dev, resno, new_size, min_align);
        if (!ret) {
+               res->flags &= ~IORESOURCE_UNSET;
                res->flags &= ~IORESOURCE_STARTALIGN;
                dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
                if (resno < PCI_BRIDGE_RESOURCES)
@@ -336,9 +343,15 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
                                (!(r->flags & IORESOURCE_ROM_ENABLE)))
                        continue;
 
+               if (r->flags & IORESOURCE_UNSET) {
+                       dev_err(&dev->dev, "can't enable device: BAR %d %pR not assigned\n",
+                               i, r);
+                       return -EINVAL;
+               }
+
                if (!r->parent) {
-                       dev_err(&dev->dev, "device not available "
-                               "(can't reserve %pR)\n", r);
+                       dev_err(&dev->dev, "can't enable device: BAR %d %pR not claimed\n",
+                               i, r);
                        return -EINVAL;
                }
 
index 6eecd7cddf5796b681b224e45a52a77476884d39..54d3089d157b628f35705cc15e311ed977894de6 100644 (file)
@@ -125,9 +125,6 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
                if (freqs->new < freqs->old)
                        sa1100_pcmcia_set_mecr(skt, freqs->new);
                break;
-       case CPUFREQ_RESUMECHANGE:
-               sa1100_pcmcia_set_mecr(skt, freqs->new);
-               break;
        }
 
        return 0;
index 8485761e76af11821f24e64bc3474dd0f5f487d4..946f90ef60203a7e3a06c89041ea3c50e2a9b364 100644 (file)
@@ -1076,7 +1076,7 @@ static void yenta_config_init(struct yenta_socket *socket)
  */
 static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
 {
-       struct list_head *tmp;
+       struct pci_bus *sibling;
        unsigned char upper_limit;
        /*
         * We only check and fix the parent bridge: All systems which need
@@ -1095,18 +1095,18 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
        /* stay within the limits of the bus range of the parent: */
        upper_limit = bridge_to_fix->parent->busn_res.end;
 
-       /* check the bus ranges of all silbling bridges to prevent overlap */
-       list_for_each(tmp, &bridge_to_fix->parent->children) {
-               struct pci_bus *silbling = pci_bus_b(tmp);
+       /* check the bus ranges of all sibling bridges to prevent overlap */
+       list_for_each_entry(sibling, &bridge_to_fix->parent->children,
+                       node) {
                /*
-                * If the silbling has a higher secondary bus number
+                * If the sibling has a higher secondary bus number
                 * and it's secondary is equal or smaller than our
                 * current upper limit, set the new upper limit to
-                * the bus number below the silbling's range:
+                * the bus number below the sibling's range:
                 */
-               if (silbling->busn_res.start > bridge_to_fix->busn_res.end
-                   && silbling->busn_res.start <= upper_limit)
-                       upper_limit = silbling->busn_res.start - 1;
+               if (sibling->busn_res.start > bridge_to_fix->busn_res.end
+                   && sibling->busn_res.start <= upper_limit)
+                       upper_limit = sibling->busn_res.start - 1;
        }
 
        /* Show that the wanted subordinate number is not possible: */
index be361b7cd30f240e4b1a78abbb3acd253620b035..06cee0189f3e4134cca8953519b742f999d92634 100644 (file)
@@ -217,14 +217,14 @@ config PINCTRL_IMX28
        select PINCTRL_MXS
 
 config PINCTRL_MSM
-       tristate
+       bool
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
 
 config PINCTRL_MSM8X74
        tristate "Qualcomm 8x74 pin controller driver"
-       depends on GPIOLIB && OF && OF_IRQ
+       depends on GPIOLIB && OF
        select PINCTRL_MSM
        help
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
index 340fb4e6c600393f0504e6d6cd5f7adc9cbad29e..eda13de2e7c0d110f5e105a84b5b19da93cadc36 100644 (file)
@@ -186,7 +186,9 @@ int pinctrl_dt_to_map(struct pinctrl *p)
 
        /* CONFIG_OF enabled, p->dev not instantiated from DT */
        if (!np) {
-               dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
+               if (of_have_populated_dt())
+                       dev_dbg(p->dev,
+                               "no of_node; not parsing pinctrl DT\n");
                return 0;
        }
 
index 366fa541ee9121591e78f66c7ec4307a5d415203..cc298fade93a79e359eb43c2daac3ef50bc91cc1 100644 (file)
@@ -8,6 +8,7 @@ config PINCTRL_MVEBU
 config PINCTRL_DOVE
        bool
        select PINCTRL_MVEBU
+       select MFD_SYSCON
 
 config PINCTRL_KIRKWOOD
        bool
@@ -17,6 +18,14 @@ config PINCTRL_ARMADA_370
        bool
        select PINCTRL_MVEBU
 
+config PINCTRL_ARMADA_375
+       bool
+       select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_38X
+       bool
+       select PINCTRL_MVEBU
+
 config PINCTRL_ARMADA_XP
        bool
        select PINCTRL_MVEBU
index 37c253297af004767252ec5c26eb8a4c75f19ef4..bc1b9f14f539a23c4e4a97312f03ae9730ac482a 100644 (file)
@@ -2,4 +2,6 @@ obj-$(CONFIG_PINCTRL_MVEBU)     += pinctrl-mvebu.o
 obj-$(CONFIG_PINCTRL_DOVE)     += pinctrl-dove.o
 obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
 obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o
+obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
 obj-$(CONFIG_PINCTRL_ARMADA_XP)  += pinctrl-armada-xp.o
index ae1f760cbdd2b28cae4c0aa17f2fae0cba0fd50f..670e5b01c6781b3b97245f8b83f72576eeb020af 100644 (file)
 
 #include "pinctrl-mvebu.h"
 
+static void __iomem *mpp_base;
+
+static int armada_370_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_370_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+       return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
 static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
        MPP_MODE(0,
           MPP_FUNCTION(0x0, "gpio", NULL),
@@ -373,7 +385,7 @@ static struct of_device_id armada_370_pinctrl_of_match[] = {
 };
 
 static struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = {
-       MPP_REG_CTRL(0, 65),
+       MPP_FUNC_CTRL(0, 65, NULL, armada_370_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
@@ -385,6 +397,12 @@ static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
 static int armada_370_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mpp_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mpp_base))
+               return PTR_ERR(mpp_base);
 
        soc->variant = 0; /* no variants for Armada 370 */
        soc->controls = mv88f6710_mpp_controls;
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-375.c b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
new file mode 100644 (file)
index 0000000..db078fe
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Marvell Armada 375 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static void __iomem *mpp_base;
+
+static int armada_375_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_375_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+       return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
+       MPP_MODE(0,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad2"),
+                MPP_FUNCTION(0x2, "spi0", "cs1"),
+                MPP_FUNCTION(0x3, "spi1", "cs1"),
+                MPP_FUNCTION(0x5, "nand", "io2")),
+       MPP_MODE(1,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad3"),
+                MPP_FUNCTION(0x2, "spi0", "mosi"),
+                MPP_FUNCTION(0x3, "spi1", "mosi"),
+                MPP_FUNCTION(0x5, "nand", "io3")),
+       MPP_MODE(2,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad4"),
+                MPP_FUNCTION(0x2, "ptp", "eventreq"),
+                MPP_FUNCTION(0x3, "led", "c0"),
+                MPP_FUNCTION(0x4, "audio", "sdi"),
+                MPP_FUNCTION(0x5, "nand", "io4"),
+                MPP_FUNCTION(0x6, "spi1", "mosi")),
+       MPP_MODE(3,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad5"),
+                MPP_FUNCTION(0x2, "ptp", "triggen"),
+                MPP_FUNCTION(0x3, "led", "p3"),
+                MPP_FUNCTION(0x4, "audio", "mclk"),
+                MPP_FUNCTION(0x5, "nand", "io5"),
+                MPP_FUNCTION(0x6, "spi1", "miso")),
+       MPP_MODE(4,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad6"),
+                MPP_FUNCTION(0x2, "spi0", "miso"),
+                MPP_FUNCTION(0x3, "spi1", "miso"),
+                MPP_FUNCTION(0x5, "nand", "io6")),
+       MPP_MODE(5,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad7"),
+                MPP_FUNCTION(0x2, "spi0", "cs2"),
+                MPP_FUNCTION(0x3, "spi1", "cs2"),
+                MPP_FUNCTION(0x5, "nand", "io7"),
+                MPP_FUNCTION(0x6, "spi1", "miso")),
+       MPP_MODE(6,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad0"),
+                MPP_FUNCTION(0x3, "led", "p1"),
+                MPP_FUNCTION(0x4, "audio", "rclk"),
+                MPP_FUNCTION(0x5, "nand", "io0")),
+       MPP_MODE(7,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "ad1"),
+                MPP_FUNCTION(0x2, "ptp", "clk"),
+                MPP_FUNCTION(0x3, "led", "p2"),
+                MPP_FUNCTION(0x4, "audio", "extclk"),
+                MPP_FUNCTION(0x5, "nand", "io1")),
+       MPP_MODE(8,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev ", "bootcs"),
+                MPP_FUNCTION(0x2, "spi0", "cs0"),
+                MPP_FUNCTION(0x3, "spi1", "cs0"),
+                MPP_FUNCTION(0x5, "nand", "ce")),
+       MPP_MODE(9,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "nf", "wen"),
+                MPP_FUNCTION(0x2, "spi0", "sck"),
+                MPP_FUNCTION(0x3, "spi1", "sck"),
+                MPP_FUNCTION(0x5, "nand", "we")),
+       MPP_MODE(10,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "nf", "ren"),
+                MPP_FUNCTION(0x2, "dram", "vttctrl"),
+                MPP_FUNCTION(0x3, "led", "c1"),
+                MPP_FUNCTION(0x5, "nand", "re"),
+                MPP_FUNCTION(0x6, "spi1", "sck")),
+       MPP_MODE(11,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "a0"),
+                MPP_FUNCTION(0x3, "led", "c2"),
+                MPP_FUNCTION(0x4, "audio", "sdo"),
+                MPP_FUNCTION(0x5, "nand", "cle")),
+       MPP_MODE(12,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "a1"),
+                MPP_FUNCTION(0x4, "audio", "bclk"),
+                MPP_FUNCTION(0x5, "nand", "ale")),
+       MPP_MODE(13,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "dev", "readyn"),
+                MPP_FUNCTION(0x2, "pcie0", "rstoutn"),
+                MPP_FUNCTION(0x3, "pcie1", "rstoutn"),
+                MPP_FUNCTION(0x5, "nand", "rb"),
+                MPP_FUNCTION(0x6, "spi1", "mosi")),
+       MPP_MODE(14,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "i2c0", "sda"),
+                MPP_FUNCTION(0x3, "uart1", "txd")),
+       MPP_MODE(15,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "i2c0", "sck"),
+                MPP_FUNCTION(0x3, "uart1", "rxd")),
+       MPP_MODE(16,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "uart0", "txd")),
+       MPP_MODE(17,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "uart0", "rxd")),
+       MPP_MODE(18,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "tdm", "intn")),
+       MPP_MODE(19,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "tdm", "rstn")),
+       MPP_MODE(20,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "tdm", "pclk")),
+       MPP_MODE(21,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "tdm", "fsync")),
+       MPP_MODE(22,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "tdm", "drx")),
+       MPP_MODE(23,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "tdm", "dtx")),
+       MPP_MODE(24,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p0"),
+                MPP_FUNCTION(0x2, "ge1", "rxd0"),
+                MPP_FUNCTION(0x3, "sd", "cmd"),
+                MPP_FUNCTION(0x4, "uart0", "rts"),
+                MPP_FUNCTION(0x5, "spi0", "cs0"),
+                MPP_FUNCTION(0x6, "dev", "cs1")),
+       MPP_MODE(25,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p2"),
+                MPP_FUNCTION(0x2, "ge1", "rxd1"),
+                MPP_FUNCTION(0x3, "sd", "d0"),
+                MPP_FUNCTION(0x4, "uart0", "cts"),
+                MPP_FUNCTION(0x5, "spi0", "mosi"),
+                MPP_FUNCTION(0x6, "dev", "cs2")),
+       MPP_MODE(26,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+                MPP_FUNCTION(0x2, "ge1", "rxd2"),
+                MPP_FUNCTION(0x3, "sd", "d2"),
+                MPP_FUNCTION(0x4, "uart1", "rts"),
+                MPP_FUNCTION(0x5, "spi0", "cs1"),
+                MPP_FUNCTION(0x6, "led", "c1")),
+       MPP_MODE(27,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+                MPP_FUNCTION(0x2, "ge1", "rxd3"),
+                MPP_FUNCTION(0x3, "sd", "d1"),
+                MPP_FUNCTION(0x4, "uart1", "cts"),
+                MPP_FUNCTION(0x5, "spi0", "miso"),
+                MPP_FUNCTION(0x6, "led", "c2")),
+       MPP_MODE(28,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p3"),
+                MPP_FUNCTION(0x2, "ge1", "txctl"),
+                MPP_FUNCTION(0x3, "sd", "clk"),
+                MPP_FUNCTION(0x5, "dram", "vttctrl")),
+       MPP_MODE(29,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+                MPP_FUNCTION(0x2, "ge1", "rxclk"),
+                MPP_FUNCTION(0x3, "sd", "d3"),
+                MPP_FUNCTION(0x5, "spi0", "sck"),
+                MPP_FUNCTION(0x6, "pcie0", "rstoutn")),
+       MPP_MODE(30,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge1", "txd0"),
+                MPP_FUNCTION(0x3, "spi1", "cs0"),
+                MPP_FUNCTION(0x5, "led", "p3"),
+                MPP_FUNCTION(0x6, "ptp", "eventreq")),
+       MPP_MODE(31,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge1", "txd1"),
+                MPP_FUNCTION(0x3, "spi1", "mosi"),
+                MPP_FUNCTION(0x5, "led", "p0")),
+       MPP_MODE(32,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge1", "txd2"),
+                MPP_FUNCTION(0x3, "spi1", "sck"),
+                MPP_FUNCTION(0x4, "ptp", "triggen"),
+                MPP_FUNCTION(0x5, "led", "c0")),
+       MPP_MODE(33,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge1", "txd3"),
+                MPP_FUNCTION(0x3, "spi1", "miso"),
+                MPP_FUNCTION(0x5, "led", "p2")),
+       MPP_MODE(34,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge1", "txclkout"),
+                MPP_FUNCTION(0x3, "spi1", "sck"),
+                MPP_FUNCTION(0x5, "led", "c1")),
+       MPP_MODE(35,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge1", "rxctl"),
+                MPP_FUNCTION(0x3, "spi1", "cs1"),
+                MPP_FUNCTION(0x4, "spi0", "cs2"),
+                MPP_FUNCTION(0x5, "led", "p1")),
+       MPP_MODE(36,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+                MPP_FUNCTION(0x5, "led", "c2")),
+       MPP_MODE(37,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+                MPP_FUNCTION(0x2, "tdm", "intn"),
+                MPP_FUNCTION(0x4, "ge", "mdc")),
+       MPP_MODE(38,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+                MPP_FUNCTION(0x4, "ge", "mdio")),
+       MPP_MODE(39,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x4, "ref", "clkout"),
+                MPP_FUNCTION(0x5, "led", "p3")),
+       MPP_MODE(40,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x4, "uart1", "txd"),
+                MPP_FUNCTION(0x5, "led", "p0")),
+       MPP_MODE(41,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x4, "uart1", "rxd"),
+                MPP_FUNCTION(0x5, "led", "p1")),
+       MPP_MODE(42,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x3, "spi1", "cs2"),
+                MPP_FUNCTION(0x4, "led", "c0"),
+                MPP_FUNCTION(0x6, "ptp", "clk")),
+       MPP_MODE(43,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "sata0", "prsnt"),
+                MPP_FUNCTION(0x4, "dram", "vttctrl"),
+                MPP_FUNCTION(0x5, "led", "c1")),
+       MPP_MODE(44,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x4, "sata0", "prsnt")),
+       MPP_MODE(45,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "spi0", "cs2"),
+                MPP_FUNCTION(0x4, "pcie0", "rstoutn"),
+                MPP_FUNCTION(0x5, "led", "c2"),
+                MPP_FUNCTION(0x6, "spi1", "cs2")),
+       MPP_MODE(46,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p0"),
+                MPP_FUNCTION(0x2, "ge0", "txd0"),
+                MPP_FUNCTION(0x3, "ge1", "txd0"),
+                MPP_FUNCTION(0x6, "dev", "wen1")),
+       MPP_MODE(47,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p1"),
+                MPP_FUNCTION(0x2, "ge0", "txd1"),
+                MPP_FUNCTION(0x3, "ge1", "txd1"),
+                MPP_FUNCTION(0x5, "ptp", "triggen"),
+                MPP_FUNCTION(0x6, "dev", "ale0")),
+       MPP_MODE(48,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p2"),
+                MPP_FUNCTION(0x2, "ge0", "txd2"),
+                MPP_FUNCTION(0x3, "ge1", "txd2"),
+                MPP_FUNCTION(0x6, "dev", "ale1")),
+       MPP_MODE(49,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "p3"),
+                MPP_FUNCTION(0x2, "ge0", "txd3"),
+                MPP_FUNCTION(0x3, "ge1", "txd3"),
+                MPP_FUNCTION(0x6, "dev", "a2")),
+       MPP_MODE(50,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "c0"),
+                MPP_FUNCTION(0x2, "ge0", "rxd0"),
+                MPP_FUNCTION(0x3, "ge1", "rxd0"),
+                MPP_FUNCTION(0x5, "ptp", "eventreq"),
+                MPP_FUNCTION(0x6, "dev", "ad12")),
+       MPP_MODE(51,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "c1"),
+                MPP_FUNCTION(0x2, "ge0", "rxd1"),
+                MPP_FUNCTION(0x3, "ge1", "rxd1"),
+                MPP_FUNCTION(0x6, "dev", "ad8")),
+       MPP_MODE(52,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "led", "c2"),
+                MPP_FUNCTION(0x2, "ge0", "rxd2"),
+                MPP_FUNCTION(0x3, "ge1", "rxd2"),
+                MPP_FUNCTION(0x5, "i2c0", "sda"),
+                MPP_FUNCTION(0x6, "dev", "ad9")),
+       MPP_MODE(53,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie1", "rstoutn"),
+                MPP_FUNCTION(0x2, "ge0", "rxd3"),
+                MPP_FUNCTION(0x3, "ge1", "rxd3"),
+                MPP_FUNCTION(0x5, "i2c0", "sck"),
+                MPP_FUNCTION(0x6, "dev", "ad10")),
+       MPP_MODE(54,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "pcie0", "rstoutn"),
+                MPP_FUNCTION(0x2, "ge0", "rxctl"),
+                MPP_FUNCTION(0x3, "ge1", "rxctl"),
+                MPP_FUNCTION(0x6, "dev", "ad11")),
+       MPP_MODE(55,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge0", "rxclk"),
+                MPP_FUNCTION(0x3, "ge1", "rxclk"),
+                MPP_FUNCTION(0x6, "dev", "cs0")),
+       MPP_MODE(56,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge0", "txclkout"),
+                MPP_FUNCTION(0x3, "ge1", "txclkout"),
+                MPP_FUNCTION(0x6, "dev", "oe")),
+       MPP_MODE(57,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ge0", "txctl"),
+                MPP_FUNCTION(0x3, "ge1", "txctl"),
+                MPP_FUNCTION(0x6, "dev", "wen0")),
+       MPP_MODE(58,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x4, "led", "c0")),
+       MPP_MODE(59,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x4, "led", "c1")),
+       MPP_MODE(60,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "uart1", "txd"),
+                MPP_FUNCTION(0x4, "led", "c2"),
+                MPP_FUNCTION(0x6, "dev", "ad13")),
+       MPP_MODE(61,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "i2c1", "sda"),
+                MPP_FUNCTION(0x2, "uart1", "rxd"),
+                MPP_FUNCTION(0x3, "spi1", "cs2"),
+                MPP_FUNCTION(0x4, "led", "p0"),
+                MPP_FUNCTION(0x6, "dev", "ad14")),
+       MPP_MODE(62,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "i2c1", "sck"),
+                MPP_FUNCTION(0x4, "led", "p1"),
+                MPP_FUNCTION(0x6, "dev", "ad15")),
+       MPP_MODE(63,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ptp", "triggen"),
+                MPP_FUNCTION(0x4, "led", "p2"),
+                MPP_FUNCTION(0x6, "dev", "burst")),
+       MPP_MODE(64,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "dram", "vttctrl"),
+                MPP_FUNCTION(0x4, "led", "p3")),
+       MPP_MODE(65,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x1, "sata1", "prsnt")),
+       MPP_MODE(66,
+                MPP_FUNCTION(0x0, "gpio", NULL),
+                MPP_FUNCTION(0x2, "ptp", "eventreq"),
+                MPP_FUNCTION(0x4, "spi1", "cs3"),
+                MPP_FUNCTION(0x5, "pcie0", "rstoutn"),
+                MPP_FUNCTION(0x6, "dev", "cs3")),
+};
+
+static struct mvebu_pinctrl_soc_info armada_375_pinctrl_info;
+
+static struct of_device_id armada_375_pinctrl_of_match[] = {
+       { .compatible = "marvell,mv88f6720-pinctrl" },
+       { },
+};
+
+static struct mvebu_mpp_ctrl mv88f6720_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 69, NULL, armada_375_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range mv88f6720_mpp_gpio_ranges[] = {
+       MPP_GPIO_RANGE(0,   0,  0, 32),
+       MPP_GPIO_RANGE(1,  32, 32, 32),
+       MPP_GPIO_RANGE(2,  64, 64,  3),
+};
+
+static int armada_375_pinctrl_probe(struct platform_device *pdev)
+{
+       struct mvebu_pinctrl_soc_info *soc = &armada_375_pinctrl_info;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mpp_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mpp_base))
+               return PTR_ERR(mpp_base);
+
+       soc->variant = 0; /* no variants for Armada 375 */
+       soc->controls = mv88f6720_mpp_controls;
+       soc->ncontrols = ARRAY_SIZE(mv88f6720_mpp_controls);
+       soc->modes = mv88f6720_mpp_modes;
+       soc->nmodes = ARRAY_SIZE(mv88f6720_mpp_modes);
+       soc->gpioranges = mv88f6720_mpp_gpio_ranges;
+       soc->ngpioranges = ARRAY_SIZE(mv88f6720_mpp_gpio_ranges);
+
+       pdev->dev.platform_data = soc;
+
+       return mvebu_pinctrl_probe(pdev);
+}
+
+static int armada_375_pinctrl_remove(struct platform_device *pdev)
+{
+       return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_375_pinctrl_driver = {
+       .driver = {
+               .name = "armada-375-pinctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(armada_375_pinctrl_of_match),
+       },
+       .probe = armada_375_pinctrl_probe,
+       .remove = armada_375_pinctrl_remove,
+};
+
+module_platform_driver(armada_375_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 375 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
new file mode 100644 (file)
index 0000000..1049f82
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Marvell Armada 380/385 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2013 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static void __iomem *mpp_base;
+
+static int armada_38x_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_38x_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+       return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+enum {
+       V_88F6810 = BIT(0),
+       V_88F6820 = BIT(1),
+       V_88F6828 = BIT(2),
+       V_88F6810_PLUS = (V_88F6810 | V_88F6820 | V_88F6828),
+       V_88F6820_PLUS = (V_88F6820 | V_88F6828),
+};
+
+static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
+       MPP_MODE(0,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ua0",   "rxd",        V_88F6810_PLUS)),
+       MPP_MODE(1,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ua0",   "txd",        V_88F6810_PLUS)),
+       MPP_MODE(2,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "i2c0",  "sck",        V_88F6810_PLUS)),
+       MPP_MODE(3,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "i2c0",  "sda",        V_88F6810_PLUS)),
+       MPP_MODE(4,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge",    "mdc",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ua1",   "txd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua0",   "rts",        V_88F6810_PLUS)),
+       MPP_MODE(5,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge",    "mdio",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ua1",   "rxd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua0",   "cts",        V_88F6810_PLUS)),
+       MPP_MODE(6,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txclkout",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge0",   "crs",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "cs3",        V_88F6810_PLUS)),
+       MPP_MODE(7,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txd0",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad9",        V_88F6810_PLUS)),
+       MPP_MODE(8,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txd1",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad10",       V_88F6810_PLUS)),
+       MPP_MODE(9,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txd2",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad11",       V_88F6810_PLUS)),
+       MPP_MODE(10,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txd3",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad12",       V_88F6810_PLUS)),
+       MPP_MODE(11,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txctl",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad13",       V_88F6810_PLUS)),
+       MPP_MODE(12,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxd0",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "cs1",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad14",       V_88F6810_PLUS)),
+       MPP_MODE(13,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxd1",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "pcie0", "clkreq",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "clkreq",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "cs2",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad15",       V_88F6810_PLUS)),
+       MPP_MODE(14,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxd2",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ptp",   "clk",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "m",     "vtt_ctrl",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "cs3",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "wen1",       V_88F6810_PLUS)),
+       MPP_MODE(15,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxd3",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge",    "mdc slave",  V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "mosi",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "pcie1", "rstout",     V_88F6820_PLUS)),
+       MPP_MODE(16,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxctl",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge",    "mdio slave", V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "m",     "decc_err",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "miso",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "pcie0", "clkreq",     V_88F6810_PLUS)),
+       MPP_MODE(17,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxclk",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ptp",   "clk",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua1",   "rxd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "sck",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sata1", "prsnt",      V_88F6810_PLUS)),
+       MPP_MODE(18,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "rxerr",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ptp",   "trig_gen",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua1",   "txd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi0",  "cs0",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "pcie1", "rstout",     V_88F6820_PLUS)),
+       MPP_MODE(19,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "col",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ptp",   "event_req",  V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie0", "clkreq",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sata1", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "ua0",   "cts",        V_88F6810_PLUS)),
+       MPP_MODE(20,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ge0",   "txclk",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ptp",   "clk",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "ua0",   "rts",        V_88F6810_PLUS)),
+       MPP_MODE(21,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "cs1",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "rxd0",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "cmd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "bootcs",     V_88F6810_PLUS)),
+       MPP_MODE(22,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "mosi",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad0",        V_88F6810_PLUS)),
+       MPP_MODE(23,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "sck",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad2",        V_88F6810_PLUS)),
+       MPP_MODE(24,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "miso",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ua0",   "cts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua1",   "rxd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d4",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ready",      V_88F6810_PLUS)),
+       MPP_MODE(25,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "cs0",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ua0",   "rts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua1",   "txd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d5",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "cs0",        V_88F6810_PLUS)),
+       MPP_MODE(26,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "cs2",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "i2c1",  "sck",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d6",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "cs1",        V_88F6810_PLUS)),
+       MPP_MODE(27,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "spi0",  "cs3",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "txclkout",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "i2c1",  "sda",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d7",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "cs2",        V_88F6810_PLUS)),
+       MPP_MODE(28,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "txd0",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "clk",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad5",        V_88F6810_PLUS)),
+       MPP_MODE(29,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "txd1",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ale0",       V_88F6810_PLUS)),
+       MPP_MODE(30,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "txd2",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "oen",        V_88F6810_PLUS)),
+       MPP_MODE(31,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "txd3",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ale1",       V_88F6810_PLUS)),
+       MPP_MODE(32,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "txctl",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "wen0",       V_88F6810_PLUS)),
+       MPP_MODE(33,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "m",     "decc_err",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad3",        V_88F6810_PLUS)),
+       MPP_MODE(34,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad1",        V_88F6810_PLUS)),
+       MPP_MODE(35,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ref",   "clk_out1",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "a1",         V_88F6810_PLUS)),
+       MPP_MODE(36,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ptp",   "trig_gen",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "a0",         V_88F6810_PLUS)),
+       MPP_MODE(37,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ptp",   "clk",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "rxclk",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d3",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad8",        V_88F6810_PLUS)),
+       MPP_MODE(38,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ptp",   "event_req",  V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "rxd1",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ref",   "clk_out0",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d0",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad4",        V_88F6810_PLUS)),
+       MPP_MODE(39,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "i2c1",  "sck",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "rxd2",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua0",   "cts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d1",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "a2",         V_88F6810_PLUS)),
+       MPP_MODE(40,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "i2c1",  "sda",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "rxd3",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua0",   "rts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "sd0",   "d2",         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad6",        V_88F6810_PLUS)),
+       MPP_MODE(41,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ua1",   "rxd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge1",   "rxctl",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua0",   "cts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi1",  "cs3",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "burst/last", V_88F6810_PLUS)),
+       MPP_MODE(42,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ua1",   "txd",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "ua0",   "rts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "ad7",        V_88F6810_PLUS)),
+       MPP_MODE(43,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "pcie0", "clkreq",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "m",     "vtt_ctrl",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "m",     "decc_err",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "dev",   "clkout",     V_88F6810_PLUS)),
+       MPP_MODE(44,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "sata1", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "sata2", "prsnt",      V_88F6828),
+                MPP_VAR_FUNCTION(4, "sata3", "prsnt",      V_88F6828),
+                MPP_VAR_FUNCTION(5, "pcie0", "rstout",     V_88F6810_PLUS)),
+       MPP_MODE(45,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ref",   "clk_out0",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "pcie2", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "pcie3", "rstout",     V_88F6810_PLUS)),
+       MPP_MODE(46,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ref",   "clk_out1",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "pcie2", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "pcie3", "rstout",     V_88F6810_PLUS)),
+       MPP_MODE(47,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "sata1", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "sata2", "prsnt",      V_88F6828),
+                MPP_VAR_FUNCTION(4, "spi1",  "cs2",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sata3", "prsnt",      V_88F6828)),
+       MPP_MODE(48,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "m",     "vtt_ctrl",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "tdm2c", "pclk",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "audio", "mclk",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d4",         V_88F6810_PLUS)),
+       MPP_MODE(49,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "sata2", "prsnt",      V_88F6828),
+                MPP_VAR_FUNCTION(2, "sata3", "prsnt",      V_88F6828),
+                MPP_VAR_FUNCTION(3, "tdm2c", "fsync",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "audio", "lrclk",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d5",         V_88F6810_PLUS)),
+       MPP_MODE(50,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(3, "tdm2c", "drx",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "audio", "extclk",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "cmd",        V_88F6810_PLUS)),
+       MPP_MODE(51,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "tdm2c", "dtx",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "audio", "sdo",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "m",     "decc_err",   V_88F6810_PLUS)),
+       MPP_MODE(52,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(3, "tdm2c", "intn",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "audio", "sdi",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d6",         V_88F6810_PLUS)),
+       MPP_MODE(53,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "sata1", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "tdm2c", "rstn",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "audio", "bclk",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d7",         V_88F6810_PLUS)),
+       MPP_MODE(54,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "sata0", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "sata1", "prsnt",      V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d3",         V_88F6810_PLUS)),
+       MPP_MODE(55,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ua1",   "cts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge",    "mdio",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "clkreq",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "spi1",  "cs1",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d0",         V_88F6810_PLUS)),
+       MPP_MODE(56,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "ua1",   "rts",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "ge",    "mdc",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "m",     "decc_err",   V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi1",  "mosi",       V_88F6810_PLUS)),
+       MPP_MODE(57,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi1",  "sck",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "clk",        V_88F6810_PLUS)),
+       MPP_MODE(58,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "pcie1", "clkreq",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(2, "i2c1",  "sck",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie2", "clkreq",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(4, "spi1",  "miso",       V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d1",         V_88F6810_PLUS)),
+       MPP_MODE(59,
+                MPP_VAR_FUNCTION(0, "gpio",  NULL,         V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(1, "pcie0", "rstout",     V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(2, "i2c1",  "sda",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(3, "pcie1", "rstout",     V_88F6820_PLUS),
+                MPP_VAR_FUNCTION(4, "spi1",  "cs0",        V_88F6810_PLUS),
+                MPP_VAR_FUNCTION(5, "sd0",   "d2",         V_88F6810_PLUS)),
+};
+
+static struct mvebu_pinctrl_soc_info armada_38x_pinctrl_info;
+
+static struct of_device_id armada_38x_pinctrl_of_match[] = {
+       {
+               .compatible = "marvell,mv88f6810-pinctrl",
+               .data       = (void *) V_88F6810,
+       },
+       {
+               .compatible = "marvell,mv88f6820-pinctrl",
+               .data       = (void *) V_88F6820,
+       },
+       {
+               .compatible = "marvell,mv88f6828-pinctrl",
+               .data       = (void *) V_88F6828,
+       },
+       { },
+};
+
+static struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 59, NULL, armada_38x_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range armada_38x_mpp_gpio_ranges[] = {
+       MPP_GPIO_RANGE(0,   0,  0, 32),
+       MPP_GPIO_RANGE(1,  32, 32, 27),
+};
+
+static int armada_38x_pinctrl_probe(struct platform_device *pdev)
+{
+       struct mvebu_pinctrl_soc_info *soc = &armada_38x_pinctrl_info;
+       const struct of_device_id *match =
+               of_match_device(armada_38x_pinctrl_of_match, &pdev->dev);
+       struct resource *res;
+
+       if (!match)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mpp_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mpp_base))
+               return PTR_ERR(mpp_base);
+
+       soc->variant = (unsigned) match->data & 0xff;
+       soc->controls = armada_38x_mpp_controls;
+       soc->ncontrols = ARRAY_SIZE(armada_38x_mpp_controls);
+       soc->gpioranges = armada_38x_mpp_gpio_ranges;
+       soc->ngpioranges = ARRAY_SIZE(armada_38x_mpp_gpio_ranges);
+       soc->modes = armada_38x_mpp_modes;
+       soc->nmodes = armada_38x_mpp_controls[0].npins;
+
+       pdev->dev.platform_data = soc;
+
+       return mvebu_pinctrl_probe(pdev);
+}
+
+static int armada_38x_pinctrl_remove(struct platform_device *pdev)
+{
+       return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_38x_pinctrl_driver = {
+       .driver = {
+               .name = "armada-38x-pinctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(armada_38x_pinctrl_of_match),
+       },
+       .probe = armada_38x_pinctrl_probe,
+       .remove = armada_38x_pinctrl_remove,
+};
+
+module_platform_driver(armada_38x_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 38x pinctrl driver");
+MODULE_LICENSE("GPL v2");
index 843a51f9d129c2d1ac6c95c202a06b07bcd24c06..de311129f7a020473acc3b46ee9ede902df86c9d 100644 (file)
 
 #include "pinctrl-mvebu.h"
 
+static void __iomem *mpp_base;
+
+static int armada_xp_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_xp_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+       return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
 enum armada_xp_variant {
        V_MV78230       = BIT(0),
        V_MV78260       = BIT(1),
@@ -366,7 +378,7 @@ static struct of_device_id armada_xp_pinctrl_of_match[] = {
 };
 
 static struct mvebu_mpp_ctrl mv78230_mpp_controls[] = {
-       MPP_REG_CTRL(0, 48),
+       MPP_FUNC_CTRL(0, 48, NULL, armada_xp_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
@@ -375,7 +387,7 @@ static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
 };
 
 static struct mvebu_mpp_ctrl mv78260_mpp_controls[] = {
-       MPP_REG_CTRL(0, 66),
+       MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
@@ -385,7 +397,7 @@ static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
 };
 
 static struct mvebu_mpp_ctrl mv78460_mpp_controls[] = {
-       MPP_REG_CTRL(0, 66),
+       MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
@@ -399,10 +411,16 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
        struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
        const struct of_device_id *match =
                of_match_device(armada_xp_pinctrl_of_match, &pdev->dev);
+       struct resource *res;
 
        if (!match)
                return -ENODEV;
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mpp_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mpp_base))
+               return PTR_ERR(mpp_base);
+
        soc->variant = (unsigned) match->data & 0xff;
 
        switch (soc->variant) {
index 47268393af34689832fd189bde3c9da27eb6c090..3b022178a566eee5d5568f9b68f3135f405cfdde 100644 (file)
 #include <linux/clk.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
 #include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
 
 #include "pinctrl-mvebu.h"
 
-#define DOVE_SB_REGS_VIRT_BASE         IOMEM(0xfde00000)
-#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)
-#define  DOVE_TWSI_ENABLE_OPTION2      BIT(20)
-#define  DOVE_TWSI_ENABLE_OPTION3      BIT(21)
-#define  DOVE_TWSI_OPTION3_GPIO                BIT(22)
-#define DOVE_SSP_CTRL_STATUS_1         (DOVE_SB_REGS_VIRT_BASE + 0xe8034)
-#define  DOVE_SSP_ON_AU1               BIT(0)
-#define DOVE_MPP_GENERAL_VIRT_BASE     (DOVE_SB_REGS_VIRT_BASE + 0xe803c)
-#define  DOVE_AU1_SPDIFO_GPIO_EN       BIT(1)
-#define  DOVE_NAND_GPIO_EN             BIT(0)
-#define DOVE_GPIO_LO_VIRT_BASE         (DOVE_SB_REGS_VIRT_BASE + 0xd0400)
-#define DOVE_MPP_CTRL4_VIRT_BASE       (DOVE_GPIO_LO_VIRT_BASE + 0x40)
-#define  DOVE_SPI_GPIO_SEL             BIT(5)
-#define  DOVE_UART1_GPIO_SEL           BIT(4)
-#define  DOVE_AU1_GPIO_SEL             BIT(3)
-#define  DOVE_CAM_GPIO_SEL             BIT(2)
-#define  DOVE_SD1_GPIO_SEL             BIT(1)
-#define  DOVE_SD0_GPIO_SEL             BIT(0)
-
-#define MPPS_PER_REG   8
-#define MPP_BITS       4
-#define MPP_MASK       0xf
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INT_REGS_MASK          ~(SZ_1M - 1)
+#define MPP4_REGS_OFFS         0xd0440
+#define PMU_REGS_OFFS          0xd802c
+#define GC_REGS_OFFS           0xe802c
+
+/* MPP Base registers */
+#define PMU_MPP_GENERAL_CTRL   0x10
+#define  AU0_AC97_SEL          BIT(16)
+
+/* MPP Control 4 register */
+#define SPI_GPIO_SEL           BIT(5)
+#define UART1_GPIO_SEL         BIT(4)
+#define AU1_GPIO_SEL           BIT(3)
+#define CAM_GPIO_SEL           BIT(2)
+#define SD1_GPIO_SEL           BIT(1)
+#define SD0_GPIO_SEL           BIT(0)
+
+/* PMU Signal Select registers */
+#define PMU_SIGNAL_SELECT_0    0x00
+#define PMU_SIGNAL_SELECT_1    0x04
+
+/* Global Config regmap registers */
+#define GLOBAL_CONFIG_1                0x00
+#define  TWSI_ENABLE_OPTION1   BIT(7)
+#define GLOBAL_CONFIG_2                0x04
+#define  TWSI_ENABLE_OPTION2   BIT(20)
+#define  TWSI_ENABLE_OPTION3   BIT(21)
+#define  TWSI_OPTION3_GPIO     BIT(22)
+#define SSP_CTRL_STATUS_1      0x08
+#define  SSP_ON_AU1            BIT(0)
+#define MPP_GENERAL_CONFIG     0x10
+#define  AU1_SPDIFO_GPIO_EN    BIT(1)
+#define  NAND_GPIO_EN          BIT(0)
 
 #define CONFIG_PMU     BIT(4)
 
-static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
-                                unsigned long *config)
+static void __iomem *mpp_base;
+static void __iomem *mpp4_base;
+static void __iomem *pmu_base;
+static struct regmap *gconfmap;
+
+static int dove_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int dove_mpp_ctrl_set(unsigned pid, unsigned long config)
 {
-       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);
+       return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static int dove_pmu_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
        unsigned long 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;
-       }
+       if ((pmu & BIT(pid)) == 0)
+               return default_mpp_ctrl_get(mpp_base, pid, config);
+
+       func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
+       *config = (func >> shift) & MVEBU_MPP_MASK;
+       *config |= CONFIG_PMU;
+
        return 0;
 }
 
-static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
-                                unsigned long config)
+static int dove_pmu_mpp_ctrl_set(unsigned pid, unsigned long config)
 {
-       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 off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
        unsigned long func;
 
-       if (config & CONFIG_PMU) {
-               writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
-               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);
-               func = readl(DOVE_MPP_VIRT_BASE + off);
-               func &= ~(MPP_MASK << shift);
-               func |= (config & MPP_MASK) << shift;
-               writel(func, DOVE_MPP_VIRT_BASE + off);
+       if ((config & CONFIG_PMU) == 0) {
+               writel(pmu & ~BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+               return default_mpp_ctrl_set(mpp_base, pid, config);
        }
+
+       writel(pmu | BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+       func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
+       func &= ~(MVEBU_MPP_MASK << shift);
+       func |= (config & MVEBU_MPP_MASK) << shift;
+       writel(func, pmu_base + PMU_SIGNAL_SELECT_0 + off);
+
        return 0;
 }
 
-static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
-                             unsigned long *config)
+static int dove_mpp4_ctrl_get(unsigned pid, unsigned long *config)
 {
-       unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+       unsigned long mpp4 = readl(mpp4_base);
        unsigned long mask;
 
-       switch (ctrl->pid) {
+       switch (pid) {
        case 24: /* mpp_camera */
-               mask = DOVE_CAM_GPIO_SEL;
+               mask = CAM_GPIO_SEL;
                break;
        case 40: /* mpp_sdio0 */
-               mask = DOVE_SD0_GPIO_SEL;
+               mask = SD0_GPIO_SEL;
                break;
        case 46: /* mpp_sdio1 */
-               mask = DOVE_SD1_GPIO_SEL;
+               mask = SD1_GPIO_SEL;
                break;
        case 58: /* mpp_spi0 */
-               mask = DOVE_SPI_GPIO_SEL;
+               mask = SPI_GPIO_SEL;
                break;
        case 62: /* mpp_uart1 */
-               mask = DOVE_UART1_GPIO_SEL;
+               mask = UART1_GPIO_SEL;
                break;
        default:
                return -EINVAL;
@@ -129,27 +144,26 @@ static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
        return 0;
 }
 
-static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
-                             unsigned long config)
+static int dove_mpp4_ctrl_set(unsigned pid, unsigned long config)
 {
-       unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+       unsigned long mpp4 = readl(mpp4_base);
        unsigned long mask;
 
-       switch (ctrl->pid) {
+       switch (pid) {
        case 24: /* mpp_camera */
-               mask = DOVE_CAM_GPIO_SEL;
+               mask = CAM_GPIO_SEL;
                break;
        case 40: /* mpp_sdio0 */
-               mask = DOVE_SD0_GPIO_SEL;
+               mask = SD0_GPIO_SEL;
                break;
        case 46: /* mpp_sdio1 */
-               mask = DOVE_SD1_GPIO_SEL;
+               mask = SD1_GPIO_SEL;
                break;
        case 58: /* mpp_spi0 */
-               mask = DOVE_SPI_GPIO_SEL;
+               mask = SPI_GPIO_SEL;
                break;
        case 62: /* mpp_uart1 */
-               mask = DOVE_UART1_GPIO_SEL;
+               mask = UART1_GPIO_SEL;
                break;
        default:
                return -EINVAL;
@@ -159,74 +173,69 @@ static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
        if (config)
                mpp4 |= mask;
 
-       writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
+       writel(mpp4, mpp4_base);
 
        return 0;
 }
 
-static int dove_nand_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
-                             unsigned long *config)
+static int dove_nand_ctrl_get(unsigned pid, unsigned long *config)
 {
-       unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+       unsigned int gmpp;
 
-       *config = ((gmpp & DOVE_NAND_GPIO_EN) != 0);
+       regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp);
+       *config = ((gmpp & NAND_GPIO_EN) != 0);
 
        return 0;
 }
 
-static int dove_nand_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
-                             unsigned long config)
+static int dove_nand_ctrl_set(unsigned pid, unsigned long config)
 {
-       unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
-
-       gmpp &= ~DOVE_NAND_GPIO_EN;
-       if (config)
-               gmpp |= DOVE_NAND_GPIO_EN;
-
-       writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
-
+       regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
+                          NAND_GPIO_EN,
+                          (config) ? NAND_GPIO_EN : 0);
        return 0;
 }
 
-static int dove_audio0_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
-                               unsigned long *config)
+static int dove_audio0_ctrl_get(unsigned pid, unsigned long *config)
 {
-       unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
 
-       *config = ((pmu & DOVE_AU0_AC97_SEL) != 0);
+       *config = ((pmu & AU0_AC97_SEL) != 0);
 
        return 0;
 }
 
-static int dove_audio0_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
-                               unsigned long config)
+static int dove_audio0_ctrl_set(unsigned pid, unsigned long config)
 {
-       unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
 
-       pmu &= ~DOVE_AU0_AC97_SEL;
+       pmu &= ~AU0_AC97_SEL;
        if (config)
-               pmu |= DOVE_AU0_AC97_SEL;
-       writel(pmu, DOVE_PMU_MPP_GENERAL_CTRL);
+               pmu |= AU0_AC97_SEL;
+       writel(pmu, mpp_base + PMU_MPP_GENERAL_CTRL);
 
        return 0;
 }
 
-static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
-                               unsigned long *config)
+static int dove_audio1_ctrl_get(unsigned pid, unsigned long *config)
 {
-       unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
-       unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
-       unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
-       unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+       unsigned int mpp4 = readl(mpp4_base);
+       unsigned int sspc1;
+       unsigned int gmpp;
+       unsigned int gcfg2;
+
+       regmap_read(gconfmap, SSP_CTRL_STATUS_1, &sspc1);
+       regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp);
+       regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2);
 
        *config = 0;
-       if (mpp4 & DOVE_AU1_GPIO_SEL)
+       if (mpp4 & AU1_GPIO_SEL)
                *config |= BIT(3);
-       if (sspc1 & DOVE_SSP_ON_AU1)
+       if (sspc1 & SSP_ON_AU1)
                *config |= BIT(2);
-       if (gmpp & DOVE_AU1_SPDIFO_GPIO_EN)
+       if (gmpp & AU1_SPDIFO_GPIO_EN)
                *config |= BIT(1);
-       if (gcfg2 & DOVE_TWSI_OPTION3_GPIO)
+       if (gcfg2 & TWSI_OPTION3_GPIO)
                *config |= BIT(0);
 
        /* SSP/TWSI only if I2S1 not set*/
@@ -238,35 +247,24 @@ static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
        return 0;
 }
 
-static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
-                               unsigned long config)
+static int dove_audio1_ctrl_set(unsigned pid, unsigned long config)
 {
-       unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
-       unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
-       unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
-       unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+       unsigned int mpp4 = readl(mpp4_base);
 
-       /*
-        * clear all audio1 related bits before configure
-        */
-       gcfg2 &= ~DOVE_TWSI_OPTION3_GPIO;
-       gmpp &= ~DOVE_AU1_SPDIFO_GPIO_EN;
-       sspc1 &= ~DOVE_SSP_ON_AU1;
-       mpp4 &= ~DOVE_AU1_GPIO_SEL;
-
-       if (config & BIT(0))
-               gcfg2 |= DOVE_TWSI_OPTION3_GPIO;
-       if (config & BIT(1))
-               gmpp |= DOVE_AU1_SPDIFO_GPIO_EN;
-       if (config & BIT(2))
-               sspc1 |= DOVE_SSP_ON_AU1;
+       mpp4 &= ~AU1_GPIO_SEL;
        if (config & BIT(3))
-               mpp4 |= DOVE_AU1_GPIO_SEL;
-
-       writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
-       writel(sspc1, DOVE_SSP_CTRL_STATUS_1);
-       writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
-       writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+               mpp4 |= AU1_GPIO_SEL;
+       writel(mpp4, mpp4_base);
+
+       regmap_update_bits(gconfmap, SSP_CTRL_STATUS_1,
+                          SSP_ON_AU1,
+                          (config & BIT(2)) ? SSP_ON_AU1 : 0);
+       regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
+                          AU1_SPDIFO_GPIO_EN,
+                          (config & BIT(1)) ? AU1_SPDIFO_GPIO_EN : 0);
+       regmap_update_bits(gconfmap, GLOBAL_CONFIG_2,
+                          TWSI_OPTION3_GPIO,
+                          (config & BIT(0)) ? TWSI_OPTION3_GPIO : 0);
 
        return 0;
 }
@@ -276,11 +274,11 @@ static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
  * break other functions. If you require all mpps as gpio
  * enforce gpio setting by pinctrl mapping.
  */
-static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
+static int dove_audio1_ctrl_gpio_req(unsigned pid)
 {
        unsigned long config;
 
-       dove_audio1_ctrl_get(ctrl, &config);
+       dove_audio1_ctrl_get(pid, &config);
 
        switch (config) {
        case 0x02: /* i2s1 : gpio[56:57] */
@@ -303,76 +301,62 @@ static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
 }
 
 /* mpp[52:57] has gpio pins capable of in and out */
-static int dove_audio1_ctrl_gpio_dir(struct mvebu_mpp_ctrl *ctrl, u8 pid,
-                               bool input)
+static int dove_audio1_ctrl_gpio_dir(unsigned pid, bool input)
 {
        if (pid < 52 || pid > 57)
                return -ENOTSUPP;
        return 0;
 }
 
-static int dove_twsi_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
-                             unsigned long *config)
+static int dove_twsi_ctrl_get(unsigned pid, unsigned long *config)
 {
-       unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
-       unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+       unsigned int gcfg1;
+       unsigned int gcfg2;
+
+       regmap_read(gconfmap, GLOBAL_CONFIG_1, &gcfg1);
+       regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2);
 
        *config = 0;
-       if (gcfg1 & DOVE_TWSI_ENABLE_OPTION1)
+       if (gcfg1 & TWSI_ENABLE_OPTION1)
                *config = 1;
-       else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION2)
+       else if (gcfg2 & TWSI_ENABLE_OPTION2)
                *config = 2;
-       else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION3)
+       else if (gcfg2 & TWSI_ENABLE_OPTION3)
                *config = 3;
 
        return 0;
 }
 
-static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
-                               unsigned long config)
+static int dove_twsi_ctrl_set(unsigned pid, unsigned long config)
 {
-       unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
-       unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
-
-       gcfg1 &= ~DOVE_TWSI_ENABLE_OPTION1;
-       gcfg2 &= ~(DOVE_TWSI_ENABLE_OPTION2 | DOVE_TWSI_ENABLE_OPTION3);
+       unsigned int gcfg1 = 0;
+       unsigned int gcfg2 = 0;
 
        switch (config) {
        case 1:
-               gcfg1 |= DOVE_TWSI_ENABLE_OPTION1;
+               gcfg1 TWSI_ENABLE_OPTION1;
                break;
        case 2:
-               gcfg2 |= DOVE_TWSI_ENABLE_OPTION2;
+               gcfg2 TWSI_ENABLE_OPTION2;
                break;
        case 3:
-               gcfg2 |= DOVE_TWSI_ENABLE_OPTION3;
+               gcfg2 TWSI_ENABLE_OPTION3;
                break;
        }
 
-       writel(gcfg1, DOVE_GLOBAL_CONFIG_1);
-       writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+       regmap_update_bits(gconfmap, GLOBAL_CONFIG_1,
+                          TWSI_ENABLE_OPTION1,
+                          gcfg1);
+       regmap_update_bits(gconfmap, GLOBAL_CONFIG_2,
+                          TWSI_ENABLE_OPTION2 | TWSI_ENABLE_OPTION3,
+                          gcfg2);
 
        return 0;
 }
 
 static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 0, "mpp0", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(1, 1, "mpp1", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(2, 2, "mpp2", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(3, 3, "mpp3", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(4, 4, "mpp4", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(5, 5, "mpp5", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(6, 6, "mpp6", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(7, 7, "mpp7", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(8, 8, "mpp8", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(9, 9, "mpp9", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(10, 10, "mpp10", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(11, 11, "mpp11", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(12, 12, "mpp12", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(13, 13, "mpp13", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(14, 14, "mpp14", dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(15, 15, "mpp15", dove_pmu_mpp_ctrl),
-       MPP_REG_CTRL(16, 23),
+       MPP_FUNC_CTRL(0, 15, NULL, dove_pmu_mpp_ctrl),
+       MPP_FUNC_CTRL(16, 23, NULL, dove_mpp_ctrl),
        MPP_FUNC_CTRL(24, 39, "mpp_camera", dove_mpp4_ctrl),
        MPP_FUNC_CTRL(40, 45, "mpp_sdio0", dove_mpp4_ctrl),
        MPP_FUNC_CTRL(46, 51, "mpp_sdio1", dove_mpp4_ctrl),
@@ -772,8 +756,17 @@ static struct of_device_id dove_pinctrl_of_match[] = {
        { }
 };
 
+static struct regmap_config gc_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = 5,
+};
+
 static int dove_pinctrl_probe(struct platform_device *pdev)
 {
+       struct resource *res, *mpp_res;
+       struct resource fb_res;
        const struct of_device_id *match =
                of_match_device(dove_pinctrl_of_match, &pdev->dev);
        pdev->dev.platform_data = (void *)match->data;
@@ -789,6 +782,59 @@ static int dove_pinctrl_probe(struct platform_device *pdev)
        }
        clk_prepare_enable(clk);
 
+       mpp_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mpp_base = devm_ioremap_resource(&pdev->dev, mpp_res);
+       if (IS_ERR(mpp_base))
+               return PTR_ERR(mpp_base);
+
+       /* prepare fallback resource */
+       memcpy(&fb_res, mpp_res, sizeof(struct resource));
+       fb_res.start = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_warn(&pdev->dev, "falling back to hardcoded MPP4 resource\n");
+               adjust_resource(&fb_res,
+                       (mpp_res->start & INT_REGS_MASK) + MPP4_REGS_OFFS, 0x4);
+               res = &fb_res;
+       }
+
+       mpp4_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mpp4_base))
+               return PTR_ERR(mpp4_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       if (!res) {
+               dev_warn(&pdev->dev, "falling back to hardcoded PMU resource\n");
+               adjust_resource(&fb_res,
+                       (mpp_res->start & INT_REGS_MASK) + PMU_REGS_OFFS, 0x8);
+               res = &fb_res;
+       }
+
+       pmu_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pmu_base))
+               return PTR_ERR(pmu_base);
+
+       gconfmap = syscon_regmap_lookup_by_compatible("marvell,dove-global-config");
+       if (IS_ERR(gconfmap)) {
+               void __iomem *gc_base;
+
+               dev_warn(&pdev->dev, "falling back to hardcoded global registers\n");
+               adjust_resource(&fb_res,
+                       (mpp_res->start & INT_REGS_MASK) + GC_REGS_OFFS, 0x14);
+               gc_base = devm_ioremap_resource(&pdev->dev, &fb_res);
+               if (IS_ERR(gc_base))
+                       return PTR_ERR(gc_base);
+               gconfmap = devm_regmap_init_mmio(&pdev->dev,
+                                                gc_base, &gc_regmap_config);
+               if (IS_ERR(gconfmap))
+                       return PTR_ERR(gconfmap);
+       }
+
+       /* Warn on any missing DT resource */
+       if (fb_res.start)
+               dev_warn(&pdev->dev, FW_BUG "Missing pinctrl regs in DTB. Please update your firmware.\n");
+
        return mvebu_pinctrl_probe(pdev);
 }
 
index 6b504b5935a5ec75ecff507a0717e82af4b72982..0d0211a1a0b005659a4ddbe557c46fd8dbe1d521 100644 (file)
 
 #include "pinctrl-mvebu.h"
 
+static void __iomem *mpp_base;
+
+static int kirkwood_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+       return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int kirkwood_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+       return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
 #define V(f6180, f6190, f6192, f6281, f6282, dx4122)   \
        ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) |   \
         (f6281 << 3) | (f6282 << 4) | (dx4122 << 5))
@@ -359,7 +371,7 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
 };
 
 static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
-       MPP_REG_CTRL(0, 29),
+       MPP_FUNC_CTRL(0, 29, NULL, kirkwood_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
@@ -367,7 +379,7 @@ static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
 };
 
 static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
-       MPP_REG_CTRL(0, 35),
+       MPP_FUNC_CTRL(0, 35, NULL, kirkwood_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
@@ -376,7 +388,7 @@ static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
 };
 
 static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = {
-       MPP_REG_CTRL(0, 49),
+       MPP_FUNC_CTRL(0, 49, NULL, kirkwood_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = {
@@ -456,9 +468,16 @@ static struct of_device_id kirkwood_pinctrl_of_match[] = {
 
 static int kirkwood_pinctrl_probe(struct platform_device *pdev)
 {
+       struct resource *res;
        const struct of_device_id *match =
                of_match_device(kirkwood_pinctrl_of_match, &pdev->dev);
        pdev->dev.platform_data = (void *)match->data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mpp_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mpp_base))
+               return PTR_ERR(mpp_base);
+
        return mvebu_pinctrl_probe(pdev);
 }
 
index 0fd1ad31fbf9aa719d19dffb7f18cc61194d2984..9908374f8f9207d0242b5fe1e081d2c066be0de3 100644 (file)
@@ -50,7 +50,6 @@ struct mvebu_pinctrl {
        struct device *dev;
        struct pinctrl_dev *pctldev;
        struct pinctrl_desc desc;
-       void __iomem *base;
        struct mvebu_pinctrl_group *groups;
        unsigned num_groups;
        struct mvebu_pinctrl_function *functions;
@@ -138,43 +137,6 @@ static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name(
        return NULL;
 }
 
-/*
- * Common mpp pin configuration registers on MVEBU are
- * registers of eight 4-bit values for each mpp setting.
- * Register offset and bit mask are calculated accordingly below.
- */
-static int mvebu_common_mpp_get(struct mvebu_pinctrl *pctl,
-                               struct mvebu_pinctrl_group *grp,
-                               unsigned long *config)
-{
-       unsigned pin = grp->gid;
-       unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
-       unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
-
-       *config = readl(pctl->base + off);
-       *config >>= shift;
-       *config &= MPP_MASK;
-
-       return 0;
-}
-
-static int mvebu_common_mpp_set(struct mvebu_pinctrl *pctl,
-                               struct mvebu_pinctrl_group *grp,
-                               unsigned long config)
-{
-       unsigned pin = grp->gid;
-       unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
-       unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
-       unsigned long reg;
-
-       reg = readl(pctl->base + off);
-       reg &= ~(MPP_MASK << shift);
-       reg |= (config << shift);
-       writel(reg, pctl->base + off);
-
-       return 0;
-}
-
 static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
                                unsigned gid, unsigned long *config)
 {
@@ -184,10 +146,7 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
        if (!grp->ctrl)
                return -EINVAL;
 
-       if (grp->ctrl->mpp_get)
-               return grp->ctrl->mpp_get(grp->ctrl, config);
-
-       return mvebu_common_mpp_get(pctl, grp, config);
+       return grp->ctrl->mpp_get(grp->pins[0], config);
 }
 
 static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
@@ -202,11 +161,7 @@ static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        for (i = 0; i < num_configs; i++) {
-               if (grp->ctrl->mpp_set)
-                       ret = grp->ctrl->mpp_set(grp->ctrl, configs[i]);
-               else
-                       ret = mvebu_common_mpp_set(pctl, grp, configs[i]);
-
+               ret = grp->ctrl->mpp_set(grp->pins[0], configs[i]);
                if (ret)
                        return ret;
        } /* for each config */
@@ -347,7 +302,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        if (grp->ctrl->mpp_gpio_req)
-               return grp->ctrl->mpp_gpio_req(grp->ctrl, offset);
+               return grp->ctrl->mpp_gpio_req(offset);
 
        setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
        if (!setting)
@@ -370,7 +325,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        if (grp->ctrl->mpp_gpio_dir)
-               return grp->ctrl->mpp_gpio_dir(grp->ctrl, offset, input);
+               return grp->ctrl->mpp_gpio_dir(offset, input);
 
        setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
        if (!setting)
@@ -593,11 +548,12 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
 int mvebu_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
-       struct resource *res;
        struct mvebu_pinctrl *pctl;
-       void __iomem *base;
        struct pinctrl_pin_desc *pdesc;
        unsigned gid, n, k;
+       unsigned size, noname = 0;
+       char *noname_buf;
+       void *p;
        int ret;
 
        if (!soc || !soc->controls || !soc->modes) {
@@ -605,11 +561,6 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-
        pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
                        GFP_KERNEL);
        if (!pctl) {
@@ -623,7 +574,6 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
        pctl->desc.pmxops = &mvebu_pinmux_ops;
        pctl->desc.confops = &mvebu_pinconf_ops;
        pctl->variant = soc->variant;
-       pctl->base = base;
        pctl->dev = &pdev->dev;
        platform_set_drvdata(pdev, pctl);
 
@@ -633,33 +583,23 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
        pctl->desc.npins = 0;
        for (n = 0; n < soc->ncontrols; n++) {
                struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
-               char *names;
 
                pctl->desc.npins += ctrl->npins;
-               /* initial control pins */
+               /* initialize control's pins[] array */
                for (k = 0; k < ctrl->npins; k++)
                        ctrl->pins[k] = ctrl->pid + k;
 
-               /* special soc specific control */
-               if (ctrl->mpp_get || ctrl->mpp_set) {
-                       if (!ctrl->name || !ctrl->mpp_get || !ctrl->mpp_set) {
-                               dev_err(&pdev->dev, "wrong soc control info\n");
-                               return -EINVAL;
-                       }
+               /*
+                * We allow to pass controls with NULL name that we treat
+                * as a range of one-pin groups with generic mvebu register
+                * controls.
+                */
+               if (!ctrl->name) {
+                       pctl->num_groups += ctrl->npins;
+                       noname += ctrl->npins;
+               } else {
                        pctl->num_groups += 1;
-                       continue;
                }
-
-               /* generic mvebu register control */
-               names = devm_kzalloc(&pdev->dev, ctrl->npins * 8, GFP_KERNEL);
-               if (!names) {
-                       dev_err(&pdev->dev, "failed to alloc mpp names\n");
-                       return -ENOMEM;
-               }
-               for (k = 0; k < ctrl->npins; k++)
-                       sprintf(names + 8*k, "mpp%d", ctrl->pid+k);
-               ctrl->name = names;
-               pctl->num_groups += ctrl->npins;
        }
 
        pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins *
@@ -673,12 +613,17 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                pdesc[n].number = n;
        pctl->desc.pins = pdesc;
 
-       pctl->groups = devm_kzalloc(&pdev->dev, pctl->num_groups *
-                            sizeof(struct mvebu_pinctrl_group), GFP_KERNEL);
-       if (!pctl->groups) {
-               dev_err(&pdev->dev, "failed to alloc pinctrl groups\n");
+       /*
+        * allocate groups and name buffers for unnamed groups.
+        */
+       size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8;
+       p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!p) {
+               dev_err(&pdev->dev, "failed to alloc group data\n");
                return -ENOMEM;
        }
+       pctl->groups = p;
+       noname_buf = p + pctl->num_groups * sizeof(*pctl->groups);
 
        /* assign mpp controls to groups */
        gid = 0;
@@ -690,17 +635,26 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                pctl->groups[gid].pins = ctrl->pins;
                pctl->groups[gid].npins = ctrl->npins;
 
-               /* generic mvebu register control maps to a number of groups */
-               if (!ctrl->mpp_get && !ctrl->mpp_set) {
+               /*
+                * We treat unnamed controls as a range of one-pin groups
+                * with generic mvebu register controls. Use one group for
+                * each in this range and assign a default group name.
+                */
+               if (!ctrl->name) {
+                       pctl->groups[gid].name = noname_buf;
                        pctl->groups[gid].npins = 1;
+                       sprintf(noname_buf, "mpp%d", ctrl->pid+0);
+                       noname_buf += 8;
 
                        for (k = 1; k < ctrl->npins; k++) {
                                gid++;
                                pctl->groups[gid].gid = gid;
                                pctl->groups[gid].ctrl = ctrl;
-                               pctl->groups[gid].name = &ctrl->name[8*k];
+                               pctl->groups[gid].name = noname_buf;
                                pctl->groups[gid].pins = &ctrl->pins[k];
                                pctl->groups[gid].npins = 1;
+                               sprintf(noname_buf, "mpp%d", ctrl->pid+k);
+                               noname_buf += 8;
                        }
                }
                gid++;
index 90bd3beee860a10dfa0b085d5d9bbb7261cae1ab..65a98e6f72657a3277154bcbe8e8adee82cde20f 100644 (file)
  * between two or more different settings, e.g. assign mpp pin 13 to
  * uart1 or sata.
  *
- * If optional mpp_get/_set functions are set these are used to get/set
- * a specific mode. Otherwise it is assumed that the mpp control is based
- * on 4-bit groups in subsequent registers. The optional mpp_gpio_req/_dir
- * functions can be used to allow pin settings with varying gpio pins.
+ * The mpp_get/_set functions are mandatory and are used to get/set a
+ * specific mode. The optional mpp_gpio_req/_dir functions can be used
+ * to allow pin settings with varying gpio pins.
  */
 struct mvebu_mpp_ctrl {
        const char *name;
        u8 pid;
        u8 npins;
        unsigned *pins;
-       int (*mpp_get)(struct mvebu_mpp_ctrl *ctrl, unsigned long *config);
-       int (*mpp_set)(struct mvebu_mpp_ctrl *ctrl, unsigned long config);
-       int (*mpp_gpio_req)(struct mvebu_mpp_ctrl *ctrl, u8 pid);
-       int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl *ctrl, u8 pid, bool input);
+       int (*mpp_get)(unsigned pid, unsigned long *config);
+       int (*mpp_set)(unsigned pid, unsigned long config);
+       int (*mpp_gpio_req)(unsigned pid);
+       int (*mpp_gpio_dir)(unsigned pid, bool input);
 };
 
 /**
@@ -114,18 +113,6 @@ struct mvebu_pinctrl_soc_info {
        int ngpioranges;
 };
 
-#define MPP_REG_CTRL(_idl, _idh)                               \
-       {                                                       \
-               .name = NULL,                                   \
-               .pid = _idl,                                    \
-               .npins = _idh - _idl + 1,                       \
-               .pins = (unsigned[_idh - _idl + 1]) { },        \
-               .mpp_get = NULL,                                \
-               .mpp_set = NULL,                                \
-               .mpp_gpio_req = NULL,                           \
-               .mpp_gpio_dir = NULL,                           \
-       }
-
 #define MPP_FUNC_CTRL(_idl, _idh, _name, _func)                        \
        {                                                       \
                .name = _name,                                  \
@@ -186,6 +173,34 @@ struct mvebu_pinctrl_soc_info {
                .npins = _npins,                                \
        }
 
+#define MVEBU_MPPS_PER_REG     8
+#define MVEBU_MPP_BITS         4
+#define MVEBU_MPP_MASK         0xf
+
+static inline int default_mpp_ctrl_get(void __iomem *base, unsigned int pid,
+                                      unsigned long *config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+
+       *config = (readl(base + off) >> shift) & MVEBU_MPP_MASK;
+
+       return 0;
+}
+
+static inline int default_mpp_ctrl_set(void __iomem *base, unsigned int pid,
+                                      unsigned long config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned long reg;
+
+       reg = readl(base + off) & ~(MVEBU_MPP_MASK << shift);
+       writel(reg | (config << shift), base + off);
+
+       return 0;
+}
+
 int mvebu_pinctrl_probe(struct platform_device *pdev);
 int mvebu_pinctrl_remove(struct platform_device *pdev);
 
index ea9d9ab9cda1dc3c1342f83a00e1e8f40a0dc2df..008a29e92e56dffe8f8151b81aa364267a69ec56 100644 (file)
@@ -309,39 +309,6 @@ static const unsigned keys_8x8_pins[] = {
        GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7,
 };
 
-static const struct adi_pin_group adi_pin_groups[] = {
-       ADI_PIN_GROUP("uart0grp", uart0_pins),
-       ADI_PIN_GROUP("uart1grp", uart1_pins),
-       ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins),
-       ADI_PIN_GROUP("uart2grp", uart2_pins),
-       ADI_PIN_GROUP("uart3grp", uart3_pins),
-       ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins),
-       ADI_PIN_GROUP("rsi0grp", rsi0_pins),
-       ADI_PIN_GROUP("spi0grp", spi0_pins),
-       ADI_PIN_GROUP("spi1grp", spi1_pins),
-       ADI_PIN_GROUP("twi0grp", twi0_pins),
-       ADI_PIN_GROUP("twi1grp", twi1_pins),
-       ADI_PIN_GROUP("rotarygrp", rotary_pins),
-       ADI_PIN_GROUP("can0grp", can0_pins),
-       ADI_PIN_GROUP("can1grp", can1_pins),
-       ADI_PIN_GROUP("smc0grp", smc0_pins),
-       ADI_PIN_GROUP("sport0grp", sport0_pins),
-       ADI_PIN_GROUP("sport1grp", sport1_pins),
-       ADI_PIN_GROUP("sport2grp", sport2_pins),
-       ADI_PIN_GROUP("sport3grp", sport3_pins),
-       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
-       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
-       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
-       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
-       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
-       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
-       ADI_PIN_GROUP("atapigrp", atapi_pins),
-       ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins),
-       ADI_PIN_GROUP("nfc0grp", nfc0_pins),
-       ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins),
-       ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins),
-};
-
 static const unsigned short uart0_mux[] = {
        P_UART0_TX, P_UART0_RX,
        0
@@ -513,6 +480,39 @@ static const unsigned short keys_8x8_mux[] = {
        0
 };
 
+static const struct adi_pin_group adi_pin_groups[] = {
+       ADI_PIN_GROUP("uart0grp", uart0_pins, uart0_mux),
+       ADI_PIN_GROUP("uart1grp", uart1_pins, uart1_mux),
+       ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins, uart1_ctsrts_mux),
+       ADI_PIN_GROUP("uart2grp", uart2_pins, uart2_mux),
+       ADI_PIN_GROUP("uart3grp", uart3_pins, uart3_mux),
+       ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins, uart3_ctsrts_mux),
+       ADI_PIN_GROUP("rsi0grp", rsi0_pins, rsi0_mux),
+       ADI_PIN_GROUP("spi0grp", spi0_pins, spi0_mux),
+       ADI_PIN_GROUP("spi1grp", spi1_pins, spi1_mux),
+       ADI_PIN_GROUP("twi0grp", twi0_pins, twi0_mux),
+       ADI_PIN_GROUP("twi1grp", twi1_pins, twi1_mux),
+       ADI_PIN_GROUP("rotarygrp", rotary_pins, rotary_mux),
+       ADI_PIN_GROUP("can0grp", can0_pins, can0_mux),
+       ADI_PIN_GROUP("can1grp", can1_pins, can1_mux),
+       ADI_PIN_GROUP("smc0grp", smc0_pins, smc0_mux),
+       ADI_PIN_GROUP("sport0grp", sport0_pins, sport0_mux),
+       ADI_PIN_GROUP("sport1grp", sport1_pins, sport1_mux),
+       ADI_PIN_GROUP("sport2grp", sport2_pins, sport2_mux),
+       ADI_PIN_GROUP("sport3grp", sport3_pins, sport3_mux),
+       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins, ppi0_8b_mux),
+       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins, ppi0_16b_mux),
+       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins, ppi0_24b_mux),
+       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins, ppi1_8b_mux),
+       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins, ppi1_16b_mux),
+       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins, ppi2_8b_mux),
+       ADI_PIN_GROUP("atapigrp", atapi_pins, atapi_mux),
+       ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins, atapi_alter_mux),
+       ADI_PIN_GROUP("nfc0grp", nfc0_pins, nfc0_mux),
+       ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins, keys_4x4_mux),
+       ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins, keys_8x8_mux),
+};
+
 static const char * const uart0grp[] = { "uart0grp" };
 static const char * const uart1grp[] = { "uart1grp" };
 static const char * const uart1ctsrtsgrp[] = { "uart1ctsrtsgrp" };
@@ -532,49 +532,45 @@ static const char * const sport0grp[] = { "sport0grp" };
 static const char * const sport1grp[] = { "sport1grp" };
 static const char * const sport2grp[] = { "sport2grp" };
 static const char * const sport3grp[] = { "sport3grp" };
-static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
-static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
-static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
-static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
-static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
-static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
+static const char * const ppi0grp[] = { "ppi0_8bgrp",
+                                       "ppi0_16bgrp",
+                                       "ppi0_24bgrp" };
+static const char * const ppi1grp[] = { "ppi1_8bgrp",
+                                       "ppi1_16bgrp" };
+static const char * const ppi2grp[] = { "ppi2_8bgrp" };
 static const char * const atapigrp[] = { "atapigrp" };
 static const char * const atapialtergrp[] = { "atapialtergrp" };
 static const char * const nfc0grp[] = { "nfc0grp" };
-static const char * const keys_4x4grp[] = { "keys_4x4grp" };
-static const char * const keys_8x8grp[] = { "keys_8x8grp" };
+static const char * const keysgrp[] = { "keys_4x4grp",
+                                       "keys_8x8grp" };
 
 static const struct adi_pmx_func adi_pmx_functions[] = {
-       ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
-       ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
-       ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux),
-       ADI_PMX_FUNCTION("uart2", uart2grp, uart2_mux),
-       ADI_PMX_FUNCTION("uart3", uart3grp, uart3_mux),
-       ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp, uart3_ctsrts_mux),
-       ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
-       ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
-       ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
-       ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
-       ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
-       ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
-       ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
-       ADI_PMX_FUNCTION("can1", can1grp, can1_mux),
-       ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
-       ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
-       ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
-       ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
-       ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux),
-       ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
-       ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
-       ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
-       ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
-       ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
-       ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
-       ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux),
-       ADI_PMX_FUNCTION("atapi_alter", atapialtergrp, atapi_alter_mux),
-       ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux),
-       ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux),
-       ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux),
+       ADI_PMX_FUNCTION("uart0", uart0grp),
+       ADI_PMX_FUNCTION("uart1", uart1grp),
+       ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp),
+       ADI_PMX_FUNCTION("uart2", uart2grp),
+       ADI_PMX_FUNCTION("uart3", uart3grp),
+       ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp),
+       ADI_PMX_FUNCTION("rsi0", rsi0grp),
+       ADI_PMX_FUNCTION("spi0", spi0grp),
+       ADI_PMX_FUNCTION("spi1", spi1grp),
+       ADI_PMX_FUNCTION("twi0", twi0grp),
+       ADI_PMX_FUNCTION("twi1", twi1grp),
+       ADI_PMX_FUNCTION("rotary", rotarygrp),
+       ADI_PMX_FUNCTION("can0", can0grp),
+       ADI_PMX_FUNCTION("can1", can1grp),
+       ADI_PMX_FUNCTION("smc0", smc0grp),
+       ADI_PMX_FUNCTION("sport0", sport0grp),
+       ADI_PMX_FUNCTION("sport1", sport1grp),
+       ADI_PMX_FUNCTION("sport2", sport2grp),
+       ADI_PMX_FUNCTION("sport3", sport3grp),
+       ADI_PMX_FUNCTION("ppi0", ppi0grp),
+       ADI_PMX_FUNCTION("ppi1", ppi1grp),
+       ADI_PMX_FUNCTION("ppi2", ppi2grp),
+       ADI_PMX_FUNCTION("atapi", atapigrp),
+       ADI_PMX_FUNCTION("atapi_alter", atapialtergrp),
+       ADI_PMX_FUNCTION("nfc0", nfc0grp),
+       ADI_PMX_FUNCTION("keys", keysgrp),
 };
 
 static const struct adi_pinctrl_soc_data adi_bf54x_soc = {
index bf57aea2826c737bcba2482614a2b690d0832b3e..4cb59fe9be7039154079f572af6a24634b9d5ac4 100644 (file)
@@ -259,37 +259,6 @@ static const unsigned lp3_pins[] = {
        GPIO_PF12, GPIO_PF13, GPIO_PF14, GPIO_PF15,
 };
 
-static const struct adi_pin_group adi_pin_groups[] = {
-       ADI_PIN_GROUP("uart0grp", uart0_pins),
-       ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins),
-       ADI_PIN_GROUP("uart1grp", uart1_pins),
-       ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins),
-       ADI_PIN_GROUP("rsi0grp", rsi0_pins),
-       ADI_PIN_GROUP("eth0grp", eth0_pins),
-       ADI_PIN_GROUP("eth1grp", eth1_pins),
-       ADI_PIN_GROUP("spi0grp", spi0_pins),
-       ADI_PIN_GROUP("spi1grp", spi1_pins),
-       ADI_PIN_GROUP("twi0grp", twi0_pins),
-       ADI_PIN_GROUP("twi1grp", twi1_pins),
-       ADI_PIN_GROUP("rotarygrp", rotary_pins),
-       ADI_PIN_GROUP("can0grp", can0_pins),
-       ADI_PIN_GROUP("smc0grp", smc0_pins),
-       ADI_PIN_GROUP("sport0grp", sport0_pins),
-       ADI_PIN_GROUP("sport1grp", sport1_pins),
-       ADI_PIN_GROUP("sport2grp", sport2_pins),
-       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
-       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
-       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
-       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
-       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
-       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
-       ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins),
-       ADI_PIN_GROUP("lp0grp", lp0_pins),
-       ADI_PIN_GROUP("lp1grp", lp1_pins),
-       ADI_PIN_GROUP("lp2grp", lp2_pins),
-       ADI_PIN_GROUP("lp3grp", lp3_pins),
-};
-
 static const unsigned short uart0_mux[] = {
        P_UART0_TX, P_UART0_RX,
        0
@@ -446,6 +415,37 @@ static const unsigned short lp3_mux[] = {
         0
 };
 
+static const struct adi_pin_group adi_pin_groups[] = {
+       ADI_PIN_GROUP("uart0grp", uart0_pins, uart0_mux),
+       ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins, uart0_ctsrts_mux),
+       ADI_PIN_GROUP("uart1grp", uart1_pins, uart1_mux),
+       ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins, uart1_ctsrts_mux),
+       ADI_PIN_GROUP("rsi0grp", rsi0_pins, rsi0_mux),
+       ADI_PIN_GROUP("eth0grp", eth0_pins, eth0_mux),
+       ADI_PIN_GROUP("eth1grp", eth1_pins, eth1_mux),
+       ADI_PIN_GROUP("spi0grp", spi0_pins, spi0_mux),
+       ADI_PIN_GROUP("spi1grp", spi1_pins, spi1_mux),
+       ADI_PIN_GROUP("twi0grp", twi0_pins, twi0_mux),
+       ADI_PIN_GROUP("twi1grp", twi1_pins, twi1_mux),
+       ADI_PIN_GROUP("rotarygrp", rotary_pins, rotary_mux),
+       ADI_PIN_GROUP("can0grp", can0_pins, can0_mux),
+       ADI_PIN_GROUP("smc0grp", smc0_pins, smc0_mux),
+       ADI_PIN_GROUP("sport0grp", sport0_pins, sport0_mux),
+       ADI_PIN_GROUP("sport1grp", sport1_pins, sport1_mux),
+       ADI_PIN_GROUP("sport2grp", sport2_pins, sport2_mux),
+       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins, ppi0_8b_mux),
+       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins, ppi0_16b_mux),
+       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins, ppi0_24b_mux),
+       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins, ppi1_8b_mux),
+       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins, ppi1_16b_mux),
+       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins, ppi2_8b_mux),
+       ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins, ppi2_16b_mux),
+       ADI_PIN_GROUP("lp0grp", lp0_pins, lp0_mux),
+       ADI_PIN_GROUP("lp1grp", lp1_pins, lp1_mux),
+       ADI_PIN_GROUP("lp2grp", lp2_pins, lp2_mux),
+       ADI_PIN_GROUP("lp3grp", lp3_pins, lp3_mux),
+};
+
 static const char * const uart0grp[] = { "uart0grp" };
 static const char * const uart0ctsrtsgrp[] = { "uart0ctsrtsgrp" };
 static const char * const uart1grp[] = { "uart1grp" };
@@ -463,47 +463,43 @@ static const char * const smc0grp[] = { "smc0grp" };
 static const char * const sport0grp[] = { "sport0grp" };
 static const char * const sport1grp[] = { "sport1grp" };
 static const char * const sport2grp[] = { "sport2grp" };
-static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
-static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
-static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
-static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
-static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
-static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
-static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" };
+static const char * const ppi0grp[] = { "ppi0_8bgrp",
+                                       "ppi0_16bgrp",
+                                       "ppi0_24bgrp" };
+static const char * const ppi1grp[] = { "ppi1_8bgrp",
+                                       "ppi1_16bgrp" };
+static const char * const ppi2grp[] = { "ppi2_8bgrp",
+                                       "ppi2_16bgrp" };
 static const char * const lp0grp[] = { "lp0grp" };
 static const char * const lp1grp[] = { "lp1grp" };
 static const char * const lp2grp[] = { "lp2grp" };
 static const char * const lp3grp[] = { "lp3grp" };
 
 static const struct adi_pmx_func adi_pmx_functions[] = {
-       ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
-       ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp, uart0_ctsrts_mux),
-       ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
-       ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux),
-       ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
-       ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux),
-       ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux),
-       ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
-       ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
-       ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
-       ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
-       ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
-       ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
-       ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
-       ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
-       ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
-       ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
-       ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
-       ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
-       ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
-       ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
-       ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
-       ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
-       ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux),
-       ADI_PMX_FUNCTION("lp0", lp0grp, lp0_mux),
-       ADI_PMX_FUNCTION("lp1", lp1grp, lp1_mux),
-       ADI_PMX_FUNCTION("lp2", lp2grp, lp2_mux),
-       ADI_PMX_FUNCTION("lp3", lp3grp, lp3_mux),
+       ADI_PMX_FUNCTION("uart0", uart0grp),
+       ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp),
+       ADI_PMX_FUNCTION("uart1", uart1grp),
+       ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp),
+       ADI_PMX_FUNCTION("rsi0", rsi0grp),
+       ADI_PMX_FUNCTION("eth0", eth0grp),
+       ADI_PMX_FUNCTION("eth1", eth1grp),
+       ADI_PMX_FUNCTION("spi0", spi0grp),
+       ADI_PMX_FUNCTION("spi1", spi1grp),
+       ADI_PMX_FUNCTION("twi0", twi0grp),
+       ADI_PMX_FUNCTION("twi1", twi1grp),
+       ADI_PMX_FUNCTION("rotary", rotarygrp),
+       ADI_PMX_FUNCTION("can0", can0grp),
+       ADI_PMX_FUNCTION("smc0", smc0grp),
+       ADI_PMX_FUNCTION("sport0", sport0grp),
+       ADI_PMX_FUNCTION("sport1", sport1grp),
+       ADI_PMX_FUNCTION("sport2", sport2grp),
+       ADI_PMX_FUNCTION("ppi0", ppi0grp),
+       ADI_PMX_FUNCTION("ppi1", ppi1grp),
+       ADI_PMX_FUNCTION("ppi2", ppi2grp),
+       ADI_PMX_FUNCTION("lp0", lp0grp),
+       ADI_PMX_FUNCTION("lp1", lp1grp),
+       ADI_PMX_FUNCTION("lp2", lp2grp),
+       ADI_PMX_FUNCTION("lp3", lp3grp),
 };
 
 static const struct adi_pinctrl_soc_data adi_bf60x_soc = {
index 7a39562c3e42f4f70fff0ffe3924edd6ba4ac609..200ea1e72d4040afb75254beef022948d45b2811 100644 (file)
@@ -89,6 +89,19 @@ struct gpio_port_saved {
        u32 mux;
 };
 
+/*
+ * struct gpio_pint_saved - PINT registers saved in PM operations
+ *
+ * @assign: ASSIGN register
+ * @edge_set: EDGE_SET register
+ * @invert_set: INVERT_SET register
+ */
+struct gpio_pint_saved {
+       u32 assign;
+       u32 edge_set;
+       u32 invert_set;
+};
+
 /**
  * struct gpio_pint - Pin interrupt controller device. Multiple ADI GPIO
  * banks can be mapped into one Pin interrupt controller.
@@ -114,7 +127,7 @@ struct gpio_pint {
        int irq;
        struct irq_domain *domain[2];
        struct gpio_pint_regs *regs;
-       struct adi_pm_pint_save saved_data;
+       struct gpio_pint_saved saved_data;
        int map_count;
        spinlock_t lock;
 
@@ -160,7 +173,7 @@ struct adi_pinctrl {
 struct gpio_port {
        struct list_head node;
        void __iomem *base;
-       unsigned int irq_base;
+       int irq_base;
        unsigned int width;
        struct gpio_port_t *regs;
        struct gpio_port_saved saved_data;
@@ -605,8 +618,8 @@ static struct pinctrl_ops adi_pctrl_ops = {
        .get_group_pins = adi_get_group_pins,
 };
 
-static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
-       unsigned group)
+static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned func_id,
+       unsigned group_id)
 {
        struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
        struct gpio_port *port;
@@ -614,7 +627,7 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
        unsigned long flags;
        unsigned short *mux, pin;
 
-       mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
+       mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
 
        while (*mux) {
                pin = P_IDENT(*mux);
@@ -628,7 +641,7 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
                spin_lock_irqsave(&port->lock, flags);
 
                portmux_setup(port, pin_to_offset(range, pin),
-                                P_FUNCT2MUX(*mux));
+                               P_FUNCT2MUX(*mux));
                port_setup(port, pin_to_offset(range, pin), false);
                mux++;
 
@@ -638,8 +651,8 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
        return 0;
 }
 
-static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
-       unsigned group)
+static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned func_id,
+       unsigned group_id)
 {
        struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
        struct gpio_port *port;
@@ -647,7 +660,7 @@ static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
        unsigned long flags;
        unsigned short *mux, pin;
 
-       mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
+       mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
 
        while (*mux) {
                pin = P_IDENT(*mux);
index 1f06f8df1fa380c6d0e832d24bdf28dd428aed1e..3ca29738213f7ba5895a886dfbf7977195acd043 100644 (file)
@@ -21,13 +21,15 @@ struct adi_pin_group {
        const char *name;
        const unsigned *pins;
        const unsigned num;
+       const unsigned short *mux;
 };
 
-#define ADI_PIN_GROUP(n, p)  \
+#define ADI_PIN_GROUP(n, p, m)  \
        {                       \
                .name = n,      \
                .pins = p,      \
                .num = ARRAY_SIZE(p),   \
+               .mux = m,                       \
        }
 
  /**
@@ -41,15 +43,13 @@ struct adi_pmx_func {
        const char *name;
        const char * const *groups;
        const unsigned num_groups;
-       const unsigned short *mux;
 };
 
-#define ADI_PMX_FUNCTION(n, g, m)              \
+#define ADI_PMX_FUNCTION(n, g)         \
        {                                       \
                .name = n,                      \
                .groups = g,                    \
                .num_groups = ARRAY_SIZE(g),    \
-               .mux = m,                       \
        }
 
 /**
index d990e33d8aa778b9a8cb1a3143db5345122ab584..5d24aaec5dbcba04f5669b4d58cef60d844a18a4 100644 (file)
@@ -1137,6 +1137,17 @@ static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
        pinctrl_free_gpio(gpio);
 }
 
+static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+       unsigned mask = 1 << offset;
+       u32 osr;
+
+       osr = readl_relaxed(pio + PIO_OSR);
+       return !(osr & mask);
+}
+
 static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
@@ -1325,6 +1336,31 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
        return 0;
 }
 
+static unsigned int gpio_irq_startup(struct irq_data *d)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       unsigned        pin = d->hwirq;
+       int ret;
+
+       ret = gpio_lock_as_irq(&at91_gpio->chip, pin);
+       if (ret) {
+               dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
+                       d->hwirq);
+               return ret;
+       }
+       gpio_irq_unmask(d);
+       return 0;
+}
+
+static void gpio_irq_shutdown(struct irq_data *d)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       unsigned        pin = d->hwirq;
+
+       gpio_irq_mask(d);
+       gpio_unlock_as_irq(&at91_gpio->chip, pin);
+}
+
 #ifdef CONFIG_PM
 
 static u32 wakeups[MAX_GPIO_BANKS];
@@ -1399,6 +1435,8 @@ void at91_pinctrl_gpio_resume(void)
 
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
+       .irq_startup    = gpio_irq_startup,
+       .irq_shutdown   = gpio_irq_shutdown,
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
@@ -1543,6 +1581,7 @@ static int at91_gpio_of_irq_setup(struct device_node *node,
 static struct gpio_chip at91_gpio_template = {
        .request                = at91_gpio_request,
        .free                   = at91_gpio_free,
+       .get_direction          = at91_gpio_get_direction,
        .direction_input        = at91_gpio_direction_input,
        .get                    = at91_gpio_get,
        .direction_output       = at91_gpio_direction_output,
index 665b96bc0c3a19799a6e8e91581b383f2c025360..bf2b3f65546986ac3a9c7b787549d16fc0fcc5b9 100644 (file)
 #define BYT_NGPIO_NCORE                28
 #define BYT_NGPIO_SUS          44
 
+#define BYT_SCORE_ACPI_UID     "1"
+#define BYT_NCORE_ACPI_UID     "2"
+#define BYT_SUS_ACPI_UID       "3"
+
 /*
  * Baytrail gpio controller consist of three separate sub-controllers called
  * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
@@ -102,17 +106,17 @@ static unsigned const sus_pins[BYT_NGPIO_SUS] = {
 
 static struct pinctrl_gpio_range byt_ranges[] = {
        {
-               .name = "1", /* match with acpi _UID in probe */
+               .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */
                .npins = BYT_NGPIO_SCORE,
                .pins = score_pins,
        },
        {
-               .name = "2",
+               .name = BYT_NCORE_ACPI_UID,
                .npins = BYT_NGPIO_NCORE,
                .pins = ncore_pins,
        },
        {
-               .name = "3",
+               .name = BYT_SUS_ACPI_UID,
                .npins = BYT_NGPIO_SUS,
                .pins = sus_pins,
        },
@@ -145,9 +149,41 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
        return vg->reg_base + reg_offset + reg;
 }
 
+static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+{
+       /* SCORE pin 92-93 */
+       if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
+               offset >= 92 && offset <= 93)
+               return true;
+
+       /* SUS pin 11-21 */
+       if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
+               offset >= 11 && offset <= 21)
+               return true;
+
+       return false;
+}
+
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
        struct byt_gpio *vg = to_byt_gpio(chip);
+       void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
+       u32 value;
+       bool special;
+
+       /*
+        * In most cases, func pin mux 000 means GPIO function.
+        * But, some pins may have func pin mux 001 represents
+        * GPIO function. Only allow user to export pin with
+        * func pin mux preset as GPIO function by BIOS/FW.
+        */
+       value = readl(reg) & BYT_PIN_MUX;
+       special = is_special_pin(vg, offset);
+       if ((special && value != 1) || (!special && value)) {
+               dev_err(&vg->pdev->dev,
+                       "pin %u cannot be used as GPIO.\n", offset);
+               return -EINVAL;
+       }
 
        pm_runtime_get(&vg->pdev->dev);
 
index 4669c53f99b0a4fc8e30ab4678263be292f014fd..eb2500212147bdc72177f3e67c31ed23f7e6ea6a 100644 (file)
@@ -1435,7 +1435,7 @@ int __init capri_pinctrl_probe(struct platform_device *pdev)
 }
 
 static struct of_device_id capri_pinctrl_of_match[] = {
-       { .compatible = "brcm,capri-pinctrl", },
+       { .compatible = "brcm,bcm11351-pinctrl", },
        { },
 };
 
index 155b1b3a0e7a71597d26d3c0c1cab2a525a9ee19..07c81306f2f3bd7b7f39b6ae5a19217a6d947398 100644 (file)
@@ -1042,6 +1042,88 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
        },
 };
 
+/* pin banks of exynos5260 pin-controller 0 */
+static struct samsung_pin_bank exynos5260_pin_banks0[] = {
+       EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10),
+       EXYNOS_PIN_BANK_EINTG(5, 0x0a0, "gpb2", 0x14),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpb3", 0x18),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpb4", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpb5", 0x20),
+       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd0", 0x24),
+       EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpd1", 0x28),
+       EXYNOS_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe0", 0x30),
+       EXYNOS_PIN_BANK_EINTG(5, 0x1a0, "gpe1", 0x34),
+       EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38),
+       EXYNOS_PIN_BANK_EINTG(8, 0x1e0, "gpf1", 0x3c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x200, "gpk0", 0x40),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gpx0", 0x00),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gpx1", 0x04),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gpx2", 0x08),
+       EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gpx3", 0x0c),
+};
+
+/* pin banks of exynos5260 pin-controller 1 */
+static struct samsung_pin_bank exynos5260_pin_banks1[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
+       EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
+       EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpc4", 0x10),
+};
+
+/* pin banks of exynos5260 pin-controller 2 */
+static struct samsung_pin_bank exynos5260_pin_banks2[] = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
+ * three gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
+       {
+               /* pin-controller instance 0 data */
+               .pin_banks      = exynos5260_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks0),
+               .geint_con      = EXYNOS_GPIO_ECON_OFFSET,
+               .geint_mask     = EXYNOS_GPIO_EMASK_OFFSET,
+               .geint_pend     = EXYNOS_GPIO_EPEND_OFFSET,
+               .weint_con      = EXYNOS_WKUP_ECON_OFFSET,
+               .weint_mask     = EXYNOS_WKUP_EMASK_OFFSET,
+               .weint_pend     = EXYNOS_WKUP_EPEND_OFFSET,
+               .svc            = EXYNOS_SVC_OFFSET,
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .eint_wkup_init = exynos_eint_wkup_init,
+               .label          = "exynos5260-gpio-ctrl0",
+       }, {
+               /* pin-controller instance 1 data */
+               .pin_banks      = exynos5260_pin_banks1,
+               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks1),
+               .geint_con      = EXYNOS_GPIO_ECON_OFFSET,
+               .geint_mask     = EXYNOS_GPIO_EMASK_OFFSET,
+               .geint_pend     = EXYNOS_GPIO_EPEND_OFFSET,
+               .svc            = EXYNOS_SVC_OFFSET,
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5260-gpio-ctrl1",
+       }, {
+               /* pin-controller instance 2 data */
+               .pin_banks      = exynos5260_pin_banks2,
+               .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks2),
+               .geint_con      = EXYNOS_GPIO_ECON_OFFSET,
+               .geint_mask     = EXYNOS_GPIO_EMASK_OFFSET,
+               .geint_pend     = EXYNOS_GPIO_EPEND_OFFSET,
+               .svc            = EXYNOS_SVC_OFFSET,
+               .eint_gpio_init = exynos_eint_gpio_init,
+               .label          = "exynos5260-gpio-ctrl2",
+       },
+};
+
 /* pin banks of exynos5420 pin-controller 0 */
 static struct samsung_pin_bank exynos5420_pin_banks0[] = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
index 4779b8e0eee8f1cb90037e78fff60a7f53e9a1ad..e118fb121e024772cbad4cd4b73f32210ad0179c 100644 (file)
@@ -491,7 +491,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
                        pin->mux_mode |= IOMUXC_CONFIG_SION;
                pin->config = config & ~IMX_PAD_SION;
 
-               dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[i].name,
+               dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[pin_id].name,
                                pin->mux_mode, pin->config);
        }
 
index ef2bf3126da6ca0c10de2ef1a1025c1df744afc9..343f421c7696ef19311fe636a606d4f56674e3ff 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
-#include <linux/of_irq.h>
 #include <linux/spinlock.h>
 
 #include "core.h"
@@ -50,7 +49,6 @@
  * @enabled_irqs:   Bitmap of currently enabled irqs.
  * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
  *                  detection.
- * @wake_irqs:      Bitmap of irqs with requested as wakeup source.
  * @soc;            Reference to soc_data of platform specific data.
  * @regs:           Base address for the TLMM register map.
  */
@@ -65,7 +63,6 @@ struct msm_pinctrl {
 
        DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
        DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
-       DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO);
 
        const struct msm_pinctrl_soc_data *soc;
        void __iomem *regs;
@@ -203,42 +200,29 @@ static const struct pinmux_ops msm_pinmux_ops = {
 static int msm_config_reg(struct msm_pinctrl *pctrl,
                          const struct msm_pingroup *g,
                          unsigned param,
-                         s16 *reg,
                          unsigned *mask,
                          unsigned *bit)
 {
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
-               *reg = g->ctl_reg;
-               *bit = g->pull_bit;
-               *mask = 3;
-               break;
        case PIN_CONFIG_BIAS_PULL_DOWN:
-               *reg = g->ctl_reg;
-               *bit = g->pull_bit;
-               *mask = 3;
-               break;
        case PIN_CONFIG_BIAS_PULL_UP:
-               *reg = g->ctl_reg;
                *bit = g->pull_bit;
                *mask = 3;
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
-               *reg = g->ctl_reg;
                *bit = g->drv_bit;
                *mask = 7;
                break;
+       case PIN_CONFIG_OUTPUT:
+               *bit = g->oe_bit;
+               *mask = 1;
+               break;
        default:
                dev_err(pctrl->dev, "Invalid config param %04x\n", param);
                return -ENOTSUPP;
        }
 
-       if (*reg < 0) {
-               dev_err(pctrl->dev, "Config param %04x not supported on group %s\n",
-                       param, g->name);
-               return -ENOTSUPP;
-       }
-
        return 0;
 }
 
@@ -261,8 +245,10 @@ static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
 #define MSM_PULL_DOWN  1
 #define MSM_PULL_UP    3
 
-static const unsigned msm_regval_to_drive[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
-static const unsigned msm_drive_to_regval[] = { -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7 };
+static unsigned msm_regval_to_drive(u32 val)
+{
+       return (val + 1) * 2;
+}
 
 static int msm_config_group_get(struct pinctrl_dev *pctldev,
                                unsigned int group,
@@ -274,17 +260,16 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
        unsigned mask;
        unsigned arg;
        unsigned bit;
-       s16 reg;
        int ret;
        u32 val;
 
        g = &pctrl->soc->groups[group];
 
-       ret = msm_config_reg(pctrl, g, param, &reg, &mask, &bit);
+       ret = msm_config_reg(pctrl, g, param, &mask, &bit);
        if (ret < 0)
                return ret;
 
-       val = readl(pctrl->regs + reg);
+       val = readl(pctrl->regs + g->ctl_reg);
        arg = (val >> bit) & mask;
 
        /* Convert register value to pinconf value */
@@ -299,7 +284,15 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
                arg = arg == MSM_PULL_UP;
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
-               arg = msm_regval_to_drive[arg];
+               arg = msm_regval_to_drive(arg);
+               break;
+       case PIN_CONFIG_OUTPUT:
+               /* Pin is not output */
+               if (!arg)
+                       return -EINVAL;
+
+               val = readl(pctrl->regs + g->io_reg);
+               arg = !!(val & BIT(g->in_bit));
                break;
        default:
                dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
@@ -324,7 +317,6 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
        unsigned mask;
        unsigned arg;
        unsigned bit;
-       s16 reg;
        int ret;
        u32 val;
        int i;
@@ -335,7 +327,7 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
                param = pinconf_to_config_param(configs[i]);
                arg = pinconf_to_config_argument(configs[i]);
 
-               ret = msm_config_reg(pctrl, g, param, &reg, &mask, &bit);
+               ret = msm_config_reg(pctrl, g, param, &mask, &bit);
                if (ret < 0)
                        return ret;
 
@@ -352,10 +344,24 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
                        break;
                case PIN_CONFIG_DRIVE_STRENGTH:
                        /* Check for invalid values */
-                       if (arg >= ARRAY_SIZE(msm_drive_to_regval))
+                       if (arg > 16 || arg < 2 || (arg % 2) != 0)
                                arg = -1;
                        else
-                               arg = msm_drive_to_regval[arg];
+                               arg = (arg / 2) - 1;
+                       break;
+               case PIN_CONFIG_OUTPUT:
+                       /* set output value */
+                       spin_lock_irqsave(&pctrl->lock, flags);
+                       val = readl(pctrl->regs + g->io_reg);
+                       if (arg)
+                               val |= BIT(g->out_bit);
+                       else
+                               val &= ~BIT(g->out_bit);
+                       writel(val, pctrl->regs + g->io_reg);
+                       spin_unlock_irqrestore(&pctrl->lock, flags);
+
+                       /* enable output */
+                       arg = 1;
                        break;
                default:
                        dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
@@ -370,10 +376,10 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
                }
 
                spin_lock_irqsave(&pctrl->lock, flags);
-               val = readl(pctrl->regs + reg);
+               val = readl(pctrl->regs + g->ctl_reg);
                val &= ~(mask << bit);
                val |= arg << bit;
-               writel(val, pctrl->regs + reg);
+               writel(val, pctrl->regs + g->ctl_reg);
                spin_unlock_irqrestore(&pctrl->lock, flags);
        }
 
@@ -402,8 +408,6 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
        u32 val;
 
        g = &pctrl->soc->groups[offset];
-       if (WARN_ON(g->io_reg < 0))
-               return -EINVAL;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -424,8 +428,6 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
        u32 val;
 
        g = &pctrl->soc->groups[offset];
-       if (WARN_ON(g->io_reg < 0))
-               return -EINVAL;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -452,8 +454,6 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
        u32 val;
 
        g = &pctrl->soc->groups[offset];
-       if (WARN_ON(g->io_reg < 0))
-               return -EINVAL;
 
        val = readl(pctrl->regs + g->io_reg);
        return !!(val & BIT(g->in_bit));
@@ -467,8 +467,6 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        u32 val;
 
        g = &pctrl->soc->groups[offset];
-       if (WARN_ON(g->io_reg < 0))
-               return;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -534,7 +532,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
        pull = (ctl_reg >> g->pull_bit) & 3;
 
        seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
-       seq_printf(s, " %dmA", msm_regval_to_drive[drive]);
+       seq_printf(s, " %dmA", msm_regval_to_drive(drive));
        seq_printf(s, " %s", pulls[pull]);
 }
 
@@ -617,8 +615,6 @@ static void msm_gpio_irq_mask(struct irq_data *d)
 
        pctrl = irq_data_get_irq_chip_data(d);
        g = &pctrl->soc->groups[d->hwirq];
-       if (WARN_ON(g->intr_cfg_reg < 0))
-               return;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -640,8 +636,6 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
 
        pctrl = irq_data_get_irq_chip_data(d);
        g = &pctrl->soc->groups[d->hwirq];
-       if (WARN_ON(g->intr_status_reg < 0))
-               return;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -667,8 +661,6 @@ static void msm_gpio_irq_ack(struct irq_data *d)
 
        pctrl = irq_data_get_irq_chip_data(d);
        g = &pctrl->soc->groups[d->hwirq];
-       if (WARN_ON(g->intr_status_reg < 0))
-               return;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -693,8 +685,6 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 
        pctrl = irq_data_get_irq_chip_data(d);
        g = &pctrl->soc->groups[d->hwirq];
-       if (WARN_ON(g->intr_cfg_reg < 0))
-               return -EINVAL;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
@@ -783,22 +773,12 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 {
        struct msm_pinctrl *pctrl;
        unsigned long flags;
-       unsigned ngpio;
 
        pctrl = irq_data_get_irq_chip_data(d);
-       ngpio = pctrl->chip.ngpio;
 
        spin_lock_irqsave(&pctrl->lock, flags);
 
-       if (on) {
-               if (bitmap_empty(pctrl->wake_irqs, ngpio))
-                       enable_irq_wake(pctrl->irq);
-               set_bit(d->hwirq, pctrl->wake_irqs);
-       } else {
-               clear_bit(d->hwirq, pctrl->wake_irqs);
-               if (bitmap_empty(pctrl->wake_irqs, ngpio))
-                       disable_irq_wake(pctrl->irq);
-       }
+       irq_set_irq_wake(pctrl->irq, on);
 
        spin_unlock_irqrestore(&pctrl->lock, flags);
 
@@ -869,6 +849,12 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
 static int msm_gpio_init(struct msm_pinctrl *pctrl)
 {
        struct gpio_chip *chip;
@@ -876,10 +862,14 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        int ret;
        int i;
        int r;
+       unsigned ngpio = pctrl->soc->ngpios;
+
+       if (WARN_ON(ngpio > MAX_NR_GPIO))
+               return -EINVAL;
 
        chip = &pctrl->chip;
        chip->base = 0;
-       chip->ngpio = pctrl->soc->ngpios;
+       chip->ngpio = ngpio;
        chip->label = dev_name(pctrl->dev);
        chip->dev = pctrl->dev;
        chip->owner = THIS_MODULE;
@@ -907,6 +897,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 
        for (i = 0; i < chip->ngpio; i++) {
                irq = irq_create_mapping(pctrl->domain, i);
+               irq_set_lockdep_class(irq, &gpio_lock_class);
                irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq);
                irq_set_chip_data(irq, pctrl);
        }
index 206e782e2daaf5c9bfc0964169a408a3ed92aed1..8fbe9fb19f36e993e34d712c02a47a530a3b915b 100644 (file)
 #ifndef __PINCTRL_MSM_H__
 #define __PINCTRL_MSM_H__
 
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/machine.h>
+struct pinctrl_pin_desc;
 
 /**
  * struct msm_function - a pinmux function
index f944bf2172ef50860c9a18722190adb73fe63928..dde5529807aab71cc78729b8ef0d3e98544385f3 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
 
 #include "pinctrl-msm.h"
 
@@ -406,6 +405,7 @@ enum msm8x74_functions {
        MSM_MUX_blsp_i2c6,
        MSM_MUX_blsp_i2c11,
        MSM_MUX_blsp_spi1,
+       MSM_MUX_blsp_spi8,
        MSM_MUX_blsp_uart2,
        MSM_MUX_blsp_uart8,
        MSM_MUX_slimbus,
@@ -416,6 +416,9 @@ static const char * const blsp_i2c2_groups[] = { "gpio6", "gpio7" };
 static const char * const blsp_i2c6_groups[] = { "gpio29", "gpio30" };
 static const char * const blsp_i2c11_groups[] = { "gpio83", "gpio84" };
 static const char * const blsp_spi1_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3" };
+static const char * const blsp_spi8_groups[] = {
+       "gpio45", "gpio46", "gpio47", "gpio48"
+};
 static const char * const blsp_uart2_groups[] = { "gpio4", "gpio5" };
 static const char * const blsp_uart8_groups[] = { "gpio45", "gpio46" };
 static const char * const slimbus_groups[] = { "gpio70", "gpio71" };
@@ -425,6 +428,7 @@ static const struct msm_function msm8x74_functions[] = {
        FUNCTION(blsp_i2c6),
        FUNCTION(blsp_i2c11),
        FUNCTION(blsp_spi1),
+       FUNCTION(blsp_spi8),
        FUNCTION(blsp_uart2),
        FUNCTION(blsp_uart8),
        FUNCTION(slimbus),
@@ -476,10 +480,10 @@ static const struct msm_pingroup msm8x74_groups[] = {
        PINGROUP(42,  NA, NA, NA, NA, NA, NA, NA),
        PINGROUP(43,  NA, NA, NA, NA, NA, NA, NA),
        PINGROUP(44,  NA, NA, NA, NA, NA, NA, NA),
-       PINGROUP(45,  NA, blsp_uart8, NA, NA, NA, NA, NA),
-       PINGROUP(46,  NA, blsp_uart8, NA, NA, NA, NA, NA),
-       PINGROUP(47,  NA, NA, NA, NA, NA, NA, NA),
-       PINGROUP(48,  NA, NA, NA, NA, NA, NA, NA),
+       PINGROUP(45,  blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA),
+       PINGROUP(46,  blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA),
+       PINGROUP(47,  blsp_spi8, NA, NA, NA, NA, NA, NA),
+       PINGROUP(48,  blsp_spi8, NA, NA, NA, NA, NA, NA),
        PINGROUP(49,  NA, NA, NA, NA, NA, NA, NA),
        PINGROUP(50,  NA, NA, NA, NA, NA, NA, NA),
        PINGROUP(51,  NA, NA, NA, NA, NA, NA, NA),
index 53a11114927fc2278456444dc22ae6ac8f1af964..cec7762cf3354592d75d7cc913dfd2a6c0cfbcdf 100644 (file)
@@ -2035,27 +2035,29 @@ static const struct of_device_id nmk_pinctrl_match[] = {
        {},
 };
 
-static int nmk_pinctrl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int nmk_pinctrl_suspend(struct device *dev)
 {
        struct nmk_pinctrl *npct;
 
-       npct = platform_get_drvdata(pdev);
+       npct = dev_get_drvdata(dev);
        if (!npct)
                return -EINVAL;
 
        return pinctrl_force_sleep(npct->pctl);
 }
 
-static int nmk_pinctrl_resume(struct platform_device *pdev)
+static int nmk_pinctrl_resume(struct device *dev)
 {
        struct nmk_pinctrl *npct;
 
-       npct = platform_get_drvdata(pdev);
+       npct = dev_get_drvdata(dev);
        if (!npct)
                return -EINVAL;
 
        return pinctrl_force_default(npct->pctl);
 }
+#endif
 
 static int nmk_pinctrl_probe(struct platform_device *pdev)
 {
@@ -2144,17 +2146,18 @@ static struct platform_driver nmk_gpio_driver = {
        .probe = nmk_gpio_probe,
 };
 
+static SIMPLE_DEV_PM_OPS(nmk_pinctrl_pm_ops,
+                       nmk_pinctrl_suspend,
+                       nmk_pinctrl_resume);
+
 static struct platform_driver nmk_pinctrl_driver = {
        .driver = {
                .owner = THIS_MODULE,
                .name = "pinctrl-nomadik",
                .of_match_table = nmk_pinctrl_match,
+               .pm = &nmk_pinctrl_pm_ops,
        },
        .probe = nmk_pinctrl_probe,
-#ifdef CONFIG_PM
-       .suspend = nmk_pinctrl_suspend,
-       .resume = nmk_pinctrl_resume,
-#endif
 };
 
 static int __init nmk_gpio_init(void)
index 47ec2e8741e4221ba3dc03a4d1ce6cdba5184bb2..0324d4cb19b22d3172a32aadb12aae5cd4f8c03c 100644 (file)
@@ -1120,6 +1120,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
                .data = (void *)exynos4x12_pin_ctrl },
        { .compatible = "samsung,exynos5250-pinctrl",
                .data = (void *)exynos5250_pin_ctrl },
+       { .compatible = "samsung,exynos5260-pinctrl",
+               .data = (void *)exynos5260_pin_ctrl },
        { .compatible = "samsung,exynos5420-pinctrl",
                .data = (void *)exynos5420_pin_ctrl },
        { .compatible = "samsung,s5pv210-pinctrl",
index 30622d9afa2ed897451944a6d2b8838fcf77ac0d..bab9c21225562fe2c2dbf13ece67aea645c37d76 100644 (file)
@@ -254,6 +254,7 @@ struct samsung_pmx_func {
 extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
 extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
 extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5260_pin_ctrl[];
 extern struct samsung_pin_ctrl exynos5420_pin_ctrl[];
 extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
 extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
index de6459628b4fe9af7d7838975bdc6a92de042bca..81075f2a1d3f87d9ac9d2cf4d62edf94e21bf75f 100644 (file)
@@ -662,6 +662,7 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
                        break;
                case PIN_CONFIG_DRIVE_STRENGTH:
                case PIN_CONFIG_SLEW_RATE:
+               case PIN_CONFIG_LOW_POWER_MODE:
                default:
                        *config = data;
                        break;
@@ -699,6 +700,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
                        case PIN_CONFIG_INPUT_SCHMITT:
                        case PIN_CONFIG_DRIVE_STRENGTH:
                        case PIN_CONFIG_SLEW_RATE:
+                       case PIN_CONFIG_LOW_POWER_MODE:
                                shift = ffs(func->conf[i].mask) - 1;
                                data &= ~func->conf[i].mask;
                                data |= (arg << shift) & func->conf[i].mask;
@@ -1101,6 +1103,7 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
                { "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
                { "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
                { "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+               { "pinctrl-single,low-power-mode", PIN_CONFIG_LOW_POWER_MODE, },
        };
        struct pcs_conf_type prop4[] = {
                { "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
index 320c27363cc87293ed0448cc0054b3b13c884995..bd725b0a43414b77ec068003ac5ddf995824cf21 100644 (file)
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/of_gpio.h>
 #include <linux/of_address.h>
 #include <linux/regmap.h>
@@ -266,11 +271,59 @@ struct st_pctl_group {
        struct st_pinconf       *pin_conf;
 };
 
+/*
+ * Edge triggers are not supported at hardware level, it is supported by
+ * software by exploiting the level trigger support in hardware.
+ * Software uses a virtual register (EDGE_CONF) for edge trigger configuration
+ * of each gpio pin in a GPIO bank.
+ *
+ * Each bank has a 32 bit EDGE_CONF register which is divided in to 8 parts of
+ * 4-bits. Each 4-bit space is allocated for each pin in a gpio bank.
+ *
+ * bit allocation per pin is:
+ * Bits:  [0 - 3] | [4 - 7]  [8 - 11] ... ... ... ...  [ 28 - 31]
+ *       --------------------------------------------------------
+ *       |  pin-0  |  pin-2 | pin-3  | ... ... ... ... | pin -7 |
+ *       --------------------------------------------------------
+ *
+ *  A pin can have one of following the values in its edge configuration field.
+ *
+ *     -------   ----------------------------
+ *     [0-3]   - Description
+ *     -------   ----------------------------
+ *     0000    - No edge IRQ.
+ *     0001    - Falling edge IRQ.
+ *     0010    - Rising edge IRQ.
+ *     0011    - Rising and Falling edge IRQ.
+ *     -------   ----------------------------
+ */
+
+#define ST_IRQ_EDGE_CONF_BITS_PER_PIN  4
+#define ST_IRQ_EDGE_MASK               0xf
+#define ST_IRQ_EDGE_FALLING            BIT(0)
+#define ST_IRQ_EDGE_RISING             BIT(1)
+#define ST_IRQ_EDGE_BOTH               (BIT(0) | BIT(1))
+
+#define ST_IRQ_RISING_EDGE_CONF(pin) \
+       (ST_IRQ_EDGE_RISING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_FALLING_EDGE_CONF(pin) \
+       (ST_IRQ_EDGE_FALLING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_BOTH_EDGE_CONF(pin) \
+       (ST_IRQ_EDGE_BOTH << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_EDGE_CONF(conf, pin) \
+       (conf >> (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN) & ST_IRQ_EDGE_MASK)
+
 struct st_gpio_bank {
        struct gpio_chip                gpio_chip;
        struct pinctrl_gpio_range       range;
        void __iomem                    *base;
        struct st_pio_control           pc;
+       struct  irq_domain              *domain;
+       unsigned long                   irq_edge_conf;
+       spinlock_t                      lock;
 };
 
 struct st_pinctrl {
@@ -284,6 +337,7 @@ struct st_pinctrl {
        int                             ngroups;
        struct regmap                   *regmap;
        const struct st_pctl_data       *data;
+       void __iomem                    *irqmux_base;
 };
 
 /* SOC specific data */
@@ -330,12 +384,25 @@ static unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
 static const struct st_pctl_data  stih416_data = {
        .rt_style       = st_retime_style_dedicated,
        .input_delays   = stih416_delays,
-       .ninput_delays  = 14,
+       .ninput_delays  = ARRAY_SIZE(stih416_delays),
        .output_delays  = stih416_delays,
-       .noutput_delays = 14,
+       .noutput_delays = ARRAY_SIZE(stih416_delays),
        .alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100,
 };
 
+static const struct st_pctl_data stih407_flashdata = {
+       .rt_style       = st_retime_style_none,
+       .input_delays   = stih416_delays,
+       .ninput_delays  = ARRAY_SIZE(stih416_delays),
+       .output_delays  = stih416_delays,
+       .noutput_delays = ARRAY_SIZE(stih416_delays),
+       .alt = 0,
+       .oe = -1, /* Not Available */
+       .pu = -1, /* Not Available */
+       .od = 60,
+       .rt = 100,
+};
+
 /* Low level functions.. */
 static inline int st_gpio_bank(int gpio)
 {
@@ -356,25 +423,29 @@ static void st_pinconf_set_config(struct st_pio_control *pc,
        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);
+       if (output_enable) {
+               regmap_field_read(output_enable, &oe_value);
+               oe_value &= ~mask;
+               if (config & ST_PINCONF_OE)
+                       oe_value |= mask;
+               regmap_field_write(output_enable, oe_value);
+       }
+
+       if (pull_up) {
+               regmap_field_read(pull_up, &pu_value);
+               pu_value &= ~mask;
+               if (config & ST_PINCONF_PU)
+                       pu_value |= mask;
+               regmap_field_write(pull_up, pu_value);
+       }
+
+       if (open_drain) {
+               regmap_field_read(open_drain, &od_value);
+               od_value &= ~mask;
+               if (config & ST_PINCONF_OD)
+                       od_value |= mask;
+               regmap_field_write(open_drain, od_value);
+       }
 }
 
 static void st_pctl_set_function(struct st_pio_control *pc,
@@ -385,6 +456,9 @@ static void st_pctl_set_function(struct st_pio_control *pc,
        int pin = st_gpio_pin(pin_id);
        int offset = pin * 4;
 
+       if (!alt)
+               return;
+
        regmap_field_read(alt, &val);
        val &= ~(0xf << offset);
        val |= function << offset;
@@ -522,17 +596,23 @@ static void st_pinconf_get_direction(struct st_pio_control *pc,
 {
        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 (pc->oe) {
+               regmap_field_read(pc->oe, &oe_value);
+               if (oe_value & BIT(pin))
+                       ST_PINCONF_PACK_OE(*config);
+       }
 
-       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);
+       if (pc->pu) {
+               regmap_field_read(pc->pu, &pu_value);
+               if (pu_value & BIT(pin))
+                       ST_PINCONF_PACK_PU(*config);
+       }
 
+       if (pc->od) {
+               regmap_field_read(pc->od, &od_value);
+               if (od_value & BIT(pin))
+                       ST_PINCONF_PACK_OD(*config);
+       }
 }
 
 static int st_pinconf_get_retime_packed(struct st_pinctrl *info,
@@ -1051,8 +1131,21 @@ static int st_pctl_dt_setup_retime(struct st_pinctrl *info,
        return -EINVAL;
 }
 
-static int st_parse_syscfgs(struct st_pinctrl *info,
-               int bank, struct device_node *np)
+
+static struct regmap_field *st_pc_get_value(struct device *dev,
+                                           struct regmap *regmap, int bank,
+                                           int data, int lsb, int msb)
+{
+       struct reg_field reg = REG_FIELD((data + bank) * 4, lsb, msb);
+
+       if (data < 0)
+               return NULL;
+
+       return devm_regmap_field_alloc(dev, regmap, reg);
+}
+
+static void st_parse_syscfgs(struct st_pinctrl *info, int bank,
+                            struct device_node *np)
 {
        const struct st_pctl_data *data = info->data;
        /**
@@ -1062,29 +1155,21 @@ static int st_parse_syscfgs(struct st_pinctrl *info,
         */
        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;
+       pc->alt = st_pc_get_value(dev, regmap, bank, data->alt, 0, 31);
+       pc->oe = st_pc_get_value(dev, regmap, bank/4, data->oe, lsb, msb);
+       pc->pu = st_pc_get_value(dev, regmap, bank/4, data->pu, lsb, msb);
+       pc->od = st_pc_get_value(dev, regmap, bank/4, data->od, lsb, msb);
 
        /* 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;
+       return;
 }
 
 /*
@@ -1200,6 +1285,194 @@ static int st_pctl_parse_functions(struct device_node *np,
        return 0;
 }
 
+static int st_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+       int irq = -ENXIO;
+
+       if (offset < chip->ngpio)
+               irq = irq_find_mapping(bank->domain, offset);
+
+       dev_info(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+                               chip->label, offset + chip->base, irq);
+       return irq;
+}
+
+static void st_gpio_irq_mask(struct irq_data *d)
+{
+       struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+       writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK);
+}
+
+static void st_gpio_irq_unmask(struct irq_data *d)
+{
+       struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+       writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
+}
+
+static unsigned int st_gpio_irq_startup(struct irq_data *d)
+{
+       struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+       if (gpio_lock_as_irq(&bank->gpio_chip, d->hwirq))
+               dev_err(bank->gpio_chip.dev,
+                       "unable to lock HW IRQ %lu for IRQ\n",
+                       d->hwirq);
+
+       st_gpio_irq_unmask(d);
+
+       return 0;
+}
+
+static void st_gpio_irq_shutdown(struct irq_data *d)
+{
+       struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+       st_gpio_irq_mask(d);
+       gpio_unlock_as_irq(&bank->gpio_chip, d->hwirq);
+}
+
+static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
+{
+       struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
+       int comp, pin = d->hwirq;
+       u32 val;
+       u32 pin_edge_conf = 0;
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               comp = 0;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               comp = 0;
+               pin_edge_conf = ST_IRQ_FALLING_EDGE_CONF(pin);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               comp = 1;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               comp = 1;
+               pin_edge_conf = ST_IRQ_RISING_EDGE_CONF(pin);
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               comp = st_gpio_get(&bank->gpio_chip, pin);
+               pin_edge_conf = ST_IRQ_BOTH_EDGE_CONF(pin);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&bank->lock, flags);
+       bank->irq_edge_conf &=  ~(ST_IRQ_EDGE_MASK << (
+                               pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN));
+       bank->irq_edge_conf |= pin_edge_conf;
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       val = readl(bank->base + REG_PIO_PCOMP);
+       val &= ~BIT(pin);
+       val |= (comp << pin);
+       writel(val, bank->base + REG_PIO_PCOMP);
+
+       return 0;
+}
+
+/*
+ * As edge triggers are not supported at hardware level, it is supported by
+ * software by exploiting the level trigger support in hardware.
+ *
+ * Steps for detection raising edge interrupt in software.
+ *
+ * Step 1: CONFIGURE pin to detect level LOW interrupts.
+ *
+ * Step 2: DETECT level LOW interrupt and in irqmux/gpio bank interrupt handler,
+ * if the value of pin is low, then CONFIGURE pin for level HIGH interrupt.
+ * IGNORE calling the actual interrupt handler for the pin at this stage.
+ *
+ * Step 3: DETECT level HIGH interrupt and in irqmux/gpio-bank interrupt handler
+ * if the value of pin is HIGH, CONFIGURE pin for level LOW interrupt and then
+ * DISPATCH the interrupt to the interrupt handler of the pin.
+ *
+ *              step-1  ________     __________
+ *                             |     | step - 3
+ *                             |     |
+ *                     step -2 |_____|
+ *
+ * falling edge is also detected int the same way.
+ *
+ */
+static void __gpio_irq_handler(struct st_gpio_bank *bank)
+{
+       unsigned long port_in, port_mask, port_comp, active_irqs;
+       unsigned long bank_edge_mask, flags;
+       int n, val, ecfg;
+
+       spin_lock_irqsave(&bank->lock, flags);
+       bank_edge_mask = bank->irq_edge_conf;
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       for (;;) {
+               port_in = readl(bank->base + REG_PIO_PIN);
+               port_comp = readl(bank->base + REG_PIO_PCOMP);
+               port_mask = readl(bank->base + REG_PIO_PMASK);
+
+               active_irqs = (port_in ^ port_comp) & port_mask;
+
+               if (active_irqs == 0)
+                       break;
+
+               for_each_set_bit(n, &active_irqs, BITS_PER_LONG) {
+                       /* check if we are detecting fake edges ... */
+                       ecfg = ST_IRQ_EDGE_CONF(bank_edge_mask, n);
+
+                       if (ecfg) {
+                               /* edge detection. */
+                               val = st_gpio_get(&bank->gpio_chip, n);
+
+                               writel(BIT(n),
+                                       val ? bank->base + REG_PIO_SET_PCOMP :
+                                       bank->base + REG_PIO_CLR_PCOMP);
+
+                               if (ecfg != ST_IRQ_EDGE_BOTH &&
+                                       !((ecfg & ST_IRQ_EDGE_FALLING) ^ val))
+                                       continue;
+                       }
+
+                       generic_handle_irq(irq_find_mapping(bank->domain, n));
+               }
+       }
+}
+
+static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       /* interrupt dedicated per bank */
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct st_gpio_bank *bank = irq_get_handler_data(irq);
+
+       chained_irq_enter(chip, desc);
+       __gpio_irq_handler(bank);
+       chained_irq_exit(chip, desc);
+}
+
+static void st_gpio_irqmux_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct st_pinctrl *info = irq_get_handler_data(irq);
+       unsigned long status;
+       int n;
+
+       chained_irq_enter(chip, desc);
+
+       status = readl(info->irqmux_base);
+
+       for_each_set_bit(n, &status, ST_GPIO_PINS_PER_BANK)
+               __gpio_irq_handler(&info->banks[n]);
+
+       chained_irq_exit(chip, desc);
+}
+
 static struct gpio_chip st_gpio_template = {
        .request                = st_gpio_request,
        .free                   = st_gpio_free,
@@ -1210,6 +1483,34 @@ static struct gpio_chip st_gpio_template = {
        .ngpio                  = ST_GPIO_PINS_PER_BANK,
        .of_gpio_n_cells        = 1,
        .of_xlate               = st_gpio_xlate,
+       .to_irq                 = st_gpio_to_irq,
+};
+
+static struct irq_chip st_gpio_irqchip = {
+       .name           = "GPIO",
+       .irq_mask       = st_gpio_irq_mask,
+       .irq_unmask     = st_gpio_irq_unmask,
+       .irq_set_type   = st_gpio_irq_set_type,
+       .irq_startup    = st_gpio_irq_startup,
+       .irq_shutdown   = st_gpio_irq_shutdown,
+};
+
+static int st_gpio_irq_domain_map(struct irq_domain *h,
+                       unsigned int virq, irq_hw_number_t hw)
+{
+       struct st_gpio_bank *bank = h->host_data;
+
+       irq_set_chip(virq, &st_gpio_irqchip);
+       irq_set_handler(virq, handle_simple_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       irq_set_chip_data(virq, bank);
+
+       return 0;
+}
+
+static struct irq_domain_ops st_gpio_irq_ops = {
+       .map    = st_gpio_irq_domain_map,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 static int st_gpiolib_register_bank(struct st_pinctrl *info,
@@ -1219,8 +1520,8 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
        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;
+       struct resource res, irq_res;
+       int gpio_irq = 0, err, i;
 
        if (of_address_to_resource(np, 0, &res))
                return -ENODEV;
@@ -1233,6 +1534,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
        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;
+       spin_lock_init(&bank->lock);
 
        of_property_read_string(np, "st,bank-name", &range->name);
        bank->gpio_chip.label = range->name;
@@ -1248,6 +1550,51 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
        }
        dev_info(dev, "%s bank added.\n", range->name);
 
+       /**
+        * GPIO bank can have one of the two possible types of
+        * interrupt-wirings.
+        *
+        * First type is via irqmux, single interrupt is used by multiple
+        * gpio banks. This reduces number of overall interrupts numbers
+        * required. All these banks belong to a single pincontroller.
+        *                _________
+        *               |         |----> [gpio-bank (n)    ]
+        *               |         |----> [gpio-bank (n + 1)]
+        *      [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
+        *               |         |----> [gpio-bank (...  )]
+        *               |_________|----> [gpio-bank (n + 7)]
+        *
+        * Second type has a dedicated interrupt per each gpio bank.
+        *
+        *      [irqN]----> [gpio-bank (n)]
+        */
+
+       if (of_irq_to_resource(np, 0, &irq_res)) {
+               gpio_irq = irq_res.start;
+               irq_set_chained_handler(gpio_irq, st_gpio_irq_handler);
+               irq_set_handler_data(gpio_irq, bank);
+       }
+
+       if (info->irqmux_base > 0 || gpio_irq > 0) {
+               /* Setup IRQ domain */
+               bank->domain  = irq_domain_add_linear(np,
+                                               ST_GPIO_PINS_PER_BANK,
+                                               &st_gpio_irq_ops, bank);
+               if (!bank->domain) {
+                       dev_err(dev, "Failed to add irq domain for %s\n",
+                               np->full_name);
+               } else  {
+                       for (i = 0; i < ST_GPIO_PINS_PER_BANK; i++) {
+                               if (irq_create_mapping(bank->domain, i) < 0)
+                                       dev_err(dev,
+                                               "Failed to map IRQ %i\n", i);
+                       }
+               }
+
+       } else {
+               dev_info(dev, "No IRQ support for %s bank\n", np->full_name);
+       }
+
        return 0;
 }
 
@@ -1264,6 +1611,10 @@ static struct of_device_id st_pctl_of_match[] = {
        { .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},
+       { .compatible = "st,stih407-sbc-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih407-front-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih407-rear-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih407-flash-pinctrl", .data = &stih407_flashdata},
        { /* sentinel */ }
 };
 
@@ -1276,6 +1627,8 @@ static int st_pctl_probe_dt(struct platform_device *pdev,
        struct device_node *np = pdev->dev.of_node;
        struct device_node *child;
        int grp_index = 0;
+       int irq = 0;
+       struct resource *res;
 
        st_pctl_dt_child_count(info, np);
        if (!info->nbanks) {
@@ -1306,6 +1659,21 @@ static int st_pctl_probe_dt(struct platform_device *pdev,
        }
        info->data = of_match_node(st_pctl_of_match, np)->data;
 
+       irq = platform_get_irq(pdev, 0);
+
+       if (irq > 0) {
+               res = platform_get_resource_byname(pdev,
+                                       IORESOURCE_MEM, "irqmux");
+               info->irqmux_base = devm_ioremap_resource(&pdev->dev, res);
+
+               if (IS_ERR(info->irqmux_base))
+                       return PTR_ERR(info->irqmux_base);
+
+               irq_set_chained_handler(irq, st_gpio_irqmux_handler);
+               irq_set_handler_data(irq, info);
+
+       }
+
        pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK;
        pdesc = devm_kzalloc(&pdev->dev,
                        sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
index 6fd8d4d951406aec5f01c021c2c80b84ebf4f4b0..3d6066988a7251cc0e234c8033dde50aff79ae0f 100644 (file)
@@ -1932,27 +1932,27 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D1 */
+                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D0 */
+                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x4, "mmc0")),         /* CLK */
+                 SUNXI_FUNCTION(0x2, "mmc0")),         /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x4, "mmc0")),         /* CMD */
+                 SUNXI_FUNCTION(0x2, "mmc0")),         /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D3 */
+                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D2 */
+                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D2 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 9ccf681dad2f4993cdf3ef20a9099a17ae62dcb9..f9fabe9bf47d433b9152cd438e259e568b3b9ff5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -584,7 +585,7 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
        spin_lock_irqsave(&pctl->lock, flags);
 
        regval = readl(pctl->membase + reg);
-       regval &= ~IRQ_CFG_IRQ_MASK;
+       regval &= ~(IRQ_CFG_IRQ_MASK << index);
        writel(regval | (mode << index), pctl->membase + reg);
 
        spin_unlock_irqrestore(&pctl->lock, flags);
@@ -665,6 +666,7 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
 
 static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
 {
+       struct irq_chip *chip = irq_get_chip(irq);
        struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
        const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
 
@@ -674,10 +676,12 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
        if (reg) {
                int irqoffset;
 
+               chained_irq_enter(chip, desc);
                for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
                        int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
                        generic_handle_irq(pin_irq);
                }
+               chained_irq_exit(chip, desc);
        }
 }
 
index 01c494f8a14f0119493d783624b86831549ccdb0..552b0e97077a858b0c1aeda6d9f1a83e4803ae35 100644 (file)
@@ -511,7 +511,7 @@ static inline u32 sunxi_pull_offset(u16 pin)
 
 static inline u32 sunxi_irq_cfg_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
+       u8 reg = irq / IRQ_CFG_IRQ_PER_REG * 0x04;
        return reg + IRQ_CFG_REG;
 }
 
@@ -523,7 +523,7 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq)
 
 static inline u32 sunxi_irq_ctrl_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
+       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG * 0x04;
        return reg + IRQ_CTRL_REG;
 }
 
@@ -535,7 +535,7 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
 
 static inline u32 sunxi_irq_status_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
+       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
        return reg + IRQ_STATUS_REG;
 }
 
index e767355ab0ad7a02fc5a1ff8cb62ad0cd943f698..65458096f41e2e3c7b998489311f573629523a2c 100644 (file)
@@ -39,6 +39,7 @@ struct tegra_pmx {
        struct pinctrl_dev *pctl;
 
        const struct tegra_pinctrl_soc_data *soc;
+       const char **group_pins;
 
        int nbanks;
        void __iomem **regs;
@@ -620,6 +621,8 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
        struct tegra_pmx *pmx;
        struct resource *res;
        int i;
+       const char **group_pins;
+       int fn, gn, gfn;
 
        pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
        if (!pmx) {
@@ -629,6 +632,41 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
        pmx->dev = &pdev->dev;
        pmx->soc = soc_data;
 
+       /*
+        * Each mux group will appear in 4 functions' list of groups.
+        * This over-allocates slightly, since not all groups are mux groups.
+        */
+       pmx->group_pins = devm_kzalloc(&pdev->dev,
+               soc_data->ngroups * 4 * sizeof(*pmx->group_pins),
+               GFP_KERNEL);
+       if (!pmx->group_pins)
+               return -ENOMEM;
+
+       group_pins = pmx->group_pins;
+       for (fn = 0; fn < soc_data->nfunctions; fn++) {
+               struct tegra_function *func = &soc_data->functions[fn];
+
+               func->groups = group_pins;
+
+               for (gn = 0; gn < soc_data->ngroups; gn++) {
+                       const struct tegra_pingroup *g = &soc_data->groups[gn];
+
+                       if (g->mux_reg == -1)
+                               continue;
+
+                       for (gfn = 0; gfn < 4; gfn++)
+                               if (g->funcs[gfn] == fn)
+                                       break;
+                       if (gfn == 4)
+                               continue;
+
+                       BUG_ON(group_pins - pmx->group_pins >=
+                               soc_data->ngroups * 4);
+                       *group_pins++ = g->name;
+                       func->ngroups++;
+               }
+       }
+
        tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
        tegra_pinctrl_desc.name = dev_name(&pdev->dev);
        tegra_pinctrl_desc.pins = pmx->soc->pins;
index 817f7061dc4cd0b332488dc92c2c647cd19bc149..6053832d433e7b9667c8a8f97bf732990412896f 100644 (file)
@@ -72,7 +72,7 @@ enum tegra_pinconf_tristate {
  */
 struct tegra_function {
        const char *name;
-       const char * const *groups;
+       const char **groups;
        unsigned ngroups;
 };
 
@@ -193,7 +193,7 @@ struct tegra_pinctrl_soc_data {
        unsigned ngpios;
        const struct pinctrl_pin_desc *pins;
        unsigned npins;
-       const struct tegra_function *functions;
+       struct tegra_function *functions;
        unsigned nfunctions;
        const struct tegra_pingroup *groups;
        unsigned ngroups;
index 93c9e3899d5e4a0230e91a7269c68b7d7d8433f4..63fe7619d3ff9d96c0978765fe2de63608e53e77 100644 (file)
@@ -1,10 +1,8 @@
 /*
- * Pinctrl data and driver for the NVIDIA Tegra114 pinmux
+ * Pinctrl data for the NVIDIA Tegra114 pinmux
  *
  * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  *
- * Author:  Pritesh Raithatha <praithatha@nvidia.com>
- *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
@@ -13,9 +11,6 @@
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/module.h>
 #define TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5                _GPIO(245)
 
 /* All non-GPIO pins follow */
-#define NUM_GPIOS      (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
-#define _PIN(offset)   (NUM_GPIOS + (offset))
+#define NUM_GPIOS                              (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
+#define _PIN(offset)                           (NUM_GPIOS + (offset))
 
 /* Non-GPIO pins */
 #define TEGRA_PIN_CORE_PWR_REQ                 _PIN(0)
 #define TEGRA_PIN_PWR_INT_N                    _PIN(2)
 #define TEGRA_PIN_RESET_OUT_N                  _PIN(3)
 #define TEGRA_PIN_OWR                          _PIN(4)
+#define TEGRA_PIN_JTAG_RTCK                    _PIN(5)
+#define TEGRA_PIN_CLK_32K_IN                   _PIN(6)
+#define TEGRA_PIN_GMI_CLK_LB                   _PIN(7)
 
-static const struct pinctrl_pin_desc  tegra114_pins[] = {
+static const struct pinctrl_pin_desc tegra114_pins[] = {
        PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"),
        PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
        PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
@@ -385,9 +383,12 @@ static const struct pinctrl_pin_desc  tegra114_pins[] = {
        PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
        PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
        PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
-       PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
        PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
        PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
+       PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
+       PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"),
+       PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
+       PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
 };
 
 static const unsigned clk_32k_out_pa0_pins[] = {
@@ -1074,10 +1075,6 @@ static const unsigned cpu_pwr_req_pins[] = {
        TEGRA_PIN_CPU_PWR_REQ,
 };
 
-static const unsigned owr_pins[] = {
-       TEGRA_PIN_OWR,
-};
-
 static const unsigned pwr_int_n_pins[] = {
        TEGRA_PIN_PWR_INT_N,
 };
@@ -1086,6 +1083,22 @@ static const unsigned reset_out_n_pins[] = {
        TEGRA_PIN_RESET_OUT_N,
 };
 
+static const unsigned owr_pins[] = {
+       TEGRA_PIN_OWR,
+};
+
+static const unsigned jtag_rtck_pins[] = {
+       TEGRA_PIN_JTAG_RTCK,
+};
+
+static const unsigned clk_32k_in_pins[] = {
+       TEGRA_PIN_CLK_32K_IN,
+};
+
+static const unsigned gmi_clk_lb_pins[] = {
+       TEGRA_PIN_GMI_CLK_LB,
+};
+
 static const unsigned drive_ao1_pins[] = {
        TEGRA_PIN_KB_ROW0_PR0,
        TEGRA_PIN_KB_ROW1_PR1,
@@ -1127,7 +1140,6 @@ static const unsigned drive_at1_pins[] = {
        TEGRA_PIN_GMI_AD13_PH5,
        TEGRA_PIN_GMI_AD14_PH6,
        TEGRA_PIN_GMI_AD15_PH7,
-
        TEGRA_PIN_GMI_IORDY_PI5,
        TEGRA_PIN_GMI_CS7_N_PI6,
 };
@@ -1141,15 +1153,12 @@ static const unsigned drive_at2_pins[] = {
        TEGRA_PIN_GMI_AD5_PG5,
        TEGRA_PIN_GMI_AD6_PG6,
        TEGRA_PIN_GMI_AD7_PG7,
-
        TEGRA_PIN_GMI_WR_N_PI0,
        TEGRA_PIN_GMI_OE_N_PI1,
        TEGRA_PIN_GMI_CS6_N_PI3,
        TEGRA_PIN_GMI_RST_N_PI4,
        TEGRA_PIN_GMI_WAIT_PI7,
-
        TEGRA_PIN_GMI_DQS_P_PJ3,
-
        TEGRA_PIN_GMI_ADV_N_PK0,
        TEGRA_PIN_GMI_CLK_PK1,
        TEGRA_PIN_GMI_CS4_N_PK2,
@@ -1342,14 +1351,37 @@ static const unsigned drive_uda_pins[] = {
 };
 
 static const unsigned drive_dev3_pins[] = {
-       TEGRA_PIN_CLK3_OUT_PEE0,
-       TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned drive_cec_pins[] = {
+};
+
+static const unsigned drive_at6_pins[] = {
+};
+
+static const unsigned drive_dap5_pins[] = {
+};
+
+static const unsigned drive_usb_vbus_en_pins[] = {
+};
+
+static const unsigned drive_ao3_pins[] = {
+};
+
+static const unsigned drive_hv0_pins[] = {
+};
+
+static const unsigned drive_sdio4_pins[] = {
+};
+
+static const unsigned drive_ao0_pins[] = {
 };
 
 enum tegra_mux {
        TEGRA_MUX_BLINK,
        TEGRA_MUX_CEC,
        TEGRA_MUX_CLDVFS,
+       TEGRA_MUX_CLK,
        TEGRA_MUX_CLK12,
        TEGRA_MUX_CPU,
        TEGRA_MUX_DAP,
@@ -1394,6 +1426,7 @@ enum tegra_mux {
        TEGRA_MUX_RSVD2,
        TEGRA_MUX_RSVD3,
        TEGRA_MUX_RSVD4,
+       TEGRA_MUX_RTCK,
        TEGRA_MUX_SDMMC1,
        TEGRA_MUX_SDMMC2,
        TEGRA_MUX_SDMMC3,
@@ -1425,944 +1458,16 @@ enum tegra_mux {
        TEGRA_MUX_VI_ALT3,
 };
 
-static const char * const blink_groups[] = {
-       "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
-       "hdmi_cec_pee3",
-};
-
-static const char * const cldvfs_groups[] = {
-       "gmi_ad9_ph1",
-       "gmi_ad10_ph2",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "dvfs_pwm_px0",
-       "dvfs_clk_px2",
-};
-
-static const char * const clk12_groups[] = {
-       "sdmmc1_wp_n_pv3",
-       "sdmmc1_clk_pz0",
-};
-
-static const char * const cpu_groups[] = {
-       "cpu_pwr_req",
-};
-
-static const char * const dap_groups[] = {
-       "clk1_req_pee2",
-       "clk2_req_pcc5",
-};
-
-static const char * const dap1_groups[] = {
-       "clk1_req_pee2",
-};
-
-static const char * const dap2_groups[] = {
-       "clk1_out_pw4",
-       "gpio_x4_aud_px4",
-};
-
-static const char * const dev3_groups[] = {
-       "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_sclk_pp3",
-       "uart3_rts_n_pc0",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "kb_col3_pq3",
-       "sdmmc3_dat2_pb5",
-};
-
-static const char * const displaya_alt_groups[] = {
-       "kb_row6_pr6",
-};
-
-static const char * const displayb_groups[] = {
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_sclk_pp3",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "sdmmc3_dat3_pb4",
-};
-
-static const char * const dtv_groups[] = {
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-       "dap4_fs_pp4",
-       "dap4_dout_pp6",
-       "gmi_wait_pi7",
-       "gmi_ad8_ph0",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-};
-
-static const char * const emc_dll_groups[] = {
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-};
-
-static const char * const extperiph1_groups[] = {
-       "clk1_out_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
-       "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
-       "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
-       "gmi_wp_n_pc7",
-
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_ad8_ph0",
-       "gmi_ad9_ph1",
-       "gmi_ad10_ph2",
-       "gmi_ad11_ph3",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_wr_n_pi0",
-       "gmi_oe_n_pi1",
-       "gmi_cs6_n_pi3",
-       "gmi_rst_n_pi4",
-       "gmi_iordy_pi5",
-       "gmi_cs7_n_pi6",
-       "gmi_wait_pi7",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-       "gmi_dqs_p_pj3",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs4_n_pk2",
-       "gmi_cs2_n_pk3",
-       "gmi_cs3_n_pk4",
-       "gmi_a16_pj7",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_a19_pk7",
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-};
-
-static const char * const gmi_alt_groups[] = {
-       "gmi_wp_n_pc7",
-       "gmi_cs3_n_pk4",
-       "gmi_a16_pj7",
-};
-
-static const char * const hda_groups[] = {
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-};
-
-static const char * const hsi_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "gpio_w2_aud_pw2",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const i2c2_groups[] = {
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-};
-
-static const char * const i2c4_groups[] = {
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-};
-
-static const char * const i2s2_groups[] = {
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
-       "dap4_fs_pp4",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
-       "pcc1",
-       "pbb0",
-       "pbb7",
-       "pcc2",
-};
-
-static const char * const irda_groups[] = {
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-};
-
-static const char * const kbc_groups[] = {
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-};
-
-static const char * const nand_groups[] = {
-       "gmi_wp_n_pc7",
-       "gmi_wait_pi7",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-       "gmi_cs2_n_pk3",
-       "gmi_cs3_n_pk4",
-       "gmi_cs4_n_pk2",
-       "gmi_cs6_n_pi3",
-       "gmi_cs7_n_pi6",
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_ad8_ph0",
-       "gmi_ad9_ph1",
-       "gmi_ad10_ph2",
-       "gmi_ad11_ph3",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_wr_n_pi0",
-       "gmi_oe_n_pi1",
-       "gmi_dqs_p_pj3",
-       "gmi_rst_n_pi4",
-};
-
-static const char * const nand_alt_groups[] = {
-       "gmi_cs6_n_pi3",
-       "gmi_cs7_n_pi6",
-       "gmi_rst_n_pi4",
-};
-
-static const char * const owr_groups[] = {
-       "pu0",
-       "kb_col4_pq4",
-       "owr",
-       "sdmmc3_cd_n_pv2",
-};
-
-static const char * const pmi_groups[] = {
-       "pwr_int_n",
-};
-
-static const char * const pwm0_groups[] = {
-       "sdmmc1_dat2_py5",
-       "uart3_rts_n_pc0",
-       "pu3",
-       "gmi_ad8_ph0",
-       "sdmmc3_dat3_pb4",
-};
-
-static const char * const pwm1_groups[] = {
-       "sdmmc1_dat1_py6",
-       "pu4",
-       "gmi_ad9_ph1",
-       "sdmmc3_dat2_pb5",
-};
-
-static const char * const pwm2_groups[] = {
-       "pu5",
-       "gmi_ad10_ph2",
-       "kb_col3_pq3",
-       "sdmmc3_dat1_pb6",
-};
-
-static const char * const pwm3_groups[] = {
-       "pu6",
-       "gmi_ad11_ph3",
-       "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwron_groups[] = {
-       "core_pwr_req",
-};
-
-static const char * const reset_out_n_groups[] = {
-       "reset_out_n",
-};
-
-static const char * const rsvd1_groups[] = {
-       "pv1",
-       "hdmi_int_pn7",
-       "pu1",
-       "pu2",
-       "gmi_wp_n_pc7",
-       "gmi_adv_n_pk0",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_wr_n_pi0",
-       "gmi_oe_n_pi1",
-       "gpio_x4_aud_px4",
-       "gpio_x5_aud_px5",
-       "gpio_x7_aud_px7",
-
-       "reset_out_n",
-};
-
-static const char * const rsvd2_groups[] = {
-       "pv0",
-       "pv1",
-       "sdmmc1_dat0_py7",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "hdmi_int_pn7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "dap4_fs_pp4",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_sclk_pp7",
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-       "gmi_iordy_pi5",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat7_paa7",
-       "pcc1",
-       "pbb7",
-       "pcc2",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "sys_clk_req_pz5",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "pwr_int_n",
-       "owr",
-       "spdif_out_pk5",
-       "gpio_x1_aud_px1",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_dat0_pb7",
-       "gpio_w2_aud_pw2",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "sdmmc3_clk_lb_out_pee4",
-       "sdmmc3_clk_lb_in_pee5",
-       "reset_out_n",
-};
-
-static const char * const rsvd3_groups[] = {
-       "pv0",
-       "pv1",
-       "sdmmc1_clk_pz0",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "hdmi_int_pn7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-       "pu0",
-       "pu1",
-       "pu2",
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "dap4_din_pp5",
-       "dap4_sclk_pp7",
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-       "pcc1",
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "pbb7",
-       "pcc2",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row3_pr3",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "clk_32k_out_pa0",
-       "sys_clk_req_pz5",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "pwr_int_n",
-       "owr",
-       "clk1_req_pee2",
-       "clk1_out_pw4",
-       "spdif_out_pk5",
-       "spdif_in_pk6",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dvfs_pwm_px0",
-       "gpio_x1_aud_px1",
-       "gpio_x3_aud_px3",
-       "dvfs_clk_px2",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_dat0_pb7",
-       "hdmi_cec_pee3",
-       "sdmmc3_cd_n_pv2",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "sdmmc3_clk_lb_out_pee4",
-       "sdmmc3_clk_lb_in_pee5",
-       "reset_out_n",
-};
-
-static const char * const rsvd4_groups[] = {
-       "pv0",
-       "pv1",
-       "sdmmc1_clk_pz0",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "hdmi_int_pn7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-       "pu0",
-       "pu1",
-       "pu2",
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "dap4_fs_pp4",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_sclk_pp7",
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_rst_n_pi4",
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-       "cam_mclk_pcc0",
-       "pcc1",
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "pbb7",
-       "pcc2",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_col2_pq2",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "clk_32k_out_pa0",
-       "sys_clk_req_pz5",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "pwr_int_n",
-       "owr",
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-       "clk1_req_pee2",
-       "clk1_out_pw4",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dvfs_pwm_px0",
-       "gpio_x1_aud_px1",
-       "gpio_x3_aud_px3",
-       "dvfs_clk_px2",
-       "gpio_x5_aud_px5",
-       "gpio_x6_aud_px6",
-       "gpio_x7_aud_px7",
-       "sdmmc3_cd_n_pv2",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "sdmmc3_clk_lb_in_pee5",
-       "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc1_groups[] = {
-
-       "sdmmc1_clk_pz0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat0_py7",
-       "uart3_cts_n_pa1",
-       "kb_col5_pq5",
-       "sdmmc1_wp_n_pv3",
-};
-
-static const char * const sdmmc2_groups[] = {
-       "gmi_iordy_pi5",
-       "gmi_clk_pk1",
-       "gmi_cs2_n_pk3",
-       "gmi_cs3_n_pk4",
-       "gmi_cs7_n_pi6",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_dqs_p_pj3",
-};
-
-static const char * const sdmmc3_groups[] = {
-       "kb_col4_pq4",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-       "hdmi_cec_pee3",
-       "sdmmc3_cd_n_pv2",
-       "sdmmc3_clk_lb_in_pee5",
-       "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc4_groups[] = {
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-};
-
-static const char * const soc_groups[] = {
-       "gmi_cs1_n_pj2",
-       "gmi_oe_n_pi1",
-       "clk_32k_out_pa0",
-       "hdmi_cec_pee3",
-};
-
-static const char * const spdif_groups[] = {
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-};
-
-static const char * const spi1_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "gpio_x3_aud_px3",
-       "gpio_x4_aud_px4",
-       "gpio_x5_aud_px5",
-       "gpio_x6_aud_px6",
-       "gpio_x7_aud_px7",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const spi2_groups[] = {
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "gpio_x4_aud_px4",
-       "gpio_x5_aud_px5",
-       "gpio_x6_aud_px6",
-       "gpio_x7_aud_px7",
-       "gpio_w2_aud_pw2",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const spi3_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-};
-
-static const char * const spi4_groups[] = {
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat0_py7",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-       "uart3_cts_n_pa1",
-       "gmi_wait_pi7",
-       "gmi_cs6_n_pi3",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_a19_pk7",
-       "gmi_wr_n_pi0",
-       "sdmmc1_wp_n_pv3",
-};
-
-static const char * const spi5_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_sclk_pp3",
-};
-
-static const char * const spi6_groups[] = {
-       "dvfs_pwm_px0",
-       "gpio_x1_aud_px1",
-       "gpio_x3_aud_px3",
-       "dvfs_clk_px2",
-       "gpio_x6_aud_px6",
-       "gpio_w2_aud_pw2",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const sysclk_groups[] = {
-       "sys_clk_req_pz5",
-};
-
-static const char * const trace_groups[] = {
-       "gmi_iordy_pi5",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs2_n_pk3",
-       "gmi_cs4_n_pk2",
-       "gmi_a16_pj7",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_a19_pk7",
-       "gmi_dqs_p_pj3",
-};
-
-static const char * const uarta_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat0_py7",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-       "pu0",
-       "pu1",
-       "pu2",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc1_wp_n_pv3",
-};
-
-static const char * const uartb_groups[] = {
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-};
-
-static const char * const uartc_groups[] = {
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-};
-
-static const char * const uartd_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "gmi_a16_pj7",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_a19_pk7",
-};
-
-static const char * const ulpi_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-};
-
-static const char * const usb_groups[] = {
-       "pv0",
-       "pu6",
-       "gmi_cs0_n_pj0",
-       "gmi_cs4_n_pk2",
-       "gmi_ad11_ph3",
-       "kb_col0_pq0",
-       "spdif_in_pk6",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-};
-
-static const char * const vgp1_groups[] = {
-       "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
-       "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
-       "pbb3",
-};
-
-static const char * const vgp4_groups[] = {
-       "pbb4",
-};
-
-static const char * const vgp5_groups[] = {
-       "pbb5",
-};
-
-static const char * const vgp6_groups[] = {
-       "pbb6",
-};
-
-static const char * const vi_groups[] = {
-       "cam_mclk_pcc0",
-       "pbb0",
-};
-
-static const char * const vi_alt1_groups[] = {
-       "cam_mclk_pcc0",
-       "pbb0",
-};
-
-static const char * const vi_alt3_groups[] = {
-       "cam_mclk_pcc0",
-       "pbb0",
-};
-
 #define FUNCTION(fname)                                        \
        {                                               \
                .name = #fname,                         \
-               .groups = fname##_groups,               \
-               .ngroups = ARRAY_SIZE(fname##_groups),  \
        }
 
-static const struct tegra_function  tegra114_functions[] = {
+static struct tegra_function tegra114_functions[] = {
        FUNCTION(blink),
        FUNCTION(cec),
        FUNCTION(cldvfs),
+       FUNCTION(clk),
        FUNCTION(clk12),
        FUNCTION(cpu),
        FUNCTION(dap),
@@ -2407,6 +1512,7 @@ static const struct tegra_function  tegra114_functions[] = {
        FUNCTION(rsvd2),
        FUNCTION(rsvd3),
        FUNCTION(rsvd4),
+       FUNCTION(rtck),
        FUNCTION(sdmmc1),
        FUNCTION(sdmmc2),
        FUNCTION(sdmmc3),
@@ -2438,11 +1544,11 @@ static const struct tegra_function  tegra114_functions[] = {
        FUNCTION(vi_alt3),
 };
 
-#define DRV_PINGROUP_REG_START                 0x868   /* bank 0 */
-#define PINGROUP_REG_START                     0x3000  /* bank 1 */
+#define DRV_PINGROUP_REG_A             0x868   /* bank 0 */
+#define PINGROUP_REG_A                 0x3000  /* bank 1 */
 
-#define PINGROUP_REG_Y(r)                      ((r) - PINGROUP_REG_START)
-#define PINGROUP_REG_N(r)                      -1
+#define PINGROUP_REG_Y(r)              ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r)              -1
 
 #define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
        {                                                               \
@@ -2484,13 +1590,14 @@ static const struct tegra_function  tegra114_functions[] = {
                .drvtype_reg = -1,                                      \
        }
 
-#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_START)
-#define DRV_PINGROUP_DVRTYPE_N(r) -1
+#define DRV_PINGROUP_REG_Y(r)          ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r)          -1
+
 
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b,             \
-                       drvdn_b, drvdn_w, drvup_b, drvup_w,             \
-                       slwr_b, slwr_w, slwf_b, slwf_w,                 \
-                       drvtype)                                        \
+                    drvdn_b, drvdn_w, drvup_b, drvup_w,                \
+                    slwr_b, slwr_w, slwf_b, slwf_w,                    \
+                    drvtype)                                           \
        {                                                               \
                .name = "drive_" #pg_name,                              \
                .pins = drive_##pg_name##_pins,                         \
@@ -2503,7 +1610,7 @@ static const struct tegra_function  tegra114_functions[] = {
                .lock_reg = -1,                                         \
                .ioreset_reg = -1,                                      \
                .rcv_sel_reg = -1,                                      \
-               .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r),                   \
+               .drv_reg = DRV_PINGROUP_REG_Y(r),                       \
                .drv_bank = 0,                                          \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
@@ -2516,14 +1623,13 @@ static const struct tegra_function  tegra114_functions[] = {
                .slwr_width = slwr_w,                                   \
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
-               .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r),       \
+               .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r),           \
                .drvtype_bank = 0,                                      \
                .drvtype_bit = 6,                                       \
        }
 
 static const struct tegra_pingroup tegra114_groups[] = {
        /*       pg_name,                f0,         f1,         f2,           f3,          safe,     r,      od, ior, rcv_sel */
-       /* FIXME: Fill in correct data in safe column */
        PINGROUP(ulpi_data0_po1,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x3000,  N,  N,  N),
        PINGROUP(ulpi_data1_po2,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x3004,  N,  N,  N),
        PINGROUP(ulpi_data2_po3,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x3008,  N,  N,  N),
@@ -2635,6 +1741,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
        PINGROUP(pbb6,                   VGP6,       DISPLAYA,   DISPLAYB,     RSVD4,       RSVD4,    0x32a4,  N,  N,  N),
        PINGROUP(pbb7,                   I2S4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32a8,  N,  N,  N),
        PINGROUP(pcc2,                   I2S4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32ac,  N,  N,  N),
+       PINGROUP(jtag_rtck,              RTCK,       RSVD2,      RSVD3,        RSVD4,       RTCK,     0x32b0,  N,  N,  N),
        PINGROUP(pwr_i2c_scl_pz6,        I2CPWR,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32b4,  Y,  N,  N),
        PINGROUP(pwr_i2c_sda_pz7,        I2CPWR,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32b8,  Y,  N,  N),
        PINGROUP(kb_row0_pr0,            KBC,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32bc,  N,  N,  N),
@@ -2661,6 +1768,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
        PINGROUP(core_pwr_req,           PWRON,      RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3324,  N,  N,  N),
        PINGROUP(cpu_pwr_req,            CPU,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3328,  N,  N,  N),
        PINGROUP(pwr_int_n,              PMI,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x332c,  N,  N,  N),
+       PINGROUP(clk_32k_in,             CLK,        RSVD2,      RSVD3,        RSVD4,       CLK,      0x3330,  N,  N,  N),
        PINGROUP(owr,                    OWR,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3334,  N,  N,  Y),
        PINGROUP(dap1_fs_pn0,            I2S0,       HDA,        GMI,          RSVD4,       RSVD4,    0x3338,  N,  N,  N),
        PINGROUP(dap1_din_pn1,           I2S0,       HDA,        GMI,          RSVD4,       RSVD4,    0x333c,  N,  N,  N),
@@ -2697,38 +1805,48 @@ static const struct tegra_pingroup tegra114_groups[] = {
        PINGROUP(usb_vbus_en1_pn5,       USB,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x33f8,  Y,  N,  N),
        PINGROUP(sdmmc3_clk_lb_in_pee5,  SDMMC3,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x33fc,  N,  N,  N),
        PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3400,  N,  N,  N),
+       PINGROUP(gmi_clk_lb,             SDMMC2,     NAND,       GMI,          RSVD4,       GMI,      0x3404,  N,  N,  N),
        PINGROUP(reset_out_n,            RSVD1,      RSVD2,      RSVD3,        RESET_OUT_N, RSVD3,    0x3408,  N,  N,  N),
 
        /* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */
-       DRV_PINGROUP(ao1,   0x868,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(ao2,   0x86c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(at1,   0x870,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
-       DRV_PINGROUP(at2,   0x874,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
-       DRV_PINGROUP(at3,   0x878,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
-       DRV_PINGROUP(at4,   0x87c,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
-       DRV_PINGROUP(at5,   0x880,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(cdev1, 0x884,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(cdev2, 0x888,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(dap1,  0x890,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(dap2,  0x894,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(dap3,  0x898,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(dap4,  0x89c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(dbg,   0x8a0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(sdio3, 0x8b0,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(spi,   0x8b4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(uaa,   0x8b8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(uab,   0x8bc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(uart2, 0x8c0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(uart3, 0x8c4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(sdio1, 0x8ec,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(ddc,   0x8fc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(gma,   0x900,  2,  3,  4,  14,  5,  20,  5,  28,  2,  30,  2,  Y),
-       DRV_PINGROUP(gme,   0x910,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(gmf,   0x914,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(gmg,   0x918,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(gmh,   0x91c,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(owr,   0x920,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
-       DRV_PINGROUP(uda,   0x924,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(ao1,         0x868,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(ao2,         0x86c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(at1,         0x870,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+       DRV_PINGROUP(at2,         0x874,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+       DRV_PINGROUP(at3,         0x878,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+       DRV_PINGROUP(at4,         0x87c,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+       DRV_PINGROUP(at5,         0x880,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(cdev1,       0x884,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(cdev2,       0x888,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(dap1,        0x890,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(dap2,        0x894,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(dap3,        0x898,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(dap4,        0x89c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(dbg,         0x8a0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(sdio3,       0x8b0,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(spi,         0x8b4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(uaa,         0x8b8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(uab,         0x8bc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(uart2,       0x8c0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(uart3,       0x8c4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(sdio1,       0x8ec,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(ddc,         0x8fc,  2,  3, -1,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(gma,         0x900,  2,  3, -1,  14,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(gme,         0x910,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(gmf,         0x914,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(gmg,         0x918,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(gmh,         0x91c,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(owr,         0x920,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(uda,         0x924,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(dev3,        0x92c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(cec,         0x938,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(at6,         0x994,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  Y),
+       DRV_PINGROUP(dap5,        0x998,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(usb_vbus_en, 0x99c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(ao3,         0x9a0,  2,  3,  4,  12,  5,  -1, -1,  28,  2,  -1, -1,  N),
+       DRV_PINGROUP(hv0,         0x9a4,  2,  3,  4,  12,  5,  -1, -1,  28,  2,  -1, -1,  N),
+       DRV_PINGROUP(sdio4,       0x9a8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+       DRV_PINGROUP(ao0,         0x9ac,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
 };
 
 static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
index c20e0e1dda83cc1bb0e6567b4d9bd10e2609b271..73773706755b6f91ff9779c22debaaef624f2dac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Pinctrl data for the NVIDIA Tegra124 pinmux
  *
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2014, 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,
 #define TEGRA_PIN_PFF2                         _GPIO(250)
 
 /* All non-GPIO pins follow */
-#define NUM_GPIOS      (TEGRA_PIN_PFF2 + 1)
-#define _PIN(offset)   (NUM_GPIOS + (offset))
+#define NUM_GPIOS                              (TEGRA_PIN_PFF2 + 1)
+#define _PIN(offset)                           (NUM_GPIOS + (offset))
 
 /* Non-GPIO pins */
 #define TEGRA_PIN_CORE_PWR_REQ                 _PIN(0)
@@ -325,13 +325,13 @@ static const struct pinctrl_pin_desc tegra124_pins[] = {
        PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
        PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
        PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW10 PS3"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW10 PS4"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW10 PS5"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW10 PS6"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW10 PS7"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW16_PT0, "KB_ROW10 PT0"),
-       PINCTRL_PIN(TEGRA_PIN_KB_ROW17_PT1, "KB_ROW10 PT1"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW11 PS3"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW12 PS4"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW13 PS5"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW14 PS6"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW15 PS7"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW16_PT0, "KB_ROW16 PT0"),
+       PINCTRL_PIN(TEGRA_PIN_KB_ROW17_PT1, "KB_ROW17 PT1"),
        PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
        PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
        PINCTRL_PIN(TEGRA_PIN_SDMMC4_CMD_PT7, "SDMMC4_CMD PT7"),
@@ -406,16 +406,16 @@ static const struct pinctrl_pin_desc tegra124_pins[] = {
        PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PEE3, "HDMI_CEC PEE3"),
        PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4, "SDMMC3_CLK_LB_OUT PEE4"),
        PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
+       PINCTRL_PIN(TEGRA_PIN_DP_HPD_PFF0, "DP_HPD PFF0"),
+       PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN2_PFF1, "USB_VBUS_EN2 PFF1"),
+       PINCTRL_PIN(TEGRA_PIN_PFF2, "PFF2"),
        PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
        PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
-       PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
        PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+       PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
        PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
-       PINCTRL_PIN(TEGRA_PIN_DP_HPD_PFF0, "DP_HPD PFF0"),
-       PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN2_PFF1, "USB_VBUS_EN2 PFF1"),
-       PINCTRL_PIN(TEGRA_PIN_PFF2, "PFF2"),
+       PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
        PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
-       PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
        PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"),
 };
 
@@ -1138,6 +1138,7 @@ static const unsigned sdmmc3_clk_lb_out_pee4_pins[] = {
 static const unsigned sdmmc3_clk_lb_in_pee5_pins[] = {
        TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
 };
+
 static const unsigned dp_hpd_pff0_pins[] = {
        TEGRA_PIN_DP_HPD_PFF0,
 };
@@ -1158,24 +1159,24 @@ static const unsigned cpu_pwr_req_pins[] = {
        TEGRA_PIN_CPU_PWR_REQ,
 };
 
-static const unsigned owr_pins[] = {
-       TEGRA_PIN_OWR,
-};
-
 static const unsigned pwr_int_n_pins[] = {
        TEGRA_PIN_PWR_INT_N,
 };
 
+static const unsigned gmi_clk_lb_pins[] = {
+       TEGRA_PIN_GMI_CLK_LB,
+};
+
 static const unsigned reset_out_n_pins[] = {
        TEGRA_PIN_RESET_OUT_N,
 };
 
-static const unsigned clk_32k_in_pins[] = {
-       TEGRA_PIN_CLK_32K_IN,
+static const unsigned owr_pins[] = {
+       TEGRA_PIN_OWR,
 };
 
-static const unsigned gmi_clk_lb_pins[] = {
-       TEGRA_PIN_GMI_CLK_LB,
+static const unsigned clk_32k_in_pins[] = {
+       TEGRA_PIN_CLK_32K_IN,
 };
 
 static const unsigned jtag_rtck_pins[] = {
@@ -1441,15 +1442,15 @@ static const unsigned drive_gpv_pins[] = {
        TEGRA_PIN_PFF2,
 };
 
-static const unsigned drive_cec_pins[] = {
-       TEGRA_PIN_HDMI_CEC_PEE3,
-};
-
 static const unsigned drive_dev3_pins[] = {
        TEGRA_PIN_CLK3_OUT_PEE0,
        TEGRA_PIN_CLK3_REQ_PEE1,
 };
 
+static const unsigned drive_cec_pins[] = {
+       TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
 static const unsigned drive_at6_pins[] = {
        TEGRA_PIN_PK1,
        TEGRA_PIN_PK3,
@@ -1496,8 +1497,10 @@ static const unsigned drive_ao4_pins[] = {
 
 enum tegra_mux {
        TEGRA_MUX_BLINK,
+       TEGRA_MUX_CCLA,
        TEGRA_MUX_CEC,
        TEGRA_MUX_CLDVFS,
+       TEGRA_MUX_CLK,
        TEGRA_MUX_CLK12,
        TEGRA_MUX_CPU,
        TEGRA_MUX_DAP,
@@ -1507,6 +1510,7 @@ enum tegra_mux {
        TEGRA_MUX_DISPLAYA,
        TEGRA_MUX_DISPLAYA_ALT,
        TEGRA_MUX_DISPLAYB,
+       TEGRA_MUX_DP,
        TEGRA_MUX_DTV,
        TEGRA_MUX_EXTPERIPH1,
        TEGRA_MUX_EXTPERIPH2,
@@ -1528,6 +1532,9 @@ enum tegra_mux {
        TEGRA_MUX_IRDA,
        TEGRA_MUX_KBC,
        TEGRA_MUX_OWR,
+       TEGRA_MUX_PE,
+       TEGRA_MUX_PE0,
+       TEGRA_MUX_PE1,
        TEGRA_MUX_PMI,
        TEGRA_MUX_PWM0,
        TEGRA_MUX_PWM1,
@@ -1539,6 +1546,8 @@ enum tegra_mux {
        TEGRA_MUX_RSVD2,
        TEGRA_MUX_RSVD3,
        TEGRA_MUX_RSVD4,
+       TEGRA_MUX_RTCK,
+       TEGRA_MUX_SATA,
        TEGRA_MUX_SDMMC1,
        TEGRA_MUX_SDMMC2,
        TEGRA_MUX_SDMMC3,
@@ -1551,6 +1560,8 @@ enum tegra_mux {
        TEGRA_MUX_SPI4,
        TEGRA_MUX_SPI5,
        TEGRA_MUX_SPI6,
+       TEGRA_MUX_SYS,
+       TEGRA_MUX_TMDS,
        TEGRA_MUX_TRACE,
        TEGRA_MUX_UARTA,
        TEGRA_MUX_UARTB,
@@ -1569,1134 +1580,19 @@ enum tegra_mux {
        TEGRA_MUX_VI_ALT3,
        TEGRA_MUX_VIMCLK2,
        TEGRA_MUX_VIMCLK2_ALT,
-       TEGRA_MUX_SATA,
-       TEGRA_MUX_CCLA,
-       TEGRA_MUX_PE0,
-       TEGRA_MUX_PE,
-       TEGRA_MUX_PE1,
-       TEGRA_MUX_DP,
-       TEGRA_MUX_RTCK,
-       TEGRA_MUX_SYS,
-       TEGRA_MUX_CLK,
-       TEGRA_MUX_TMDS,
-};
-
-static const char * const blink_groups[] = {
-       "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
-       "hdmi_cec_pee3",
-};
-
-static const char * const cldvfs_groups[] = {
-       "ph2",
-       "ph3",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "dvfs_pwm_px0",
-       "dvfs_clk_px2",
-};
-
-static const char * const clk12_groups[] = {
-       "sdmmc1_wp_n_pv3",
-       "sdmmc1_clk_pz0",
-};
-
-static const char * const cpu_groups[] = {
-       "cpu_pwr_req",
-};
-
-static const char * const dap_groups[] = {
-       "dap_mclk1_pee2",
-       "clk2_req_pcc5",
-};
-
-static const char * const dap1_groups[] = {
-       "dap_mclk1_pee2",
-};
-
-static const char * const dap2_groups[] = {
-       "dap_mclk1_pw4",
-       "gpio_x4_aud_px4",
-};
-
-static const char * const dev3_groups[] = {
-       "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "ph1",
-       "pi4",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "kb_col3_pq3",
-       "sdmmc3_dat2_pb5",
-};
-
-static const char * const displaya_alt_groups[] = {
-       "kb_row6_pr6",
-};
-
-static const char * const displayb_groups[] = {
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_sclk_pp3",
-
-       "pu3",
-       "pu4",
-       "pu5",
-
-       "pbb3",
-       "pbb4",
-       "pbb6",
-
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-
-       "sdmmc3_dat3_pb4",
-};
-
-static const char * const dtv_groups[] = {
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-       "dap4_fs_pp4",
-       "dap4_dout_pp6",
-       "pi7",
-       "ph0",
-       "ph6",
-       "ph7",
-};
-
-static const char * const extperiph1_groups[] = {
-       "dap_mclk1_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
-       "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
-       "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
-       "uart2_cts_n_pj5",
-       "uart2_rts_n_pj6",
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-
-       "pu0",
-       "pu1",
-       "pu2",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-
-       "dap4_fs_pp4",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_sclk_pp7",
-
-       "pc7",
-
-       "pg0",
-       "pg1",
-       "pg2",
-       "pg3",
-       "pg4",
-       "pg5",
-       "pg6",
-       "pg7",
-
-       "ph0",
-       "ph1",
-       "ph2",
-       "ph3",
-       "ph4",
-       "ph5",
-       "ph6",
-       "ph7",
-
-       "pi0",
-       "pi1",
-       "pi2",
-       "pi3",
-       "pi4",
-       "pi5",
-       "pi6",
-       "pi7",
-
-       "pj0",
-       "pj2",
-
-       "pk0",
-       "pk1",
-       "pk2",
-       "pk3",
-       "pk4",
-
-       "pj7",
-       "pb0",
-       "pb1",
-       "pk7",
-
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "gmi_clk_lb",
-
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-
-       "dap2_fs_pa2",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dap2_sclk_pa3",
-
-       "dvfs_pwm_px0",
-       "dvfs_clk_px2",
-       "gpio_x1_aud_px1",
-       "gpio_x3_aud_px3",
-       "gpio_x4_aud_px4",
-       "gpio_x5_aud_px5",
-       "gpio_x6_aud_px6",
-};
-
-static const char * const gmi_alt_groups[] = {
-       "pc7",
-       "pk4",
-       "pj7",
-};
-
-static const char * const hda_groups[] = {
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-};
-
-static const char * const hsi_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "gpio_w2_aud_pw2",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const i2c2_groups[] = {
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-};
-
-static const char * const i2c4_groups[] = {
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-};
-
-static const char * const i2s2_groups[] = {
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
-       "dap4_fs_pp4",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
-       "pcc1",
-       "pbb6",
-       "pbb7",
-       "pcc2",
-};
-
-static const char * const irda_groups[] = {
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-};
-
-static const char * const kbc_groups[] = {
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-       "kb_row16_pt0",
-       "kb_row17_pt1",
-
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-};
-
-static const char * const owr_groups[] = {
-       "pu0",
-       "kb_col4_pq4",
-       "owr",
-       "sdmmc3_cd_n_pv2",
-};
-
-static const char * const pmi_groups[] = {
-       "pwr_int_n",
-};
-
-static const char * const pwm0_groups[] = {
-       "sdmmc1_dat2_py5",
-       "uart3_rts_n_pc0",
-       "pu3",
-       "ph0",
-       "sdmmc3_dat3_pb4",
-};
-
-static const char * const pwm1_groups[] = {
-       "sdmmc1_dat1_py6",
-       "pu4",
-       "ph1",
-       "sdmmc3_dat2_pb5",
-};
-
-static const char * const pwm2_groups[] = {
-       "pu5",
-       "ph2",
-       "kb_col3_pq3",
-       "sdmmc3_dat1_pb6",
-};
-
-static const char * const pwm3_groups[] = {
-       "pu6",
-       "ph3",
-       "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwron_groups[] = {
-       "core_pwr_req",
-};
-
-static const char * const reset_out_n_groups[] = {
-       "reset_out_n",
-};
-
-static const char * const rsvd1_groups[] = {
-       "pv0",
-       "pv1",
-
-       "hdmi_int_pn7",
-       "pu1",
-       "pu2",
-       "pc7",
-       "pi7",
-       "pk0",
-       "pj0",
-       "pj2",
-       "pk2",
-       "pi3",
-       "pi6",
-
-       "pg0",
-       "pg1",
-       "pg2",
-       "pg3",
-       "pg4",
-       "pg5",
-       "pg6",
-       "pg7",
-
-       "pi0",
-       "pi1",
-
-       "gpio_x7_aud_px7",
-
-       "reset_out_n",
-};
-
-static const char * const rsvd2_groups[] = {
-       "pv0",
-       "pv1",
-
-       "sdmmc1_dat0_py7",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "hdmi_int_pn7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-
-       "clk2_out_pee0",
-       "clk2_req_pee1",
-       "pc7",
-       "pi5",
-       "pj0",
-       "pj2",
-
-       "pk4",
-       "pk2",
-       "pi3",
-       "pi6",
-       "pg0",
-       "pg1",
-       "pg5",
-       "pg6",
-       "pg7",
-
-       "ph4",
-       "ph5",
-       "pj7",
-       "pb0",
-       "pb1",
-       "pk7",
-       "pi0",
-       "pi1",
-
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat7_paa7",
-       "pcc1",
-       "pbb6",
-       "pbb7",
-       "pcc2",
-       "jtag_rtck",
-
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "pwr_int_n",
-       "clk_32k_in",
-       "owr",
-
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "gpio_x1_aud_px1",
-
-       "sdmmc3_clk_pa6",
-       "sdmmc3_dat0_pb7",
-
-       "pex_l0_rst_n_pdd1",
-       "pex_l0_clkreq_n_pdd2",
-       "pex_wake_n_pdd3",
-       "pex_l1_rst_n_pdd5",
-       "pex_l1_clkreq_n_pdd6",
-       "hdmi_cec_pee3",
-
-       "gpio_w2_aud_pw2",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "sdmmc3_clk_lb_out_pee4",
-       "sdmmc3_clk_lb_in_pee5",
-       "gmi_clk_lb",
-       "reset_out_n",
-       "kb_row16_pt0",
-       "kb_row17_pt1",
-       "dp_hpd_pff0",
-       "usb_vbus_en2_pff1",
-       "pff2",
-};
-
-static const char * const rsvd3_groups[] = {
-       "dap3_sclk_pp3",
-       "pv0",
-       "pv1",
-       "sdmmc1_clk_pz0",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "hdmi_int_pn7",
-
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-
-       "pu6",
-
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-
-       "dap4_din_pp5",
-       "dap4_sclk_pp7",
-
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-
-       "sdmmc4_dat5_paa5",
-       "gpio_pcc1",
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "pbb5",
-       "pbb7",
-       "jtag_rtck",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row15_ps7",
-
-       "clk_32k_out_pa0",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "pwr_int_n",
-       "clk_32k_in",
-       "owr",
-
-       "dap_mclk1_pw4",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_dat0_pb7",
-
-       "pex_l0_rst_n_pdd1",
-       "pex_l0_clkreq_n_pdd2",
-       "pex_wake_n_pdd3",
-       "pex_l1_rst_n_pdd5",
-       "pex_l1_clkreq_n_pdd6",
-       "hdmi_cec_pee3",
-
-       "sdmmc3_cd_n_pv2",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "sdmmc3_clk_lb_out_pee4",
-       "sdmmc3_clk_lb_in_pee5",
-       "reset_out_n",
-       "kb_row16_pt0",
-       "kb_row17_pt1",
-       "dp_hpd_pff0",
-       "usb_vbus_en2_pff1",
-       "pff2",
-};
-
-static const char * const rsvd4_groups[] = {
-       "dap3_dout_pp2",
-       "pv0",
-       "pv1",
-       "sdmmc1_clk_pz0",
-
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "hdmi_int_pn7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-
-       "pu0",
-       "pu1",
-       "pu2",
-
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-
-       "dap4_fs_pp4",
-       "dap4_dout_pp6",
-       "dap4_din_pp5",
-       "dap4_sclk_pp7",
-
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-
-       "pi5",
-       "pk1",
-       "pk2",
-       "pg0",
-       "pg1",
-       "pg2",
-       "pg3",
-       "ph4",
-       "ph5",
-       "pb0",
-       "pb1",
-       "pk7",
-       "pi0",
-       "pi1",
-       "pi2",
-
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-
-       "jtag_rtck",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col5_pq5",
-
-       "clk_32k_out_pa0",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "pwr_int_n",
-       "clk_32k_in",
-       "owr",
-
-       "dap1_fs_pn0",
-       "dap1_din_pn1",
-       "dap1_sclk_pn3",
-       "dap_mclk1_req_pee2",
-       "dap_mclk1_pw5",
-
-       "dap2_fs_pa2",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dap2_sclk_pa3",
-
-       "dvfs_pwm_px0",
-       "dvfs_clk_px2",
-       "gpio_x1_aud_px1",
-       "gpio_x3_aud_px3",
-
-       "gpio_x5_aud_px5",
-       "gpio_x7_aud_px7",
-
-       "pex_l0_rst_n_pdd1",
-       "pex_l0_clkreq_n_pdd2",
-       "pex_wake_n_pdd3",
-       "pex_l1_rst_n_pdd5",
-       "pex_l1_clkreq_n_pdd6",
-       "hdmi_cec_pee3",
-
-       "sdmmc3_cd_n_pv2",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "sdmmc3_clk_lb_out_pee4",
-       "sdmmc3_clk_lb_in_pee5",
-       "gmi_clk_lb",
-
-       "dp_hpd_pff0",
-       "usb_vbus_en2_pff1",
-       "pff2",
-};
-
-static const char * const sdmmc1_groups[] = {
-       "sdmmc1_clk_pz0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat0_py7",
-       "clk2_out_pw5",
-       "clk2_req_pcc",
-       "uart3_cts_n_pa1",
-       "sdmmc1_wp_n_pv3",
-};
-
-static const char * const sdmmc2_groups[] = {
-       "pi5",
-       "pk1",
-       "pk3",
-       "pk4",
-       "pi6",
-       "ph4",
-       "ph5",
-       "ph6",
-       "ph7",
-       "pi2",
-       "cam_mclk_pcc0",
-       "pcc1",
-       "pbb0",
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "pbb7",
-       "pcc2",
-       "gmi_clk_lb",
-};
-
-static const char * const sdmmc3_groups[] = {
-       "pk0",
-       "pcc2",
-
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-
-       "sdmmc3_clk_pa6",
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-
-       "sdmmc3_cd_n_pv2",
-       "sdmmc3_clk_lb_in_pee5",
-       "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc4_groups[] = {
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-};
-
-static const char * const soc_groups[] = {
-       "pk0",
-       "pj2",
-       "kb_row15_ps7",
-       "clk_32k_out_pa0",
-};
-
-static const char * const spdif_groups[] = {
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-};
-
-static const char * const spi1_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "gpio_x3_aud_px3",
-       "gpio_x4_aud_px4",
-       "gpio_x5_aud_px5",
-       "gpio_x6_aud_px6",
-       "gpio_x7_aud_px7",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const spi2_groups[] = {
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "gpio_x4_aud_px4",
-       "gpio_x5_aud_px5",
-       "gpio_x6_aud_px6",
-       "gpio_x7_aud_px7",
-       "gpio_w2_aud_pw2",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const spi3_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-};
-
-static const char * const spi4_groups[] = {
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat0_py7",
-
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-
-       "pi3",
-       "pg4",
-       "pg5",
-       "pg6",
-       "pg7",
-       "ph3",
-       "pi4",
-       "sdmmc1_wp_n_pv3",
-};
-
-static const char * const spi5_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "dap3_fs_pp0",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_sclk_pp3",
-};
-
-static const char * const spi6_groups[] = {
-       "dvfs_pwm_px0",
-       "gpio_x1_aud_px1",
-       "gpio_x3_aud_px3",
-       "dvfs_clk_px2",
-       "gpio_x6_aud_px6",
-       "gpio_w2_aud_pw2",
-       "gpio_w3_aud_pw3",
-};
-
-static const char * const trace_groups[] = {
-       "pi2",
-       "pi4",
-       "pi7",
-       "ph0",
-       "ph6",
-       "ph7",
-       "pg2",
-       "pg3",
-       "pk1",
-       "pk3",
-};
-
-static const char * const uarta_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat3_py4",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat0_py7",
-
-
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-
-       "pu0",
-       "pu1",
-       "pu2",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "kb_row10_ps2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc1_wp_n_pv3",
-
-};
-
-static const char * const uartb_groups[] = {
-       "uart2_rts_n_pj6",
-       "uart2_cts_n_pj5",
-};
-
-static const char * const uartc_groups[] = {
-       "uart3_txd_pw6",
-       "uart3_rxd_pw7",
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-       "kb_row16_pt0",
-       "kn_row17_pt1",
-};
-
-static const char * const uartd_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "pj7",
-       "pb0",
-       "pb1",
-       "pk7",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-};
-
-static const char * const ulpi_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-};
-
-static const char * const usb_groups[] = {
-       "pj0",
-       "usb_vbus_en0_pn4",
-       "usb_vbus_en1_pn5",
-       "usb_vbus_en2_pff1",
-};
-
-static const char * const vgp1_groups[] = {
-       "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
-       "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
-       "pbb3",
-};
-
-static const char * const vgp4_groups[] = {
-       "pbb4",
-};
-
-static const char * const vgp5_groups[] = {
-       "pbb5",
-};
-
-static const char * const vgp6_groups[] = {
-       "pbb0",
-};
-
-static const char * const vi_groups[] = {
-       "cam_mclk_pcc0",
-};
-
-static const char * const vi_alt1_groups[] = {
-       "cam_mclk_pcc0",
-};
-
-static const char * const vi_alt3_groups[] = {
-       "cam_mclk_pcc0",
-};
-
-static const char * const vimclk2_groups[] = {
-       "pbb0",
-};
-
-static const char * const vimclk2_alt_groups[] = {
-       "pbb0",
-};
-
-static const char * const sata_groups[] = {
-       "dap_mclk1_req_pee2",
-       "dap1_dout_pn2",
-       "pff2",
-};
-
-static const char * const ccla_groups[] = {
-       "pk3",
-};
-
-static const char * const rtck_groups[] = {
-       "jtag_rtck",
-};
-
-static const char * const sys_groups[] = {
-       "kb_row3_pr3",
-};
-
-static const char * const pe0_groups[] = {
-       "pex_l0_rst_n_pdd1",
-       "pex_l0_clkreq_n_pdd2",
-};
-
-static const char * const pe_groups[] = {
-       "pex_wake_n_pdd3",
-};
-
-static const char * const pe1_groups[] = {
-       "pex_l1_rst_n_pdd5",
-       "pex_l1_clkreq_n_pdd6",
-};
-
-static const char * const dp_groups[] = {
-       "dp_hpd_pff0",
-};
-
-static const char * const clk_groups[] = {
-       "clk_32k_in",
-};
-
-static const char * const tmds_groups[] = {
-       "pg4",
-       "ph1",
-       "ph2",
 };
 
 #define FUNCTION(fname)                                        \
        {                                               \
                .name = #fname,                         \
-               .groups = fname##_groups,               \
-               .ngroups = ARRAY_SIZE(fname##_groups),  \
        }
 
-static const struct tegra_function tegra124_functions[] = {
+static struct tegra_function tegra124_functions[] = {
        FUNCTION(blink),
+       FUNCTION(ccla),
        FUNCTION(cec),
        FUNCTION(cldvfs),
+       FUNCTION(clk),
        FUNCTION(clk12),
        FUNCTION(cpu),
        FUNCTION(dap),
@@ -2706,6 +1602,7 @@ static const struct tegra_function tegra124_functions[] = {
        FUNCTION(displaya),
        FUNCTION(displaya_alt),
        FUNCTION(displayb),
+       FUNCTION(dp),
        FUNCTION(dtv),
        FUNCTION(extperiph1),
        FUNCTION(extperiph2),
@@ -2727,6 +1624,9 @@ static const struct tegra_function tegra124_functions[] = {
        FUNCTION(irda),
        FUNCTION(kbc),
        FUNCTION(owr),
+       FUNCTION(pe),
+       FUNCTION(pe0),
+       FUNCTION(pe1),
        FUNCTION(pmi),
        FUNCTION(pwm0),
        FUNCTION(pwm1),
@@ -2738,6 +1638,8 @@ static const struct tegra_function tegra124_functions[] = {
        FUNCTION(rsvd2),
        FUNCTION(rsvd3),
        FUNCTION(rsvd4),
+       FUNCTION(rtck),
+       FUNCTION(sata),
        FUNCTION(sdmmc1),
        FUNCTION(sdmmc2),
        FUNCTION(sdmmc3),
@@ -2750,6 +1652,8 @@ static const struct tegra_function tegra124_functions[] = {
        FUNCTION(spi4),
        FUNCTION(spi5),
        FUNCTION(spi6),
+       FUNCTION(sys),
+       FUNCTION(tmds),
        FUNCTION(trace),
        FUNCTION(uarta),
        FUNCTION(uartb),
@@ -2768,23 +1672,13 @@ static const struct tegra_function tegra124_functions[] = {
        FUNCTION(vi_alt3),
        FUNCTION(vimclk2),
        FUNCTION(vimclk2_alt),
-       FUNCTION(sata),
-       FUNCTION(ccla),
-       FUNCTION(pe0),
-       FUNCTION(pe),
-       FUNCTION(pe1),
-       FUNCTION(dp),
-       FUNCTION(rtck),
-       FUNCTION(sys),
-       FUNCTION(clk),
-       FUNCTION(tmds),
 };
 
-#define DRV_PINGROUP_REG_A     0x868   /* bank 0 */
-#define PINGROUP_REG_A         0x3000  /* bank 1 */
+#define DRV_PINGROUP_REG_A             0x868   /* bank 0 */
+#define PINGROUP_REG_A                 0x3000  /* bank 1 */
 
-#define PINGROUP_REG_Y(r)      ((r) - PINGROUP_REG_A)
-#define PINGROUP_REG_N(r)      -1
+#define PINGROUP_REG_Y(r)              ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r)              -1
 
 #define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
        {                                                               \
@@ -2792,12 +1686,12 @@ static const struct tegra_function tegra124_functions[] = {
                .pins = pg_name##_pins,                                 \
                .npins = ARRAY_SIZE(pg_name##_pins),                    \
                .funcs = {                                              \
-                       TEGRA_MUX_ ## f0,                               \
-                       TEGRA_MUX_ ## f1,                               \
-                       TEGRA_MUX_ ## f2,                               \
-                       TEGRA_MUX_ ## f3,                               \
+                       TEGRA_MUX_##f0,                                 \
+                       TEGRA_MUX_##f1,                                 \
+                       TEGRA_MUX_##f2,                                 \
+                       TEGRA_MUX_##f3,                                 \
                },                                                      \
-               .func_safe = TEGRA_MUX_ ## f_safe,                      \
+               .func_safe = TEGRA_MUX_##f_safe,                        \
                .mux_reg = PINGROUP_REG_Y(r),                           \
                .mux_bank = 1,                                          \
                .mux_bit = 0,                                           \
@@ -2826,8 +1720,9 @@ static const struct tegra_function tegra124_functions[] = {
                .drvtype_reg = -1,                                      \
        }
 
-#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_A)
-#define DRV_PINGROUP_DVRTYPE_N(r) -1
+#define DRV_PINGROUP_REG_Y(r)          ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r)          -1
+
 
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b,             \
                     drvdn_b, drvdn_w, drvup_b, drvup_w,                \
@@ -2845,7 +1740,7 @@ static const struct tegra_function tegra124_functions[] = {
                .lock_reg = -1,                                         \
                .ioreset_reg = -1,                                      \
                .rcv_sel_reg = -1,                                      \
-               .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r),                   \
+               .drv_reg = DRV_PINGROUP_REG_Y(r),                       \
                .drv_bank = 0,                                          \
                .hsm_bit = hsm_b,                                       \
                .schmitt_bit = schmitt_b,                               \
@@ -2858,7 +1753,7 @@ static const struct tegra_function tegra124_functions[] = {
                .slwr_width = slwr_w,                                   \
                .slwf_bit = slwf_b,                                     \
                .slwf_width = slwf_w,                                   \
-               .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r),       \
+               .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r),           \
                .drvtype_bank = 0,                                      \
                .drvtype_bit = 6,                                       \
        }
@@ -2909,8 +1804,8 @@ static const struct tegra_pingroup tegra124_groups[] = {
        PINGROUP(pu4,                    PWM1,       UARTA,      GMI,          DISPLAYB,    PWM1,       0x3194,  N,  N,  N),
        PINGROUP(pu5,                    PWM2,       UARTA,      GMI,          DISPLAYB,    PWM2,       0x3198,  N,  N,  N),
        PINGROUP(pu6,                    PWM3,       UARTA,      RSVD3,        GMI,         RSVD3,      0x319c,  N,  N,  N),
-       PINGROUP(gen1_i2c_scl_pc4,       I2C1,       RSVD2,      RSVD3,        RSVD4,       I2C1,       0x31a0,  Y,  N,  N),
-       PINGROUP(gen1_i2c_sda_pc5,       I2C1,       RSVD2,      RSVD3,        RSVD4,       I2C1,       0x31a4,  Y,  N,  N),
+       PINGROUP(gen1_i2c_sda_pc5,       I2C1,       RSVD2,      RSVD3,        RSVD4,       I2C1,       0x31a0,  Y,  N,  N),
+       PINGROUP(gen1_i2c_scl_pc4,       I2C1,       RSVD2,      RSVD3,        RSVD4,       I2C1,       0x31a4,  Y,  N,  N),
        PINGROUP(dap4_fs_pp4,            I2S3,       GMI,        DTV,          RSVD4,       I2S3,       0x31a8,  N,  N,  N),
        PINGROUP(dap4_din_pp5,           I2S3,       GMI,        RSVD3,        RSVD4,       I2S3,       0x31ac,  N,  N,  N),
        PINGROUP(dap4_dout_pp6,          I2S3,       GMI,        DTV,          RSVD4,       I2S3,       0x31b0,  N,  N,  N),
@@ -2964,9 +1859,9 @@ static const struct tegra_pingroup tegra124_groups[] = {
        PINGROUP(sdmmc4_dat4_paa4,       SDMMC4,     SPI3,       GMI,          RSVD4,       SDMMC4,     0x3270,  N,  Y,  N),
        PINGROUP(sdmmc4_dat5_paa5,       SDMMC4,     SPI3,       RSVD3,        RSVD4,       SDMMC4,     0x3274,  N,  Y,  N),
        PINGROUP(sdmmc4_dat6_paa6,       SDMMC4,     SPI3,       GMI,          RSVD4,       SDMMC4,     0x3278,  N,  Y,  N),
-       PINGROUP(sdmmc4_dat7_paa7,       SDMMC4,     RSVD1,      GMI,          RSVD4,       SDMMC4,     0x327c,  N,  Y,  N),
+       PINGROUP(sdmmc4_dat7_paa7,       SDMMC4,     RSVD2,      GMI,          RSVD4,       SDMMC4,     0x327c,  N,  Y,  N),
        PINGROUP(cam_mclk_pcc0,          VI,         VI_ALT1,    VI_ALT3,      SDMMC2,      VI,         0x3284,  N,  N,  N),
-       PINGROUP(pcc1,                   I2S4,       RSVD1,      RSVD3,        SDMMC2,      I2S4,       0x3288,  N,  N,  N),
+       PINGROUP(pcc1,                   I2S4,       RSVD2,      RSVD3,        SDMMC2,      I2S4,       0x3288,  N,  N,  N),
        PINGROUP(pbb0,                   VGP6,       VIMCLK2,    SDMMC2,       VIMCLK2_ALT, VGP6,       0x328c,  N,  N,  N),
        PINGROUP(cam_i2c_scl_pbb1,       VGP1,       I2C3,       RSVD3,        SDMMC2,      VGP1,       0x3290,  Y,  N,  N),
        PINGROUP(cam_i2c_sda_pbb2,       VGP2,       I2C3,       RSVD3,        SDMMC2,      VGP2,       0x3294,  Y,  N,  N),
@@ -3047,8 +1942,8 @@ static const struct tegra_pingroup tegra124_groups[] = {
        PINGROUP(gpio_w3_aud_pw3,        SPI6,       SPI1,       SPI2,         I2C1,        SPI1,       0x33f0,  N,  N,  N),
        PINGROUP(usb_vbus_en0_pn4,       USB,        RSVD2,      RSVD3,        RSVD4,       USB,        0x33f4,  Y,  N,  N),
        PINGROUP(usb_vbus_en1_pn5,       USB,        RSVD2,      RSVD3,        RSVD4,       USB,        0x33f8,  Y,  N,  N),
-       PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3,     RSVD2,      RSVD3,        RSVD4,       SDMMC3,     0x33fc,  N,  N,  N),
-       PINGROUP(sdmmc3_clk_lb_in_pee5,  SDMMC3,     RSVD2,      RSVD3,        RSVD4,       SDMMC3,     0x3400,  N,  N,  N),
+       PINGROUP(sdmmc3_clk_lb_in_pee5,  SDMMC3,     RSVD2,      RSVD3,        RSVD4,       SDMMC3,     0x33fc,  N,  N,  N),
+       PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3,     RSVD2,      RSVD3,        RSVD4,       SDMMC3,     0x3400,  N,  N,  N),
        PINGROUP(gmi_clk_lb,             SDMMC2,     RSVD2,      GMI,          RSVD4,       SDMMC2,     0x3404,  N,  N,  N),
        PINGROUP(reset_out_n,            RSVD1,      RSVD2,      RSVD3,        RESET_OUT_N, RSVD1,      0x3408,  N,  N,  N),
        PINGROUP(kb_row16_pt0,           KBC,        RSVD2,      RSVD3,        UARTC,       KBC,        0x340c,  N,  N,  N),
index fcfb7d012c5b68bda551917f89c657956f2af6dd..e0b5040883873ed06738f5d21858a3cc22a72f77 100644 (file)
@@ -1894,637 +1894,12 @@ enum tegra_mux {
        TEGRA_MUX_XIO,
 };
 
-static const char * const ahb_clk_groups[] = {
-       "cdev2",
-};
-
-static const char * const apb_clk_groups[] = {
-       "cdev2",
-};
-
-static const char * const audio_sync_groups[] = {
-       "cdev1",
-};
-
-static const char * const crt_groups[] = {
-       "crtp",
-       "lm1",
-};
-
-static const char * const dap1_groups[] = {
-       "dap1",
-};
-
-static const char * const dap2_groups[] = {
-       "dap2",
-};
-
-static const char * const dap3_groups[] = {
-       "dap3",
-};
-
-static const char * const dap4_groups[] = {
-       "dap4",
-};
-
-static const char * const dap5_groups[] = {
-       "gme",
-};
-
-static const char * const displaya_groups[] = {
-       "lcsn",
-       "ld0",
-       "ld1",
-       "ld10",
-       "ld11",
-       "ld12",
-       "ld13",
-       "ld14",
-       "ld15",
-       "ld16",
-       "ld17",
-       "ld2",
-       "ld3",
-       "ld4",
-       "ld5",
-       "ld6",
-       "ld7",
-       "ld8",
-       "ld9",
-       "ldc",
-       "ldi",
-       "lhp0",
-       "lhp1",
-       "lhp2",
-       "lhs",
-       "lm0",
-       "lm1",
-       "lpp",
-       "lpw0",
-       "lpw1",
-       "lpw2",
-       "lsc0",
-       "lsc1",
-       "lsck",
-       "lsda",
-       "lsdi",
-       "lspi",
-       "lvp0",
-       "lvp1",
-       "lvs",
-};
-
-static const char * const displayb_groups[] = {
-       "lcsn",
-       "ld0",
-       "ld1",
-       "ld10",
-       "ld11",
-       "ld12",
-       "ld13",
-       "ld14",
-       "ld15",
-       "ld16",
-       "ld17",
-       "ld2",
-       "ld3",
-       "ld4",
-       "ld5",
-       "ld6",
-       "ld7",
-       "ld8",
-       "ld9",
-       "ldc",
-       "ldi",
-       "lhp0",
-       "lhp1",
-       "lhp2",
-       "lhs",
-       "lm0",
-       "lm1",
-       "lpp",
-       "lpw0",
-       "lpw1",
-       "lpw2",
-       "lsc0",
-       "lsc1",
-       "lsck",
-       "lsda",
-       "lsdi",
-       "lspi",
-       "lvp0",
-       "lvp1",
-       "lvs",
-};
-
-static const char * const emc_test0_dll_groups[] = {
-       "kbca",
-};
-
-static const char * const emc_test1_dll_groups[] = {
-       "kbcc",
-};
-
-static const char * const gmi_groups[] = {
-       "ata",
-       "atb",
-       "atc",
-       "atd",
-       "ate",
-       "dap1",
-       "dap2",
-       "dap4",
-       "gma",
-       "gmb",
-       "gmc",
-       "gmd",
-       "gme",
-       "gpu",
-       "irrx",
-       "irtx",
-       "pta",
-       "spia",
-       "spib",
-       "spic",
-       "spid",
-       "spie",
-       "uca",
-       "ucb",
-};
-
-static const char * const gmi_int_groups[] = {
-       "gmb",
-};
-
-static const char * const hdmi_groups[] = {
-       "hdint",
-       "lpw0",
-       "lpw2",
-       "lsc1",
-       "lsck",
-       "lsda",
-       "lspi",
-       "pta",
-};
-
-static const char * const i2cp_groups[] = {
-       "i2cp",
-};
-
-static const char * const i2c1_groups[] = {
-       "rm",
-       "spdi",
-       "spdo",
-       "spig",
-       "spih",
-};
-
-static const char * const i2c2_groups[] = {
-       "ddc",
-       "pta",
-};
-
-static const char * const i2c3_groups[] = {
-       "dtf",
-};
-
-static const char * const ide_groups[] = {
-       "ata",
-       "atb",
-       "atc",
-       "atd",
-       "ate",
-       "gmb",
-};
-
-static const char * const irda_groups[] = {
-       "uad",
-};
-
-static const char * const kbc_groups[] = {
-       "kbca",
-       "kbcb",
-       "kbcc",
-       "kbcd",
-       "kbce",
-       "kbcf",
-};
-
-static const char * const mio_groups[] = {
-       "kbcb",
-       "kbcd",
-       "kbcf",
-};
-
-static const char * const mipi_hs_groups[] = {
-       "uaa",
-       "uab",
-};
-
-static const char * const nand_groups[] = {
-       "ata",
-       "atb",
-       "atc",
-       "atd",
-       "ate",
-       "gmb",
-       "gmd",
-       "kbca",
-       "kbcb",
-       "kbcc",
-       "kbcd",
-       "kbce",
-       "kbcf",
-};
-
-static const char * const osc_groups[] = {
-       "cdev1",
-       "cdev2",
-};
-
-static const char * const owr_groups[] = {
-       "kbce",
-       "owc",
-       "uac",
-};
-
-static const char * const pcie_groups[] = {
-       "gpv",
-       "slxa",
-       "slxk",
-};
-
-static const char * const plla_out_groups[] = {
-       "cdev1",
-};
-
-static const char * const pllc_out1_groups[] = {
-       "csus",
-};
-
-static const char * const pllm_out1_groups[] = {
-       "cdev1",
-};
-
-static const char * const pllp_out2_groups[] = {
-       "csus",
-};
-
-static const char * const pllp_out3_groups[] = {
-       "csus",
-};
-
-static const char * const pllp_out4_groups[] = {
-       "cdev2",
-};
-
-static const char * const pwm_groups[] = {
-       "gpu",
-       "sdb",
-       "sdc",
-       "sdd",
-       "ucb",
-};
-
-static const char * const pwr_intr_groups[] = {
-       "pmc",
-};
-
-static const char * const pwr_on_groups[] = {
-       "pmc",
-};
-
-static const char * const rsvd1_groups[] = {
-       "dta",
-       "dtb",
-       "dtc",
-       "dtd",
-       "dte",
-       "gmd",
-       "gme",
-};
-
-static const char * const rsvd2_groups[] = {
-       "crtp",
-       "dap1",
-       "dap3",
-       "dap4",
-       "ddc",
-       "dtb",
-       "dtc",
-       "dte",
-       "dtf",
-       "gpu7",
-       "gpv",
-       "hdint",
-       "i2cp",
-       "owc",
-       "rm",
-       "sdio1",
-       "spdi",
-       "spdo",
-       "uac",
-       "uca",
-       "uda",
-};
-
-static const char * const rsvd3_groups[] = {
-       "crtp",
-       "dap2",
-       "dap3",
-       "ddc",
-       "gpu7",
-       "gpv",
-       "hdint",
-       "i2cp",
-       "ld17",
-       "ldc",
-       "ldi",
-       "lhp0",
-       "lhp1",
-       "lhp2",
-       "lm1",
-       "lpp",
-       "lpw1",
-       "lvp0",
-       "lvp1",
-       "owc",
-       "pmc",
-       "rm",
-       "uac",
-};
-
-static const char * const rsvd4_groups[] = {
-       "ata",
-       "ate",
-       "crtp",
-       "dap3",
-       "dap4",
-       "ddc",
-       "dta",
-       "dtc",
-       "dtd",
-       "dtf",
-       "gpu",
-       "gpu7",
-       "gpv",
-       "hdint",
-       "i2cp",
-       "kbce",
-       "lcsn",
-       "ld0",
-       "ld1",
-       "ld2",
-       "ld3",
-       "ld4",
-       "ld5",
-       "ld6",
-       "ld7",
-       "ld8",
-       "ld9",
-       "ld10",
-       "ld11",
-       "ld12",
-       "ld13",
-       "ld14",
-       "ld15",
-       "ld16",
-       "ld17",
-       "ldc",
-       "ldi",
-       "lhp0",
-       "lhp1",
-       "lhp2",
-       "lhs",
-       "lm0",
-       "lpp",
-       "lpw1",
-       "lsc0",
-       "lsdi",
-       "lvp0",
-       "lvp1",
-       "lvs",
-       "owc",
-       "pmc",
-       "pta",
-       "rm",
-       "spif",
-       "uac",
-       "uca",
-       "ucb",
-};
-
-static const char * const rtck_groups[] = {
-       "gpu7",
-};
-
-static const char * const sdio1_groups[] = {
-       "sdio1",
-};
-
-static const char * const sdio2_groups[] = {
-       "dap1",
-       "dta",
-       "dtd",
-       "kbca",
-       "kbcb",
-       "kbcd",
-       "spdi",
-       "spdo",
-};
-
-static const char * const sdio3_groups[] = {
-       "sdb",
-       "sdc",
-       "sdd",
-       "slxa",
-       "slxc",
-       "slxd",
-       "slxk",
-};
-
-static const char * const sdio4_groups[] = {
-       "atb",
-       "atc",
-       "atd",
-       "gma",
-       "gme",
-};
-
-static const char * const sflash_groups[] = {
-       "gmc",
-       "gmd",
-};
-
-static const char * const spdif_groups[] = {
-       "slxc",
-       "slxd",
-       "spdi",
-       "spdo",
-       "uad",
-};
-
-static const char * const spi1_groups[] = {
-       "dtb",
-       "dte",
-       "spia",
-       "spib",
-       "spic",
-       "spid",
-       "spie",
-       "spif",
-       "uda",
-};
-
-static const char * const spi2_groups[] = {
-       "sdb",
-       "slxa",
-       "slxc",
-       "slxd",
-       "slxk",
-       "spia",
-       "spib",
-       "spic",
-       "spid",
-       "spie",
-       "spif",
-       "spig",
-       "spih",
-       "uab",
-};
-
-static const char * const spi2_alt_groups[] = {
-       "spid",
-       "spie",
-       "spig",
-       "spih",
-};
-
-static const char * const spi3_groups[] = {
-       "gma",
-       "lcsn",
-       "lm0",
-       "lpw0",
-       "lpw2",
-       "lsc1",
-       "lsck",
-       "lsda",
-       "lsdi",
-       "sdc",
-       "sdd",
-       "spia",
-       "spib",
-       "spic",
-       "spif",
-       "spig",
-       "spih",
-       "uaa",
-};
-
-static const char * const spi4_groups[] = {
-       "gmc",
-       "irrx",
-       "irtx",
-       "slxa",
-       "slxc",
-       "slxd",
-       "slxk",
-       "uad",
-};
-
-static const char * const trace_groups[] = {
-       "kbcc",
-       "kbcf",
-};
-
-static const char * const twc_groups[] = {
-       "dap2",
-       "sdc",
-};
-
-static const char * const uarta_groups[] = {
-       "gpu",
-       "irrx",
-       "irtx",
-       "sdb",
-       "sdd",
-       "sdio1",
-       "uaa",
-       "uab",
-       "uad",
-};
-
-static const char * const uartb_groups[] = {
-       "irrx",
-       "irtx",
-};
-
-static const char * const uartc_groups[] = {
-       "uca",
-       "ucb",
-};
-
-static const char * const uartd_groups[] = {
-       "gmc",
-       "uda",
-};
-
-static const char * const uarte_groups[] = {
-       "gma",
-       "sdio1",
-};
-
-static const char * const ulpi_groups[] = {
-       "uaa",
-       "uab",
-       "uda",
-};
-
-static const char * const vi_groups[] = {
-       "dta",
-       "dtb",
-       "dtc",
-       "dtd",
-       "dte",
-       "dtf",
-};
-
-static const char * const vi_sensor_clk_groups[] = {
-       "csus",
-};
-
-static const char * const xio_groups[] = {
-       "ld0",
-       "ld1",
-       "ld10",
-       "ld11",
-       "ld12",
-       "ld13",
-       "ld14",
-       "ld15",
-       "ld16",
-       "ld2",
-       "ld3",
-       "ld4",
-       "ld5",
-       "ld6",
-       "ld7",
-       "ld8",
-       "ld9",
-       "lhs",
-       "lsc0",
-       "lspi",
-       "lvs",
-};
-
 #define FUNCTION(fname)                                        \
        {                                               \
                .name = #fname,                         \
-               .groups = fname##_groups,               \
-               .ngroups = ARRAY_SIZE(fname##_groups),  \
        }
 
-static const struct tegra_function tegra20_functions[] = {
+static struct tegra_function tegra20_functions[] = {
        FUNCTION(ahb_clk),
        FUNCTION(apb_clk),
        FUNCTION(audio_sync),
@@ -2881,18 +2256,7 @@ static struct platform_driver tegra20_pinctrl_driver = {
        .probe = tegra20_pinctrl_probe,
        .remove = tegra_pinctrl_remove,
 };
-
-static int __init tegra20_pinctrl_init(void)
-{
-       return platform_driver_register(&tegra20_pinctrl_driver);
-}
-arch_initcall(tegra20_pinctrl_init);
-
-static void __exit tegra20_pinctrl_exit(void)
-{
-       platform_driver_unregister(&tegra20_pinctrl_driver);
-}
-module_exit(tegra20_pinctrl_exit);
+module_platform_driver(tegra20_pinctrl_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver");
index 2300deba25bd4b39157a5a8f1e8524f965488bd3..41d24f5c28540953bb18bbb47f44fdf50e910a08 100644 (file)
@@ -25,7 +25,7 @@
  * Most pins affected by the pinmux can also be GPIOs. Define these first.
  * These must match how the GPIO driver names/numbers its pins.
  */
-#define _GPIO(offset)                          (offset)
+#define _GPIO(offset)                  (offset)
 
 #define TEGRA_PIN_CLK_32K_OUT_PA0      _GPIO(0)
 #define TEGRA_PIN_UART3_CTS_N_PA1      _GPIO(1)
 #define TEGRA_PIN_PEE7                 _GPIO(247)
 
 /* All non-GPIO pins follow */
-#define NUM_GPIOS                              (TEGRA_PIN_PEE7 + 1)
-#define _PIN(offset)                           (NUM_GPIOS + (offset))
+#define NUM_GPIOS                      (TEGRA_PIN_PEE7 + 1)
+#define _PIN(offset)                   (NUM_GPIOS + (offset))
 
 /* Non-GPIO pins */
 #define TEGRA_PIN_CLK_32K_IN           _PIN(0)
@@ -2015,1253 +2015,13 @@ enum tegra_mux {
        TEGRA_MUX_VI_ALT2,
        TEGRA_MUX_VI_ALT3,
 };
-static const char * const blink_groups[] = {
-       "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
-       "hdmi_cec_pee3",
-       "owr",
-};
-
-static const char * const clk_12m_out_groups[] = {
-       "pv3",
-};
-
-static const char * const clk_32k_in_groups[] = {
-       "clk_32k_in",
-};
-
-static const char * const core_pwr_req_groups[] = {
-       "core_pwr_req",
-};
-
-static const char * const cpu_pwr_req_groups[] = {
-       "cpu_pwr_req",
-};
-
-static const char * const crt_groups[] = {
-       "crt_hsync_pv6",
-       "crt_vsync_pv7",
-};
-
-static const char * const dap_groups[] = {
-       "clk1_req_pee2",
-       "clk2_req_pcc5",
-};
-
-static const char * const ddr_groups[] = {
-       "vi_d0_pt4",
-       "vi_d1_pd5",
-       "vi_d10_pt2",
-       "vi_d11_pt3",
-       "vi_d2_pl0",
-       "vi_d3_pl1",
-       "vi_d4_pl2",
-       "vi_d5_pl3",
-       "vi_d6_pl4",
-       "vi_d7_pl5",
-       "vi_d8_pl6",
-       "vi_d9_pl7",
-       "vi_hsync_pd7",
-       "vi_vsync_pd6",
-};
-
-static const char * const dev3_groups[] = {
-       "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_fs_pp0",
-       "dap3_sclk_pp3",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "lcd_cs0_n_pn4",
-       "lcd_cs1_n_pw0",
-       "lcd_d0_pe0",
-       "lcd_d1_pe1",
-       "lcd_d10_pf2",
-       "lcd_d11_pf3",
-       "lcd_d12_pf4",
-       "lcd_d13_pf5",
-       "lcd_d14_pf6",
-       "lcd_d15_pf7",
-       "lcd_d16_pm0",
-       "lcd_d17_pm1",
-       "lcd_d18_pm2",
-       "lcd_d19_pm3",
-       "lcd_d2_pe2",
-       "lcd_d20_pm4",
-       "lcd_d21_pm5",
-       "lcd_d22_pm6",
-       "lcd_d23_pm7",
-       "lcd_d3_pe3",
-       "lcd_d4_pe4",
-       "lcd_d5_pe5",
-       "lcd_d6_pe6",
-       "lcd_d7_pe7",
-       "lcd_d8_pf0",
-       "lcd_d9_pf1",
-       "lcd_dc0_pn6",
-       "lcd_dc1_pd2",
-       "lcd_de_pj1",
-       "lcd_hsync_pj3",
-       "lcd_m1_pw1",
-       "lcd_pclk_pb3",
-       "lcd_pwr0_pb2",
-       "lcd_pwr1_pc1",
-       "lcd_pwr2_pc6",
-       "lcd_sck_pz4",
-       "lcd_sdin_pz2",
-       "lcd_sdout_pn5",
-       "lcd_vsync_pj4",
-       "lcd_wr_n_pz3",
-};
-
-static const char * const displayb_groups[] = {
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_fs_pp0",
-       "dap3_sclk_pp3",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "lcd_cs0_n_pn4",
-       "lcd_cs1_n_pw0",
-       "lcd_d0_pe0",
-       "lcd_d1_pe1",
-       "lcd_d10_pf2",
-       "lcd_d11_pf3",
-       "lcd_d12_pf4",
-       "lcd_d13_pf5",
-       "lcd_d14_pf6",
-       "lcd_d15_pf7",
-       "lcd_d16_pm0",
-       "lcd_d17_pm1",
-       "lcd_d18_pm2",
-       "lcd_d19_pm3",
-       "lcd_d2_pe2",
-       "lcd_d20_pm4",
-       "lcd_d21_pm5",
-       "lcd_d22_pm6",
-       "lcd_d23_pm7",
-       "lcd_d3_pe3",
-       "lcd_d4_pe4",
-       "lcd_d5_pe5",
-       "lcd_d6_pe6",
-       "lcd_d7_pe7",
-       "lcd_d8_pf0",
-       "lcd_d9_pf1",
-       "lcd_dc0_pn6",
-       "lcd_dc1_pd2",
-       "lcd_de_pj1",
-       "lcd_hsync_pj3",
-       "lcd_m1_pw1",
-       "lcd_pclk_pb3",
-       "lcd_pwr0_pb2",
-       "lcd_pwr1_pc1",
-       "lcd_pwr2_pc6",
-       "lcd_sck_pz4",
-       "lcd_sdin_pz2",
-       "lcd_sdout_pn5",
-       "lcd_vsync_pj4",
-       "lcd_wr_n_pz3",
-};
-
-static const char * const dtv_groups[] = {
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-};
-
-static const char * const extperiph1_groups[] = {
-       "clk1_out_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
-       "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
-       "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_fs_pn0",
-       "dap1_sclk_pn3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_fs_pp4",
-       "dap4_sclk_pp7",
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "gmi_a16_pj7",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_a19_pk7",
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad10_ph2",
-       "gmi_ad11_ph3",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_ad8_ph0",
-       "gmi_ad9_ph1",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-       "gmi_cs2_n_pk3",
-       "gmi_cs3_n_pk4",
-       "gmi_cs4_n_pk2",
-       "gmi_cs6_n_pi3",
-       "gmi_cs7_n_pi6",
-       "gmi_dqs_pi2",
-       "gmi_iordy_pi5",
-       "gmi_oe_n_pi1",
-       "gmi_rst_n_pi4",
-       "gmi_wait_pi7",
-       "gmi_wp_n_pc7",
-       "gmi_wr_n_pi0",
-       "pu0",
-       "pu1",
-       "pu2",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-       "spi1_cs0_n_px6",
-       "spi1_mosi_px4",
-       "spi1_sck_px5",
-       "spi2_cs0_n_px3",
-       "spi2_miso_px1",
-       "spi2_mosi_px0",
-       "spi2_sck_px2",
-       "uart2_cts_n_pj5",
-       "uart2_rts_n_pj6",
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-       "uart3_rxd_pw7",
-       "uart3_txd_pw6",
-};
-
-static const char * const gmi_alt_groups[] = {
-       "gmi_a16_pj7",
-       "gmi_cs3_n_pk4",
-       "gmi_cs7_n_pi6",
-       "gmi_wp_n_pc7",
-};
-
-static const char * const hda_groups[] = {
-       "clk1_req_pee2",
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_fs_pn0",
-       "dap1_sclk_pn3",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "pex_l0_clkreq_n_pdd2",
-       "pex_l0_prsnt_n_pdd0",
-       "pex_l0_rst_n_pdd1",
-       "pex_l1_clkreq_n_pdd6",
-       "pex_l1_prsnt_n_pdd4",
-       "pex_l1_rst_n_pdd5",
-       "pex_l2_clkreq_n_pcc7",
-       "pex_l2_prsnt_n_pdd7",
-       "pex_l2_rst_n_pcc6",
-       "pex_wake_n_pdd3",
-       "spdif_in_pk6",
-};
-
-static const char * const hdcp_groups[] = {
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "lcd_pwr0_pb2",
-       "lcd_pwr2_pc6",
-       "lcd_sck_pz4",
-       "lcd_sdout_pn5",
-       "lcd_wr_n_pz3",
-};
-
-static const char * const hdmi_groups[] = {
-       "hdmi_int_pn7",
-};
-
-static const char * const hsi_groups[] = {
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "spi2_cs1_n_pw2",
-       "spi2_cs2_n_pw3",
-};
-
-static const char * const i2c2_groups[] = {
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat4_paa4",
-};
-
-static const char * const i2c4_groups[] = {
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_fs_pn0",
-       "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-};
-
-static const char * const i2s2_groups[] = {
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_fs_pp0",
-       "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_fs_pp4",
-       "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
-       "pbb0",
-       "pbb7",
-       "pcc1",
-       "pcc2",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-};
-
-static const char * const invalid_groups[] = {
-       "kb_row3_pr3",
-       "sdmmc4_clk_pcc4",
-};
-
-static const char * const kbc_groups[] = {
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-       "kb_row2_pr2",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-};
-
-static const char * const mio_groups[] = {
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-       "kb_row6_pr6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-};
-
-static const char * const nand_groups[] = {
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad10_ph2",
-       "gmi_ad11_ph3",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_ad8_ph0",
-       "gmi_ad9_ph1",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-       "gmi_cs2_n_pk3",
-       "gmi_cs3_n_pk4",
-       "gmi_cs4_n_pk2",
-       "gmi_cs6_n_pi3",
-       "gmi_cs7_n_pi6",
-       "gmi_dqs_pi2",
-       "gmi_iordy_pi5",
-       "gmi_oe_n_pi1",
-       "gmi_rst_n_pi4",
-       "gmi_wait_pi7",
-       "gmi_wp_n_pc7",
-       "gmi_wr_n_pi0",
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-       "kb_row2_pr2",
-       "kb_row3_pr3",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-       "kb_row6_pr6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-};
-
-static const char * const nand_alt_groups[] = {
-       "gmi_cs6_n_pi3",
-       "gmi_cs7_n_pi6",
-       "gmi_rst_n_pi4",
-};
-
-static const char * const owr_groups[] = {
-       "pu0",
-       "pv2",
-       "kb_row5_pr5",
-       "owr",
-};
-
-static const char * const pcie_groups[] = {
-       "pex_l0_clkreq_n_pdd2",
-       "pex_l0_prsnt_n_pdd0",
-       "pex_l0_rst_n_pdd1",
-       "pex_l1_clkreq_n_pdd6",
-       "pex_l1_prsnt_n_pdd4",
-       "pex_l1_rst_n_pdd5",
-       "pex_l2_clkreq_n_pcc7",
-       "pex_l2_prsnt_n_pdd7",
-       "pex_l2_rst_n_pcc6",
-       "pex_wake_n_pdd3",
-};
-
-static const char * const pwm0_groups[] = {
-       "gmi_ad8_ph0",
-       "pu3",
-       "sdmmc3_dat3_pb4",
-       "sdmmc3_dat5_pd0",
-       "uart3_rts_n_pc0",
-};
-
-static const char * const pwm1_groups[] = {
-       "gmi_ad9_ph1",
-       "pu4",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat4_pd1",
-};
-
-static const char * const pwm2_groups[] = {
-       "gmi_ad10_ph2",
-       "pu5",
-       "sdmmc3_clk_pa6",
-};
-
-static const char * const pwm3_groups[] = {
-       "gmi_ad11_ph3",
-       "pu6",
-       "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwr_int_n_groups[] = {
-       "pwr_int_n",
-};
-
-static const char * const rsvd1_groups[] = {
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs0_n_pj0",
-       "gmi_cs1_n_pj2",
-       "gmi_cs2_n_pk3",
-       "gmi_cs3_n_pk4",
-       "gmi_cs4_n_pk2",
-       "gmi_dqs_pi2",
-       "gmi_iordy_pi5",
-       "gmi_oe_n_pi1",
-       "gmi_wait_pi7",
-       "gmi_wp_n_pc7",
-       "gmi_wr_n_pi0",
-       "pu1",
-       "pu2",
-       "pv0",
-       "pv1",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-       "vi_pclk_pt0",
-};
-
-static const char * const rsvd2_groups[] = {
-       "clk1_out_pw4",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-       "clk_32k_in",
-       "clk_32k_out_pa0",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "crt_hsync_pv6",
-       "crt_vsync_pv7",
-       "dap3_din_pp1",
-       "dap3_dout_pp2",
-       "dap3_fs_pp0",
-       "dap3_sclk_pp3",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_fs_pp4",
-       "dap4_sclk_pp7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "pbb0",
-       "pbb7",
-       "pcc1",
-       "pcc2",
-       "pv0",
-       "pv1",
-       "pv2",
-       "pv3",
-       "hdmi_cec_pee3",
-       "hdmi_int_pn7",
-       "jtag_rtck_pu7",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-       "pwr_int_n",
-       "sdmmc1_clk_pz0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat0_py7",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat3_py4",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc4_rst_n_pcc3",
-       "spdif_out_pk5",
-       "sys_clk_req_pz5",
-       "uart3_cts_n_pa1",
-       "uart3_rxd_pw7",
-       "uart3_txd_pw6",
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-       "vi_d0_pt4",
-       "vi_d10_pt2",
-       "vi_d11_pt3",
-       "vi_hsync_pd7",
-       "vi_vsync_pd6",
-};
-
-static const char * const rsvd3_groups[] = {
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "clk1_out_pw4",
-       "clk1_req_pee2",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-       "clk_32k_in",
-       "clk_32k_out_pa0",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "crt_hsync_pv6",
-       "crt_vsync_pv7",
-       "dap2_din_pa4",
-       "dap2_dout_pa5",
-       "dap2_fs_pa2",
-       "dap2_sclk_pa3",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "pbb0",
-       "pbb7",
-       "pcc1",
-       "pcc2",
-       "pv0",
-       "pv1",
-       "pv2",
-       "pv3",
-       "hdmi_cec_pee3",
-       "hdmi_int_pn7",
-       "jtag_rtck_pu7",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row3_pr3",
-       "lcd_d0_pe0",
-       "lcd_d1_pe1",
-       "lcd_d10_pf2",
-       "lcd_d11_pf3",
-       "lcd_d12_pf4",
-       "lcd_d13_pf5",
-       "lcd_d14_pf6",
-       "lcd_d15_pf7",
-       "lcd_d16_pm0",
-       "lcd_d17_pm1",
-       "lcd_d18_pm2",
-       "lcd_d19_pm3",
-       "lcd_d2_pe2",
-       "lcd_d20_pm4",
-       "lcd_d21_pm5",
-       "lcd_d22_pm6",
-       "lcd_d23_pm7",
-       "lcd_d3_pe3",
-       "lcd_d4_pe4",
-       "lcd_d5_pe5",
-       "lcd_d6_pe6",
-       "lcd_d7_pe7",
-       "lcd_d8_pf0",
-       "lcd_d9_pf1",
-       "lcd_dc0_pn6",
-       "lcd_dc1_pd2",
-       "lcd_de_pj1",
-       "lcd_hsync_pj3",
-       "lcd_m1_pw1",
-       "lcd_pclk_pb3",
-       "lcd_pwr1_pc1",
-       "lcd_vsync_pj4",
-       "owr",
-       "pex_l0_clkreq_n_pdd2",
-       "pex_l0_prsnt_n_pdd0",
-       "pex_l0_rst_n_pdd1",
-       "pex_l1_clkreq_n_pdd6",
-       "pex_l1_prsnt_n_pdd4",
-       "pex_l1_rst_n_pdd5",
-       "pex_l2_clkreq_n_pcc7",
-       "pex_l2_prsnt_n_pdd7",
-       "pex_l2_rst_n_pcc6",
-       "pex_wake_n_pdd3",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-       "pwr_int_n",
-       "sdmmc1_clk_pz0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc4_rst_n_pcc3",
-       "sys_clk_req_pz5",
-};
-
-static const char * const rsvd4_groups[] = {
-       "clk1_out_pw4",
-       "clk1_req_pee2",
-       "clk2_out_pw5",
-       "clk2_req_pcc5",
-       "clk3_out_pee0",
-       "clk3_req_pee1",
-       "clk_32k_in",
-       "clk_32k_out_pa0",
-       "core_pwr_req",
-       "cpu_pwr_req",
-       "crt_hsync_pv6",
-       "crt_vsync_pv7",
-       "dap4_din_pp5",
-       "dap4_dout_pp6",
-       "dap4_fs_pp4",
-       "dap4_sclk_pp7",
-       "ddc_scl_pv4",
-       "ddc_sda_pv5",
-       "gen1_i2c_scl_pc4",
-       "gen1_i2c_sda_pc5",
-       "gen2_i2c_scl_pt5",
-       "gen2_i2c_sda_pt6",
-       "gmi_a19_pk7",
-       "gmi_ad0_pg0",
-       "gmi_ad1_pg1",
-       "gmi_ad10_ph2",
-       "gmi_ad11_ph3",
-       "gmi_ad12_ph4",
-       "gmi_ad13_ph5",
-       "gmi_ad14_ph6",
-       "gmi_ad15_ph7",
-       "gmi_ad2_pg2",
-       "gmi_ad3_pg3",
-       "gmi_ad4_pg4",
-       "gmi_ad5_pg5",
-       "gmi_ad6_pg6",
-       "gmi_ad7_pg7",
-       "gmi_ad8_ph0",
-       "gmi_ad9_ph1",
-       "gmi_adv_n_pk0",
-       "gmi_clk_pk1",
-       "gmi_cs2_n_pk3",
-       "gmi_cs4_n_pk2",
-       "gmi_dqs_pi2",
-       "gmi_iordy_pi5",
-       "gmi_oe_n_pi1",
-       "gmi_rst_n_pi4",
-       "gmi_wait_pi7",
-       "gmi_wr_n_pi0",
-       "pcc2",
-       "pu0",
-       "pu1",
-       "pu2",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-       "pv0",
-       "pv1",
-       "pv2",
-       "pv3",
-       "hdmi_cec_pee3",
-       "hdmi_int_pn7",
-       "jtag_rtck_pu7",
-       "kb_col2_pq2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-       "kb_row0_pr0",
-       "kb_row1_pr1",
-       "kb_row2_pr2",
-       "kb_row4_pr4",
-       "lcd_cs0_n_pn4",
-       "lcd_cs1_n_pw0",
-       "lcd_d0_pe0",
-       "lcd_d1_pe1",
-       "lcd_d10_pf2",
-       "lcd_d11_pf3",
-       "lcd_d12_pf4",
-       "lcd_d13_pf5",
-       "lcd_d14_pf6",
-       "lcd_d15_pf7",
-       "lcd_d16_pm0",
-       "lcd_d17_pm1",
-       "lcd_d18_pm2",
-       "lcd_d19_pm3",
-       "lcd_d2_pe2",
-       "lcd_d20_pm4",
-       "lcd_d21_pm5",
-       "lcd_d22_pm6",
-       "lcd_d23_pm7",
-       "lcd_d3_pe3",
-       "lcd_d4_pe4",
-       "lcd_d5_pe5",
-       "lcd_d6_pe6",
-       "lcd_d7_pe7",
-       "lcd_d8_pf0",
-       "lcd_d9_pf1",
-       "lcd_dc0_pn6",
-       "lcd_dc1_pd2",
-       "lcd_de_pj1",
-       "lcd_hsync_pj3",
-       "lcd_m1_pw1",
-       "lcd_pclk_pb3",
-       "lcd_pwr1_pc1",
-       "lcd_sdin_pz2",
-       "lcd_vsync_pj4",
-       "owr",
-       "pex_l0_clkreq_n_pdd2",
-       "pex_l0_prsnt_n_pdd0",
-       "pex_l0_rst_n_pdd1",
-       "pex_l1_clkreq_n_pdd6",
-       "pex_l1_prsnt_n_pdd4",
-       "pex_l1_rst_n_pdd5",
-       "pex_l2_clkreq_n_pcc7",
-       "pex_l2_prsnt_n_pdd7",
-       "pex_l2_rst_n_pcc6",
-       "pex_wake_n_pdd3",
-       "pwr_i2c_scl_pz6",
-       "pwr_i2c_sda_pz7",
-       "pwr_int_n",
-       "spi1_miso_px7",
-       "sys_clk_req_pz5",
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-       "uart3_rxd_pw7",
-       "uart3_txd_pw6",
-       "vi_d0_pt4",
-       "vi_d1_pd5",
-       "vi_d10_pt2",
-       "vi_d11_pt3",
-       "vi_d2_pl0",
-       "vi_d3_pl1",
-       "vi_d4_pl2",
-       "vi_d5_pl3",
-       "vi_d6_pl4",
-       "vi_d7_pl5",
-       "vi_d8_pl6",
-       "vi_d9_pl7",
-       "vi_hsync_pd7",
-       "vi_pclk_pt0",
-       "vi_vsync_pd6",
-};
-
-static const char * const rtck_groups[] = {
-       "jtag_rtck_pu7",
-};
-
-static const char * const sata_groups[] = {
-       "gmi_cs6_n_pi3",
-};
-
-static const char * const sdmmc1_groups[] = {
-       "sdmmc1_clk_pz0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat0_py7",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat3_py4",
-};
-
-static const char * const sdmmc2_groups[] = {
-       "dap1_din_pn1",
-       "dap1_dout_pn2",
-       "dap1_fs_pn0",
-       "dap1_sclk_pn3",
-       "kb_row10_ps2",
-       "kb_row11_ps3",
-       "kb_row12_ps4",
-       "kb_row13_ps5",
-       "kb_row14_ps6",
-       "kb_row15_ps7",
-       "kb_row6_pr6",
-       "kb_row7_pr7",
-       "kb_row8_ps0",
-       "kb_row9_ps1",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "vi_d1_pd5",
-       "vi_d2_pl0",
-       "vi_d3_pl1",
-       "vi_d4_pl2",
-       "vi_d5_pl3",
-       "vi_d6_pl4",
-       "vi_d7_pl5",
-       "vi_d8_pl6",
-       "vi_d9_pl7",
-       "vi_pclk_pt0",
-};
-
-static const char * const sdmmc3_groups[] = {
-       "sdmmc3_clk_pa6",
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-       "sdmmc3_dat4_pd1",
-       "sdmmc3_dat5_pd0",
-       "sdmmc3_dat6_pd3",
-       "sdmmc3_dat7_pd4",
-};
-
-static const char * const sdmmc4_groups[] = {
-       "cam_i2c_scl_pbb1",
-       "cam_i2c_sda_pbb2",
-       "cam_mclk_pcc0",
-       "pbb0",
-       "pbb3",
-       "pbb4",
-       "pbb5",
-       "pbb6",
-       "pbb7",
-       "pcc1",
-       "sdmmc4_clk_pcc4",
-       "sdmmc4_cmd_pt7",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "sdmmc4_dat4_paa4",
-       "sdmmc4_dat5_paa5",
-       "sdmmc4_dat6_paa6",
-       "sdmmc4_dat7_paa7",
-       "sdmmc4_rst_n_pcc3",
-};
-
-static const char * const spdif_groups[] = {
-       "sdmmc3_dat6_pd3",
-       "sdmmc3_dat7_pd4",
-       "spdif_in_pk6",
-       "spdif_out_pk5",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-};
-
-static const char * const spi1_groups[] = {
-       "spi1_cs0_n_px6",
-       "spi1_miso_px7",
-       "spi1_mosi_px4",
-       "spi1_sck_px5",
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-};
-
-static const char * const spi2_groups[] = {
-       "sdmmc3_cmd_pa7",
-       "sdmmc3_dat4_pd1",
-       "sdmmc3_dat5_pd0",
-       "sdmmc3_dat6_pd3",
-       "sdmmc3_dat7_pd4",
-       "spi1_cs0_n_px6",
-       "spi1_mosi_px4",
-       "spi1_sck_px5",
-       "spi2_cs0_n_px3",
-       "spi2_cs1_n_pw2",
-       "spi2_cs2_n_pw3",
-       "spi2_miso_px1",
-       "spi2_mosi_px0",
-       "spi2_sck_px2",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-};
-
-static const char * const spi2_alt_groups[] = {
-       "spi1_cs0_n_px6",
-       "spi1_miso_px7",
-       "spi1_mosi_px4",
-       "spi1_sck_px5",
-       "spi2_cs1_n_pw2",
-       "spi2_cs2_n_pw3",
-};
-
-static const char * const spi3_groups[] = {
-       "sdmmc3_clk_pa6",
-       "sdmmc3_dat0_pb7",
-       "sdmmc3_dat1_pb6",
-       "sdmmc3_dat2_pb5",
-       "sdmmc3_dat3_pb4",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-       "spi1_miso_px7",
-       "spi2_cs0_n_px3",
-       "spi2_cs1_n_pw2",
-       "spi2_cs2_n_pw3",
-       "spi2_miso_px1",
-       "spi2_mosi_px0",
-       "spi2_sck_px2",
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-};
-
-static const char * const spi4_groups[] = {
-       "gmi_a16_pj7",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_a19_pk7",
-       "sdmmc3_dat4_pd1",
-       "sdmmc3_dat5_pd0",
-       "sdmmc3_dat6_pd3",
-       "sdmmc3_dat7_pd4",
-       "uart2_cts_n_pj5",
-       "uart2_rts_n_pj6",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-};
-
-static const char * const spi5_groups[] = {
-       "lcd_cs0_n_pn4",
-       "lcd_cs1_n_pw0",
-       "lcd_pwr0_pb2",
-       "lcd_pwr2_pc6",
-       "lcd_sck_pz4",
-       "lcd_sdin_pz2",
-       "lcd_sdout_pn5",
-       "lcd_wr_n_pz3",
-};
-
-static const char * const spi6_groups[] = {
-       "spi2_cs0_n_px3",
-       "spi2_miso_px1",
-       "spi2_mosi_px0",
-       "spi2_sck_px2",
-};
-
-static const char * const sysclk_groups[] = {
-       "sys_clk_req_pz5",
-};
-
-static const char * const test_groups[] = {
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-};
-
-static const char * const trace_groups[] = {
-       "kb_col0_pq0",
-       "kb_col1_pq1",
-       "kb_col2_pq2",
-       "kb_col3_pq3",
-       "kb_col4_pq4",
-       "kb_col5_pq5",
-       "kb_col6_pq6",
-       "kb_col7_pq7",
-       "kb_row4_pr4",
-       "kb_row5_pr5",
-};
-
-static const char * const uarta_groups[] = {
-       "pu0",
-       "pu1",
-       "pu2",
-       "pu3",
-       "pu4",
-       "pu5",
-       "pu6",
-       "sdmmc1_clk_pz0",
-       "sdmmc1_cmd_pz1",
-       "sdmmc1_dat0_py7",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat3_py4",
-       "sdmmc3_clk_pa6",
-       "sdmmc3_cmd_pa7",
-       "uart2_cts_n_pj5",
-       "uart2_rts_n_pj6",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-};
-
-static const char * const uartb_groups[] = {
-       "uart2_cts_n_pj5",
-       "uart2_rts_n_pj6",
-       "uart2_rxd_pc3",
-       "uart2_txd_pc2",
-};
-
-static const char * const uartc_groups[] = {
-       "uart3_cts_n_pa1",
-       "uart3_rts_n_pc0",
-       "uart3_rxd_pw7",
-       "uart3_txd_pw6",
-};
-
-static const char * const uartd_groups[] = {
-       "gmi_a16_pj7",
-       "gmi_a17_pb0",
-       "gmi_a18_pb1",
-       "gmi_a19_pk7",
-       "ulpi_clk_py0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-};
-
-static const char * const uarte_groups[] = {
-       "sdmmc1_dat0_py7",
-       "sdmmc1_dat1_py6",
-       "sdmmc1_dat2_py5",
-       "sdmmc1_dat3_py4",
-       "sdmmc4_dat0_paa0",
-       "sdmmc4_dat1_paa1",
-       "sdmmc4_dat2_paa2",
-       "sdmmc4_dat3_paa3",
-};
-
-static const char * const ulpi_groups[] = {
-       "ulpi_clk_py0",
-       "ulpi_data0_po1",
-       "ulpi_data1_po2",
-       "ulpi_data2_po3",
-       "ulpi_data3_po4",
-       "ulpi_data4_po5",
-       "ulpi_data5_po6",
-       "ulpi_data6_po7",
-       "ulpi_data7_po0",
-       "ulpi_dir_py1",
-       "ulpi_nxt_py2",
-       "ulpi_stp_py3",
-};
-
-static const char * const vgp1_groups[] = {
-       "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
-       "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
-       "pbb3",
-       "sdmmc4_dat5_paa5",
-};
-
-static const char * const vgp4_groups[] = {
-       "pbb4",
-       "sdmmc4_dat6_paa6",
-};
-
-static const char * const vgp5_groups[] = {
-       "pbb5",
-       "sdmmc4_dat7_paa7",
-};
-
-static const char * const vgp6_groups[] = {
-       "pbb6",
-       "sdmmc4_rst_n_pcc3",
-};
-
-static const char * const vi_groups[] = {
-       "cam_mclk_pcc0",
-       "vi_d0_pt4",
-       "vi_d1_pd5",
-       "vi_d10_pt2",
-       "vi_d11_pt3",
-       "vi_d2_pl0",
-       "vi_d3_pl1",
-       "vi_d4_pl2",
-       "vi_d5_pl3",
-       "vi_d6_pl4",
-       "vi_d7_pl5",
-       "vi_d8_pl6",
-       "vi_d9_pl7",
-       "vi_hsync_pd7",
-       "vi_mclk_pt1",
-       "vi_pclk_pt0",
-       "vi_vsync_pd6",
-};
-
-static const char * const vi_alt1_groups[] = {
-       "cam_mclk_pcc0",
-       "vi_mclk_pt1",
-};
-
-static const char * const vi_alt2_groups[] = {
-       "vi_mclk_pt1",
-};
-
-static const char * const vi_alt3_groups[] = {
-       "cam_mclk_pcc0",
-       "vi_mclk_pt1",
-};
 
 #define FUNCTION(fname)                                        \
        {                                               \
                .name = #fname,                         \
-               .groups = fname##_groups,               \
-               .ngroups = ARRAY_SIZE(fname##_groups),  \
        }
 
-static const struct tegra_function tegra30_functions[] = {
+static struct tegra_function tegra30_functions[] = {
        FUNCTION(blink),
        FUNCTION(cec),
        FUNCTION(clk_12m_out),
@@ -3345,11 +2105,11 @@ static const struct tegra_function tegra30_functions[] = {
        FUNCTION(vi_alt3),
 };
 
-#define DRV_PINGROUP_REG_A     0x868   /* bank 0 */
-#define PINGROUP_REG_A         0x3000  /* bank 1 */
+#define DRV_PINGROUP_REG_A             0x868   /* bank 0 */
+#define PINGROUP_REG_A                 0x3000  /* bank 1 */
 
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r)              ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r)              -1
 
 #define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior)  \
        {                                                       \
@@ -3357,12 +2117,12 @@ static const struct tegra_function tegra30_functions[] = {
                .pins = pg_name##_pins,                         \
                .npins = ARRAY_SIZE(pg_name##_pins),            \
                .funcs = {                                      \
-                       TEGRA_MUX_ ## f0,                       \
-                       TEGRA_MUX_ ## f1,                       \
-                       TEGRA_MUX_ ## f2,                       \
-                       TEGRA_MUX_ ## f3,                       \
+                       TEGRA_MUX_##f0,                         \
+                       TEGRA_MUX_##f1,                         \
+                       TEGRA_MUX_##f2,                         \
+                       TEGRA_MUX_##f3,                         \
                },                                              \
-               .func_safe = TEGRA_MUX_ ## f_safe,              \
+               .func_safe = TEGRA_MUX_##f_safe,                \
                .mux_reg = PINGROUP_REG_Y(r),                   \
                .mux_bank = 1,                                  \
                .mux_bit = 0,                                   \
@@ -3389,6 +2149,9 @@ static const struct tegra_function tegra30_functions[] = {
                .drvtype_reg = -1,                              \
        }
 
+#define DRV_PINGROUP_REG_Y(r)          ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r)          -1
+
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b,     \
                     drvdn_b, drvdn_w, drvup_b, drvup_w,        \
                     slwr_b, slwr_w, slwf_b, slwf_w)            \
@@ -3404,7 +2167,7 @@ static const struct tegra_function tegra30_functions[] = {
                .lock_reg = -1,                                 \
                .ioreset_reg = -1,                              \
                .rcv_sel_reg = -1,                              \
-               .drv_reg = ((r) - DRV_PINGROUP_REG_A),          \
+               .drv_reg = DRV_PINGROUP_REG_Y(r),               \
                .drv_bank = 0,                                  \
                .hsm_bit = hsm_b,                               \
                .schmitt_bit = schmitt_b,                       \
@@ -3422,7 +2185,6 @@ static const struct tegra_function tegra30_functions[] = {
 
 static const struct tegra_pingroup tegra30_groups[] = {
        /*       pg_name,              f0,           f1,           f2,           f3,           safe,         r,      od, ior */
-       /* FIXME: Fill in correct data in safe column */
        PINGROUP(clk_32k_out_pa0,      BLINK,        RSVD2,        RSVD3,        RSVD4,        RSVD4,        0x331c, N, N),
        PINGROUP(uart3_cts_n_pa1,      UARTC,        RSVD2,        GMI,          RSVD4,        RSVD4,        0x317c, N, N),
        PINGROUP(dap2_fs_pa2,          I2S1,         HDA,          RSVD3,        GMI,          RSVD3,        0x3358, N, N),
@@ -3735,6 +2497,7 @@ static struct of_device_id tegra30_pinctrl_of_match[] = {
        { .compatible = "nvidia,tegra30-pinmux", },
        { },
 };
+MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
 
 static struct platform_driver tegra30_pinctrl_driver = {
        .driver = {
@@ -3745,20 +2508,8 @@ static struct platform_driver tegra30_pinctrl_driver = {
        .probe = tegra30_pinctrl_probe,
        .remove = tegra_pinctrl_remove,
 };
-
-static int __init tegra30_pinctrl_init(void)
-{
-       return platform_driver_register(&tegra30_pinctrl_driver);
-}
-arch_initcall(tegra30_pinctrl_init);
-
-static void __exit tegra30_pinctrl_exit(void)
-{
-       platform_driver_unregister(&tegra30_pinctrl_driver);
-}
-module_exit(tegra30_pinctrl_exit);
+module_platform_driver(tegra30_pinctrl_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver");
 MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
index c381ae63c5083a51b190d5a9161ffbe3099a9173..48093719167abd91e27f93eb869eab3f1edd5c51 100644 (file)
@@ -2260,6 +2260,42 @@ static const unsigned int msiof0_tx_pins[] = {
 static const unsigned int msiof0_tx_mux[] = {
        MSIOF0_TXD_MARK,
 };
+
+static const unsigned int msiof0_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof0_clk_b_mux[] = {
+       MSIOF0_SCK_B_MARK,
+};
+static const unsigned int msiof0_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(1, 12),
+};
+static const unsigned int msiof0_ss1_b_mux[] = {
+       MSIOF0_SS1_B_MARK,
+};
+static const unsigned int msiof0_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof0_ss2_b_mux[] = {
+       MSIOF0_SS2_B_MARK,
+};
+static const unsigned int msiof0_rx_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(1, 29),
+};
+static const unsigned int msiof0_rx_b_mux[] = {
+       MSIOF0_RXD_B_MARK,
+};
+static const unsigned int msiof0_tx_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(1, 28),
+};
+static const unsigned int msiof0_tx_b_mux[] = {
+       MSIOF0_TXD_B_MARK,
+};
 /* - MSIOF1 ----------------------------------------------------------------- */
 static const unsigned int msiof1_clk_pins[] = {
        /* SCK */
@@ -2303,6 +2339,42 @@ static const unsigned int msiof1_tx_pins[] = {
 static const unsigned int msiof1_tx_mux[] = {
        MSIOF1_TXD_MARK,
 };
+
+static const unsigned int msiof1_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 16),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+       MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+       MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(0, 19),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+       MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(1, 17),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+       MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 20),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+       MSIOF1_TXD_B_MARK,
+};
 /* - MSIOF2 ----------------------------------------------------------------- */
 static const unsigned int msiof2_clk_pins[] = {
        /* SCK */
@@ -2389,6 +2461,58 @@ static const unsigned int msiof3_tx_pins[] = {
 static const unsigned int msiof3_tx_mux[] = {
        MSIOF3_TXD_MARK,
 };
+
+static const unsigned int msiof3_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof3_clk_b_mux[] = {
+       MSIOF3_SCK_B_MARK,
+};
+static const unsigned int msiof3_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_sync_b_mux[] = {
+       MSIOF3_SYNC_B_MARK,
+};
+static const unsigned int msiof3_rx_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_rx_b_mux[] = {
+       MSIOF3_RXD_B_MARK,
+};
+static const unsigned int msiof3_tx_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_tx_b_mux[] = {
+       MSIOF3_TXD_B_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+       /* SPCLK, SSL */
+       RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+       SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+       /* MOSI_IO0, MISO_IO1 */
+       RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+       MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+       /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+       RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+       RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+       MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
 /* - SCIF0 ------------------------------------------------------------------ */
 static const unsigned int scif0_data_pins[] = {
        /* RX, TX */
@@ -3231,6 +3355,13 @@ static const unsigned int usb0_pins[] = {
 static const unsigned int usb0_mux[] = {
        USB0_PWEN_MARK, USB0_OVC_VBUS_MARK,
 };
+static const unsigned int usb0_ovc_vbus_pins[] = {
+       /* OVC/VBUS */
+       RCAR_GP_PIN(5, 19),
+};
+static const unsigned int usb0_ovc_vbus_mux[] = {
+       USB0_OVC_VBUS_MARK,
+};
 /* - USB1 ------------------------------------------------------------------- */
 static const unsigned int usb1_pins[] = {
        /* PWEN, OVC */
@@ -3653,12 +3784,22 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(msiof0_ss2),
        SH_PFC_PIN_GROUP(msiof0_rx),
        SH_PFC_PIN_GROUP(msiof0_tx),
+       SH_PFC_PIN_GROUP(msiof0_clk_b),
+       SH_PFC_PIN_GROUP(msiof0_ss1_b),
+       SH_PFC_PIN_GROUP(msiof0_ss2_b),
+       SH_PFC_PIN_GROUP(msiof0_rx_b),
+       SH_PFC_PIN_GROUP(msiof0_tx_b),
        SH_PFC_PIN_GROUP(msiof1_clk),
        SH_PFC_PIN_GROUP(msiof1_sync),
        SH_PFC_PIN_GROUP(msiof1_ss1),
        SH_PFC_PIN_GROUP(msiof1_ss2),
        SH_PFC_PIN_GROUP(msiof1_rx),
        SH_PFC_PIN_GROUP(msiof1_tx),
+       SH_PFC_PIN_GROUP(msiof1_clk_b),
+       SH_PFC_PIN_GROUP(msiof1_ss1_b),
+       SH_PFC_PIN_GROUP(msiof1_ss2_b),
+       SH_PFC_PIN_GROUP(msiof1_rx_b),
+       SH_PFC_PIN_GROUP(msiof1_tx_b),
        SH_PFC_PIN_GROUP(msiof2_clk),
        SH_PFC_PIN_GROUP(msiof2_sync),
        SH_PFC_PIN_GROUP(msiof2_ss1),
@@ -3671,6 +3812,13 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(msiof3_ss2),
        SH_PFC_PIN_GROUP(msiof3_rx),
        SH_PFC_PIN_GROUP(msiof3_tx),
+       SH_PFC_PIN_GROUP(msiof3_clk_b),
+       SH_PFC_PIN_GROUP(msiof3_sync_b),
+       SH_PFC_PIN_GROUP(msiof3_rx_b),
+       SH_PFC_PIN_GROUP(msiof3_tx_b),
+       SH_PFC_PIN_GROUP(qspi_ctrl),
+       SH_PFC_PIN_GROUP(qspi_data2),
+       SH_PFC_PIN_GROUP(qspi_data4),
        SH_PFC_PIN_GROUP(scif0_data),
        SH_PFC_PIN_GROUP(scif0_clk),
        SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -3789,6 +3937,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(tpu0_to2),
        SH_PFC_PIN_GROUP(tpu0_to3),
        SH_PFC_PIN_GROUP(usb0),
+       SH_PFC_PIN_GROUP(usb0_ovc_vbus),
        SH_PFC_PIN_GROUP(usb1),
        SH_PFC_PIN_GROUP(usb2),
        VIN_DATA_PIN_GROUP(vin0_data, 24),
@@ -3941,6 +4090,11 @@ static const char * const msiof0_groups[] = {
        "msiof0_ss2",
        "msiof0_rx",
        "msiof0_tx",
+       "msiof0_clk_b",
+       "msiof0_ss1_b",
+       "msiof0_ss2_b",
+       "msiof0_rx_b",
+       "msiof0_tx_b",
 };
 
 static const char * const msiof1_groups[] = {
@@ -3950,6 +4104,11 @@ static const char * const msiof1_groups[] = {
        "msiof1_ss2",
        "msiof1_rx",
        "msiof1_tx",
+       "msiof1_clk_b",
+       "msiof1_ss1_b",
+       "msiof1_ss2_b",
+       "msiof1_rx_b",
+       "msiof1_tx_b",
 };
 
 static const char * const msiof2_groups[] = {
@@ -3968,6 +4127,16 @@ static const char * const msiof3_groups[] = {
        "msiof3_ss2",
        "msiof3_rx",
        "msiof3_tx",
+       "msiof3_clk_b",
+       "msiof3_sync_b",
+       "msiof3_rx_b",
+       "msiof3_tx_b",
+};
+
+static const char * const qspi_groups[] = {
+       "qspi_ctrl",
+       "qspi_data2",
+       "qspi_data4",
 };
 
 static const char * const scif0_groups[] = {
@@ -4134,6 +4303,7 @@ static const char * const tpu0_groups[] = {
 
 static const char * const usb0_groups[] = {
        "usb0",
+       "usb0_ovc_vbus",
 };
 
 static const char * const usb1_groups[] = {
@@ -4213,6 +4383,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(msiof1),
        SH_PFC_FUNCTION(msiof2),
        SH_PFC_FUNCTION(msiof3),
+       SH_PFC_FUNCTION(qspi),
        SH_PFC_FUNCTION(scif0),
        SH_PFC_FUNCTION(scif1),
        SH_PFC_FUNCTION(scif2),
index 77d103fe39d90c8ad0bb82485ec1896dd1b5889a..5186d70c49d43326bc0a3e1f0405332d512cb989 100644 (file)
@@ -89,7 +89,8 @@ enum {
 
        /* GPSR6 */
        FN_IP13_10, FN_IP13_11, FN_IP13_12, FN_IP13_13, FN_IP13_14,
-       FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19, FN_IP13_22, FN_IP13_24_23,
+       FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19,
+       FN_IP13_22, FN_IP13_24_23, FN_SD1_CLK,
        FN_IP13_25, FN_IP13_26, FN_IP13_27, FN_IP13_30_28, FN_IP14_1_0,
        FN_IP14_2, FN_IP14_3, FN_IP14_4, FN_IP14_5, FN_IP14_6, FN_IP14_7,
        FN_IP14_10_8, FN_IP14_13_11, FN_IP14_16_14, FN_IP14_19_17,
@@ -788,6 +789,7 @@ static const u16 pinmux_data[] = {
        PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
        PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
        PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
+       PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_0, D0),
@@ -1943,6 +1945,50 @@ static const unsigned int i2c4_c_pins[] = {
 static const unsigned int i2c4_c_mux[] = {
        SCL4_C_MARK, SDA4_C_MARK,
 };
+/* - I2C7 ------------------------------------------------------------------- */
+static const unsigned int i2c7_pins[] = {
+       /* SCL, SDA */
+       RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int i2c7_mux[] = {
+       SCL7_MARK, SDA7_MARK,
+};
+static const unsigned int i2c7_b_pins[] = {
+       /* SCL, SDA */
+       RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+};
+static const unsigned int i2c7_b_mux[] = {
+       SCL7_B_MARK, SDA7_B_MARK,
+};
+static const unsigned int i2c7_c_pins[] = {
+       /* SCL, SDA */
+       RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29),
+};
+static const unsigned int i2c7_c_mux[] = {
+       SCL7_C_MARK, SDA7_C_MARK,
+};
+/* - I2C8 ------------------------------------------------------------------- */
+static const unsigned int i2c8_pins[] = {
+       /* SCL, SDA */
+       RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 14),
+};
+static const unsigned int i2c8_mux[] = {
+       SCL8_MARK, SDA8_MARK,
+};
+static const unsigned int i2c8_b_pins[] = {
+       /* SCL, SDA */
+       RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5),
+};
+static const unsigned int i2c8_b_mux[] = {
+       SCL8_B_MARK, SDA8_B_MARK,
+};
+static const unsigned int i2c8_c_pins[] = {
+       /* SCL, SDA */
+       RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23),
+};
+static const unsigned int i2c8_c_mux[] = {
+       SCL8_C_MARK, SDA8_C_MARK,
+};
 /* - INTC ------------------------------------------------------------------- */
 static const unsigned int intc_irq0_pins[] = {
        /* IRQ */
@@ -2049,6 +2095,92 @@ static const unsigned int msiof0_tx_pins[] = {
 static const unsigned int msiof0_tx_mux[] = {
        MSIOF0_TXD_MARK,
 };
+
+static const unsigned int msiof0_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(0, 16),
+};
+static const unsigned int msiof0_clk_b_mux[] = {
+       MSIOF0_SCK_B_MARK,
+};
+static const unsigned int msiof0_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(0, 17),
+};
+static const unsigned int msiof0_sync_b_mux[] = {
+       MSIOF0_SYNC_B_MARK,
+};
+static const unsigned int msiof0_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof0_ss1_b_mux[] = {
+       MSIOF0_SS1_B_MARK,
+};
+static const unsigned int msiof0_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(0, 19),
+};
+static const unsigned int msiof0_ss2_b_mux[] = {
+       MSIOF0_SS2_B_MARK,
+};
+static const unsigned int msiof0_rx_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(0, 21),
+};
+static const unsigned int msiof0_rx_b_mux[] = {
+       MSIOF0_RXD_B_MARK,
+};
+static const unsigned int msiof0_tx_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 20),
+};
+static const unsigned int msiof0_tx_b_mux[] = {
+       MSIOF0_TXD_B_MARK,
+};
+
+static const unsigned int msiof0_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 26),
+};
+static const unsigned int msiof0_clk_c_mux[] = {
+       MSIOF0_SCK_C_MARK,
+};
+static const unsigned int msiof0_sync_c_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(5, 25),
+};
+static const unsigned int msiof0_sync_c_mux[] = {
+       MSIOF0_SYNC_C_MARK,
+};
+static const unsigned int msiof0_ss1_c_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(5, 27),
+};
+static const unsigned int msiof0_ss1_c_mux[] = {
+       MSIOF0_SS1_C_MARK,
+};
+static const unsigned int msiof0_ss2_c_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(5, 28),
+};
+static const unsigned int msiof0_ss2_c_mux[] = {
+       MSIOF0_SS2_C_MARK,
+};
+static const unsigned int msiof0_rx_c_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(5, 29),
+};
+static const unsigned int msiof0_rx_c_mux[] = {
+       MSIOF0_RXD_C_MARK,
+};
+static const unsigned int msiof0_tx_c_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(5, 30),
+};
+static const unsigned int msiof0_tx_c_mux[] = {
+       MSIOF0_TXD_C_MARK,
+};
 /* - MSIOF1 ----------------------------------------------------------------- */
 static const unsigned int msiof1_clk_pins[] = {
        /* SCK */
@@ -2092,6 +2224,143 @@ static const unsigned int msiof1_tx_pins[] = {
 static const unsigned int msiof1_tx_mux[] = {
        MSIOF1_TXD_MARK,
 };
+
+static const unsigned int msiof1_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(2, 29),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+       MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(2, 30),
+};
+static const unsigned int msiof1_sync_b_mux[] = {
+       MSIOF1_SYNC_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(2, 31),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+       MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(7, 16),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+       MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(7, 18),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+       MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(7, 17),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+       MSIOF1_TXD_B_MARK,
+};
+
+static const unsigned int msiof1_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(2, 15),
+};
+static const unsigned int msiof1_clk_c_mux[] = {
+       MSIOF1_SCK_C_MARK,
+};
+static const unsigned int msiof1_sync_c_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(2, 16),
+};
+static const unsigned int msiof1_sync_c_mux[] = {
+       MSIOF1_SYNC_C_MARK,
+};
+static const unsigned int msiof1_rx_c_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(2, 18),
+};
+static const unsigned int msiof1_rx_c_mux[] = {
+       MSIOF1_RXD_C_MARK,
+};
+static const unsigned int msiof1_tx_c_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(2, 17),
+};
+static const unsigned int msiof1_tx_c_mux[] = {
+       MSIOF1_TXD_C_MARK,
+};
+
+static const unsigned int msiof1_clk_d_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(0, 28),
+};
+static const unsigned int msiof1_clk_d_mux[] = {
+       MSIOF1_SCK_D_MARK,
+};
+static const unsigned int msiof1_sync_d_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(0, 30),
+};
+static const unsigned int msiof1_sync_d_mux[] = {
+       MSIOF1_SYNC_D_MARK,
+};
+static const unsigned int msiof1_ss1_d_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(0, 29),
+};
+static const unsigned int msiof1_ss1_d_mux[] = {
+       MSIOF1_SS1_D_MARK,
+};
+static const unsigned int msiof1_rx_d_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(0, 27),
+};
+static const unsigned int msiof1_rx_d_mux[] = {
+       MSIOF1_RXD_D_MARK,
+};
+static const unsigned int msiof1_tx_d_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 26),
+};
+static const unsigned int msiof1_tx_d_mux[] = {
+       MSIOF1_TXD_D_MARK,
+};
+
+static const unsigned int msiof1_clk_e_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 18),
+};
+static const unsigned int msiof1_clk_e_mux[] = {
+       MSIOF1_SCK_E_MARK,
+};
+static const unsigned int msiof1_sync_e_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(5, 19),
+};
+static const unsigned int msiof1_sync_e_mux[] = {
+       MSIOF1_SYNC_E_MARK,
+};
+static const unsigned int msiof1_rx_e_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(5, 17),
+};
+static const unsigned int msiof1_rx_e_mux[] = {
+       MSIOF1_RXD_E_MARK,
+};
+static const unsigned int msiof1_tx_e_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(5, 20),
+};
+static const unsigned int msiof1_tx_e_mux[] = {
+       MSIOF1_TXD_E_MARK,
+};
 /* - MSIOF2 ----------------------------------------------------------------- */
 static const unsigned int msiof2_clk_pins[] = {
        /* SCK */
@@ -2135,6 +2404,197 @@ static const unsigned int msiof2_tx_pins[] = {
 static const unsigned int msiof2_tx_mux[] = {
        MSIOF2_TXD_MARK,
 };
+
+static const unsigned int msiof2_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(3, 0),
+};
+static const unsigned int msiof2_clk_b_mux[] = {
+       MSIOF2_SCK_B_MARK,
+};
+static const unsigned int msiof2_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(3, 1),
+};
+static const unsigned int msiof2_sync_b_mux[] = {
+       MSIOF2_SYNC_B_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(3, 8),
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+       MSIOF2_SS1_B_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(3, 9),
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+       MSIOF2_SS2_B_MARK,
+};
+static const unsigned int msiof2_rx_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(3, 17),
+};
+static const unsigned int msiof2_rx_b_mux[] = {
+       MSIOF2_RXD_B_MARK,
+};
+static const unsigned int msiof2_tx_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(3, 16),
+};
+static const unsigned int msiof2_tx_b_mux[] = {
+       MSIOF2_TXD_B_MARK,
+};
+
+static const unsigned int msiof2_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(2, 2),
+};
+static const unsigned int msiof2_clk_c_mux[] = {
+       MSIOF2_SCK_C_MARK,
+};
+static const unsigned int msiof2_sync_c_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(2, 3),
+};
+static const unsigned int msiof2_sync_c_mux[] = {
+       MSIOF2_SYNC_C_MARK,
+};
+static const unsigned int msiof2_rx_c_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(2, 5),
+};
+static const unsigned int msiof2_rx_c_mux[] = {
+       MSIOF2_RXD_C_MARK,
+};
+static const unsigned int msiof2_tx_c_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(2, 4),
+};
+static const unsigned int msiof2_tx_c_mux[] = {
+       MSIOF2_TXD_C_MARK,
+};
+
+static const unsigned int msiof2_clk_d_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(2, 14),
+};
+static const unsigned int msiof2_clk_d_mux[] = {
+       MSIOF2_SCK_D_MARK,
+};
+static const unsigned int msiof2_sync_d_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(2, 15),
+};
+static const unsigned int msiof2_sync_d_mux[] = {
+       MSIOF2_SYNC_D_MARK,
+};
+static const unsigned int msiof2_ss1_d_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(2, 17),
+};
+static const unsigned int msiof2_ss1_d_mux[] = {
+       MSIOF2_SS1_D_MARK,
+};
+static const unsigned int msiof2_ss2_d_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(2, 19),
+};
+static const unsigned int msiof2_ss2_d_mux[] = {
+       MSIOF2_SS2_D_MARK,
+};
+static const unsigned int msiof2_rx_d_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(2, 18),
+};
+static const unsigned int msiof2_rx_d_mux[] = {
+       MSIOF2_RXD_D_MARK,
+};
+static const unsigned int msiof2_tx_d_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(2, 16),
+};
+static const unsigned int msiof2_tx_d_mux[] = {
+       MSIOF2_TXD_D_MARK,
+};
+
+static const unsigned int msiof2_clk_e_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(7, 15),
+};
+static const unsigned int msiof2_clk_e_mux[] = {
+       MSIOF2_SCK_E_MARK,
+};
+static const unsigned int msiof2_sync_e_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(7, 16),
+};
+static const unsigned int msiof2_sync_e_mux[] = {
+       MSIOF2_SYNC_E_MARK,
+};
+static const unsigned int msiof2_rx_e_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(7, 14),
+};
+static const unsigned int msiof2_rx_e_mux[] = {
+       MSIOF2_RXD_E_MARK,
+};
+static const unsigned int msiof2_tx_e_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(7, 13),
+};
+static const unsigned int msiof2_tx_e_mux[] = {
+       MSIOF2_TXD_E_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+       /* SPCLK, SSL */
+       RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+       SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+       /* MOSI_IO0, MISO_IO1 */
+       RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+       MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+       /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+       RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+       RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+       MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
+
+static const unsigned int qspi_ctrl_b_pins[] = {
+       /* SPCLK, SSL */
+       RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 5),
+};
+static const unsigned int qspi_ctrl_b_mux[] = {
+       SPCLK_B_MARK, SSL_B_MARK,
+};
+static const unsigned int qspi_data2_b_pins[] = {
+       /* MOSI_IO0, MISO_IO1 */
+       RCAR_GP_PIN(6, 1), RCAR_GP_PIN(6, 2),
+};
+static const unsigned int qspi_data2_b_mux[] = {
+       MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
+};
+static const unsigned int qspi_data4_b_pins[] = {
+       /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+       RCAR_GP_PIN(6, 1), RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 3),
+       RCAR_GP_PIN(6, 4),
+};
+static const unsigned int qspi_data4_b_mux[] = {
+       SPCLK_B_MARK, MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
+       IO2_B_MARK, IO3_B_MARK, SSL_B_MARK,
+};
 /* - SCIF0 ------------------------------------------------------------------ */
 static const unsigned int scif0_data_pins[] = {
        /* RX, TX */
@@ -3123,6 +3583,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(i2c4),
        SH_PFC_PIN_GROUP(i2c4_b),
        SH_PFC_PIN_GROUP(i2c4_c),
+       SH_PFC_PIN_GROUP(i2c7),
+       SH_PFC_PIN_GROUP(i2c7_b),
+       SH_PFC_PIN_GROUP(i2c7_c),
+       SH_PFC_PIN_GROUP(i2c8),
+       SH_PFC_PIN_GROUP(i2c8_b),
+       SH_PFC_PIN_GROUP(i2c8_c),
        SH_PFC_PIN_GROUP(intc_irq0),
        SH_PFC_PIN_GROUP(intc_irq1),
        SH_PFC_PIN_GROUP(intc_irq2),
@@ -3137,18 +3603,75 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(msiof0_ss2),
        SH_PFC_PIN_GROUP(msiof0_rx),
        SH_PFC_PIN_GROUP(msiof0_tx),
+       SH_PFC_PIN_GROUP(msiof0_clk_b),
+       SH_PFC_PIN_GROUP(msiof0_sync_b),
+       SH_PFC_PIN_GROUP(msiof0_ss1_b),
+       SH_PFC_PIN_GROUP(msiof0_ss2_b),
+       SH_PFC_PIN_GROUP(msiof0_rx_b),
+       SH_PFC_PIN_GROUP(msiof0_tx_b),
+       SH_PFC_PIN_GROUP(msiof0_clk_c),
+       SH_PFC_PIN_GROUP(msiof0_sync_c),
+       SH_PFC_PIN_GROUP(msiof0_ss1_c),
+       SH_PFC_PIN_GROUP(msiof0_ss2_c),
+       SH_PFC_PIN_GROUP(msiof0_rx_c),
+       SH_PFC_PIN_GROUP(msiof0_tx_c),
        SH_PFC_PIN_GROUP(msiof1_clk),
        SH_PFC_PIN_GROUP(msiof1_sync),
        SH_PFC_PIN_GROUP(msiof1_ss1),
        SH_PFC_PIN_GROUP(msiof1_ss2),
        SH_PFC_PIN_GROUP(msiof1_rx),
        SH_PFC_PIN_GROUP(msiof1_tx),
+       SH_PFC_PIN_GROUP(msiof1_clk_b),
+       SH_PFC_PIN_GROUP(msiof1_sync_b),
+       SH_PFC_PIN_GROUP(msiof1_ss1_b),
+       SH_PFC_PIN_GROUP(msiof1_ss2_b),
+       SH_PFC_PIN_GROUP(msiof1_rx_b),
+       SH_PFC_PIN_GROUP(msiof1_tx_b),
+       SH_PFC_PIN_GROUP(msiof1_clk_c),
+       SH_PFC_PIN_GROUP(msiof1_sync_c),
+       SH_PFC_PIN_GROUP(msiof1_rx_c),
+       SH_PFC_PIN_GROUP(msiof1_tx_c),
+       SH_PFC_PIN_GROUP(msiof1_clk_d),
+       SH_PFC_PIN_GROUP(msiof1_sync_d),
+       SH_PFC_PIN_GROUP(msiof1_ss1_d),
+       SH_PFC_PIN_GROUP(msiof1_rx_d),
+       SH_PFC_PIN_GROUP(msiof1_tx_d),
+       SH_PFC_PIN_GROUP(msiof1_clk_e),
+       SH_PFC_PIN_GROUP(msiof1_sync_e),
+       SH_PFC_PIN_GROUP(msiof1_rx_e),
+       SH_PFC_PIN_GROUP(msiof1_tx_e),
        SH_PFC_PIN_GROUP(msiof2_clk),
        SH_PFC_PIN_GROUP(msiof2_sync),
        SH_PFC_PIN_GROUP(msiof2_ss1),
        SH_PFC_PIN_GROUP(msiof2_ss2),
        SH_PFC_PIN_GROUP(msiof2_rx),
        SH_PFC_PIN_GROUP(msiof2_tx),
+       SH_PFC_PIN_GROUP(msiof2_clk_b),
+       SH_PFC_PIN_GROUP(msiof2_sync_b),
+       SH_PFC_PIN_GROUP(msiof2_ss1_b),
+       SH_PFC_PIN_GROUP(msiof2_ss2_b),
+       SH_PFC_PIN_GROUP(msiof2_rx_b),
+       SH_PFC_PIN_GROUP(msiof2_tx_b),
+       SH_PFC_PIN_GROUP(msiof2_clk_c),
+       SH_PFC_PIN_GROUP(msiof2_sync_c),
+       SH_PFC_PIN_GROUP(msiof2_rx_c),
+       SH_PFC_PIN_GROUP(msiof2_tx_c),
+       SH_PFC_PIN_GROUP(msiof2_clk_d),
+       SH_PFC_PIN_GROUP(msiof2_sync_d),
+       SH_PFC_PIN_GROUP(msiof2_ss1_d),
+       SH_PFC_PIN_GROUP(msiof2_ss2_d),
+       SH_PFC_PIN_GROUP(msiof2_rx_d),
+       SH_PFC_PIN_GROUP(msiof2_tx_d),
+       SH_PFC_PIN_GROUP(msiof2_clk_e),
+       SH_PFC_PIN_GROUP(msiof2_sync_e),
+       SH_PFC_PIN_GROUP(msiof2_rx_e),
+       SH_PFC_PIN_GROUP(msiof2_tx_e),
+       SH_PFC_PIN_GROUP(qspi_ctrl),
+       SH_PFC_PIN_GROUP(qspi_data2),
+       SH_PFC_PIN_GROUP(qspi_data4),
+       SH_PFC_PIN_GROUP(qspi_ctrl_b),
+       SH_PFC_PIN_GROUP(qspi_data2_b),
+       SH_PFC_PIN_GROUP(qspi_data4_b),
        SH_PFC_PIN_GROUP(scif0_data),
        SH_PFC_PIN_GROUP(scif0_data_b),
        SH_PFC_PIN_GROUP(scif0_data_c),
@@ -3335,6 +3858,18 @@ static const char * const i2c4_groups[] = {
        "i2c4_c",
 };
 
+static const char * const i2c7_groups[] = {
+       "i2c7",
+       "i2c7_b",
+       "i2c7_c",
+};
+
+static const char * const i2c8_groups[] = {
+       "i2c8",
+       "i2c8_b",
+       "i2c8_c",
+};
+
 static const char * const intc_groups[] = {
        "intc_irq0",
        "intc_irq1",
@@ -3356,6 +3891,18 @@ static const char * const msiof0_groups[] = {
        "msiof0_ss2",
        "msiof0_rx",
        "msiof0_tx",
+       "msiof0_clk_b",
+       "msiof0_sync_b",
+       "msiof0_ss1_b",
+       "msiof0_ss2_b",
+       "msiof0_rx_b",
+       "msiof0_tx_b",
+       "msiof0_clk_c",
+       "msiof0_sync_c",
+       "msiof0_ss1_c",
+       "msiof0_ss2_c",
+       "msiof0_rx_c",
+       "msiof0_tx_c",
 };
 
 static const char * const msiof1_groups[] = {
@@ -3365,6 +3912,25 @@ static const char * const msiof1_groups[] = {
        "msiof1_ss2",
        "msiof1_rx",
        "msiof1_tx",
+       "msiof1_clk_b",
+       "msiof1_sync_b",
+       "msiof1_ss1_b",
+       "msiof1_ss2_b",
+       "msiof1_rx_b",
+       "msiof1_tx_b",
+       "msiof1_clk_c",
+       "msiof1_sync_c",
+       "msiof1_rx_c",
+       "msiof1_tx_c",
+       "msiof1_clk_d",
+       "msiof1_sync_d",
+       "msiof1_ss1_d",
+       "msiof1_rx_d",
+       "msiof1_tx_d",
+       "msiof1_clk_e",
+       "msiof1_sync_e",
+       "msiof1_rx_e",
+       "msiof1_tx_e",
 };
 
 static const char * const msiof2_groups[] = {
@@ -3374,6 +3940,35 @@ static const char * const msiof2_groups[] = {
        "msiof2_ss2",
        "msiof2_rx",
        "msiof2_tx",
+       "msiof2_clk_b",
+       "msiof2_sync_b",
+       "msiof2_ss1_b",
+       "msiof2_ss2_b",
+       "msiof2_rx_b",
+       "msiof2_tx_b",
+       "msiof2_clk_c",
+       "msiof2_sync_c",
+       "msiof2_rx_c",
+       "msiof2_tx_c",
+       "msiof2_clk_d",
+       "msiof2_sync_d",
+       "msiof2_ss1_d",
+       "msiof2_ss2_d",
+       "msiof2_rx_d",
+       "msiof2_tx_d",
+       "msiof2_clk_e",
+       "msiof2_sync_e",
+       "msiof2_rx_e",
+       "msiof2_tx_e",
+};
+
+static const char * const qspi_groups[] = {
+       "qspi_ctrl",
+       "qspi_data2",
+       "qspi_data4",
+       "qspi_ctrl_b",
+       "qspi_data2_b",
+       "qspi_data4_b",
 };
 
 static const char * const scif0_groups[] = {
@@ -3566,11 +4161,14 @@ static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(i2c2),
        SH_PFC_FUNCTION(i2c3),
        SH_PFC_FUNCTION(i2c4),
+       SH_PFC_FUNCTION(i2c7),
+       SH_PFC_FUNCTION(i2c8),
        SH_PFC_FUNCTION(intc),
        SH_PFC_FUNCTION(mmc),
        SH_PFC_FUNCTION(msiof0),
        SH_PFC_FUNCTION(msiof1),
        SH_PFC_FUNCTION(msiof2),
+       SH_PFC_FUNCTION(qspi),
        SH_PFC_FUNCTION(scif0),
        SH_PFC_FUNCTION(scif1),
        SH_PFC_FUNCTION(scif2),
@@ -3825,7 +4423,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
                GP_6_11_FN, FN_IP13_25,
                GP_6_10_FN, FN_IP13_24_23,
                GP_6_9_FN, FN_IP13_22,
-               0, 0,
+               GP_6_8_FN, FN_SD1_CLK,
                GP_6_7_FN, FN_IP13_21_19,
                GP_6_6_FN, FN_IP13_18_16,
                GP_6_5_FN, FN_IP13_15,
index 2b9f32065920a44f68cb2f7e7e958c7598bd4ced..c4dd3d5cf9c35875322ea943b7f7ad9665ab637a 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * pinctrl pads, groups, functions for CSR SiRFatlasVI
  *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
  *
  * Licensed under GPLv2 or later.
  */
@@ -529,6 +530,40 @@ static const struct sirfsoc_padmux usp0_padmux = {
 
 static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 };
 
+static const struct sirfsoc_muxmask usp0_only_utfs_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
+       },
+};
+
+static const struct sirfsoc_padmux usp0_only_utfs_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usp0_only_utfs_muxmask),
+       .muxmask = usp0_only_utfs_muxmask,
+       .ctrlreg = SIRFSOC_RSC_PIN_MUX,
+       .funcmask = BIT(1) | BIT(2) | BIT(6),
+       .funcval = 0,
+};
+
+static const unsigned usp0_only_utfs_pins[] = { 51, 52, 53, 54 };
+
+static const struct sirfsoc_muxmask usp0_only_urfs_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(19) | BIT(20) | BIT(21) | BIT(23),
+       },
+};
+
+static const struct sirfsoc_padmux usp0_only_urfs_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usp0_only_urfs_muxmask),
+       .muxmask = usp0_only_urfs_muxmask,
+       .ctrlreg = SIRFSOC_RSC_PIN_MUX,
+       .funcmask = BIT(1) | BIT(2) | BIT(9),
+       .funcval = 0,
+};
+
+static const unsigned usp0_only_urfs_pins[] = { 51, 52, 53, 55 };
+
 static const struct sirfsoc_muxmask usp0_uart_nostreamctrl_muxmask[] = {
        {
                .group = 1,
@@ -905,6 +940,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
        SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
        SIRFSOC_PIN_GROUP("usp0_uart_nostreamctrl_grp",
                                        usp0_uart_nostreamctrl_pins),
+       SIRFSOC_PIN_GROUP("usp0_only_utfs_grp", usp0_only_utfs_pins),
+       SIRFSOC_PIN_GROUP("usp0_only_urfs_grp", usp0_only_urfs_pins),
        SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
        SIRFSOC_PIN_GROUP("usp1_uart_nostreamctrl_grp",
                                        usp1_uart_nostreamctrl_pins),
@@ -953,6 +990,9 @@ static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
 static const char * const usp0_uart_nostreamctrl_grp[] = {
                                        "usp0_uart_nostreamctrl_grp" };
 static const char * const usp0grp[] = { "usp0grp" };
+static const char * const usp0_only_utfs_grp[] = { "usp0_only_utfs_grp" };
+static const char * const usp0_only_urfs_grp[] = { "usp0_only_urfs_grp" };
+
 static const char * const usp1grp[] = { "usp1grp" };
 static const char * const usp1_uart_nostreamctrl_grp[] = {
                                        "usp1_uart_nostreamctrl_grp" };
@@ -1003,6 +1043,10 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
        SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl",
                                                usp0_uart_nostreamctrl_grp,
                                                usp0_uart_nostreamctrl_padmux),
+       SIRFSOC_PMX_FUNCTION("usp0_only_utfs", usp0_only_utfs_grp,
+                                               usp0_only_utfs_padmux),
+       SIRFSOC_PMX_FUNCTION("usp0_only_urfs", usp0_only_urfs_grp,
+                                               usp0_only_urfs_padmux),
        SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
        SIRFSOC_PMX_FUNCTION("usp1_uart_nostreamctrl",
                                                usp1_uart_nostreamctrl_grp,
index dde0285544d6ad95a6c392955df3ce976c3e11a4..8aa76f0776d777ee5beb5598d7f80a354b23caed 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * pinctrl pads, groups, functions for CSR SiRFprimaII
  *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
  *
  * Licensed under GPLv2 or later.
  */
index a0d6152701cdf3d3aa5a64bbb435f93526d0a324..5f3adb87c1efe8f3670b9c79d2f5db78671260d8 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * pinmux driver for CSR SiRFprimaII
  *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
  *
  * Licensed under GPLv2 or later.
  */
@@ -598,7 +599,7 @@ static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d)
 {
        struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 
-       if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq))
+       if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE))
                dev_err(bank->chip.gc.dev,
                        "unable to lock HW IRQ %lu for IRQ\n",
                        d->hwirq);
@@ -611,7 +612,7 @@ static void sirfsoc_gpio_irq_shutdown(struct irq_data *d)
        struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 
        sirfsoc_gpio_irq_mask(d);
-       gpio_unlock_as_irq(&bank->chip.gc, d->hwirq);
+       gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
 }
 
 static struct irq_chip sirfsoc_irq_chip = {
index 5ae65c11d544d4feb9affb727b6e00bec4b13894..5f67843c7fb7388c158ade858a90c18c61f8f2c7 100644 (file)
@@ -27,8 +27,6 @@ config ACER_WMI
        depends on ACPI_WMI
        select INPUT_SPARSEKMAP
        # Acer WMI depends on ACPI_VIDEO when ACPI is enabled
-       # but for select to work, need to select ACPI_VIDEO's dependencies, ick
-        select VIDEO_OUTPUT_CONTROL if ACPI
         select ACPI_VIDEO if ACPI
        ---help---
          This is a driver for newer Acer (and Wistron) laptops. It adds
index be02bcc346d30cb9dc17fff807aa414d0147216a..e6f336270c2191fd9cd1418f869b5aa4dcc499de 100644 (file)
@@ -66,7 +66,6 @@
 #include <linux/backlight.h>
 #include <linux/input.h>
 #include <linux/kfifo.h>
-#include <linux/video_output.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
index defb6afc1409cc7fff0863d6829c5c26478b6a4a..94bb6157c957b495a955159ea4916769f373862f 100644 (file)
@@ -6776,8 +6776,9 @@ static int __init volume_create_alsa_mixer(void)
        struct snd_kcontrol *ctl_mute;
        int rc;
 
-       rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
-                           sizeof(struct tpacpi_alsa_data), &card);
+       rc = snd_card_new(&tpacpi_pdev->dev,
+                         alsa_index, alsa_id, THIS_MODULE,
+                         sizeof(struct tpacpi_alsa_data), &card);
        if (rc < 0 || !card) {
                pr_err("Failed to create ALSA card structures: %d\n", rc);
                return 1;
@@ -6828,7 +6829,6 @@ static int __init volume_create_alsa_mixer(void)
        }
        data->ctl_mute_id = &ctl_mute->id;
 
-       snd_card_set_dev(card, &tpacpi_pdev->dev);
        rc = snd_card_register(card);
        if (rc < 0) {
                pr_err("Failed to register ALSA card: %d\n", rc);
index 167f3d00c916d2e30a63dcc31d260a45d1e5cada..66977ebf13b30cba09b6bb1b7c06eeb07e2e5bd0 100644 (file)
@@ -183,9 +183,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        struct resource r = {0};
        int i, flags;
 
-       if (acpi_dev_resource_memory(res, &r)
-           || acpi_dev_resource_io(res, &r)
-           || acpi_dev_resource_address_space(res, &r)
+       if (acpi_dev_resource_address_space(res, &r)
            || acpi_dev_resource_ext_address_space(res, &r)) {
                pnp_add_resource(dev, &r);
                return AE_OK;
@@ -217,6 +215,17 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        }
 
        switch (res->type) {
+       case ACPI_RESOURCE_TYPE_MEMORY24:
+       case ACPI_RESOURCE_TYPE_MEMORY32:
+       case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+               if (acpi_dev_resource_memory(res, &r))
+                       pnp_add_resource(dev, &r);
+               break;
+       case ACPI_RESOURCE_TYPE_IO:
+       case ACPI_RESOURCE_TYPE_FIXED_IO:
+               if (acpi_dev_resource_io(res, &r))
+                       pnp_add_resource(dev, &r);
+               break;
        case ACPI_RESOURCE_TYPE_DMA:
                dma = &res->data.dma;
                if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
index 769d265b221b9c3abee2b8ea86a1d84ef00ac795..deb7f4bcdb7b6b6a770ce08f1d2535dccfa82100 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "pnpbios.h"
 
-static struct {
+__visible struct {
        u16 offset;
        u16 segment;
 } pnp_bios_callpoint;
@@ -41,6 +41,7 @@ asmlinkage void pnp_bios_callfunc(void);
 
 __asm__(".text                 \n"
        __ALIGN_STR "\n"
+       ".globl pnp_bios_callfunc\n"
        "pnp_bios_callfunc:\n"
        "       pushl %edx      \n"
        "       pushl %ecx      \n"
@@ -66,9 +67,9 @@ static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092,
  * after PnP BIOS oopses.
  */
 
-u32 pnp_bios_fault_esp;
-u32 pnp_bios_fault_eip;
-u32 pnp_bios_is_utter_crap = 0;
+__visible u32 pnp_bios_fault_esp;
+__visible u32 pnp_bios_fault_eip;
+__visible u32 pnp_bios_is_utter_crap = 0;
 
 static spinlock_t pnp_bios_lock;
 
index 3c6768378a94600bc487c61bc9d3fffcbf581750..61b51e17d932a5c81db81fd99f46c7411dcf79c6 100644 (file)
@@ -834,7 +834,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
 }
 
 static const struct x86_cpu_id energy_unit_quirk_ids[] = {
-       { X86_VENDOR_INTEL, 6, 0x37},/* VLV */
+       { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
        {}
 };
 
@@ -947,11 +947,11 @@ static void package_power_limit_irq_restore(int package_id)
 }
 
 static const struct x86_cpu_id rapl_ids[] = {
-       { X86_VENDOR_INTEL, 6, 0x2a},/* SNB */
-       { X86_VENDOR_INTEL, 6, 0x2d},/* SNB EP */
-       { X86_VENDOR_INTEL, 6, 0x37},/* VLV */
-       { X86_VENDOR_INTEL, 6, 0x3a},/* IVB */
-       { X86_VENDOR_INTEL, 6, 0x45},/* HSW */
+       { X86_VENDOR_INTEL, 6, 0x2a},/* Sandy Bridge */
+       { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
+       { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
+       { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
+       { X86_VENDOR_INTEL, 6, 0x45},/* Haswell */
        /* TODO: Add more CPU IDs after testing */
        {}
 };
@@ -1147,6 +1147,11 @@ static int rapl_check_domain(int cpu, int domain)
        if (rdmsrl_safe_on_cpu(cpu, msr, &val1))
                return -ENODEV;
 
+       /* PP1/uncore/graphics domain may not be active at the time of
+        * driver loading. So skip further checks.
+        */
+       if (domain == RAPL_DOMAIN_PP1)
+               return 0;
        /* energy counters roll slowly on some domains */
        while (++retry < 10) {
                usleep_range(10000, 15000);
index fb7300837feef25a6b2a80de582baf01031bf22a..bc1e5139ba2957712e9800182fe6d7a24c568468 100644 (file)
@@ -699,8 +699,6 @@ int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes)
 
        BUG_ON(!bytes);
 
-       PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work);
-
        spin_lock_irqsave(&priv->rx_list.lock, flags);
        if (priv->rx_list.bytes_held >= bytes) {
                dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
@@ -1052,7 +1050,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
        INIT_LIST_HEAD(&priv->rx_list.head);
        spin_lock_init(&priv->rx_list.lock);
 
-       INIT_WORK(&priv->rx_list.work.work, NULL);
+       INIT_WORK(&priv->rx_list.work.work, ps3_vuart_work);
        priv->rx_list.work.trigger = 0;
        priv->rx_list.work.dev = dev;
 
index b4b0d83f9ef6437dfb97f33037aaee1acf7bda59..7061ac0ad4287c0d84edb39058ef6abc295e43ce 100644 (file)
@@ -678,6 +678,7 @@ struct tsi721_bdma_chan {
        struct list_head        free_list;
        dma_cookie_t            completed_cookie;
        struct tasklet_struct   tasklet;
+       bool                    active;
 };
 
 #endif /* CONFIG_RAPIDIO_DMA_ENGINE */
index 502663f5f7c65a847f45881dcac4821081a314cf..91245f5dbe81a7d235f13a2dd2edbe741508d584 100644 (file)
@@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
 {
        /* Disable BDMA channel interrupts */
        iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
-
-       tasklet_schedule(&bdma_chan->tasklet);
+       if (bdma_chan->active)
+               tasklet_schedule(&bdma_chan->tasklet);
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -562,7 +562,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
        }
 #endif /* CONFIG_PCI_MSI */
 
-       tasklet_enable(&bdma_chan->tasklet);
+       bdma_chan->active = true;
        tsi721_bdma_interrupt_enable(bdma_chan, 1);
 
        return bdma_chan->bd_num - 1;
@@ -576,9 +576,7 @@ err_out:
 static void tsi721_free_chan_resources(struct dma_chan *dchan)
 {
        struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
-#ifdef CONFIG_PCI_MSI
        struct tsi721_device *priv = to_tsi721(dchan->device);
-#endif
        LIST_HEAD(list);
 
        dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
@@ -589,14 +587,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan)
        BUG_ON(!list_empty(&bdma_chan->active_list));
        BUG_ON(!list_empty(&bdma_chan->queue));
 
-       tasklet_disable(&bdma_chan->tasklet);
+       tsi721_bdma_interrupt_enable(bdma_chan, 0);
+       bdma_chan->active = false;
+
+#ifdef CONFIG_PCI_MSI
+       if (priv->flags & TSI721_USING_MSIX) {
+               synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE +
+                                          bdma_chan->id].vector);
+               synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT +
+                                          bdma_chan->id].vector);
+       } else
+#endif
+       synchronize_irq(priv->pdev->irq);
+
+       tasklet_kill(&bdma_chan->tasklet);
 
        spin_lock_bh(&bdma_chan->lock);
        list_splice_init(&bdma_chan->free_list, &list);
        spin_unlock_bh(&bdma_chan->lock);
 
-       tsi721_bdma_interrupt_enable(bdma_chan, 0);
-
 #ifdef CONFIG_PCI_MSI
        if (priv->flags & TSI721_USING_MSIX) {
                free_irq(priv->msix[TSI721_VECT_DMA0_DONE +
@@ -790,6 +799,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
                bdma_chan->dchan.cookie = 1;
                bdma_chan->dchan.chan_id = i;
                bdma_chan->id = i;
+               bdma_chan->active = false;
 
                spin_lock_init(&bdma_chan->lock);
 
@@ -799,7 +809,6 @@ int tsi721_register_dma(struct tsi721_device *priv)
 
                tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet,
                             (unsigned long)bdma_chan);
-               tasklet_disable(&bdma_chan->tasklet);
                list_add_tail(&bdma_chan->dchan.device_node,
                              &mport->dma.channels);
        }
index d333f7eac106f1ae9cab88f0850f2fc4ca03c19f..7a721d67e6aca8ce8425ebc0e29477009fbe9c6c 100644 (file)
@@ -310,10 +310,8 @@ static int pm800_regulator_probe(struct platform_device *pdev)
 
        pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
                                        GFP_KERNEL);
-       if (!pm800_data) {
-               dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
+       if (!pm800_data)
                return -ENOMEM;
-       }
 
        pm800_data->map = chip->subchip->regmap_power;
        pm800_data->chip = chip;
index f704d83c93c4a95fc729cc48c510611d4b5cd33f..337634ad0562449495c12fb4e39efd989f85edef 100644 (file)
@@ -2,7 +2,7 @@
  * Regulators driver for Marvell 88PM8607
  *
  * Copyright (C) 2009 Marvell International Ltd.
- *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *     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
@@ -78,7 +78,7 @@ static const unsigned int BUCK2_suspend_table[] = {
 };
 
 static const unsigned int BUCK3_table[] = {
-              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+             0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
         200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
         400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
         600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
@@ -89,7 +89,7 @@ static const unsigned int BUCK3_table[] = {
 };
 
 static const unsigned int BUCK3_suspend_table[] = {
-              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+             0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
         200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
         400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
         600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
@@ -322,7 +322,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
        nproot = of_node_get(pdev->dev.parent->of_node);
        if (!nproot)
                return -ENODEV;
-       nproot = of_find_node_by_name(nproot, "regulators");
+       nproot = of_get_child_by_name(nproot, "regulators");
        if (!nproot) {
                dev_err(&pdev->dev, "failed to find regulators node\n");
                return -ENODEV;
index 6a7932822e373317caba9c5c799c9439f5444927..1cd8584a7b887ffd9fd8fd0089c8148dba595064 100644 (file)
@@ -139,6 +139,14 @@ config REGULATOR_AS3722
          AS3722 PMIC. This will enable support for all the software
          controllable DCDC/LDO regulators.
 
+config REGULATOR_BCM590XX
+       tristate "Broadcom BCM590xx PMU Regulators"
+       depends on MFD_BCM590XX
+       help
+         This driver provides support for the voltage regulators on the
+         BCM590xx PMUs. This will enable support for the software
+         controllable LDO/Switching regulators.
+
 config REGULATOR_DA903X
        tristate "Dialog Semiconductor DA9030/DA9034 regulators"
        depends on PMIC_DA903X
@@ -399,12 +407,12 @@ config REGULATOR_PCF50633
         on PCF50633
 
 config REGULATOR_PFUZE100
-       tristate "Freescale PFUZE100 regulator driver"
+       tristate "Freescale PFUZE100/PFUZE200 regulator driver"
        depends on I2C
        select REGMAP_I2C
        help
-         Say y here to support the regulators found on the Freescale PFUZE100
-         PMIC.
+         Say y here to support the regulators found on the Freescale
+         PFUZE100/PFUZE200 PMIC.
 
 config REGULATOR_RC5T583
        tristate "RICOH RC5T583 Power regulators"
@@ -416,13 +424,21 @@ config REGULATOR_RC5T583
          through regulator interface. The device supports multiple DCDC/LDO
          outputs which can be controlled by i2c communication.
 
+config REGULATOR_S2MPA01
+       tristate "Samsung S2MPA01 voltage regulator"
+       depends on MFD_SEC_CORE
+       help
+        This driver controls Samsung S2MPA01 voltage output regulator
+        via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
+
 config REGULATOR_S2MPS11
-       tristate "Samsung S2MPS11 voltage regulator"
+       tristate "Samsung S2MPS11/S2MPS14 voltage regulator"
        depends on MFD_SEC_CORE
        help
-        This driver supports a Samsung S2MPS11 voltage output regulator
-        via I2C bus. S2MPS11 is comprised of high efficient Buck converters
-        including Dual-Phase Buck converter, Buck-Boost converter, various LDOs.
+        This driver supports a Samsung S2MPS11/S2MPS14 voltage output
+        regulator via I2C bus. The chip is comprised of high efficient Buck
+        converters including Dual-Phase Buck converter, Buck-Boost converter,
+        various LDOs.
 
 config REGULATOR_S5M8767
        tristate "Samsung S5M8767A voltage regulator"
@@ -432,6 +448,12 @@ config REGULATOR_S5M8767
         via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
         supports DVS mode with 8bits of output voltage control.
 
+config REGULATOR_ST_PWM
+       tristate "STMicroelectronics PWM voltage regulator"
+       depends on ARCH_STI
+       help
+        This driver supports ST's PWM controlled voltage regulators.
+
 config REGULATOR_TI_ABB
        tristate "TI Adaptive Body Bias on-chip LDO"
        depends on ARCH_OMAP
@@ -513,6 +535,15 @@ config REGULATOR_TPS65217
          voltage regulators. It supports software based voltage control
          for different voltage domains
 
+config REGULATOR_TPS65218
+       tristate "TI TPS65218 Power regulators"
+       depends on MFD_TPS65218 && OF
+       help
+         This driver supports TPS65218 voltage regulator chips. TPS65218
+         provides six step-down converters and one general-purpose LDO
+         voltage regulators. It supports software based voltage control
+         for different voltage domains
+
 config REGULATOR_TPS6524X
        tristate "TI TPS6524X Power regulators"
        depends on SPI
index 979f9ddcf259bd5a82b6b5d91f81981902e6185c..f0fe0c50b59c23ffc36680536f17bf0486e4226d 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
 obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
 obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
 obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
+obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
@@ -57,8 +58,10 @@ obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
+obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
@@ -67,6 +70,7 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
index f70a9bfa5ff2e9b4845d9493e3cbda9cb012e042..c873ee0082cf2d83e79d678efe2c662561c53e81 100644 (file)
@@ -99,6 +99,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
 
 static struct regulator_ops aat2870_ldo_ops = {
        .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_ascend,
        .set_voltage_sel = aat2870_ldo_set_voltage_sel,
        .get_voltage_sel = aat2870_ldo_get_voltage_sel,
        .enable = aat2870_ldo_enable,
index 084cc0819a52f95a24c1f6c2bed63c1f416d5532..b92d7dd01a1899356dff99641164380c693a3911 100644 (file)
@@ -62,7 +62,6 @@
 #define        ACT8865_VOLTAGE_NUM     64
 
 struct act8865 {
-       struct regulator_dev *rdev[ACT8865_REG_NUM];
        struct regmap *regmap;
 };
 
@@ -213,7 +212,7 @@ static int act8865_pdata_from_dt(struct device *dev,
        struct device_node *np;
        struct act8865_regulator_data *regulator;
 
-       np = of_find_node_by_name(dev->of_node, "regulators");
+       np = of_get_child_by_name(dev->of_node, "regulators");
        if (!np) {
                dev_err(dev, "missing 'regulators' subnode in DT\n");
                return -EINVAL;
@@ -221,17 +220,15 @@ static int act8865_pdata_from_dt(struct device *dev,
 
        matched = of_regulator_match(dev, np,
                                act8865_matches, ARRAY_SIZE(act8865_matches));
+       of_node_put(np);
        if (matched <= 0)
                return matched;
 
        pdata->regulators = devm_kzalloc(dev,
                                sizeof(struct act8865_regulator_data) *
                                ARRAY_SIZE(act8865_matches), GFP_KERNEL);
-       if (!pdata->regulators) {
-               dev_err(dev, "%s: failed to allocate act8865 registor\n",
-                                               __func__);
+       if (!pdata->regulators)
                return -ENOMEM;
-       }
 
        pdata->num_regulators = matched;
        regulator = pdata->regulators;
@@ -258,7 +255,7 @@ static inline int act8865_pdata_from_dt(struct device *dev,
 static int act8865_pmic_probe(struct i2c_client *client,
                           const struct i2c_device_id *i2c_id)
 {
-       struct regulator_dev **rdev;
+       struct regulator_dev *rdev;
        struct device *dev = &client->dev;
        struct act8865_platform_data *pdata = dev_get_platdata(dev);
        struct regulator_config config = { };
@@ -292,8 +289,6 @@ static int act8865_pmic_probe(struct i2c_client *client,
        if (!act8865)
                return -ENOMEM;
 
-       rdev = act8865->rdev;
-
        act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
        if (IS_ERR(act8865->regmap)) {
                error = PTR_ERR(act8865->regmap);
@@ -313,12 +308,12 @@ static int act8865_pmic_probe(struct i2c_client *client,
                config.driver_data = act8865;
                config.regmap = act8865->regmap;
 
-               rdev[i] = devm_regulator_register(&client->dev,
-                                               &act8865_reg[i], &config);
-               if (IS_ERR(rdev[i])) {
+               rdev = devm_regulator_register(&client->dev, &act8865_reg[i],
+                                              &config);
+               if (IS_ERR(rdev)) {
                        dev_err(dev, "failed to register %s\n",
                                act8865_reg[id].name);
-                       return PTR_ERR(rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index 862e63e451d02235a8549bd474c49dbe1829dc4e..7c397bb81e01eb3f8cba61472e4d15b47e16ddc8 100644 (file)
@@ -34,6 +34,9 @@
 #define LDO_RAMP_UP_UNIT_IN_CYCLES      64 /* 64 cycles per step */
 #define LDO_RAMP_UP_FREQ_IN_MHZ         24 /* cycle based on 24M OSC */
 
+#define LDO_POWER_GATE                 0x00
+#define LDO_FET_FULL_ON                        0x1f
+
 struct anatop_regulator {
        const char *name;
        u32 control_reg;
@@ -48,19 +51,10 @@ struct anatop_regulator {
        int max_voltage;
        struct regulator_desc rdesc;
        struct regulator_init_data *initdata;
+       bool bypass;
+       int sel;
 };
 
-static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
-                                       unsigned selector)
-{
-       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-
-       if (!anatop_reg->control_reg)
-               return -ENOTSUPP;
-
-       return regulator_set_voltage_sel_regmap(reg, selector);
-}
-
 static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
        unsigned int old_sel,
        unsigned int new_sel)
@@ -87,22 +81,99 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
        return ret;
 }
 
-static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
+static int anatop_regmap_enable(struct regulator_dev *reg)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int sel;
 
-       if (!anatop_reg->control_reg)
-               return -ENOTSUPP;
+       sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel;
+       return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
+static int anatop_regmap_disable(struct regulator_dev *reg)
+{
+       return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE);
+}
+
+static int anatop_regmap_is_enabled(struct regulator_dev *reg)
+{
+       return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
+}
+
+static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
+                                             unsigned selector)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int ret;
+
+       if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
+               anatop_reg->sel = selector;
+               return 0;
+       }
+
+       ret = regulator_set_voltage_sel_regmap(reg, selector);
+       if (!ret)
+               anatop_reg->sel = selector;
+       return ret;
+}
+
+static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+       if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg))
+               return anatop_reg->sel;
 
        return regulator_get_voltage_sel_regmap(reg);
 }
 
+static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int sel;
+
+       sel = regulator_get_voltage_sel_regmap(reg);
+       if (sel == LDO_FET_FULL_ON)
+               WARN_ON(!anatop_reg->bypass);
+       else if (sel != LDO_POWER_GATE)
+               WARN_ON(anatop_reg->bypass);
+
+       *enable = anatop_reg->bypass;
+       return 0;
+}
+
+static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
+{
+       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+       int sel;
+
+       if (enable == anatop_reg->bypass)
+               return 0;
+
+       sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
+       anatop_reg->bypass = enable;
+
+       return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
 static struct regulator_ops anatop_rops = {
-       .set_voltage_sel = anatop_regmap_set_voltage_sel,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
+};
+
+static struct regulator_ops anatop_core_rops = {
+       .enable = anatop_regmap_enable,
+       .disable = anatop_regmap_disable,
+       .is_enabled = anatop_regmap_is_enabled,
+       .set_voltage_sel = anatop_regmap_core_set_voltage_sel,
        .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
-       .get_voltage_sel = anatop_regmap_get_voltage_sel,
+       .get_voltage_sel = anatop_regmap_core_get_voltage_sel,
        .list_voltage = regulator_list_voltage_linear,
        .map_voltage = regulator_map_voltage_linear,
+       .get_bypass = anatop_regmap_get_bypass,
+       .set_bypass = anatop_regmap_set_bypass,
 };
 
 static int anatop_regulator_probe(struct platform_device *pdev)
@@ -116,6 +187,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
        struct regulator_init_data *initdata;
        struct regulator_config config = { };
        int ret = 0;
+       u32 val;
 
        initdata = of_get_regulator_init_data(dev, np);
        sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
@@ -125,7 +197,6 @@ static int anatop_regulator_probe(struct platform_device *pdev)
        sreg->name = of_get_property(np, "regulator-name", NULL);
        rdesc = &sreg->rdesc;
        rdesc->name = sreg->name;
-       rdesc->ops = &anatop_rops;
        rdesc->type = REGULATOR_VOLTAGE;
        rdesc->owner = THIS_MODULE;
 
@@ -197,6 +268,25 @@ static int anatop_regulator_probe(struct platform_device *pdev)
        config.of_node = pdev->dev.of_node;
        config.regmap = sreg->anatop;
 
+       /* Only core regulators have the ramp up delay configuration. */
+       if (sreg->control_reg && sreg->delay_bit_width) {
+               rdesc->ops = &anatop_core_rops;
+
+               ret = regmap_read(config.regmap, rdesc->vsel_reg, &val);
+               if (ret) {
+                       dev_err(dev, "failed to read initial state\n");
+                       return ret;
+               }
+
+               sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift;
+               if (sreg->sel == LDO_FET_FULL_ON) {
+                       sreg->sel = 0;
+                       sreg->bypass = true;
+               }
+       } else {
+               rdesc->ops = &anatop_rops;
+       }
+
        /* register regulator */
        rdev = devm_regulator_register(dev, rdesc, &config);
        if (IS_ERR(rdev)) {
index 4f6c2055f6b210436a5c1a9565b9f302ecdd21da..b1033d30b504c70cd50364bd5dcbdbca198474f6 100644 (file)
@@ -153,11 +153,9 @@ static const struct regulator_desc arizona_ldo1 = {
 
        .vsel_reg = ARIZONA_LDO1_CONTROL_1,
        .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
-       .bypass_reg = ARIZONA_LDO1_CONTROL_1,
-       .bypass_mask = ARIZONA_LDO1_BYPASS,
        .min_uV = 900000,
-       .uV_step = 50000,
-       .n_voltages = 7,
+       .uV_step = 25000,
+       .n_voltages = 13,
        .enable_time = 500,
 
        .owner = THIS_MODULE,
@@ -189,10 +187,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
        int ret;
 
        ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
-       if (ldo1 == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!ldo1)
                return -ENOMEM;
-       }
 
        ldo1->arizona = arizona;
 
@@ -203,6 +199,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
         */
        switch (arizona->type) {
        case WM5102:
+       case WM8997:
                desc = &arizona_ldo1_hc;
                ldo1->init_data = arizona_ldo1_dvfs;
                break;
index 034ece7070838991a59d45f88f0e0ace95c6abba..6fdd9bf6927fcb39763156d34d2747c34ff2ebee 100644 (file)
@@ -204,10 +204,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
        int ret;
 
        micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
-       if (micsupp == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!micsupp)
                return -ENOMEM;
-       }
 
        micsupp->arizona = arizona;
        INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
index c77a58478cca6b11ffd2c5a69990eddda1900230..b47283f91e2db940974b48c0103c9a5207b462af 100644 (file)
@@ -191,7 +191,7 @@ static int as3711_regulator_parse_dt(struct device *dev,
 {
        struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
        struct device_node *regulators =
-               of_find_node_by_name(dev->parent->of_node, "regulators");
+               of_get_child_by_name(dev->parent->of_node, "regulators");
        struct of_regulator_match *match;
        int ret, i;
 
@@ -221,7 +221,6 @@ static int as3711_regulator_probe(struct platform_device *pdev)
 {
        struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
        struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent);
-       struct regulator_init_data *reg_data;
        struct regulator_config config = {.dev = &pdev->dev,};
        struct as3711_regulator *reg = NULL;
        struct as3711_regulator *regs;
@@ -246,22 +245,14 @@ static int as3711_regulator_probe(struct platform_device *pdev)
 
        regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
                        sizeof(struct as3711_regulator), GFP_KERNEL);
-       if (!regs) {
-               dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+       if (!regs)
                return -ENOMEM;
-       }
 
        for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
-               reg_data = pdata->init_data[id];
-
-               /* No need to register if there is no regulator data */
-               if (!reg_data)
-                       continue;
-
                reg = &regs[id];
                reg->reg_info = ri;
 
-               config.init_data = reg_data;
+               config.init_data = pdata->init_data[id];
                config.driver_data = reg;
                config.regmap = as3711->regmap;
                config.of_node = of_node[id];
index 8b17d786cb713d5176996a36fa66bd2dae96f0b8..85585219ce824140ef3a8f48fed2539ff5b11f07 100644 (file)
@@ -719,6 +719,7 @@ static int as3722_get_regulator_dt_data(struct platform_device *pdev,
 
        ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches,
                        ARRAY_SIZE(as3722_regulator_matches));
+       of_node_put(np);
        if (ret < 0) {
                dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n",
                        ret);
diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c
new file mode 100644 (file)
index 0000000..ab08ca7
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Broadcom BCM590xx regulator driver
+ *
+ * Copyright 2014 Linaro Limited
+ * Author: Matt Porter <mporter@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/bcm590xx.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/slab.h>
+
+/* Register defs */
+#define BCM590XX_RFLDOPMCTRL1  0x60
+#define BCM590XX_IOSR1PMCTRL1  0x7a
+#define BCM590XX_IOSR2PMCTRL1  0x7c
+#define BCM590XX_CSRPMCTRL1    0x7e
+#define BCM590XX_SDSR1PMCTRL1  0x82
+#define BCM590XX_SDSR2PMCTRL1  0x86
+#define BCM590XX_MSRPMCTRL1    0x8a
+#define BCM590XX_VSRPMCTRL1    0x8e
+#define BCM590XX_REG_ENABLE    BIT(7)
+
+#define BCM590XX_RFLDOCTRL     0x96
+#define BCM590XX_CSRVOUT1      0xc0
+#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3)
+#define BCM590XX_SR_VSEL_MASK  GENMASK(5, 0)
+
+/* LDO regulator IDs */
+#define BCM590XX_REG_RFLDO     0
+#define BCM590XX_REG_CAMLDO1   1
+#define BCM590XX_REG_CAMLDO2   2
+#define BCM590XX_REG_SIMLDO1   3
+#define BCM590XX_REG_SIMLDO2   4
+#define BCM590XX_REG_SDLDO     5
+#define BCM590XX_REG_SDXLDO    6
+#define BCM590XX_REG_MMCLDO1   7
+#define BCM590XX_REG_MMCLDO2   8
+#define BCM590XX_REG_AUDLDO    9
+#define BCM590XX_REG_MICLDO    10
+#define BCM590XX_REG_USBLDO    11
+#define BCM590XX_REG_VIBLDO    12
+
+/* DCDC regulator IDs */
+#define BCM590XX_REG_CSR       13
+#define BCM590XX_REG_IOSR1     14
+#define BCM590XX_REG_IOSR2     15
+#define BCM590XX_REG_MSR       16
+#define BCM590XX_REG_SDSR1     17
+#define BCM590XX_REG_SDSR2     18
+#define BCM590XX_REG_VSR       19
+
+#define BCM590XX_NUM_REGS      20
+
+#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR)
+
+struct bcm590xx_board {
+       struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS];
+};
+
+/* LDO group A: supported voltages in microvolts */
+static const unsigned int ldo_a_table[] = {
+       1200000, 1800000, 2500000, 2700000, 2800000,
+       2900000, 3000000, 3300000,
+};
+
+/* LDO group C: supported voltages in microvolts */
+static const unsigned int ldo_c_table[] = {
+       3100000, 1800000, 2500000, 2700000, 2800000,
+       2900000, 3000000, 3300000,
+};
+
+/* DCDC group CSR: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_csr_ranges[] = {
+       REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
+       REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000),
+       REGULATOR_LINEAR_RANGE(900000, 56, 63, 0),
+};
+
+/* DCDC group IOSR1: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_iosr1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000),
+       REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0),
+       REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0),
+       REGULATOR_LINEAR_RANGE(900000, 54, 63, 0),
+};
+
+/* DCDC group SDSR1: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_sdsr1_ranges[] = {
+       REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
+       REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0),
+       REGULATOR_LINEAR_RANGE(900000, 52, 63, 0),
+};
+
+struct bcm590xx_info {
+       const char *name;
+       const char *vin_name;
+       u8 n_voltages;
+       const unsigned int *volt_table;
+       u8 n_linear_ranges;
+       const struct regulator_linear_range *linear_ranges;
+};
+
+#define BCM590XX_REG_TABLE(_name, _table) \
+       { \
+               .name = #_name, \
+               .n_voltages = ARRAY_SIZE(_table), \
+               .volt_table = _table, \
+       }
+
+#define BCM590XX_REG_RANGES(_name, _ranges) \
+       { \
+               .name = #_name, \
+               .n_linear_ranges = ARRAY_SIZE(_ranges), \
+               .linear_ranges = _ranges, \
+       }
+
+static struct bcm590xx_info bcm590xx_regs[] = {
+       BCM590XX_REG_TABLE(rfldo, ldo_a_table),
+       BCM590XX_REG_TABLE(camldo1, ldo_c_table),
+       BCM590XX_REG_TABLE(camldo2, ldo_c_table),
+       BCM590XX_REG_TABLE(simldo1, ldo_a_table),
+       BCM590XX_REG_TABLE(simldo2, ldo_a_table),
+       BCM590XX_REG_TABLE(sdldo, ldo_c_table),
+       BCM590XX_REG_TABLE(sdxldo, ldo_a_table),
+       BCM590XX_REG_TABLE(mmcldo1, ldo_a_table),
+       BCM590XX_REG_TABLE(mmcldo2, ldo_a_table),
+       BCM590XX_REG_TABLE(audldo, ldo_a_table),
+       BCM590XX_REG_TABLE(micldo, ldo_a_table),
+       BCM590XX_REG_TABLE(usbldo, ldo_a_table),
+       BCM590XX_REG_TABLE(vibldo, ldo_c_table),
+       BCM590XX_REG_RANGES(csr, dcdc_csr_ranges),
+       BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges),
+       BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges),
+       BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges),
+       BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges),
+       BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges),
+       BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges),
+};
+
+struct bcm590xx_reg {
+       struct regulator_desc *desc;
+       struct bcm590xx *mfd;
+       struct bcm590xx_info **info;
+};
+
+static int bcm590xx_get_vsel_register(int id)
+{
+       if (BCM590XX_REG_IS_LDO(id))
+               return BCM590XX_RFLDOCTRL + id;
+       else
+               return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3;
+}
+
+static int bcm590xx_get_enable_register(int id)
+{
+       int reg = 0;
+
+       if (BCM590XX_REG_IS_LDO(id))
+               reg = BCM590XX_RFLDOPMCTRL1 + id * 2;
+       else
+               switch (id) {
+               case BCM590XX_REG_CSR:
+                       reg = BCM590XX_CSRPMCTRL1;
+                       break;
+               case BCM590XX_REG_IOSR1:
+                       reg = BCM590XX_IOSR1PMCTRL1;
+                       break;
+               case BCM590XX_REG_IOSR2:
+                       reg = BCM590XX_IOSR2PMCTRL1;
+                       break;
+               case BCM590XX_REG_MSR:
+                       reg = BCM590XX_MSRPMCTRL1;
+                       break;
+               case BCM590XX_REG_SDSR1:
+                       reg = BCM590XX_SDSR1PMCTRL1;
+                       break;
+               case BCM590XX_REG_SDSR2:
+                       reg = BCM590XX_SDSR2PMCTRL1;
+                       break;
+               };
+
+       return reg;
+}
+
+static struct regulator_ops bcm590xx_ops_ldo = {
+       .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,
+       .list_voltage           = regulator_list_voltage_table,
+       .map_voltage            = regulator_map_voltage_iterate,
+};
+
+static struct regulator_ops bcm590xx_ops_dcdc = {
+       .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,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
+};
+
+#define BCM590XX_MATCH(_name, _id) \
+       { \
+               .name = #_name, \
+               .driver_data = (void *)&bcm590xx_regs[BCM590XX_REG_##_id], \
+       }
+
+static struct of_regulator_match bcm590xx_matches[] = {
+       BCM590XX_MATCH(rfldo, RFLDO),
+       BCM590XX_MATCH(camldo1, CAMLDO1),
+       BCM590XX_MATCH(camldo2, CAMLDO2),
+       BCM590XX_MATCH(simldo1, SIMLDO1),
+       BCM590XX_MATCH(simldo2, SIMLDO2),
+       BCM590XX_MATCH(sdldo, SDLDO),
+       BCM590XX_MATCH(sdxldo, SDXLDO),
+       BCM590XX_MATCH(mmcldo1, MMCLDO1),
+       BCM590XX_MATCH(mmcldo2, MMCLDO2),
+       BCM590XX_MATCH(audldo, AUDLDO),
+       BCM590XX_MATCH(micldo, MICLDO),
+       BCM590XX_MATCH(usbldo, USBLDO),
+       BCM590XX_MATCH(vibldo, VIBLDO),
+       BCM590XX_MATCH(csr, CSR),
+       BCM590XX_MATCH(iosr1, IOSR1),
+       BCM590XX_MATCH(iosr2, IOSR2),
+       BCM590XX_MATCH(msr, MSR),
+       BCM590XX_MATCH(sdsr1, SDSR1),
+       BCM590XX_MATCH(sdsr2, SDSR2),
+       BCM590XX_MATCH(vsr, VSR),
+};
+
+static struct bcm590xx_board *bcm590xx_parse_dt_reg_data(
+               struct platform_device *pdev,
+               struct of_regulator_match **bcm590xx_reg_matches)
+{
+       struct bcm590xx_board *data;
+       struct device_node *np = pdev->dev.parent->of_node;
+       struct device_node *regulators;
+       struct of_regulator_match *matches = bcm590xx_matches;
+       int count = ARRAY_SIZE(bcm590xx_matches);
+       int idx = 0;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "of node not found\n");
+               return NULL;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(&pdev->dev, "failed to allocate regulator board data\n");
+               return NULL;
+       }
+
+       np = of_node_get(np);
+       regulators = of_get_child_by_name(np, "regulators");
+       if (!regulators) {
+               dev_warn(&pdev->dev, "regulator node not found\n");
+               return NULL;
+       }
+
+       ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+       of_node_put(regulators);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+                       ret);
+               return NULL;
+       }
+
+       *bcm590xx_reg_matches = matches;
+
+       for (idx = 0; idx < count; idx++) {
+               if (!matches[idx].init_data || !matches[idx].of_node)
+                       continue;
+
+               data->bcm590xx_pmu_init_data[idx] = matches[idx].init_data;
+       }
+
+       return data;
+}
+
+static int bcm590xx_probe(struct platform_device *pdev)
+{
+       struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent);
+       struct bcm590xx_board *pmu_data = NULL;
+       struct bcm590xx_reg *pmu;
+       struct regulator_config config = { };
+       struct bcm590xx_info *info;
+       struct regulator_init_data *reg_data;
+       struct regulator_dev *rdev;
+       struct of_regulator_match *bcm590xx_reg_matches = NULL;
+       int i;
+
+       pmu_data = bcm590xx_parse_dt_reg_data(pdev,
+                                             &bcm590xx_reg_matches);
+
+       pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
+       if (!pmu) {
+               dev_err(&pdev->dev, "Memory allocation failed for pmu\n");
+               return -ENOMEM;
+       }
+
+       pmu->mfd = bcm590xx;
+
+       platform_set_drvdata(pdev, pmu);
+
+       pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
+                       sizeof(struct regulator_desc), GFP_KERNEL);
+       if (!pmu->desc) {
+               dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+               return -ENOMEM;
+       }
+
+       pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
+                       sizeof(struct bcm590xx_info *), GFP_KERNEL);
+       if (!pmu->info) {
+               dev_err(&pdev->dev, "Memory alloc fails for info\n");
+               return -ENOMEM;
+       }
+
+       info = bcm590xx_regs;
+
+       for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) {
+               if (pmu_data)
+                       reg_data = pmu_data->bcm590xx_pmu_init_data[i];
+               else
+                       reg_data = NULL;
+
+               /* Register the regulators */
+               pmu->info[i] = info;
+
+               pmu->desc[i].name = info->name;
+               pmu->desc[i].supply_name = info->vin_name;
+               pmu->desc[i].id = i;
+               pmu->desc[i].volt_table = info->volt_table;
+               pmu->desc[i].n_voltages = info->n_voltages;
+               pmu->desc[i].linear_ranges = info->linear_ranges;
+               pmu->desc[i].n_linear_ranges = info->n_linear_ranges;
+
+               if (BCM590XX_REG_IS_LDO(i)) {
+                       pmu->desc[i].ops = &bcm590xx_ops_ldo;
+                       pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK;
+               } else {
+                       pmu->desc[i].ops = &bcm590xx_ops_dcdc;
+                       pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK;
+               }
+
+               pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i);
+               pmu->desc[i].enable_is_inverted = true;
+               pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE;
+               pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i);
+               pmu->desc[i].type = REGULATOR_VOLTAGE;
+               pmu->desc[i].owner = THIS_MODULE;
+
+               config.dev = bcm590xx->dev;
+               config.init_data = reg_data;
+               config.driver_data = pmu;
+               config.regmap = bcm590xx->regmap;
+
+               if (bcm590xx_reg_matches)
+                       config.of_node = bcm590xx_reg_matches[i].of_node;
+
+               rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(bcm590xx->dev,
+                               "failed to register %s regulator\n",
+                               pdev->name);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver bcm590xx_regulator_driver = {
+       .driver = {
+               .name = "bcm590xx-vregs",
+               .owner = THIS_MODULE,
+       },
+       .probe = bcm590xx_probe,
+};
+module_platform_driver(bcm590xx_regulator_driver);
+
+MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
+MODULE_DESCRIPTION("BCM590xx voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bcm590xx-vregs");
index d1ac4caaf1b05d4b68dd4bd986355dc59263c6fd..bac485acc7f37dd83d472b4601daa7ef814cb30d 100644 (file)
@@ -953,6 +953,8 @@ static int machine_constraints_current(struct regulator_dev *rdev,
        return 0;
 }
 
+static int _regulator_do_enable(struct regulator_dev *rdev);
+
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1013,10 +1015,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,
        /* If the constraints say the regulator should be on at this point
         * and we have control then make sure it is enabled.
         */
-       if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
-           ops->enable) {
-               ret = ops->enable(rdev);
-               if (ret < 0) {
+       if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+               ret = _regulator_do_enable(rdev);
+               if (ret < 0 && ret != -EINVAL) {
                        rdev_err(rdev, "failed to enable\n");
                        goto out;
                }
@@ -1907,8 +1908,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
 
        trace_regulator_disable_complete(rdev_get_name(rdev));
 
-       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
-                            NULL);
        return 0;
 }
 
@@ -1932,6 +1931,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
                                rdev_err(rdev, "failed to disable\n");
                                return ret;
                        }
+                       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+                                       NULL);
                }
 
                rdev->use_count = 0;
@@ -1984,20 +1985,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
-       /* force disable */
-       if (rdev->desc->ops->disable) {
-               /* ah well, who wants to live forever... */
-               ret = rdev->desc->ops->disable(rdev);
-               if (ret < 0) {
-                       rdev_err(rdev, "failed to force disable\n");
-                       return ret;
-               }
-               /* notify other consumers that power has been forced off */
-               _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
-                       REGULATOR_EVENT_DISABLE, NULL);
+       ret = _regulator_do_disable(rdev);
+       if (ret < 0) {
+               rdev_err(rdev, "failed to force disable\n");
+               return ret;
        }
 
-       return ret;
+       _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+                       REGULATOR_EVENT_DISABLE, NULL);
+
+       return 0;
 }
 
 /**
@@ -2402,6 +2399,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
        int old_min_uV, old_max_uV;
+       int current_uV;
 
        mutex_lock(&rdev->mutex);
 
@@ -2412,6 +2410,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
        if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
                goto out;
 
+       /* If we're trying to set a range that overlaps the current voltage,
+        * return succesfully even though the regulator does not support
+        * changing the voltage.
+        */
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+               current_uV = _regulator_get_voltage(rdev);
+               if (min_uV <= current_uV && current_uV <= max_uV) {
+                       regulator->min_uV = min_uV;
+                       regulator->max_uV = max_uV;
+                       goto out;
+               }
+       }
+
        /* sanity check */
        if (!rdev->desc->ops->set_voltage &&
            !rdev->desc->ops->set_voltage_sel) {
@@ -3630,23 +3641,18 @@ int regulator_suspend_finish(void)
 
        mutex_lock(&regulator_list_mutex);
        list_for_each_entry(rdev, &regulator_list, list) {
-               struct regulator_ops *ops = rdev->desc->ops;
-
                mutex_lock(&rdev->mutex);
-               if ((rdev->use_count > 0  || rdev->constraints->always_on) &&
-                               ops->enable) {
-                       error = ops->enable(rdev);
+               if (rdev->use_count > 0  || rdev->constraints->always_on) {
+                       error = _regulator_do_enable(rdev);
                        if (error)
                                ret = error;
                } else {
                        if (!have_full_constraints())
                                goto unlock;
-                       if (!ops->disable)
-                               goto unlock;
                        if (!_regulator_is_enabled(rdev))
                                goto unlock;
 
-                       error = ops->disable(rdev);
+                       error = _regulator_do_disable(rdev);
                        if (error)
                                ret = error;
                }
@@ -3820,7 +3826,7 @@ static int __init regulator_init_complete(void)
                ops = rdev->desc->ops;
                c = rdev->constraints;
 
-               if (!ops->disable || (c && c->always_on))
+               if (c && c->always_on)
                        continue;
 
                mutex_lock(&rdev->mutex);
@@ -3841,7 +3847,7 @@ static int __init regulator_init_complete(void)
                        /* We log since this may kill the system if it
                         * goes wrong. */
                        rdev_info(rdev, "disabling\n");
-                       ret = ops->disable(rdev);
+                       ret = _regulator_do_disable(rdev);
                        if (ret != 0)
                                rdev_err(rdev, "couldn't disable: %d\n", ret);
                } else {
index 3adeaeffc485c0abe791487531a1c8ed87f91400..fdb6ea8ae7e64dc73a7cb2cc4f16a8b43c533b72 100644 (file)
@@ -240,6 +240,31 @@ static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
        return ret;
 }
 
+static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+                                                unsigned int old_sel,
+                                                unsigned int new_sel)
+{
+       struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+       struct da9052_regulator_info *info = regulator->info;
+       int id = rdev_get_id(rdev);
+       int ret = 0;
+
+       /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling
+        * the activate bit.
+        */
+       switch (id) {
+       case DA9052_ID_BUCK1:
+       case DA9052_ID_BUCK2:
+       case DA9052_ID_BUCK3:
+       case DA9052_ID_LDO2:
+       case DA9052_ID_LDO3:
+               ret = (new_sel - old_sel) * info->step_uV / 6250;
+               break;
+       }
+
+       return ret;
+}
+
 static struct regulator_ops da9052_dcdc_ops = {
        .get_current_limit = da9052_dcdc_get_current_limit,
        .set_current_limit = da9052_dcdc_set_current_limit,
@@ -248,6 +273,7 @@ static struct regulator_ops da9052_dcdc_ops = {
        .map_voltage = da9052_map_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = da9052_regulator_set_voltage_sel,
+       .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -258,6 +284,7 @@ static struct regulator_ops da9052_ldo_ops = {
        .map_voltage = da9052_map_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = da9052_regulator_set_voltage_sel,
+       .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
@@ -401,7 +428,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
                if (!nproot)
                        return -ENODEV;
 
-               nproot = of_find_node_by_name(nproot, "regulators");
+               nproot = of_get_child_by_name(nproot, "regulators");
                if (!nproot)
                        return -ENODEV;
 
index b14ebdad5dd2508f30854ac97e2b803cb5fa6e03..9516317e1a9fbf45ea4bc3eff65170a24f070d8c 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
 
 #include <linux/mfd/da9055/core.h>
 #include <linux/mfd/da9055/reg.h>
@@ -446,6 +448,9 @@ static int da9055_gpio_init(struct da9055_regulator *regulator,
        struct da9055_regulator_info *info = regulator->info;
        int ret = 0;
 
+       if (!pdata)
+               return 0;
+
        if (pdata->gpio_ren && pdata->gpio_ren[id]) {
                char name[18];
                int gpio_mux = pdata->gpio_ren[id];
@@ -530,6 +535,59 @@ static inline struct da9055_regulator_info *find_regulator_info(int id)
        return NULL;
 }
 
+#ifdef CONFIG_OF
+static struct of_regulator_match da9055_reg_matches[] = {
+       { .name = "BUCK1", },
+       { .name = "BUCK2", },
+       { .name = "LDO1", },
+       { .name = "LDO2", },
+       { .name = "LDO3", },
+       { .name = "LDO4", },
+       { .name = "LDO5", },
+       { .name = "LDO6", },
+};
+
+static int da9055_regulator_dt_init(struct platform_device *pdev,
+                                   struct da9055_regulator *regulator,
+                                   struct regulator_config *config,
+                                   int regid)
+{
+       struct device_node *nproot, *np;
+       int ret;
+
+       nproot = of_node_get(pdev->dev.parent->of_node);
+       if (!nproot)
+               return -ENODEV;
+
+       np = of_get_child_by_name(nproot, "regulators");
+       if (!np)
+               return -ENODEV;
+
+       ret = of_regulator_match(&pdev->dev, np, &da9055_reg_matches[regid], 1);
+       of_node_put(nproot);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error matching regulator: %d\n", ret);
+               return ret;
+       }
+
+       config->init_data = da9055_reg_matches[regid].init_data;
+       config->of_node = da9055_reg_matches[regid].of_node;
+
+       if (!config->of_node)
+               return -ENODEV;
+
+       return 0;
+}
+#else
+static inline int da9055_regulator_dt_init(struct platform_device *pdev,
+                                      struct da9055_regulator *regulator,
+                                      struct regulator_config *config,
+                                      int regid)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
 static int da9055_regulator_probe(struct platform_device *pdev)
 {
        struct regulator_config config = { };
@@ -538,9 +596,6 @@ static int da9055_regulator_probe(struct platform_device *pdev)
        struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
        int ret, irq;
 
-       if (pdata == NULL || pdata->regulators[pdev->id] == NULL)
-               return -ENODEV;
-
        regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator),
                                 GFP_KERNEL);
        if (!regulator)
@@ -557,8 +612,14 @@ static int da9055_regulator_probe(struct platform_device *pdev)
        config.driver_data = regulator;
        config.regmap = da9055->regmap;
 
-       if (pdata && pdata->regulators)
+       if (pdata && pdata->regulators) {
                config.init_data = pdata->regulators[pdev->id];
+       } else {
+               ret = da9055_regulator_dt_init(pdev, regulator, &config,
+                                              pdev->id);
+               if (ret < 0)
+                       return ret;
+       }
 
        ret = da9055_gpio_init(regulator, &config, pdata, pdev->id);
        if (ret < 0)
index 91e99a2c8dc14354c4f60368f025fef15d78786e..7c9461d13313ea1c4d1ddd86d3cf7e6ac783b7ee 100644 (file)
@@ -365,7 +365,7 @@ static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 
        sel = regulator_map_voltage_linear(rdev, uV, uV);
        if (sel < 0)
-               return -EINVAL;
+               return sel;
 
        sel <<= ffs(rdev->desc->vsel_mask) - 1;
 
@@ -666,7 +666,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
        struct device_node *node;
        int i, n, num;
 
-       node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+       node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
        if (!node) {
                dev_err(&pdev->dev, "Regulators device node not found\n");
                return ERR_PTR(-ENODEV);
@@ -674,6 +674,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
 
        num = of_regulator_match(&pdev->dev, node, da9063_matches,
                                 ARRAY_SIZE(da9063_matches));
+       of_node_put(node);
        if (num < 0) {
                dev_err(&pdev->dev, "Failed to match regulators\n");
                return ERR_PTR(-EINVAL);
@@ -710,7 +711,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
                struct platform_device *pdev,
                struct of_regulator_match **da9063_reg_matches)
 {
-       da9063_reg_matches = NULL;
+       *da9063_reg_matches = NULL;
        return ERR_PTR(-ENODEV);
 }
 #endif
@@ -756,7 +757,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "Error while reading BUCKs configuration\n");
-               return -EIO;
+               return ret;
        }
        bcores_merged = val & DA9063_BCORE_MERGE;
        bmem_bio_merged = val & DA9063_BUCK_MERGE;
@@ -775,10 +776,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)
        size = sizeof(struct da9063_regulators) +
                n_regulators * sizeof(struct da9063_regulator);
        regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!regulators) {
-               dev_err(&pdev->dev, "No memory for regulators\n");
+       if (!regulators)
                return -ENOMEM;
-       }
 
        regulators->n_regulators = n_regulators;
        platform_set_drvdata(pdev, regulators);
index 6f5ecbe1132e7da4f02496672578ef2301285767..7a320dd11c46220bfff3869510f1abcd7903ae2d 100644 (file)
@@ -134,11 +134,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
        int error;
 
        chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
-       if (NULL == chip) {
-               dev_err(&i2c->dev,
-                       "Cannot kzalloc memory for regulator structure\n");
+       if (!chip)
                return -ENOMEM;
-       }
 
        chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
        if (IS_ERR(chip->regmap)) {
index 846acf240e486d138319cbf26ce9434b71e6bc6e..617c1adca816160b81edaf3a20b28bc84efca5d1 100644 (file)
@@ -263,6 +263,8 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
                        .ops    = &db8500_regulator_ops,
                        .type   = REGULATOR_VOLTAGE,
                        .owner  = THIS_MODULE,
+                       .fixed_uV = 1800000,
+                       .n_voltages = 1,
                },
                .exclude_from_power_state = true,
        },
index ce89f7848a57f00d58c6f879cb2b3157d28fd303..2d16b9f16de73f5ce42ffb2370bba98c9bccf20b 100644 (file)
@@ -78,6 +78,7 @@ static struct ux500_regulator_debug {
 void ux500_regulator_suspend_debug(void)
 {
        int i;
+
        for (i = 0; i < rdebug.num_regulators; i++)
                rdebug.state_before_suspend[i] =
                        rdebug.regulator_array[i].is_enabled;
@@ -86,6 +87,7 @@ void ux500_regulator_suspend_debug(void)
 void ux500_regulator_resume_debug(void)
 {
        int i;
+
        for (i = 0; i < rdebug.num_regulators; i++)
                rdebug.state_after_suspend[i] =
                        rdebug.regulator_array[i].is_enabled;
@@ -127,9 +129,9 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)
        int i;
 
        /* print dump header */
-       err = seq_printf(s, "ux500-regulator status:\n");
+       err = seq_puts(s, "ux500-regulator status:\n");
        if (err < 0)
-               dev_err(dev, "seq_printf overflow\n");
+               dev_err(dev, "seq_puts overflow\n");
 
        err = seq_printf(s, "%31s : %8s : %8s\n", "current",
                "before", "after");
@@ -202,18 +204,12 @@ ux500_regulator_debug_init(struct platform_device *pdev,
        rdebug.num_regulators = num_regulators;
 
        rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
-       if (!rdebug.state_before_suspend) {
-               dev_err(&pdev->dev,
-                       "could not allocate memory for saving state\n");
+       if (!rdebug.state_before_suspend)
                goto exit_destroy_power_state;
-       }
 
        rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
-       if (!rdebug.state_after_suspend) {
-               dev_err(&pdev->dev,
-                       "could not allocate memory for saving state\n");
+       if (!rdebug.state_after_suspend)
                goto exit_free;
-       }
 
        dbx500_regulator_testcase(regulator_info, num_regulators);
        return 0;
index df9f42524abb3fd1164f61e7bee4065985d59d24..2436db9e2ca35f60875ab56cc825050c0d6a3ff2 100644 (file)
 
 struct regulator_dev *dummy_regulator_rdev;
 
-static struct regulator_init_data dummy_initdata;
+static struct regulator_init_data dummy_initdata = {
+       .constraints = {
+               .always_on = 1,
+       },
+};
 
 static struct regulator_ops dummy_ops;
 
index 7ca3d9e3b0fe22e426fb5419d76b9a4089224c7f..714fd9a89aa137b7484e437ff5017374e834f191 100644 (file)
@@ -90,11 +90,11 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
                return 0;
        ret = regulator_map_voltage_linear(rdev, uV, uV);
        if (ret < 0)
-               return -EINVAL;
+               return ret;
        ret = regmap_update_bits(di->regmap, di->sleep_reg,
                                        VSEL_NSEL_MASK, ret);
        if (ret < 0)
-               return -EINVAL;
+               return ret;
        /* Cache the sleep voltage setting.
         * Might not be the real voltage which is rounded */
        di->sleep_vol_cache = uV;
@@ -244,10 +244,9 @@ static int fan53555_regulator_probe(struct i2c_client *client,
 
        di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
                                        GFP_KERNEL);
-       if (!di) {
-               dev_err(&client->dev, "Failed to allocate device info data!\n");
+       if (!di)
                return -ENOMEM;
-       }
+
        di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
        if (IS_ERR(di->regmap)) {
                dev_err(&client->dev, "Failed to allocate regmap!\n");
@@ -260,14 +259,14 @@ static int fan53555_regulator_probe(struct i2c_client *client,
        ret = regmap_read(di->regmap, FAN53555_ID1, &val);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to get chip ID!\n");
-               return -ENODEV;
+               return ret;
        }
        di->chip_id = val & DIE_ID;
        /* Get chip revision */
        ret = regmap_read(di->regmap, FAN53555_ID2, &val);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to get chip Rev!\n");
-               return -ENODEV;
+               return ret;
        }
        di->chip_rev = val & DIE_REV;
        dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
index 5ea64b94341c5f7a926b07d83536c9d4fe0dba32..c61f7e97e4f8c663f06837439eceb55bde63efca 100644 (file)
@@ -130,17 +130,15 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
 
        drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
                               GFP_KERNEL);
-       if (drvdata == NULL) {
-               dev_err(&pdev->dev, "Failed to allocate device data\n");
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!drvdata)
+               return -ENOMEM;
 
-       drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
+       drvdata->desc.name = devm_kstrdup(&pdev->dev,
+                                         config->supply_name,
+                                         GFP_KERNEL);
        if (drvdata->desc.name == NULL) {
                dev_err(&pdev->dev, "Failed to allocate supply name\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
        drvdata->desc.type = REGULATOR_VOLTAGE;
        drvdata->desc.owner = THIS_MODULE;
@@ -149,13 +147,13 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
        drvdata->desc.enable_time = config->startup_delay;
 
        if (config->input_supply) {
-               drvdata->desc.supply_name = kstrdup(config->input_supply,
-                                                       GFP_KERNEL);
+               drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
+                                           config->input_supply,
+                                           GFP_KERNEL);
                if (!drvdata->desc.supply_name) {
                        dev_err(&pdev->dev,
                                "Failed to allocate input supply\n");
-                       ret = -ENOMEM;
-                       goto err_name;
+                       return -ENOMEM;
                }
        }
 
@@ -186,11 +184,12 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
        cfg.driver_data = drvdata;
        cfg.of_node = pdev->dev.of_node;
 
-       drvdata->dev = regulator_register(&drvdata->desc, &cfg);
+       drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
+                                              &cfg);
        if (IS_ERR(drvdata->dev)) {
                ret = PTR_ERR(drvdata->dev);
                dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
-               goto err_input;
+               return ret;
        }
 
        platform_set_drvdata(pdev, drvdata);
@@ -199,24 +198,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
                drvdata->desc.fixed_uV);
 
        return 0;
-
-err_input:
-       kfree(drvdata->desc.supply_name);
-err_name:
-       kfree(drvdata->desc.name);
-err:
-       return ret;
-}
-
-static int reg_fixed_voltage_remove(struct platform_device *pdev)
-{
-       struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
-
-       regulator_unregister(drvdata->dev);
-       kfree(drvdata->desc.supply_name);
-       kfree(drvdata->desc.name);
-
-       return 0;
 }
 
 #if defined(CONFIG_OF)
@@ -229,7 +210,6 @@ MODULE_DEVICE_TABLE(of, fixed_of_match);
 
 static struct platform_driver regulator_fixed_voltage_driver = {
        .probe          = reg_fixed_voltage_probe,
-       .remove         = reg_fixed_voltage_remove,
        .driver         = {
                .name           = "reg-fixed-voltage",
                .owner          = THIS_MODULE,
index c0a1d00b78c932a6982961334f9e3e9501592c50..989b23b377c0d2bb511227749e871ce72f46398b 100644 (file)
@@ -136,7 +136,6 @@ static struct gpio_regulator_config *
 of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
 {
        struct gpio_regulator_config *config;
-       struct property *prop;
        const char *regtype;
        int proplen, gpio, i;
        int ret;
@@ -172,22 +171,35 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
        if (!config->gpios)
                return ERR_PTR(-ENOMEM);
 
+       proplen = of_property_count_u32_elems(np, "gpios-states");
+       /* optional property */
+       if (proplen < 0)
+               proplen = 0;
+
+       if (proplen > 0 && proplen != config->nr_gpios) {
+               dev_warn(dev, "gpios <-> gpios-states mismatch\n");
+               proplen = 0;
+       }
+
        for (i = 0; i < config->nr_gpios; i++) {
                gpio = of_get_named_gpio(np, "gpios", i);
                if (gpio < 0)
                        break;
                config->gpios[i].gpio = gpio;
+               if (proplen > 0) {
+                       of_property_read_u32_index(np, "gpios-states", i, &ret);
+                       if (ret)
+                               config->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
+               }
        }
 
        /* Fetch states. */
-       prop = of_find_property(np, "states", NULL);
-       if (!prop) {
+       proplen = of_property_count_u32_elems(np, "states");
+       if (proplen < 0) {
                dev_err(dev, "No 'states' property found\n");
                return ERR_PTR(-EINVAL);
        }
 
-       proplen = prop->length / sizeof(int);
-
        config->states = devm_kzalloc(dev,
                                sizeof(struct gpio_regulator_state)
                                * (proplen / 2),
@@ -196,10 +208,10 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
                return ERR_PTR(-ENOMEM);
 
        for (i = 0; i < proplen / 2; i++) {
-               config->states[i].value =
-                       be32_to_cpup((int *)prop->value + (i * 2));
-               config->states[i].gpios =
-                       be32_to_cpup((int *)prop->value + (i * 2 + 1));
+               of_property_read_u32_index(np, "states", i * 2,
+                                          &config->states[i].value);
+               of_property_read_u32_index(np, "states", i * 2 + 1,
+                                          &config->states[i].gpios);
        }
        config->nr_states = i;
 
@@ -239,10 +251,8 @@ static int gpio_regulator_probe(struct platform_device *pdev)
 
        drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),
                               GFP_KERNEL);
-       if (drvdata == NULL) {
-               dev_err(&pdev->dev, "Failed to allocate device data\n");
+       if (drvdata == NULL)
                return -ENOMEM;
-       }
 
        drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
        if (drvdata->desc.name == NULL) {
index e221a271ba56601d12f5fc3d14a09db967a7d292..cbc39096c78d436f8206aa7107811bc43da6fd20 100644 (file)
@@ -37,10 +37,17 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev)
        if (ret != 0)
                return ret;
 
-       if (rdev->desc->enable_is_inverted)
-               return (val & rdev->desc->enable_mask) == 0;
-       else
-               return (val & rdev->desc->enable_mask) != 0;
+       val &= rdev->desc->enable_mask;
+
+       if (rdev->desc->enable_is_inverted) {
+               if (rdev->desc->enable_val)
+                       return val != rdev->desc->enable_val;
+               return val == 0;
+       } else {
+               if (rdev->desc->enable_val)
+                       return val == rdev->desc->enable_val;
+               return val != 0;
+       }
 }
 EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
 
@@ -57,10 +64,13 @@ int regulator_enable_regmap(struct regulator_dev *rdev)
 {
        unsigned int val;
 
-       if (rdev->desc->enable_is_inverted)
-               val = 0;
-       else
-               val = rdev->desc->enable_mask;
+       if (rdev->desc->enable_is_inverted) {
+               val = rdev->desc->disable_val;
+       } else {
+               val = rdev->desc->enable_val;
+               if (!val)
+                       val = rdev->desc->enable_mask;
+       }
 
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask, val);
@@ -80,10 +90,13 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
 {
        unsigned int val;
 
-       if (rdev->desc->enable_is_inverted)
-               val = rdev->desc->enable_mask;
-       else
-               val = 0;
+       if (rdev->desc->enable_is_inverted) {
+               val = rdev->desc->enable_val;
+               if (!val)
+                       val = rdev->desc->enable_mask;
+       } else {
+               val = rdev->desc->disable_val;
+       }
 
        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  rdev->desc->enable_mask, val);
@@ -419,10 +432,13 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
 {
        unsigned int val;
 
-       if (enable)
-               val = rdev->desc->bypass_mask;
-       else
-               val = 0;
+       if (enable) {
+               val = rdev->desc->bypass_val_on;
+               if (!val)
+                       val = rdev->desc->bypass_mask;
+       } else {
+               val = rdev->desc->bypass_val_off;
+       }
 
        return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
                                  rdev->desc->bypass_mask, val);
index 3b1102b75071f9d9f73fa0b34db63e43f9784614..66fd2330dca043a2627c8443f090ba5822f5de14 100644 (file)
@@ -327,7 +327,7 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
                return -EIO;
        ret = i2c_smbus_read_byte_data(i2c, reg);
        if (ret < 0)
-               return -EIO;
+               return ret;
 
        *dest = ret;
        return 0;
index 2e4734ff79fce29eaa2cab621b2e13cfa565a0da..2e022aabd951264bdc575d6b32fbdaa148d77298 100644 (file)
@@ -211,7 +211,7 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)
 
        ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
        if (ret)
-               return -EINVAL;
+               return ret;
 
        val = (val & mask) >> shift;
        if (val >= size)
@@ -229,7 +229,7 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
        u8 addr, val;
 
        if (time_step_us < 0)
-               return -EINVAL;
+               return time_step_us;
 
        switch (rid) {
        case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
index e0619526708c88393069abf4411fa2ff9473e510..ed60baaeceeca79cc9ba2b9c770973d5039da3fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * max14577.c - Regulator driver for the Maxim 14577
  *
- * Copyright (C) 2013 Samsung Electronics
+ * Copyright (C) 2013,2014 Samsung Electronics
  * Krzysztof Kozlowski <k.kozlowski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/mfd/max14577-private.h>
 #include <linux/regulator/of_regulator.h>
 
-struct max14577_regulator {
-       struct device *dev;
-       struct max14577 *max14577;
-       struct regulator_dev **regulators;
-};
-
 static int max14577_reg_is_enabled(struct regulator_dev *rdev)
 {
        int rid = rdev_get_id(rdev);
index e242dd316d363bb7f4226f2abfdee051c4d095d3..d23d0577754ba64334659aba14fe6671aba2a38a 100644 (file)
@@ -46,8 +46,6 @@ struct max1586_data {
 
        unsigned int v3_curr_sel;
        unsigned int v6_curr_sel;
-
-       struct regulator_dev *rdev[0];
 };
 
 /*
@@ -162,14 +160,12 @@ static struct regulator_desc max1586_reg[] = {
 static int max1586_pmic_probe(struct i2c_client *client,
                                        const struct i2c_device_id *i2c_id)
 {
-       struct regulator_dev **rdev;
        struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        struct max1586_data *max1586;
        int i, id;
 
-       max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) +
-                       sizeof(struct regulator_dev *) * (MAX1586_V6 + 1),
+       max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data),
                        GFP_KERNEL);
        if (!max1586)
                return -ENOMEM;
@@ -186,8 +182,9 @@ static int max1586_pmic_probe(struct i2c_client *client,
        max1586->v3_curr_sel = 24; /* 1.3V */
        max1586->v6_curr_sel = 0;
 
-       rdev = max1586->rdev;
        for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) {
+               struct regulator_dev *rdev;
+
                id = pdata->subdevs[i].id;
                if (!pdata->subdevs[i].platform_data)
                        continue;
@@ -207,12 +204,12 @@ static int max1586_pmic_probe(struct i2c_client *client,
                config.init_data = pdata->subdevs[i].platform_data;
                config.driver_data = max1586;
 
-               rdev[i] = devm_regulator_register(&client->dev,
+               rdev = devm_regulator_register(&client->dev,
                                                  &max1586_reg[id], &config);
-               if (IS_ERR(rdev[i])) {
+               if (IS_ERR(rdev)) {
                        dev_err(&client->dev, "failed to register %s\n",
                                max1586_reg[id].name);
-                       return PTR_ERR(rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index ae001ccf26f42d952bec37c2a821c250e2307b3c..ef1af2debbd293af555cbcde4ed5c72d866ad47a 100644 (file)
@@ -65,7 +65,6 @@ enum max77686_ramp_rate {
 };
 
 struct max77686_data {
-       struct regulator_dev *rdev[MAX77686_REGULATORS];
        unsigned int opmode[MAX77686_REGULATORS];
 };
 
@@ -400,7 +399,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
        unsigned int i;
 
        pmic_np = iodev->dev->of_node;
-       regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
+       regulators_np = of_get_child_by_name(pmic_np, "voltage-regulators");
        if (!regulators_np) {
                dev_err(&pdev->dev, "could not find regulators sub-node\n");
                return -EINVAL;
@@ -410,8 +409,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
        rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
                             pdata->num_regulators, GFP_KERNEL);
        if (!rdata) {
-               dev_err(&pdev->dev,
-                       "could not allocate memory for regulator data\n");
+               of_node_put(regulators_np);
                return -ENOMEM;
        }
 
@@ -425,6 +423,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
        }
 
        pdata->regulators = rdata;
+       of_node_put(regulators_np);
 
        return 0;
 }
@@ -474,16 +473,18 @@ static int max77686_pmic_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, max77686);
 
        for (i = 0; i < MAX77686_REGULATORS; i++) {
+               struct regulator_dev *rdev;
+
                config.init_data = pdata->regulators[i].initdata;
                config.of_node = pdata->regulators[i].of_node;
 
                max77686->opmode[i] = regulators[i].enable_mask;
-               max77686->rdev[i] = devm_regulator_register(&pdev->dev,
+               rdev = devm_regulator_register(&pdev->dev,
                                                &regulators[i], &config);
-               if (IS_ERR(max77686->rdev[i])) {
+               if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev,
                                "regulator init failed for %d\n", i);
-                       return PTR_ERR(max77686->rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index 5fb899f461d0c47a666715fc6bf3813083ee17a3..653a58b49cdff81b3f3ab724bc05e8417d1c913d 100644 (file)
 
 #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)
@@ -170,19 +163,22 @@ static int max77693_pmic_dt_parse_rdata(struct device *dev,
        struct max77693_regulator_data *tmp;
        int i, matched = 0;
 
-       np = of_find_node_by_name(dev->parent->of_node, "regulators");
+       np = of_get_child_by_name(dev->parent->of_node, "regulators");
        if (!np)
                return -EINVAL;
 
        rmatch = devm_kzalloc(dev,
                 sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL);
-       if (!rmatch)
+       if (!rmatch) {
+               of_node_put(np);
                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));
+       of_node_put(np);
        if (matched <= 0)
                return matched;
        *rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL);
@@ -229,7 +225,6 @@ static int max77693_pmic_init_rdata(struct device *dev,
 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;
        struct regulator_config config;
@@ -240,39 +235,22 @@ static int max77693_pmic_probe(struct platform_device *pdev)
                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++) {
+       for (i = 0; i < num_rdata; i++) {
                int id = rdata[i].id;
+               struct regulator_dev *rdev;
 
                config.init_data = rdata[i].initdata;
                config.of_node = rdata[i].of_node;
 
-               max77693_pmic->rdev[i] = devm_regulator_register(&pdev->dev,
+               rdev = devm_regulator_register(&pdev->dev,
                                                &regulators[id], &config);
-               if (IS_ERR(max77693_pmic->rdev[i])) {
-                       dev_err(max77693_pmic->dev,
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev,
                                "Failed to initialize regulator-%d\n", id);
-                       return PTR_ERR(max77693_pmic->rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index 7f049c92ee52406bbbc7bd3e08573bdd89f25159..3172da847d248bfbb039162447d282ee99299abd 100644 (file)
@@ -49,7 +49,6 @@
 #define MAX8649_RAMP_DOWN      (1 << 1)
 
 struct max8649_regulator_info {
-       struct regulator_dev    *regulator;
        struct device           *dev;
        struct regmap           *regmap;
 
@@ -154,6 +153,7 @@ static int max8649_regulator_probe(struct i2c_client *client,
 {
        struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
        struct max8649_regulator_info *info = NULL;
+       struct regulator_dev *regulator;
        struct regulator_config config = { };
        unsigned int val;
        unsigned char data;
@@ -234,12 +234,12 @@ static int max8649_regulator_probe(struct i2c_client *client,
        config.driver_data = info;
        config.regmap = info->regmap;
 
-       info->regulator = devm_regulator_register(&client->dev, &dcdc_desc,
+       regulator = devm_regulator_register(&client->dev, &dcdc_desc,
                                                  &config);
-       if (IS_ERR(info->regulator)) {
+       if (IS_ERR(regulator)) {
                dev_err(info->dev, "failed to register regulator %s\n",
                        dcdc_desc.name);
-               return PTR_ERR(info->regulator);
+               return PTR_ERR(regulator);
        }
 
        return 0;
index 8d94d3d7f97f22336fb973d5659ed50b4a3e6a97..2fc4111887949e01e04b023d6065962853779d42 100644 (file)
@@ -81,16 +81,17 @@ enum {
 struct max8660 {
        struct i2c_client *client;
        u8 shadow_regs[MAX8660_N_REGS];         /* as chip is write only */
-       struct regulator_dev *rdev[];
 };
 
 static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
 {
-       static const u8 max8660_addresses[MAX8660_N_REGS] =
-         { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+       static const u8 max8660_addresses[MAX8660_N_REGS] = {
+        0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80
+       };
 
        int ret;
        u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+
        dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
                        max8660_addresses[reg], reg_val);
 
@@ -112,6 +113,7 @@ static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
        u8 val = max8660->shadow_regs[MAX8660_OVER1];
        u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+
        return !!(val & mask);
 }
 
@@ -119,6 +121,7 @@ static int max8660_dcdc_enable(struct regulator_dev *rdev)
 {
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
        u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+
        return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
 }
 
@@ -126,15 +129,16 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev)
 {
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
        u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+
        return max8660_write(max8660, MAX8660_OVER1, mask, 0);
 }
 
 static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
-
        u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
        u8 selector = max8660->shadow_regs[reg];
+
        return selector;
 }
 
@@ -207,6 +211,7 @@ static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
        u8 val = max8660->shadow_regs[MAX8660_OVER2];
        u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+
        return !!(val & mask);
 }
 
@@ -214,6 +219,7 @@ static int max8660_ldo67_enable(struct regulator_dev *rdev)
 {
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
        u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+
        return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
 }
 
@@ -221,15 +227,16 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev)
 {
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
        u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+
        return max8660_write(max8660, MAX8660_OVER2, mask, 0);
 }
 
 static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct max8660 *max8660 = rdev_get_drvdata(rdev);
-
        u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
        u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
        return selector;
 }
 
@@ -330,7 +337,7 @@ static int max8660_pdata_from_dt(struct device *dev,
        struct max8660_subdev_data *sub;
        struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)];
 
-       np = of_find_node_by_name(dev->of_node, "regulators");
+       np = of_get_child_by_name(dev->of_node, "regulators");
        if (!np) {
                dev_err(dev, "missing 'regulators' subnode in DT\n");
                return -EINVAL;
@@ -340,6 +347,7 @@ static int max8660_pdata_from_dt(struct device *dev,
                rmatch[i].name = max8660_reg[i].name;
 
        matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch));
+       of_node_put(np);
        if (matched <= 0)
                return matched;
 
@@ -373,7 +381,6 @@ static inline int max8660_pdata_from_dt(struct device *dev,
 static int max8660_probe(struct i2c_client *client,
                                   const struct i2c_device_id *i2c_id)
 {
-       struct regulator_dev **rdev;
        struct device *dev = &client->dev;
        struct max8660_platform_data *pdata = dev_get_platdata(dev);
        struct regulator_config config = { };
@@ -406,14 +413,11 @@ static int max8660_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       max8660 = devm_kzalloc(dev, sizeof(struct max8660) +
-                       sizeof(struct regulator_dev *) * MAX8660_V_END,
-                       GFP_KERNEL);
+       max8660 = devm_kzalloc(dev, sizeof(struct max8660), GFP_KERNEL);
        if (!max8660)
                return -ENOMEM;
 
        max8660->client = client;
-       rdev = max8660->rdev;
 
        if (pdata->en34_is_high) {
                /* Simulate always on */
@@ -481,6 +485,7 @@ static int max8660_probe(struct i2c_client *client,
 
        /* Finally register devices */
        for (i = 0; i < pdata->num_subdevs; i++) {
+               struct regulator_dev *rdev;
 
                id = pdata->subdevs[i].id;
 
@@ -489,13 +494,13 @@ static int max8660_probe(struct i2c_client *client,
                config.of_node = of_node[i];
                config.driver_data = max8660;
 
-               rdev[i] = devm_regulator_register(&client->dev,
+               rdev = devm_regulator_register(&client->dev,
                                                  &max8660_reg[id], &config);
-               if (IS_ERR(rdev[i])) {
-                       ret = PTR_ERR(rdev[i]);
+               if (IS_ERR(rdev)) {
+                       ret = PTR_ERR(rdev);
                        dev_err(&client->dev, "failed to register %s\n",
                                max8660_reg[id].name);
-                       return PTR_ERR(rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index 0c5fe6c6ac26eb22ba248c3b64bbe9c98129283b..9623e9e290bf91bb1b7a330946b6783e5bdc7707 100644 (file)
@@ -34,7 +34,6 @@
 
 struct max8907_regulator {
        struct regulator_desc desc[MAX8907_NUM_REGULATORS];
-       struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
 };
 
 #define REG_MBATT() \
@@ -231,7 +230,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
        if (!np)
                return 0;
 
-       regulators = of_find_node_by_name(np, "regulators");
+       regulators = of_get_child_by_name(np, "regulators");
        if (!regulators) {
                dev_err(&pdev->dev, "regulators node not found\n");
                return -EINVAL;
@@ -292,10 +291,9 @@ static int max8907_regulator_probe(struct platform_device *pdev)
                return ret;
 
        pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
-       if (!pmic) {
-               dev_err(&pdev->dev, "Failed to alloc pmic\n");
+       if (!pmic)
                return -ENOMEM;
-       }
+
        platform_set_drvdata(pdev, pmic);
 
        memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
@@ -311,6 +309,8 @@ static int max8907_regulator_probe(struct platform_device *pdev)
        }
 
        for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
+               struct regulator_dev *rdev;
+
                config.dev = pdev->dev.parent;
                if (pdata)
                        idata = pdata->init_data[i];
@@ -350,13 +350,13 @@ static int max8907_regulator_probe(struct platform_device *pdev)
                                pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
                }
 
-               pmic->rdev[i] = devm_regulator_register(&pdev->dev,
+               rdev = devm_regulator_register(&pdev->dev,
                                                &pmic->desc[i], &config);
-               if (IS_ERR(pmic->rdev[i])) {
+               if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev,
                                "failed to register %s regulator\n",
                                pmic->desc[i].name);
-                       return PTR_ERR(pmic->rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index 759510789e71db39b0b287f9849cea88827d50c4..dad2bcd14e962759d9f5e7b9ae579f6c1369b325 100644 (file)
@@ -36,9 +36,7 @@
 
 struct max8925_regulator_info {
        struct regulator_desc   desc;
-       struct regulator_dev    *regulator;
        struct i2c_client       *i2c;
-       struct max8925_chip     *chip;
 
        int     vol_reg;
        int     enable_reg;
@@ -251,10 +249,11 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
 {
        struct device_node *nproot, *np;
        int rcount;
+
        nproot = of_node_get(pdev->dev.parent->of_node);
        if (!nproot)
                return -ENODEV;
-       np = of_find_node_by_name(nproot, "regulators");
+       np = of_get_child_by_name(nproot, "regulators");
        if (!np) {
                dev_err(&pdev->dev, "failed to find regulators node\n");
                return -ENODEV;
@@ -264,7 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
                                &max8925_regulator_matches[ridx], 1);
        of_node_put(np);
        if (rcount < 0)
-               return -ENODEV;
+               return rcount;
        config->init_data =     max8925_regulator_matches[ridx].init_data;
        config->of_node = max8925_regulator_matches[ridx].of_node;
 
@@ -303,7 +302,6 @@ static int max8925_regulator_probe(struct platform_device *pdev)
                return -EINVAL;
        }
        ri->i2c = chip->i2c;
-       ri->chip = chip;
 
        config.dev = &pdev->dev;
        config.driver_data = ri;
index 788e5ae2af1b51464b16dca99c4d190a067cc67a..d920f5a32ec8e935bd5288b571dd9adb3076c319 100644 (file)
@@ -48,9 +48,7 @@ enum {
 
 struct max8952_data {
        struct i2c_client       *client;
-       struct device           *dev;
        struct max8952_platform_data *pdata;
-       struct regulator_dev    *rdev;
 
        bool vid0;
        bool vid1;
@@ -59,6 +57,7 @@ struct max8952_data {
 static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
 {
        int ret = i2c_smbus_read_byte_data(max8952->client, reg);
+
        if (ret > 0)
                ret &= 0xff;
 
@@ -144,10 +143,8 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
        int i;
 
        pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
-       if (!pd) {
-               dev_err(dev, "Failed to allocate platform data\n");
+       if (!pd)
                return NULL;
-       }
 
        pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0);
        pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1);
@@ -199,6 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
        struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        struct max8952_data *max8952;
+       struct regulator_dev *rdev;
 
        int ret = 0, err = 0;
 
@@ -219,10 +217,9 @@ static int max8952_pmic_probe(struct i2c_client *client,
                return -ENOMEM;
 
        max8952->client = client;
-       max8952->dev = &client->dev;
        max8952->pdata = pdata;
 
-       config.dev = max8952->dev;
+       config.dev = &client->dev;
        config.init_data = pdata->reg_data;
        config.driver_data = max8952;
        config.of_node = client->dev.of_node;
@@ -231,11 +228,11 @@ static int max8952_pmic_probe(struct i2c_client *client,
        if (pdata->reg_data->constraints.boot_on)
                config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
 
-       max8952->rdev = regulator_register(&regulator, &config);
+       rdev = devm_regulator_register(&client->dev, &regulator, &config);
 
-       if (IS_ERR(max8952->rdev)) {
-               ret = PTR_ERR(max8952->rdev);
-               dev_err(max8952->dev, "regulator init failed (%d)\n", ret);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
+               dev_err(&client->dev, "regulator init failed (%d)\n", ret);
                return ret;
        }
 
@@ -263,7 +260,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
                err = 3;
 
        if (err) {
-               dev_warn(max8952->dev, "VID0/1 gpio invalid: "
+               dev_warn(&client->dev, "VID0/1 gpio invalid: "
                                "DVS not available.\n");
                max8952->vid0 = 0;
                max8952->vid1 = 0;
@@ -274,7 +271,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
                /* Disable Pulldown of EN only */
                max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
 
-               dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1"
+               dev_err(&client->dev, "DVS modes disabled because VID0 and VID1"
                                " do not have proper controls.\n");
        } else {
                /*
@@ -321,9 +318,6 @@ static int max8952_pmic_remove(struct i2c_client *client)
 {
        struct max8952_data *max8952 = i2c_get_clientdata(client);
        struct max8952_platform_data *pdata = max8952->pdata;
-       struct regulator_dev *rdev = max8952->rdev;
-
-       regulator_unregister(rdev);
 
        gpio_free(pdata->gpio_vid0);
        gpio_free(pdata->gpio_vid1);
index 892aa1e5b96c65dc2d879be20b3bb97b290af67a..dbedf1768db0268f4f07f168bb89eb36f0c74429 100644 (file)
@@ -93,7 +93,6 @@
 struct max8973_chip {
        struct device *dev;
        struct regulator_desc desc;
-       struct regulator_dev *rdev;
        struct regmap *regmap;
        bool enable_external_control;
        int dvs_gpio;
@@ -379,10 +378,8 @@ static int max8973_probe(struct i2c_client *client,
        }
 
        max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL);
-       if (!max) {
-               dev_err(&client->dev, "Memory allocation for max failed\n");
+       if (!max)
                return -ENOMEM;
-       }
 
        max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config);
        if (IS_ERR(max->regmap)) {
@@ -474,7 +471,6 @@ static int max8973_probe(struct i2c_client *client,
                return ret;
        }
 
-       max->rdev = rdev;
        return 0;
 }
 
index 2d618fc9c1af51da55ebce43be2e7c62db8c3eab..90b4c530dee530b7255b21d238929d744de5abcd 100644 (file)
@@ -38,7 +38,6 @@ struct max8997_data {
        struct device *dev;
        struct max8997_dev *iodev;
        int num_regulators;
-       struct regulator_dev **rdev;
        int ramp_delay; /* in mV/us */
 
        bool buck1_gpiodvs;
@@ -924,7 +923,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
                return -ENODEV;
        }
 
-       regulators_np = of_find_node_by_name(pmic_np, "regulators");
+       regulators_np = of_get_child_by_name(pmic_np, "regulators");
        if (!regulators_np) {
                dev_err(&pdev->dev, "could not find regulators sub-node\n");
                return -EINVAL;
@@ -937,7 +936,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
                                pdata->num_regulators, GFP_KERNEL);
        if (!rdata) {
                of_node_put(regulators_np);
-               dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
                return -ENOMEM;
        }
 
@@ -1030,10 +1028,10 @@ static int max8997_pmic_probe(struct platform_device *pdev)
        struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct max8997_platform_data *pdata = iodev->pdata;
        struct regulator_config config = { };
-       struct regulator_dev **rdev;
+       struct regulator_dev *rdev;
        struct max8997_data *max8997;
        struct i2c_client *i2c;
-       int i, ret, size, nr_dvs;
+       int i, ret, nr_dvs;
        u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
 
        if (!pdata) {
@@ -1052,12 +1050,6 @@ static int max8997_pmic_probe(struct platform_device *pdev)
        if (!max8997)
                return -ENOMEM;
 
-       size = sizeof(struct regulator_dev *) * pdata->num_regulators;
-       max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!max8997->rdev)
-               return -ENOMEM;
-
-       rdev = max8997->rdev;
        max8997->dev = &pdev->dev;
        max8997->iodev = iodev;
        max8997->num_regulators = pdata->num_regulators;
@@ -1205,12 +1197,12 @@ static int max8997_pmic_probe(struct platform_device *pdev)
                config.driver_data = max8997;
                config.of_node = pdata->regulators[i].reg_node;
 
-               rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
-                                                 &config);
-               if (IS_ERR(rdev[i])) {
+               rdev = devm_regulator_register(&pdev->dev, &regulators[id],
+                                              &config);
+               if (IS_ERR(rdev)) {
                        dev_err(max8997->dev, "regulator init failed for %d\n",
                                        id);
-                       return PTR_ERR(rdev[i]);
+                       return PTR_ERR(rdev);
                }
        }
 
index ae3f0656feb00c406ca438642c051a6453ab9171..961091b46557a40cc4e20029c9056afd4a34e80b 100644 (file)
@@ -40,7 +40,6 @@ struct max8998_data {
        struct device           *dev;
        struct max8998_dev      *iodev;
        int                     num_regulators;
-       struct regulator_dev    **rdev;
        u8                      buck1_vol[4]; /* voltages for selection */
        u8                      buck2_vol[2];
        unsigned int            buck1_idx; /* index to last changed voltage */
@@ -674,8 +673,10 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
 
        rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
                                pdata->num_regulators, GFP_KERNEL);
-       if (!rdata)
+       if (!rdata) {
+               of_node_put(regulators_np);
                return -ENOMEM;
+       }
 
        pdata->regulators = rdata;
        for (i = 0; i < ARRAY_SIZE(regulators); ++i) {
@@ -692,6 +693,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
        }
        pdata->num_regulators = rdata - pdata->regulators;
 
+       of_node_put(reg_np);
+       of_node_put(regulators_np);
+
        ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
        if (ret)
                return -EINVAL;
@@ -741,10 +745,10 @@ static int max8998_pmic_probe(struct platform_device *pdev)
        struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct max8998_platform_data *pdata = iodev->pdata;
        struct regulator_config config = { };
-       struct regulator_dev **rdev;
+       struct regulator_dev *rdev;
        struct max8998_data *max8998;
        struct i2c_client *i2c;
-       int i, ret, size;
+       int i, ret;
        unsigned int v;
 
        if (!pdata) {
@@ -763,12 +767,6 @@ static int max8998_pmic_probe(struct platform_device *pdev)
        if (!max8998)
                return -ENOMEM;
 
-       size = sizeof(struct regulator_dev *) * pdata->num_regulators;
-       max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!max8998->rdev)
-               return -ENOMEM;
-
-       rdev = max8998->rdev;
        max8998->dev = &pdev->dev;
        max8998->iodev = iodev;
        max8998->num_regulators = pdata->num_regulators;
@@ -872,13 +870,12 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                config.init_data = pdata->regulators[i].initdata;
                config.driver_data = max8998;
 
-               rdev[i] = devm_regulator_register(&pdev->dev,
-                                                 &regulators[index], &config);
-               if (IS_ERR(rdev[i])) {
-                       ret = PTR_ERR(rdev[i]);
+               rdev = devm_regulator_register(&pdev->dev, &regulators[index],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       ret = PTR_ERR(rdev);
                        dev_err(max8998->dev, "regulator %s init failed (%d)\n",
                                                regulators[index].name, ret);
-                       rdev[i] = NULL;
                        return ret;
                }
        }
index da48592823020af8a10b025816a74aaea0226758..05b971726ffaa0700e9147c912c35a83ebef9fc6 100644 (file)
@@ -167,8 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
        struct device_node *parent;
        int num;
 
-       of_node_get(pdev->dev.parent->of_node);
-       parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+       if (!pdev->dev.parent->of_node)
+               return -ENODEV;
+
+       parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
        if (!parent)
                return -ENODEV;
 
@@ -187,8 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
        struct device_node *parent, *child;
        int i, parsed = 0;
 
-       of_node_get(pdev->dev.parent->of_node);
-       parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+       if (!pdev->dev.parent->of_node)
+               return NULL;
+
+       parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
        if (!parent)
                return NULL;
 
index ab174f20ca11f473c889848b1d7e6b7545a9e3ef..67e678c4301c4d1e6dd0d4b4fc5b6238231557cd 100644 (file)
@@ -56,6 +56,8 @@
 #define PFUZE100_VGEN5VOL      0x70
 #define PFUZE100_VGEN6VOL      0x71
 
+enum chips { PFUZE100, PFUZE200 };
+
 struct pfuze_regulator {
        struct regulator_desc desc;
        unsigned char stby_reg;
@@ -63,6 +65,7 @@ struct pfuze_regulator {
 };
 
 struct pfuze_chip {
+       int     chip_id;
        struct regmap *regmap;
        struct device *dev;
        struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
@@ -78,21 +81,23 @@ static const int pfuze100_vsnvs[] = {
 };
 
 static const struct i2c_device_id pfuze_device_id[] = {
-       {.name = "pfuze100"},
-       {},
+       {.name = "pfuze100", .driver_data = PFUZE100},
+       {.name = "pfuze200", .driver_data = PFUZE200},
+       { }
 };
 MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
 
 static const struct of_device_id pfuze_dt_ids[] = {
-       { .compatible = "fsl,pfuze100" },
-       {},
+       { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
+       { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
+       { }
 };
 MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
 
 static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
 {
        struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
-       int id = rdev->desc->id;
+       int id = rdev_get_id(rdev);
        unsigned int ramp_bits;
        int ret;
 
@@ -139,14 +144,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
 
 };
 
-#define PFUZE100_FIXED_REG(_name, base, voltage)       \
-       [PFUZE100_ ## _name] = {        \
+#define PFUZE100_FIXED_REG(_chip, _name, base, voltage)        \
+       [_chip ## _ ## _name] = {       \
                .desc = {       \
                        .name = #_name, \
                        .n_voltages = 1,        \
                        .ops = &pfuze100_fixed_regulator_ops,   \
                        .type = REGULATOR_VOLTAGE,      \
-                       .id = PFUZE100_ ## _name,       \
+                       .id = _chip ## _ ## _name,      \
                        .owner = THIS_MODULE,   \
                        .min_uV = (voltage),    \
                        .enable_reg = (base),   \
@@ -154,14 +159,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
                },      \
        }
 
-#define PFUZE100_SW_REG(_name, base, min, max, step)   \
-       [PFUZE100_ ## _name] = {        \
+#define PFUZE100_SW_REG(_chip, _name, base, min, max, step)    \
+       [_chip ## _ ## _name] = {       \
                .desc = {       \
                        .name = #_name,\
                        .n_voltages = ((max) - (min)) / (step) + 1,     \
                        .ops = &pfuze100_sw_regulator_ops,      \
                        .type = REGULATOR_VOLTAGE,      \
-                       .id = PFUZE100_ ## _name,       \
+                       .id = _chip ## _ ## _name,      \
                        .owner = THIS_MODULE,   \
                        .min_uV = (min),        \
                        .uV_step = (step),      \
@@ -172,14 +177,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
                .stby_mask = 0x3f,      \
        }
 
-#define PFUZE100_SWB_REG(_name, base, mask, voltages)  \
-       [PFUZE100_ ## _name] = {        \
+#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages)   \
+       [_chip ## _ ##  _name] = {      \
                .desc = {       \
                        .name = #_name, \
                        .n_voltages = ARRAY_SIZE(voltages),     \
                        .ops = &pfuze100_swb_regulator_ops,     \
                        .type = REGULATOR_VOLTAGE,      \
-                       .id = PFUZE100_ ## _name,       \
+                       .id = _chip ## _ ## _name,      \
                        .owner = THIS_MODULE,   \
                        .volt_table = voltages, \
                        .vsel_reg = (base),     \
@@ -187,14 +192,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
                },      \
        }
 
-#define PFUZE100_VGEN_REG(_name, base, min, max, step) \
-       [PFUZE100_ ## _name] = {        \
+#define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step)  \
+       [_chip ## _ ## _name] = {       \
                .desc = {       \
                        .name = #_name, \
                        .n_voltages = ((max) - (min)) / (step) + 1,     \
                        .ops = &pfuze100_ldo_regulator_ops,     \
                        .type = REGULATOR_VOLTAGE,      \
-                       .id = PFUZE100_ ## _name,       \
+                       .id = _chip ## _ ## _name,      \
                        .owner = THIS_MODULE,   \
                        .min_uV = (min),        \
                        .uV_step = (step),      \
@@ -207,25 +212,45 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
                .stby_mask = 0x20,      \
        }
 
+/* PFUZE100 */
 static struct pfuze_regulator pfuze100_regulators[] = {
-       PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
-       PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
-       PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
-       PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
-       PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
-       PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
-       PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
-       PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
-       PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000),
-       PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
-       PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
-       PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
-       PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
-       PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
-       PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+       PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+       PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
+       PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
+       PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+       PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+       PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+       PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+       PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+       PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
+static struct pfuze_regulator pfuze200_regulators[] = {
+       PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+       PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+       PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+       PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+       PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+       PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+       PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+       PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
 };
 
+static struct pfuze_regulator *pfuze_regulators;
+
 #ifdef CONFIG_OF
+/* PFUZE100 */
 static struct of_regulator_match pfuze100_matches[] = {
        { .name = "sw1ab",      },
        { .name = "sw1c",       },
@@ -244,24 +269,56 @@ static struct of_regulator_match pfuze100_matches[] = {
        { .name = "vgen6",      },
 };
 
+/* PFUZE200 */
+static struct of_regulator_match pfuze200_matches[] = {
+
+       { .name = "sw1ab",      },
+       { .name = "sw2",        },
+       { .name = "sw3a",       },
+       { .name = "sw3b",       },
+       { .name = "swbst",      },
+       { .name = "vsnvs",      },
+       { .name = "vrefddr",    },
+       { .name = "vgen1",      },
+       { .name = "vgen2",      },
+       { .name = "vgen3",      },
+       { .name = "vgen4",      },
+       { .name = "vgen5",      },
+       { .name = "vgen6",      },
+};
+
+static struct of_regulator_match *pfuze_matches;
+
 static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
 {
        struct device *dev = chip->dev;
        struct device_node *np, *parent;
        int ret;
 
-       np = of_node_get(dev->parent->of_node);
+       np = of_node_get(dev->of_node);
        if (!np)
-               return 0;
+               return -EINVAL;
 
-       parent = of_find_node_by_name(np, "regulators");
+       parent = of_get_child_by_name(np, "regulators");
        if (!parent) {
                dev_err(dev, "regulators node not found\n");
                return -EINVAL;
        }
 
-       ret = of_regulator_match(dev, parent, pfuze100_matches,
-                                ARRAY_SIZE(pfuze100_matches));
+       switch (chip->chip_id) {
+       case PFUZE200:
+               pfuze_matches = pfuze200_matches;
+               ret = of_regulator_match(dev, parent, pfuze200_matches,
+                                        ARRAY_SIZE(pfuze200_matches));
+               break;
+
+       case PFUZE100:
+       default:
+               pfuze_matches = pfuze100_matches;
+               ret = of_regulator_match(dev, parent, pfuze100_matches,
+                                        ARRAY_SIZE(pfuze100_matches));
+               break;
+       }
 
        of_node_put(parent);
        if (ret < 0) {
@@ -275,12 +332,12 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
 
 static inline struct regulator_init_data *match_init_data(int index)
 {
-       return pfuze100_matches[index].init_data;
+       return pfuze_matches[index].init_data;
 }
 
 static inline struct device_node *match_of_node(int index)
 {
-       return pfuze100_matches[index].of_node;
+       return pfuze_matches[index].of_node;
 }
 #else
 static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
@@ -308,16 +365,14 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)
        if (ret)
                return ret;
 
-       switch (value & 0x0f) {
-       /*
-        * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
-        * as ID=8
-        */
-       case 0x8:
+       if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) {
+               /*
+                * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
+                * as ID=8 in PFUZE100
+                */
                dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
-       case 0x0:
-               break;
-       default:
+       } else if ((value & 0x0f) != pfuze_chip->chip_id) {
+               /* device id NOT match with your setting */
                dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
                return -ENODEV;
        }
@@ -353,17 +408,31 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
            dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        int i, ret;
+       const struct of_device_id *match;
+       u32 regulator_num;
+       u32 sw_check_start, sw_check_end;
 
        pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
                        GFP_KERNEL);
        if (!pfuze_chip)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, pfuze_chip);
-
-       memcpy(pfuze_chip->regulator_descs, pfuze100_regulators,
-               sizeof(pfuze_chip->regulator_descs));
+       if (client->dev.of_node) {
+               match = of_match_device(of_match_ptr(pfuze_dt_ids),
+                               &client->dev);
+               if (!match) {
+                       dev_err(&client->dev, "Error: No device match found\n");
+                       return -ENODEV;
+               }
+               pfuze_chip->chip_id = (int)(long)match->data;
+       } else if (id) {
+               pfuze_chip->chip_id = id->driver_data;
+       } else {
+               dev_err(&client->dev, "No dts match or id table match found\n");
+               return -ENODEV;
+       }
 
+       i2c_set_clientdata(client, pfuze_chip);
        pfuze_chip->dev = &client->dev;
 
        pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
@@ -380,11 +449,34 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                return ret;
        }
 
+       /* use the right regulators after identify the right device */
+       switch (pfuze_chip->chip_id) {
+       case PFUZE200:
+               pfuze_regulators = pfuze200_regulators;
+               regulator_num = ARRAY_SIZE(pfuze200_regulators);
+               sw_check_start = PFUZE200_SW2;
+               sw_check_end = PFUZE200_SW3B;
+               break;
+
+       case PFUZE100:
+       default:
+               pfuze_regulators = pfuze100_regulators;
+               regulator_num = ARRAY_SIZE(pfuze100_regulators);
+               sw_check_start = PFUZE100_SW2;
+               sw_check_end = PFUZE100_SW4;
+               break;
+       }
+       dev_info(&client->dev, "pfuze%s found.\n",
+               (pfuze_chip->chip_id == PFUZE100) ? "100" : "200");
+
+       memcpy(pfuze_chip->regulator_descs, pfuze_regulators,
+               sizeof(pfuze_chip->regulator_descs));
+
        ret = pfuze_parse_regulators_dt(pfuze_chip);
        if (ret)
                return ret;
 
-       for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) {
+       for (i = 0; i < regulator_num; i++) {
                struct regulator_init_data *init_data;
                struct regulator_desc *desc;
                int val;
@@ -397,7 +489,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                        init_data = match_init_data(i);
 
                /* SW2~SW4 high bit check and modify the voltage value table */
-               if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) {
+               if (i >= sw_check_start && i <= sw_check_end) {
                        regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
                        if (val & 0x40) {
                                desc->min_uV = 800000;
@@ -415,7 +507,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
                        devm_regulator_register(&client->dev, desc, &config);
                if (IS_ERR(pfuze_chip->regulators[i])) {
                        dev_err(&client->dev, "register regulator%s failed\n",
-                               pfuze100_regulators[i].desc.name);
+                               pfuze_regulators[i].desc.name);
                        return PTR_ERR(pfuze_chip->regulators[i]);
                }
        }
@@ -435,6 +527,6 @@ static struct i2c_driver pfuze_driver = {
 module_i2c_driver(pfuze_driver);
 
 MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
-MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("i2c:pfuze100-regulator");
index b58affb33143903d9044a8de2a614a8f20ee0e5f..4c414ae109ae5eb6edc44094e0c608a325a9cb63 100644 (file)
@@ -119,7 +119,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
 {
        struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
        struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
-       struct regulator_init_data *reg_data;
        struct regulator_config config = { };
        struct rc5t583_regulator *reg = NULL;
        struct rc5t583_regulator *regs;
@@ -135,19 +134,11 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
 
        regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX *
                        sizeof(struct rc5t583_regulator), GFP_KERNEL);
-       if (!regs) {
-               dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+       if (!regs)
                return -ENOMEM;
-       }
 
 
        for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) {
-               reg_data = pdata->reg_init_data[id];
-
-               /* No need to register if there is no regulator data */
-               if (!reg_data)
-                       continue;
-
                reg = &regs[id];
                ri = &rc5t583_reg_info[id];
                reg->reg_info = ri;
@@ -169,7 +160,7 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
 
 skip_ext_pwr_config:
                config.dev = &pdev->dev;
-               config.init_data = reg_data;
+               config.init_data = pdata->reg_init_data[id];
                config.driver_data = reg;
                config.regmap = rc5t583->regmap;
 
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
new file mode 100644 (file)
index 0000000..808b3aa
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ *             http://www.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.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.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/samsung/core.h>
+#include <linux/mfd/samsung/s2mpa01.h>
+
+#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
+
+struct s2mpa01_info {
+       int ramp_delay24;
+       int ramp_delay3;
+       int ramp_delay5;
+       int ramp_delay16;
+       int ramp_delay7;
+       int ramp_delay8910;
+};
+
+static int get_ramp_delay(int ramp_delay)
+{
+       unsigned char cnt = 0;
+
+       ramp_delay /= 6250;
+
+       while (true) {
+               ramp_delay = ramp_delay >> 1;
+               if (ramp_delay == 0)
+                       break;
+               cnt++;
+       }
+
+       if (cnt > 3)
+               cnt = 3;
+
+       return cnt;
+}
+
+static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+                                  unsigned int old_selector,
+                                  unsigned int new_selector)
+{
+       struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+       unsigned int ramp_delay = 0;
+       int old_volt, new_volt;
+
+       switch (rdev->desc->id) {
+       case S2MPA01_BUCK2:
+       case S2MPA01_BUCK4:
+               ramp_delay = s2mpa01->ramp_delay24;
+               break;
+       case S2MPA01_BUCK3:
+               ramp_delay = s2mpa01->ramp_delay3;
+               break;
+       case S2MPA01_BUCK5:
+               ramp_delay = s2mpa01->ramp_delay5;
+               break;
+       case S2MPA01_BUCK1:
+       case S2MPA01_BUCK6:
+               ramp_delay = s2mpa01->ramp_delay16;
+               break;
+       case S2MPA01_BUCK7:
+               ramp_delay = s2mpa01->ramp_delay7;
+               break;
+       case S2MPA01_BUCK8:
+       case S2MPA01_BUCK9:
+       case S2MPA01_BUCK10:
+               ramp_delay = s2mpa01->ramp_delay8910;
+               break;
+       }
+
+       if (ramp_delay == 0)
+               ramp_delay = rdev->desc->ramp_delay;
+
+       old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
+       new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
+
+       return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+
+static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+       struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+       unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2;
+       unsigned int ramp_enable = 1, enable_shift = 0;
+       int ret;
+
+       switch (rdev->desc->id) {
+       case S2MPA01_BUCK1:
+               enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               if (ramp_delay > s2mpa01->ramp_delay16)
+                       s2mpa01->ramp_delay16 = ramp_delay;
+               else
+                       ramp_delay = s2mpa01->ramp_delay16;
+
+               ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+               ramp_reg = S2MPA01_REG_RAMP1;
+               break;
+       case S2MPA01_BUCK2:
+               enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               if (ramp_delay > s2mpa01->ramp_delay24)
+                       s2mpa01->ramp_delay24 = ramp_delay;
+               else
+                       ramp_delay = s2mpa01->ramp_delay24;
+
+               ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+               ramp_reg = S2MPA01_REG_RAMP1;
+               break;
+       case S2MPA01_BUCK3:
+               enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               s2mpa01->ramp_delay3 = ramp_delay;
+               ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT;
+               ramp_reg = S2MPA01_REG_RAMP1;
+               break;
+       case S2MPA01_BUCK4:
+               enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               if (ramp_delay > s2mpa01->ramp_delay24)
+                       s2mpa01->ramp_delay24 = ramp_delay;
+               else
+                       ramp_delay = s2mpa01->ramp_delay24;
+
+               ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+               ramp_reg = S2MPA01_REG_RAMP1;
+               break;
+       case S2MPA01_BUCK5:
+               s2mpa01->ramp_delay5 = ramp_delay;
+               ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT;
+               break;
+       case S2MPA01_BUCK6:
+               if (ramp_delay > s2mpa01->ramp_delay16)
+                       s2mpa01->ramp_delay16 = ramp_delay;
+               else
+                       ramp_delay = s2mpa01->ramp_delay16;
+
+               ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+               break;
+       case S2MPA01_BUCK7:
+               s2mpa01->ramp_delay7 = ramp_delay;
+               ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT;
+               break;
+       case S2MPA01_BUCK8:
+       case S2MPA01_BUCK9:
+       case S2MPA01_BUCK10:
+               if (ramp_delay > s2mpa01->ramp_delay8910)
+                       s2mpa01->ramp_delay8910 = ramp_delay;
+               else
+                       ramp_delay = s2mpa01->ramp_delay8910;
+
+               ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT;
+               break;
+       default:
+               return 0;
+       }
+
+       if (!ramp_enable)
+               goto ramp_disable;
+
+       if (enable_shift) {
+               ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+                                       1 << enable_shift, 1 << enable_shift);
+               if (ret) {
+                       dev_err(&rdev->dev, "failed to enable ramp rate\n");
+                       return ret;
+               }
+       }
+
+       ramp_val = get_ramp_delay(ramp_delay);
+
+       return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,
+                                 ramp_val << ramp_shift);
+
+ramp_disable:
+       return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+                                 1 << enable_shift, 0);
+}
+
+static struct regulator_ops s2mpa01_ldo_ops = {
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+       .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,
+       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops s2mpa01_buck_ops = {
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+       .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,
+       .set_voltage_time_sel   = s2mpa01_regulator_set_voltage_time_sel,
+       .set_ramp_delay         = s2mpa01_set_ramp_delay,
+};
+
+#define regulator_desc_ldo1(num)       {               \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPA01_LDO##num,             \
+       .ops            = &s2mpa01_ldo_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPA01_LDO_MIN,              \
+       .uV_step        = S2MPA01_LDO_STEP1,            \
+       .n_voltages     = S2MPA01_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPA01_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPA01_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPA01_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPA01_ENABLE_MASK           \
+}
+#define regulator_desc_ldo2(num)       {               \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPA01_LDO##num,             \
+       .ops            = &s2mpa01_ldo_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPA01_LDO_MIN,              \
+       .uV_step        = S2MPA01_LDO_STEP2,            \
+       .n_voltages     = S2MPA01_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPA01_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPA01_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPA01_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPA01_ENABLE_MASK           \
+}
+
+#define regulator_desc_buck1_4(num)    {                       \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPA01_BUCK##num,                    \
+       .ops            = &s2mpa01_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPA01_BUCK_MIN1,                    \
+       .uV_step        = S2MPA01_BUCK_STEP1,                   \
+       .n_voltages     = S2MPA01_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPA01_RAMP_DELAY,                   \
+       .vsel_reg       = S2MPA01_REG_B1CTRL2 + (num - 1) * 2,  \
+       .vsel_mask      = S2MPA01_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPA01_REG_B1CTRL1 + (num - 1) * 2,  \
+       .enable_mask    = S2MPA01_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck5   {                               \
+       .name           = "BUCK5",                              \
+       .id             = S2MPA01_BUCK5,                        \
+       .ops            = &s2mpa01_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPA01_BUCK_MIN2,                    \
+       .uV_step        = S2MPA01_BUCK_STEP1,                   \
+       .n_voltages     = S2MPA01_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPA01_RAMP_DELAY,                   \
+       .vsel_reg       = S2MPA01_REG_B5CTRL2,                  \
+       .vsel_mask      = S2MPA01_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPA01_REG_B5CTRL1,                  \
+       .enable_mask    = S2MPA01_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck6_7(num)    {                       \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPA01_BUCK##num,                    \
+       .ops            = &s2mpa01_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPA01_BUCK_MIN1,                    \
+       .uV_step        = S2MPA01_BUCK_STEP1,                   \
+       .n_voltages     = S2MPA01_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPA01_RAMP_DELAY,                   \
+       .vsel_reg       = S2MPA01_REG_B6CTRL2 + (num - 6) * 2,  \
+       .vsel_mask      = S2MPA01_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPA01_REG_B6CTRL1 + (num - 6) * 2,  \
+       .enable_mask    = S2MPA01_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck8   {                               \
+       .name           = "BUCK8",                              \
+       .id             = S2MPA01_BUCK8,                        \
+       .ops            = &s2mpa01_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPA01_BUCK_MIN2,                    \
+       .uV_step        = S2MPA01_BUCK_STEP2,                   \
+       .n_voltages     = S2MPA01_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPA01_RAMP_DELAY,                   \
+       .vsel_reg       = S2MPA01_REG_B8CTRL2,                  \
+       .vsel_mask      = S2MPA01_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPA01_REG_B8CTRL1,                  \
+       .enable_mask    = S2MPA01_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck9   {                               \
+       .name           = "BUCK9",                              \
+       .id             = S2MPA01_BUCK9,                        \
+       .ops            = &s2mpa01_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPA01_BUCK_MIN4,                    \
+       .uV_step        = S2MPA01_BUCK_STEP2,                   \
+       .n_voltages     = S2MPA01_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPA01_RAMP_DELAY,                   \
+       .vsel_reg       = S2MPA01_REG_B9CTRL2,                  \
+       .vsel_mask      = S2MPA01_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPA01_REG_B9CTRL1,                  \
+       .enable_mask    = S2MPA01_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck10  {                               \
+       .name           = "BUCK10",                             \
+       .id             = S2MPA01_BUCK10,                       \
+       .ops            = &s2mpa01_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPA01_BUCK_MIN3,                    \
+       .uV_step        = S2MPA01_BUCK_STEP2,                   \
+       .n_voltages     = S2MPA01_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPA01_RAMP_DELAY,                   \
+       .vsel_reg       = S2MPA01_REG_B10CTRL2,                 \
+       .vsel_mask      = S2MPA01_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPA01_REG_B10CTRL1,                 \
+       .enable_mask    = S2MPA01_ENABLE_MASK                   \
+}
+
+static struct regulator_desc regulators[] = {
+       regulator_desc_ldo2(1),
+       regulator_desc_ldo1(2),
+       regulator_desc_ldo1(3),
+       regulator_desc_ldo1(4),
+       regulator_desc_ldo1(5),
+       regulator_desc_ldo2(6),
+       regulator_desc_ldo1(7),
+       regulator_desc_ldo1(8),
+       regulator_desc_ldo1(9),
+       regulator_desc_ldo1(10),
+       regulator_desc_ldo2(11),
+       regulator_desc_ldo1(12),
+       regulator_desc_ldo1(13),
+       regulator_desc_ldo1(14),
+       regulator_desc_ldo1(15),
+       regulator_desc_ldo1(16),
+       regulator_desc_ldo1(17),
+       regulator_desc_ldo1(18),
+       regulator_desc_ldo1(19),
+       regulator_desc_ldo1(20),
+       regulator_desc_ldo1(21),
+       regulator_desc_ldo2(22),
+       regulator_desc_ldo2(23),
+       regulator_desc_ldo1(24),
+       regulator_desc_ldo1(25),
+       regulator_desc_ldo1(26),
+       regulator_desc_buck1_4(1),
+       regulator_desc_buck1_4(2),
+       regulator_desc_buck1_4(3),
+       regulator_desc_buck1_4(4),
+       regulator_desc_buck5,
+       regulator_desc_buck6_7(6),
+       regulator_desc_buck6_7(7),
+       regulator_desc_buck8,
+       regulator_desc_buck9,
+       regulator_desc_buck10,
+};
+
+static int s2mpa01_pmic_probe(struct platform_device *pdev)
+{
+       struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX];
+       struct device_node *reg_np = NULL;
+       struct regulator_config config = { };
+       struct s2mpa01_info *s2mpa01;
+       int i;
+
+       s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL);
+       if (!s2mpa01)
+               return -ENOMEM;
+
+       for (i = 0; i < S2MPA01_REGULATOR_CNT; i++)
+               rdata[i].name = regulators[i].name;
+
+       if (iodev->dev->of_node) {
+               reg_np = of_get_child_by_name(iodev->dev->of_node,
+                                                       "regulators");
+                       if (!reg_np) {
+                               dev_err(&pdev->dev,
+                                       "could not find regulators sub-node\n");
+                               return -EINVAL;
+                       }
+
+               of_regulator_match(&pdev->dev, reg_np, rdata,
+                                               S2MPA01_REGULATOR_MAX);
+               of_node_put(reg_np);
+       }
+
+       platform_set_drvdata(pdev, s2mpa01);
+
+       config.dev = &pdev->dev;
+       config.regmap = iodev->regmap_pmic;
+       config.driver_data = s2mpa01;
+
+       for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {
+               struct regulator_dev *rdev;
+               if (pdata)
+                       config.init_data = pdata->regulators[i].initdata;
+               else
+                       config.init_data = rdata[i].init_data;
+
+               if (reg_np)
+                       config.of_node = rdata[i].of_node;
+
+               rdev = devm_regulator_register(&pdev->dev,
+                                               &regulators[i], &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "regulator init failed for %d\n",
+                               i);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id s2mpa01_pmic_id[] = {
+       { "s2mpa01-pmic", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id);
+
+static struct platform_driver s2mpa01_pmic_driver = {
+       .driver = {
+               .name = "s2mpa01-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = s2mpa01_pmic_probe,
+       .id_table = s2mpa01_pmic_id,
+};
+
+module_platform_driver(s2mpa01_pmic_driver);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver");
+MODULE_LICENSE("GPL");
index cd0b9e35a56d90ccc4fd78fe5fe781f2f009cd77..68fd54702edbf12436fbd5f7b7ebd2a6cb68e7ef 100644 (file)
@@ -1,13 +1,18 @@
 /*
  * s2mps11.c
  *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd
  *              http://www.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 free software; you can redistribute  it and/or modify it
+ * under  the terms of  the 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/regulator/of_regulator.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s2mps11.h>
-
-#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators)
+#include <linux/mfd/samsung/s2mps14.h>
 
 struct s2mps11_info {
-       struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
-
+       unsigned int rdev_num;
        int ramp_delay2;
        int ramp_delay34;
        int ramp_delay5;
        int ramp_delay16;
        int ramp_delay7810;
        int ramp_delay9;
+       /*
+        * One bit for each S2MPS14 regulator whether the suspend mode
+        * was enabled.
+        */
+       unsigned int s2mps14_suspend_state:30;
 };
 
 static int get_ramp_delay(int ramp_delay)
@@ -65,7 +73,7 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
        unsigned int ramp_delay = 0;
        int old_volt, new_volt;
 
-       switch (rdev->desc->id) {
+       switch (rdev_get_id(rdev)) {
        case S2MPS11_BUCK2:
                ramp_delay = s2mps11->ramp_delay2;
                break;
@@ -105,7 +113,7 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
        unsigned int ramp_enable = 1, enable_shift = 0;
        int ret;
 
-       switch (rdev->desc->id) {
+       switch (rdev_get_id(rdev)) {
        case S2MPS11_BUCK1:
                if (ramp_delay > s2mps11->ramp_delay16)
                        s2mps11->ramp_delay16 = ramp_delay;
@@ -236,7 +244,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .set_ramp_delay         = s2mps11_set_ramp_delay,
 };
 
-#define regulator_desc_ldo1(num)       {               \
+#define regulator_desc_s2mps11_ldo1(num)       {               \
        .name           = "LDO"#num,                    \
        .id             = S2MPS11_LDO##num,             \
        .ops            = &s2mps11_ldo_ops,             \
@@ -250,7 +258,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_reg     = S2MPS11_REG_L1CTRL + num - 1, \
        .enable_mask    = S2MPS11_ENABLE_MASK           \
 }
-#define regulator_desc_ldo2(num)       {               \
+#define regulator_desc_s2mps11_ldo2(num) {             \
        .name           = "LDO"#num,                    \
        .id             = S2MPS11_LDO##num,             \
        .ops            = &s2mps11_ldo_ops,             \
@@ -265,7 +273,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_mask    = S2MPS11_ENABLE_MASK           \
 }
 
-#define regulator_desc_buck1_4(num)    {                       \
+#define regulator_desc_s2mps11_buck1_4(num) {                  \
        .name           = "BUCK"#num,                           \
        .id             = S2MPS11_BUCK##num,                    \
        .ops            = &s2mps11_buck_ops,                    \
@@ -281,7 +289,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_mask    = S2MPS11_ENABLE_MASK                   \
 }
 
-#define regulator_desc_buck5   {                               \
+#define regulator_desc_s2mps11_buck5 {                         \
        .name           = "BUCK5",                              \
        .id             = S2MPS11_BUCK5,                        \
        .ops            = &s2mps11_buck_ops,                    \
@@ -297,7 +305,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_mask    = S2MPS11_ENABLE_MASK                   \
 }
 
-#define regulator_desc_buck6_8(num)    {                       \
+#define regulator_desc_s2mps11_buck6_8(num) {                  \
        .name           = "BUCK"#num,                           \
        .id             = S2MPS11_BUCK##num,                    \
        .ops            = &s2mps11_buck_ops,                    \
@@ -313,7 +321,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_mask    = S2MPS11_ENABLE_MASK                   \
 }
 
-#define regulator_desc_buck9   {                               \
+#define regulator_desc_s2mps11_buck9 {                         \
        .name           = "BUCK9",                              \
        .id             = S2MPS11_BUCK9,                        \
        .ops            = &s2mps11_buck_ops,                    \
@@ -329,7 +337,7 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_mask    = S2MPS11_ENABLE_MASK                   \
 }
 
-#define regulator_desc_buck10  {                               \
+#define regulator_desc_s2mps11_buck10 {                                \
        .name           = "BUCK10",                             \
        .id             = S2MPS11_BUCK10,                       \
        .ops            = &s2mps11_buck_ops,                    \
@@ -345,72 +353,252 @@ static struct regulator_ops s2mps11_buck_ops = {
        .enable_mask    = S2MPS11_ENABLE_MASK                   \
 }
 
-static struct regulator_desc regulators[] = {
-       regulator_desc_ldo2(1),
-       regulator_desc_ldo1(2),
-       regulator_desc_ldo1(3),
-       regulator_desc_ldo1(4),
-       regulator_desc_ldo1(5),
-       regulator_desc_ldo2(6),
-       regulator_desc_ldo1(7),
-       regulator_desc_ldo1(8),
-       regulator_desc_ldo1(9),
-       regulator_desc_ldo1(10),
-       regulator_desc_ldo2(11),
-       regulator_desc_ldo1(12),
-       regulator_desc_ldo1(13),
-       regulator_desc_ldo1(14),
-       regulator_desc_ldo1(15),
-       regulator_desc_ldo1(16),
-       regulator_desc_ldo1(17),
-       regulator_desc_ldo1(18),
-       regulator_desc_ldo1(19),
-       regulator_desc_ldo1(20),
-       regulator_desc_ldo1(21),
-       regulator_desc_ldo2(22),
-       regulator_desc_ldo2(23),
-       regulator_desc_ldo1(24),
-       regulator_desc_ldo1(25),
-       regulator_desc_ldo1(26),
-       regulator_desc_ldo2(27),
-       regulator_desc_ldo1(28),
-       regulator_desc_ldo1(29),
-       regulator_desc_ldo1(30),
-       regulator_desc_ldo1(31),
-       regulator_desc_ldo1(32),
-       regulator_desc_ldo1(33),
-       regulator_desc_ldo1(34),
-       regulator_desc_ldo1(35),
-       regulator_desc_ldo1(36),
-       regulator_desc_ldo1(37),
-       regulator_desc_ldo1(38),
-       regulator_desc_buck1_4(1),
-       regulator_desc_buck1_4(2),
-       regulator_desc_buck1_4(3),
-       regulator_desc_buck1_4(4),
-       regulator_desc_buck5,
-       regulator_desc_buck6_8(6),
-       regulator_desc_buck6_8(7),
-       regulator_desc_buck6_8(8),
-       regulator_desc_buck9,
-       regulator_desc_buck10,
+static const struct regulator_desc s2mps11_regulators[] = {
+       regulator_desc_s2mps11_ldo2(1),
+       regulator_desc_s2mps11_ldo1(2),
+       regulator_desc_s2mps11_ldo1(3),
+       regulator_desc_s2mps11_ldo1(4),
+       regulator_desc_s2mps11_ldo1(5),
+       regulator_desc_s2mps11_ldo2(6),
+       regulator_desc_s2mps11_ldo1(7),
+       regulator_desc_s2mps11_ldo1(8),
+       regulator_desc_s2mps11_ldo1(9),
+       regulator_desc_s2mps11_ldo1(10),
+       regulator_desc_s2mps11_ldo2(11),
+       regulator_desc_s2mps11_ldo1(12),
+       regulator_desc_s2mps11_ldo1(13),
+       regulator_desc_s2mps11_ldo1(14),
+       regulator_desc_s2mps11_ldo1(15),
+       regulator_desc_s2mps11_ldo1(16),
+       regulator_desc_s2mps11_ldo1(17),
+       regulator_desc_s2mps11_ldo1(18),
+       regulator_desc_s2mps11_ldo1(19),
+       regulator_desc_s2mps11_ldo1(20),
+       regulator_desc_s2mps11_ldo1(21),
+       regulator_desc_s2mps11_ldo2(22),
+       regulator_desc_s2mps11_ldo2(23),
+       regulator_desc_s2mps11_ldo1(24),
+       regulator_desc_s2mps11_ldo1(25),
+       regulator_desc_s2mps11_ldo1(26),
+       regulator_desc_s2mps11_ldo2(27),
+       regulator_desc_s2mps11_ldo1(28),
+       regulator_desc_s2mps11_ldo1(29),
+       regulator_desc_s2mps11_ldo1(30),
+       regulator_desc_s2mps11_ldo1(31),
+       regulator_desc_s2mps11_ldo1(32),
+       regulator_desc_s2mps11_ldo1(33),
+       regulator_desc_s2mps11_ldo1(34),
+       regulator_desc_s2mps11_ldo1(35),
+       regulator_desc_s2mps11_ldo1(36),
+       regulator_desc_s2mps11_ldo1(37),
+       regulator_desc_s2mps11_ldo1(38),
+       regulator_desc_s2mps11_buck1_4(1),
+       regulator_desc_s2mps11_buck1_4(2),
+       regulator_desc_s2mps11_buck1_4(3),
+       regulator_desc_s2mps11_buck1_4(4),
+       regulator_desc_s2mps11_buck5,
+       regulator_desc_s2mps11_buck6_8(6),
+       regulator_desc_s2mps11_buck6_8(7),
+       regulator_desc_s2mps11_buck6_8(8),
+       regulator_desc_s2mps11_buck9,
+       regulator_desc_s2mps11_buck10,
+};
+
+static int s2mps14_regulator_enable(struct regulator_dev *rdev)
+{
+       struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+       unsigned int val;
+
+       if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+               val = S2MPS14_ENABLE_SUSPEND;
+       else
+               val = rdev->desc->enable_mask;
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                       rdev->desc->enable_mask, val);
+}
+
+static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
+{
+       int ret;
+       unsigned int val;
+       struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+
+       /* LDO3 should be always on and does not support suspend mode */
+       if (rdev_get_id(rdev) == S2MPS14_LDO3)
+               return 0;
+
+       ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+       if (ret < 0)
+               return ret;
+
+       s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev));
+       /*
+        * Don't enable suspend mode if regulator is already disabled because
+        * this would effectively for a short time turn on the regulator after
+        * resuming.
+        * However we still want to toggle the suspend_state bit for regulator
+        * in case if it got enabled before suspending the system.
+        */
+       if (!(val & rdev->desc->enable_mask))
+               return 0;
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                       rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND);
+}
+
+static struct regulator_ops s2mps14_reg_ops = {
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = s2mps14_regulator_enable,
+       .disable                = regulator_disable_regmap,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
+       .set_suspend_disable    = s2mps14_regulator_set_suspend_disable,
+};
+
+#define regulator_desc_s2mps14_ldo1(num) {             \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPS14_LDO##num,             \
+       .ops            = &s2mps14_reg_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPS14_LDO_MIN_800MV,        \
+       .uV_step        = S2MPS14_LDO_STEP_25MV,        \
+       .n_voltages     = S2MPS14_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPS14_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPS14_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPS14_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPS14_ENABLE_MASK           \
+}
+#define regulator_desc_s2mps14_ldo2(num) {             \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPS14_LDO##num,             \
+       .ops            = &s2mps14_reg_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPS14_LDO_MIN_1800MV,       \
+       .uV_step        = S2MPS14_LDO_STEP_25MV,        \
+       .n_voltages     = S2MPS14_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPS14_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPS14_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPS14_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPS14_ENABLE_MASK           \
+}
+#define regulator_desc_s2mps14_ldo3(num) {             \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPS14_LDO##num,             \
+       .ops            = &s2mps14_reg_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPS14_LDO_MIN_800MV,        \
+       .uV_step        = S2MPS14_LDO_STEP_12_5MV,      \
+       .n_voltages     = S2MPS14_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPS14_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPS14_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPS14_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPS14_ENABLE_MASK           \
+}
+#define regulator_desc_s2mps14_buck1235(num) {                 \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPS14_BUCK##num,                    \
+       .ops            = &s2mps14_reg_ops,                     \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS14_BUCK1235_MIN_600MV,           \
+       .uV_step        = S2MPS14_BUCK1235_STEP_6_25MV,         \
+       .n_voltages     = S2MPS14_BUCK_N_VOLTAGES,              \
+       .linear_min_sel = S2MPS14_BUCK1235_START_SEL,           \
+       .ramp_delay     = S2MPS14_BUCK_RAMP_DELAY,              \
+       .vsel_reg       = S2MPS14_REG_B1CTRL2 + (num - 1) * 2,  \
+       .vsel_mask      = S2MPS14_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS14_REG_B1CTRL1 + (num - 1) * 2,  \
+       .enable_mask    = S2MPS14_ENABLE_MASK                   \
+}
+#define regulator_desc_s2mps14_buck4(num) {                    \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPS14_BUCK##num,                    \
+       .ops            = &s2mps14_reg_ops,                     \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS14_BUCK4_MIN_1400MV,             \
+       .uV_step        = S2MPS14_BUCK4_STEP_12_5MV,            \
+       .n_voltages     = S2MPS14_BUCK_N_VOLTAGES,              \
+       .linear_min_sel = S2MPS14_BUCK4_START_SEL,              \
+       .ramp_delay     = S2MPS14_BUCK_RAMP_DELAY,              \
+       .vsel_reg       = S2MPS14_REG_B1CTRL2 + (num - 1) * 2,  \
+       .vsel_mask      = S2MPS14_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS14_REG_B1CTRL1 + (num - 1) * 2,  \
+       .enable_mask    = S2MPS14_ENABLE_MASK                   \
+}
+
+static const struct regulator_desc s2mps14_regulators[] = {
+       regulator_desc_s2mps14_ldo3(1),
+       regulator_desc_s2mps14_ldo3(2),
+       regulator_desc_s2mps14_ldo1(3),
+       regulator_desc_s2mps14_ldo1(4),
+       regulator_desc_s2mps14_ldo3(5),
+       regulator_desc_s2mps14_ldo3(6),
+       regulator_desc_s2mps14_ldo1(7),
+       regulator_desc_s2mps14_ldo2(8),
+       regulator_desc_s2mps14_ldo3(9),
+       regulator_desc_s2mps14_ldo3(10),
+       regulator_desc_s2mps14_ldo1(11),
+       regulator_desc_s2mps14_ldo2(12),
+       regulator_desc_s2mps14_ldo2(13),
+       regulator_desc_s2mps14_ldo2(14),
+       regulator_desc_s2mps14_ldo2(15),
+       regulator_desc_s2mps14_ldo2(16),
+       regulator_desc_s2mps14_ldo2(17),
+       regulator_desc_s2mps14_ldo2(18),
+       regulator_desc_s2mps14_ldo1(19),
+       regulator_desc_s2mps14_ldo1(20),
+       regulator_desc_s2mps14_ldo1(21),
+       regulator_desc_s2mps14_ldo3(22),
+       regulator_desc_s2mps14_ldo1(23),
+       regulator_desc_s2mps14_ldo2(24),
+       regulator_desc_s2mps14_ldo2(25),
+       regulator_desc_s2mps14_buck1235(1),
+       regulator_desc_s2mps14_buck1235(2),
+       regulator_desc_s2mps14_buck1235(3),
+       regulator_desc_s2mps14_buck4(4),
+       regulator_desc_s2mps14_buck1235(5),
 };
 
 static int s2mps11_pmic_probe(struct platform_device *pdev)
 {
        struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-       struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
-       struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX];
+       struct sec_platform_data *pdata = iodev->pdata;
+       struct of_regulator_match *rdata = NULL;
        struct device_node *reg_np = NULL;
        struct regulator_config config = { };
        struct s2mps11_info *s2mps11;
-       int i, ret;
+       int i, ret = 0;
+       const struct regulator_desc *regulators;
+       enum sec_device_type dev_type;
 
        s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
                                GFP_KERNEL);
        if (!s2mps11)
                return -ENOMEM;
 
+       dev_type = platform_get_device_id(pdev)->driver_data;
+       switch (dev_type) {
+       case S2MPS11X:
+               s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
+               regulators = s2mps11_regulators;
+               break;
+       case S2MPS14X:
+               s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
+               regulators = s2mps14_regulators;
+               break;
+       default:
+               dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type);
+               return -EINVAL;
+       };
+
        if (!iodev->dev->of_node) {
                if (pdata) {
                        goto common_reg;
@@ -421,16 +609,22 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
                }
        }
 
-       for (i = 0; i < S2MPS11_REGULATOR_CNT; i++)
+       rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL);
+       if (!rdata)
+               return -ENOMEM;
+
+       for (i = 0; i < s2mps11->rdev_num; i++)
                rdata[i].name = regulators[i].name;
 
-       reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators");
+       reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators");
        if (!reg_np) {
                dev_err(&pdev->dev, "could not find regulators sub-node\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
-       of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX);
+       of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+       of_node_put(reg_np);
 
 common_reg:
        platform_set_drvdata(pdev, s2mps11);
@@ -438,7 +632,9 @@ common_reg:
        config.dev = &pdev->dev;
        config.regmap = iodev->regmap_pmic;
        config.driver_data = s2mps11;
-       for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+       for (i = 0; i < s2mps11->rdev_num; i++) {
+               struct regulator_dev *regulator;
+
                if (!reg_np) {
                        config.init_data = pdata->regulators[i].initdata;
                        config.of_node = pdata->regulators[i].reg_node;
@@ -447,21 +643,25 @@ common_reg:
                        config.of_node = rdata[i].of_node;
                }
 
-               s2mps11->rdev[i] = devm_regulator_register(&pdev->dev,
+               regulator = devm_regulator_register(&pdev->dev,
                                                &regulators[i], &config);
-               if (IS_ERR(s2mps11->rdev[i])) {
-                       ret = PTR_ERR(s2mps11->rdev[i]);
+               if (IS_ERR(regulator)) {
+                       ret = PTR_ERR(regulator);
                        dev_err(&pdev->dev, "regulator init failed for %d\n",
                                i);
-                       return ret;
+                       goto out;
                }
        }
 
-       return 0;
+out:
+       kfree(rdata);
+
+       return ret;
 }
 
 static const struct platform_device_id s2mps11_pmic_id[] = {
-       { "s2mps11-pmic", 0},
+       { "s2mps11-pmic", S2MPS11X},
+       { "s2mps14-pmic", S2MPS14X},
        { },
 };
 MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
@@ -489,5 +689,5 @@ module_exit(s2mps11_pmic_exit);
 
 /* Module information */
 MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver");
 MODULE_LICENSE("GPL");
index d958dfa051254866808fe6c36cf9db7184627b94..f05badabd69e99169a0adcb9f4d4d335891cafb8 100644 (file)
  *
  */
 
-#include <linux/bug.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/of_gpio.h>
-#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
@@ -170,12 +167,11 @@ static unsigned int s5m8767_opmode_reg[][4] = {
        {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
 };
 
-static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
-                               int *enable_ctrl)
+static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
+                               int *reg, int *enable_ctrl)
 {
-       int i, reg_id = rdev_get_id(rdev);
+       int i;
        unsigned int mode;
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
 
        switch (reg_id) {
        case S5M8767_LDO1 ... S5M8767_LDO2:
@@ -214,53 +210,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
        return 0;
 }
 
-static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int ret, reg;
-       int enable_ctrl;
-       unsigned int val;
-
-       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
-       if (ret == -EINVAL)
-               return 1;
-       else if (ret)
-               return ret;
-
-       ret = regmap_read(s5m8767->iodev->regmap_pmic, reg, &val);
-       if (ret)
-               return ret;
-
-       return (val & S5M8767_ENCTRL_MASK) == enable_ctrl;
-}
-
-static int s5m8767_reg_enable(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int ret, reg;
-       int enable_ctrl;
-
-       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
-       if (ret)
-               return ret;
-
-       return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
-                       S5M8767_ENCTRL_MASK, enable_ctrl);
-}
-
-static int s5m8767_reg_disable(struct regulator_dev *rdev)
-{
-       struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       int ret, reg, enable_ctrl;
-
-       ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
-       if (ret)
-               return ret;
-
-       return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
-                       S5M8767_ENCTRL_MASK, ~S5M8767_ENCTRL_MASK);
-}
-
 static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
 {
        int reg;
@@ -410,9 +359,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
 
 static struct regulator_ops s5m8767_ops = {
        .list_voltage           = regulator_list_voltage_linear,
-       .is_enabled             = s5m8767_reg_is_enabled,
-       .enable                 = s5m8767_reg_enable,
-       .disable                = s5m8767_reg_disable,
+       .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        = s5m8767_set_voltage_sel,
        .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
@@ -420,9 +369,9 @@ static struct regulator_ops s5m8767_ops = {
 
 static struct regulator_ops s5m8767_buck78_ops = {
        .list_voltage           = regulator_list_voltage_linear,
-       .is_enabled             = s5m8767_reg_is_enabled,
-       .enable                 = s5m8767_reg_enable,
-       .disable                = s5m8767_reg_disable,
+       .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,
 };
@@ -483,6 +432,66 @@ static struct regulator_desc regulators[] = {
        s5m8767_regulator_desc(BUCK9),
 };
 
+/*
+ * Enable GPIO control over BUCK9 in regulator_config for that regulator.
+ */
+static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
+               struct sec_regulator_data *rdata,
+               struct regulator_config *config)
+{
+       int i, mode = 0;
+
+       if (rdata->id != S5M8767_BUCK9)
+               return;
+
+       /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */
+       for (i = 0; i < s5m8767->num_regulators; i++) {
+               const struct sec_opmode_data *opmode = &s5m8767->opmode[i];
+               if (opmode->id == rdata->id) {
+                       mode = s5m8767_opmode_reg[rdata->id][opmode->mode];
+                       break;
+               }
+       }
+       if (mode != S5M8767_ENCTRL_USE_GPIO) {
+               dev_warn(s5m8767->dev,
+                               "ext-control for %s: mismatched op_mode (%x), ignoring\n",
+                               rdata->reg_node->name, mode);
+               return;
+       }
+
+       if (!gpio_is_valid(rdata->ext_control_gpio)) {
+               dev_warn(s5m8767->dev,
+                               "ext-control for %s: GPIO not valid, ignoring\n",
+                               rdata->reg_node->name);
+               return;
+       }
+
+       config->ena_gpio = rdata->ext_control_gpio;
+       config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+}
+
+/*
+ * Turn on GPIO control over BUCK9.
+ */
+static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
+               struct regulator_dev *rdev)
+{
+       int id = rdev_get_id(rdev);
+       int ret, reg, enable_ctrl;
+
+       if (id != S5M8767_BUCK9)
+               return -EINVAL;
+
+       ret = s5m8767_get_register(s5m8767, id, &reg, &enable_ctrl);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(s5m8767->iodev->regmap_pmic,
+                       reg, S5M8767_ENCTRL_MASK,
+                       S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT);
+}
+
+
 #ifdef CONFIG_OF
 static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
                        struct sec_platform_data *pdata,
@@ -520,6 +529,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
        return 0;
 }
 
+static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
+               struct sec_regulator_data *rdata,
+               struct device_node *reg_np)
+{
+       rdata->ext_control_gpio = of_get_named_gpio(reg_np,
+                       "s5m8767,pmic-ext-control-gpios", 0);
+       if (!gpio_is_valid(rdata->ext_control_gpio))
+               rdata->ext_control_gpio = 0;
+}
+
 static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                                        struct sec_platform_data *pdata)
 {
@@ -546,19 +565,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
 
        rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
                                pdata->num_regulators, GFP_KERNEL);
-       if (!rdata) {
-               dev_err(iodev->dev,
-                       "could not allocate memory for regulator data\n");
+       if (!rdata)
                return -ENOMEM;
-       }
 
        rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
                                pdata->num_regulators, GFP_KERNEL);
-       if (!rmode) {
-               dev_err(iodev->dev,
-                       "could not allocate memory for regulator mode\n");
+       if (!rmode)
                return -ENOMEM;
-       }
 
        pdata->regulators = rdata;
        pdata->opmode = rmode;
@@ -574,6 +587,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                        continue;
                }
 
+               s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
+
                rdata->id = i;
                rdata->initdata = of_get_regulator_init_data(
                                                &pdev->dev, reg_np);
@@ -922,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
        for (i = 0; i < pdata->num_regulators; i++) {
                const struct sec_voltage_desc *desc;
                int id = pdata->regulators[i].id;
+               int enable_reg, enable_val;
 
                desc = reg_voltage_map[id];
                if (desc) {
@@ -935,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                                regulators[id].vsel_mask = 0x3f;
                        else
                                regulators[id].vsel_mask = 0xff;
+
+                       s5m8767_get_register(s5m8767, id, &enable_reg,
+                                            &enable_val);
+                       regulators[id].enable_reg = enable_reg;
+                       regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
+                       regulators[id].enable_val = enable_val;
                }
 
                config.dev = s5m8767->dev;
@@ -942,6 +964,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                config.driver_data = s5m8767;
                config.regmap = iodev->regmap_pmic;
                config.of_node = pdata->regulators[i].reg_node;
+               if (pdata->regulators[i].ext_control_gpio)
+                       s5m8767_regulator_config_ext_control(s5m8767,
+                                       &pdata->regulators[i], &config);
 
                rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
                                                  &config);
@@ -951,6 +976,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                                        id);
                        return ret;
                }
+
+               if (pdata->regulators[i].ext_control_gpio) {
+                       ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
+                       if (ret < 0) {
+                               dev_err(s5m8767->dev,
+                                               "failed to enable gpio control over %s: %d\n",
+                                               rdev[i]->desc->name, ret);
+                               return ret;
+                       }
+               }
        }
 
        return 0;
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
new file mode 100644 (file)
index 0000000..e367af1
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Regulator driver for ST's PWM Regulators
+ *
+ * Copyright (C) 2014 - STMicroelectronics Inc.
+ *
+ * Author: Lee Jones <lee.jones@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pwm.h>
+
+#define ST_PWM_REG_PERIOD 8448
+
+struct st_pwm_regulator_pdata {
+       const struct regulator_desc *desc;
+       struct st_pwm_voltages *duty_cycle_table;
+};
+
+struct st_pwm_regulator_data {
+       const struct st_pwm_regulator_pdata *pdata;
+       struct pwm_device *pwm;
+       bool enabled;
+       int state;
+};
+
+struct st_pwm_voltages {
+       unsigned int uV;
+       unsigned int dutycycle;
+};
+
+static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
+{
+       struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+       return drvdata->state;
+}
+
+static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
+                                           unsigned selector)
+{
+       struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+       int dutycycle;
+       int ret;
+
+       dutycycle = (ST_PWM_REG_PERIOD / 100) *
+               drvdata->pdata->duty_cycle_table[selector].dutycycle;
+
+       ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
+       if (ret) {
+               dev_err(&dev->dev, "Failed to configure PWM\n");
+               return ret;
+       }
+
+       drvdata->state = selector;
+
+       if (!drvdata->enabled) {
+               ret = pwm_enable(drvdata->pwm);
+               if (ret) {
+                       dev_err(&dev->dev, "Failed to enable PWM\n");
+                       return ret;
+               }
+               drvdata->enabled = true;
+       }
+
+       return 0;
+}
+
+static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
+                                        unsigned selector)
+{
+       struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+       if (selector >= dev->desc->n_voltages)
+               return -EINVAL;
+
+       return drvdata->pdata->duty_cycle_table[selector].uV;
+}
+
+static struct regulator_ops st_pwm_regulator_voltage_ops = {
+       .set_voltage_sel = st_pwm_regulator_set_voltage_sel,
+       .get_voltage_sel = st_pwm_regulator_get_voltage_sel,
+       .list_voltage    = st_pwm_regulator_list_voltage,
+       .map_voltage     = regulator_map_voltage_iterate,
+};
+
+static struct st_pwm_voltages b2105_duty_cycle_table[] = {
+       { .uV = 1114000, .dutycycle = 0,  },
+       { .uV = 1095000, .dutycycle = 10, },
+       { .uV = 1076000, .dutycycle = 20, },
+       { .uV = 1056000, .dutycycle = 30, },
+       { .uV = 1036000, .dutycycle = 40, },
+       { .uV = 1016000, .dutycycle = 50, },
+       /* WARNING: Values above 50% duty-cycle cause boot failures. */
+};
+
+static const struct regulator_desc b2105_desc = {
+       .name           = "b2105-pwm-regulator",
+       .ops            = &st_pwm_regulator_voltage_ops,
+       .type           = REGULATOR_VOLTAGE,
+       .owner          = THIS_MODULE,
+       .n_voltages     = ARRAY_SIZE(b2105_duty_cycle_table),
+       .supply_name    = "pwm",
+};
+
+static const struct st_pwm_regulator_pdata b2105_info = {
+       .desc             = &b2105_desc,
+       .duty_cycle_table = b2105_duty_cycle_table,
+};
+
+static struct of_device_id st_pwm_of_match[] = {
+       { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
+       { },
+};
+MODULE_DEVICE_TABLE(of, st_pwm_of_match);
+
+static int st_pwm_regulator_probe(struct platform_device *pdev)
+{
+       struct st_pwm_regulator_data *drvdata;
+       struct regulator_dev *regulator;
+       struct regulator_config config = { };
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_match;
+
+       if (!np) {
+               dev_err(&pdev->dev, "Device Tree node missing\n");
+               return -EINVAL;
+       }
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       of_match = of_match_device(st_pwm_of_match, &pdev->dev);
+       if (!of_match) {
+               dev_err(&pdev->dev, "failed to match of device\n");
+               return -ENODEV;
+       }
+       drvdata->pdata = of_match->data;
+
+       config.init_data = of_get_regulator_init_data(&pdev->dev, np);
+       if (!config.init_data)
+               return -ENOMEM;
+
+       config.of_node = np;
+       config.dev = &pdev->dev;
+       config.driver_data = drvdata;
+
+       drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
+       if (IS_ERR(drvdata->pwm)) {
+               dev_err(&pdev->dev, "Failed to get PWM\n");
+               return PTR_ERR(drvdata->pwm);
+       }
+
+       regulator = devm_regulator_register(&pdev->dev,
+                                           drvdata->pdata->desc, &config);
+       if (IS_ERR(regulator)) {
+               dev_err(&pdev->dev, "Failed to register regulator %s\n",
+                       drvdata->pdata->desc->name);
+               return PTR_ERR(regulator);
+       }
+
+       return 0;
+}
+
+static struct platform_driver st_pwm_regulator_driver = {
+       .driver = {
+               .name           = "st-pwm-regulator",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(st_pwm_of_match),
+       },
+       .probe = st_pwm_regulator_probe,
+};
+
+module_platform_driver(st_pwm_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
+MODULE_DESCRIPTION("ST PWM Regulator Driver");
+MODULE_ALIAS("platform:st_pwm-regulator");
index b187b6bba7ad485a9a8d97ba248b0a70de89c5c8..a2dabb575b97d6260837da1deca24e821accc4f0 100644 (file)
@@ -54,8 +54,8 @@ struct ti_abb_info {
 
 /**
  * struct ti_abb_reg - Register description for ABB block
- * @setup_reg:                 setup register offset from base
- * @control_reg:               control register offset from base
+ * @setup_off:                 setup register offset from base
+ * @control_off:               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
@@ -64,8 +64,8 @@ struct ti_abb_info {
  * @opp_sel_mask:              control register - mask for mode to operate
  */
 struct ti_abb_reg {
-       u32 setup_reg;
-       u32 control_reg;
+       u32 setup_off;
+       u32 control_off;
 
        /* Setup register fields */
        u32 sr2_wtcnt_value_mask;
@@ -83,6 +83,8 @@ struct ti_abb_reg {
  * @rdesc:                     regulator descriptor
  * @clk:                       clock(usually sysclk) supplying ABB block
  * @base:                      base address of ABB block
+ * @setup_reg:                 setup register of ABB block
+ * @control_reg:               control register 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
@@ -99,6 +101,8 @@ struct ti_abb {
        struct regulator_desc rdesc;
        struct clk *clk;
        void __iomem *base;
+       void __iomem *setup_reg;
+       void __iomem *control_reg;
        void __iomem *int_base;
        void __iomem *efuse_base;
        void __iomem *ldo_base;
@@ -118,20 +122,18 @@ struct ti_abb {
  * 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
+ * @reg:       register address
  *
  * Return: final register value (may be unused)
  */
-static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset,
-                            void __iomem *base)
+static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg)
 {
        u32 val;
 
-       val = readl(base + offset);
+       val = readl(reg);
        val &= ~mask;
        val |= (value << __ffs(mask)) & mask;
-       writel(val, base + offset);
+       writel(val, reg);
 
        return val;
 }
@@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
        if (ret)
                goto out;
 
-       ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg,
-                  abb->base);
+       ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg);
 
        switch (info->opp_sel) {
        case TI_ABB_SLOW_OPP:
-               ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base);
+               ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg);
                break;
        case TI_ABB_FAST_OPP:
-               ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base);
+               ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg);
                break;
        }
 
        /* program next state of ABB ldo */
-       ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
-                  abb->base);
+       ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg);
 
        /*
         * program LDO VBB vset override if needed for !bypass mode
@@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
                ti_abb_program_ldovbb(dev, abb, info);
 
        /* Initiate ABB ldo change */
-       ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base);
+       ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg);
 
        /* Wait for ABB LDO to complete transition to new Bias setting */
        ret = ti_abb_wait_txdone(dev, abb);
@@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb)
        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);
+       ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg);
 
        return 0;
 }
@@ -508,32 +507,24 @@ 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;
+       u32 i;
        unsigned int *volt_table;
-       int min_uV = INT_MAX, max_uV = 0;
+       int num_entries, 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);
+       num_entries = of_property_count_u32_elems(dev->of_node, pname);
+       if (num_entries < 0) {
+               dev_err(dev, "No '%s' property?\n", pname);
+               return num_entries;
+       }
+
        if (!num_entries || (num_entries % num_values)) {
                dev_err(dev, "All '%s' list entries need %d vals\n", pname,
                        num_values);
@@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
        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);
+       if (!info)
                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);
+       if (!volt_table)
                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++);
+               of_property_read_u32_index(dev->of_node, pname, i * num_values,
+                                          volt_table);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 1, &info->opp_sel);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 2, &efuse_offset);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 3, &rbb_mask);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 4, &fbb_mask);
+               of_property_read_u32_index(dev->of_node, pname,
+                                          i * num_values + 5, &vset_mask);
 
                dev_dbg(dev,
                        "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n",
@@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = {
 /* 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,
+       .setup_off              = 0x04,
+       .control_off            = 0x00,
 
        .sr2_wtcnt_value_mask   = (0xff << 8),
        .fbb_sel_mask           = (0x01 << 2),
@@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = {
 };
 
 static const struct ti_abb_reg abb_regs_v2 = {
-       .setup_reg              = 0x00,
-       .control_reg            = 0x04,
+       .setup_off              = 0x00,
+       .control_off            = 0x04,
 
        .sr2_wtcnt_value_mask   = (0xff << 8),
        .fbb_sel_mask           = (0x01 << 2),
@@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = {
        .opp_sel_mask           = (0x03 << 0),
 };
 
+static const struct ti_abb_reg abb_regs_generic = {
+       .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},
+       {.compatible = "ti,abb-v3", .data = &abb_regs_generic},
        { },
 };
 
@@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev)
        abb->regs = match->data;
 
        /* Map ABB resources */
-       pname = "base-address";
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
-       abb->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(abb->base))
-               return PTR_ERR(abb->base);
+       if (abb->regs->setup_off || abb->regs->control_off) {
+               pname = "base-address";
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+               abb->base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(abb->base))
+                       return PTR_ERR(abb->base);
+
+               abb->setup_reg = abb->base + abb->regs->setup_off;
+               abb->control_reg = abb->base + abb->regs->control_off;
+
+       } else {
+               pname = "control-address";
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+               abb->control_reg = devm_ioremap_resource(dev, res);
+               if (IS_ERR(abb->control_reg))
+                       return PTR_ERR(abb->control_reg);
+
+               pname = "setup-address";
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+               abb->setup_reg = devm_ioremap_resource(dev, res);
+               if (IS_ERR(abb->setup_reg))
+                       return PTR_ERR(abb->setup_reg);
+       }
 
        pname = "int-address";
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
@@ -860,7 +880,7 @@ skip_opt:
        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);
+       ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg);
 
        return 0;
 }
index b3764f594ee933703394ebacd0e6610aa7c809bc..f31f22e3e1bd56c0b6f1e36a07152f8c3d0039bc 100644 (file)
@@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data *
        struct device_node *np = dev->of_node;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata) {
-               dev_err(dev, "Memory alloc failed for platform data\n");
+       if (!pdata)
                return NULL;
-       }
 
        pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
        if (!pdata->reg_init_data) {
@@ -299,10 +297,8 @@ static int tps51632_probe(struct i2c_client *client,
        }
 
        tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
-       if (!tps) {
-               dev_err(&client->dev, "Memory allocation failed\n");
+       if (!tps)
                return -ENOMEM;
-       }
 
        tps->dev = &client->dev;
        tps->desc.name = client->name;
index c3fa15a299b16fb4ea48cca9f4173a8e0b4d9c8a..a1672044e5195304095f5de99e5c4e01218cb828 100644 (file)
@@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data *
        struct device_node *np = dev->of_node;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata) {
-               dev_err(dev, "Memory alloc failed for platform data\n");
+       if (!pdata)
                return NULL;
-       }
 
        pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
        if (!pdata->reg_init_data) {
@@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client,
        }
 
        tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
-       if (!tps) {
-               dev_err(&client->dev, "%s(): Memory allocation failed\n",
-                                               __func__);
+       if (!tps)
                return -ENOMEM;
-       }
 
        tps->en_discharge = pdata->en_discharge;
        tps->en_internal_pulldn = pdata->en_internal_pulldn;
index 162a0fae20b317bd0b4899e07520a45f496e43c6..98e66ce26723fac64c2cbd7b836f03c878465e28 100644 (file)
@@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = {
        .map_voltage = regulator_map_voltage_ascend,
 };
 
-#ifdef CONFIG_OF
 static struct of_regulator_match tps6507x_matches[] = {
        { .name = "VDCDC1"},
        { .name = "VDCDC2"},
@@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
 
        tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
                                        GFP_KERNEL);
-       if (!tps_board) {
-               dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+       if (!tps_board)
                return NULL;
-       }
 
-       regulators = of_find_node_by_name(np, "regulators");
+       regulators = of_get_child_by_name(np, "regulators");
        if (!regulators) {
                dev_err(&pdev->dev, "regulator node not found\n");
                return NULL;
@@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
        matches = tps6507x_matches;
 
        ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+       of_node_put(regulators);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
                        ret);
@@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
 
        reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
                                        * TPS6507X_NUM_REGULATOR), GFP_KERNEL);
-       if (!reg_data) {
-               dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
+       if (!reg_data)
                return NULL;
-       }
 
        tps_board->tps6507x_pmic_init_data = reg_data;
 
@@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
 
        return tps_board;
 }
-#else
-static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
-                       struct platform_device *pdev,
-                       struct of_regulator_match **tps6507x_reg_matches)
-{
-       *tps6507x_reg_matches = NULL;
-       return NULL;
-}
-#endif
+
 static int tps6507x_pmic_probe(struct platform_device *pdev)
 {
        struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
@@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
         */
 
        tps_board = dev_get_platdata(tps6507x_dev->dev);
-       if (!tps_board && tps6507x_dev->dev->of_node)
+       if (IS_ENABLED(CONFIG_OF) && !tps_board &&
+               tps6507x_dev->dev->of_node)
                tps_board = tps6507x_parse_dt_reg_data(pdev,
-                                               &tps6507x_reg_matches);
+                               &tps6507x_reg_matches);
        if (!tps_board)
                return -EINVAL;
 
@@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
                tps->info[i] = info;
                if (init_data->driver_data) {
                        struct tps6507x_reg_platform_data *data =
-                                                       init_data->driver_data;
+                                       init_data->driver_data;
                        tps->info[i]->defdcdc_default = data->defdcdc_default;
                }
 
index 676f75548f0028435b6795bc0371490c462a641e..2e92ef68574da733e6fd81d3aed1760e627d5bc4 100644 (file)
@@ -168,17 +168,13 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
 
        tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
                                GFP_KERNEL);
-       if (!tps65090_pdata) {
-               dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+       if (!tps65090_pdata)
                return ERR_PTR(-ENOMEM);
-       }
 
        reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
                                sizeof(*reg_pdata), GFP_KERNEL);
-       if (!reg_pdata) {
-               dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
+       if (!reg_pdata)
                return ERR_PTR(-ENOMEM);
-       }
 
        regulators = of_get_child_by_name(np, "regulators");
        if (!regulators) {
@@ -188,6 +184,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
 
        ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
                        ARRAY_SIZE(tps65090_matches));
+       of_node_put(regulators);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "Error parsing regulator init data: %d\n", ret);
@@ -252,10 +249,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
 
        pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
                        GFP_KERNEL);
-       if (!pmic) {
-               dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+       if (!pmic)
                return -ENOMEM;
-       }
 
        for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
                tps_pdata = tps65090_pdata->reg_pdata[num];
index 9ea1bf26bd137b4b4e33dcede0c6c1551ff6d79c..10b78d2b766aa3394b1ee51b2bf47e616f6f95d4 100644 (file)
@@ -187,7 +187,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
        struct device_node *regs;
        int i, count;
 
-       regs = of_find_node_by_name(node, "regulators");
+       regs = of_get_child_by_name(node, "regulators");
        if (!regs)
                return NULL;
 
@@ -202,7 +202,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
                return NULL;
 
        for (i = 0; i < count; i++) {
-               if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+               if (!reg_matches[i].of_node)
                        continue;
 
                pdata->tps65217_init_data[i] = reg_matches[i].init_data;
@@ -222,7 +222,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
 {
        struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
        struct tps65217_board *pdata = dev_get_platdata(tps->dev);
-       struct regulator_init_data *reg_data;
        struct regulator_dev *rdev;
        struct regulator_config config = { };
        int i;
@@ -243,19 +242,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, tps);
 
        for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
-
-               reg_data = pdata->tps65217_init_data[i];
-
-               /*
-                * Regulator API handles empty constraints but not NULL
-                * constraints
-                */
-               if (!reg_data)
-                       continue;
-
                /* Register the regulators */
                config.dev = tps->dev;
-               config.init_data = reg_data;
+               config.init_data = pdata->tps65217_init_data[i];
                config.driver_data = tps;
                config.regmap = tps->regmap;
                if (tps->dev->of_node)
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
new file mode 100644 (file)
index 0000000..cec72fa
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * tps65218-regulator.c
+ *
+ * Regulator driver for TPS65218 PMIC
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2 for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps65218.h>
+
+static unsigned int tps65218_ramp_delay = 4000;
+
+enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
+
+#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, _t, \
+                           _lr, _nlr)                          \
+       {                                                       \
+               .name                   = _name,                \
+               .id                     = _id,                  \
+               .ops                    = &_ops,                \
+               .n_voltages             = _n,                   \
+               .type                   = REGULATOR_VOLTAGE,    \
+               .owner                  = THIS_MODULE,          \
+               .vsel_reg               = _vr,                  \
+               .vsel_mask              = _vm,                  \
+               .enable_reg             = _er,                  \
+               .enable_mask            = _em,                  \
+               .volt_table             = _t,                   \
+               .linear_ranges          = _lr,                  \
+               .n_linear_ranges        = _nlr,                 \
+       }                                                       \
+
+#define TPS65218_INFO(_id, _nm, _min, _max)    \
+       {                                               \
+               .id             = _id,                  \
+               .name           = _nm,                  \
+               .min_uV         = _min,                 \
+               .max_uV         = _max,                 \
+       }
+
+static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = {
+       REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000),
+       REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000),
+};
+
+static const struct regulator_linear_range ldo1_dcdc3_ranges[] = {
+       REGULATOR_LINEAR_RANGE(900000, 0x0, 0x1a, 25000),
+       REGULATOR_LINEAR_RANGE(1600000, 0x1b, 0x3f, 50000),
+};
+
+static const struct regulator_linear_range dcdc4_ranges[] = {
+       REGULATOR_LINEAR_RANGE(1175000, 0x0, 0xf, 25000),
+       REGULATOR_LINEAR_RANGE(1550000, 0x10, 0x34, 50000),
+};
+
+static struct tps_info tps65218_pmic_regs[] = {
+       TPS65218_INFO(0, "DCDC1", 850000, 167500),
+       TPS65218_INFO(1, "DCDC2", 850000, 1675000),
+       TPS65218_INFO(2, "DCDC3", 900000, 3400000),
+       TPS65218_INFO(3, "DCDC4", 1175000, 3400000),
+       TPS65218_INFO(4, "DCDC5", 1000000, 1000000),
+       TPS65218_INFO(5, "DCDC6", 1800000, 1800000),
+       TPS65218_INFO(6, "LDO1", 900000, 3400000),
+};
+
+#define TPS65218_OF_MATCH(comp, label) \
+       { \
+               .compatible = comp, \
+               .data = &label, \
+       }
+
+static const struct of_device_id tps65218_of_match[] = {
+       TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]),
+       TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]),
+       TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]),
+       TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]),
+       TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
+       TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
+       TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
+       { }
+};
+MODULE_DEVICE_TABLE(of, tps65218_of_match);
+
+static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev,
+                                        unsigned selector)
+{
+       int ret;
+       struct tps65218 *tps = rdev_get_drvdata(dev);
+       unsigned int rid = rdev_get_id(dev);
+
+       /* Set the voltage based on vsel value and write protect level is 2 */
+       ret = tps65218_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
+                               selector, TPS65218_PROTECT_L1);
+
+       /* Set GO bit for DCDC1/2 to initiate voltage transistion */
+       switch (rid) {
+       case TPS65218_DCDC_1:
+       case TPS65218_DCDC_2:
+               ret = tps65218_set_bits(tps, TPS65218_REG_CONTRL_SLEW_RATE,
+                                       TPS65218_SLEW_RATE_GO,
+                                       TPS65218_SLEW_RATE_GO,
+                                       TPS65218_PROTECT_L1);
+               break;
+       }
+
+       return ret;
+}
+
+static int tps65218_pmic_enable(struct regulator_dev *dev)
+{
+       struct tps65218 *tps = rdev_get_drvdata(dev);
+       unsigned int rid = rdev_get_id(dev);
+
+       if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+               return -EINVAL;
+
+       /* Enable the regulator and password protection is level 1 */
+       return tps65218_set_bits(tps, dev->desc->enable_reg,
+                                dev->desc->enable_mask, dev->desc->enable_mask,
+                                TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_disable(struct regulator_dev *dev)
+{
+       struct tps65218 *tps = rdev_get_drvdata(dev);
+       unsigned int rid = rdev_get_id(dev);
+
+       if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+               return -EINVAL;
+
+       /* Disable the regulator and password protection is level 1 */
+       return tps65218_clear_bits(tps, dev->desc->enable_reg,
+                                  dev->desc->enable_mask, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_set_voltage_time_sel(struct regulator_dev *rdev,
+       unsigned int old_selector, unsigned int new_selector)
+{
+       int old_uv, new_uv;
+
+       old_uv = regulator_list_voltage_linear_range(rdev, old_selector);
+       if (old_uv < 0)
+               return old_uv;
+
+       new_uv = regulator_list_voltage_linear_range(rdev, new_selector);
+       if (new_uv < 0)
+               return new_uv;
+
+       return DIV_ROUND_UP(abs(old_uv - new_uv), tps65218_ramp_delay);
+}
+
+/* Operations permitted on DCDC1, DCDC2 */
+static struct regulator_ops tps65218_dcdc12_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = tps65218_pmic_enable,
+       .disable                = tps65218_pmic_disable,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = tps65218_pmic_set_voltage_sel,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
+       .set_voltage_time_sel   = tps65218_set_voltage_time_sel,
+};
+
+/* Operations permitted on DCDC3, DCDC4 and LDO1 */
+static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = tps65218_pmic_enable,
+       .disable                = tps65218_pmic_disable,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = tps65218_pmic_set_voltage_sel,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
+};
+
+/* Operations permitted on DCDC5, DCDC6 */
+static struct regulator_ops tps65218_dcdc56_pmic_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = tps65218_pmic_enable,
+       .disable                = tps65218_pmic_disable,
+};
+
+static const struct regulator_desc regulators[] = {
+       TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC1,
+                          TPS65218_CONTROL_DCDC1_MASK,
+                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, NULL,
+                          dcdc1_dcdc2_ranges, 2),
+       TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC2,
+                          TPS65218_CONTROL_DCDC2_MASK,
+                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, NULL,
+                          dcdc1_dcdc2_ranges, 2),
+       TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
+                          64, TPS65218_REG_CONTROL_DCDC3,
+                          TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
+                          TPS65218_ENABLE1_DC3_EN, NULL,
+                          ldo1_dcdc3_ranges, 2),
+       TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
+                          53, TPS65218_REG_CONTROL_DCDC4,
+                          TPS65218_CONTROL_DCDC4_MASK,
+                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, NULL,
+                          dcdc4_ranges, 2),
+       TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
+                          1, -1, -1, TPS65218_REG_ENABLE1,
+                          TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0),
+       TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
+                          1, -1, -1, TPS65218_REG_ENABLE1,
+                          TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0),
+       TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC4,
+                          TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
+                          TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges,
+                          2),
+};
+
+static int tps65218_regulator_probe(struct platform_device *pdev)
+{
+       struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_init_data *init_data;
+       const struct tps_info   *template;
+       struct regulator_dev *rdev;
+       const struct of_device_id       *match;
+       struct regulator_config config = { };
+       int id;
+
+       match = of_match_device(tps65218_of_match, &pdev->dev);
+       if (!match)
+               return -ENODEV;
+
+       template = match->data;
+       id = template->id;
+       init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+
+       platform_set_drvdata(pdev, tps);
+
+       tps->info[id] = &tps65218_pmic_regs[id];
+       config.dev = &pdev->dev;
+       config.init_data = init_data;
+       config.driver_data = tps;
+       config.regmap = tps->regmap;
+
+       rdev = devm_regulator_register(&pdev->dev, &regulators[id], &config);
+       if (IS_ERR(rdev)) {
+               dev_err(tps->dev, "failed to register %s regulator\n",
+                       pdev->name);
+               return PTR_ERR(rdev);
+       }
+
+       return 0;
+}
+
+static struct platform_driver tps65218_regulator_driver = {
+       .driver = {
+               .name = "tps65218-pmic",
+               .owner = THIS_MODULE,
+               .of_match_table = tps65218_of_match,
+       },
+       .probe = tps65218_regulator_probe,
+};
+
+module_platform_driver(tps65218_regulator_driver);
+
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("TPS65218 voltage regulator driver");
+MODULE_ALIAS("platform:tps65218-pmic");
+MODULE_LICENSE("GPL v2");
index 9f6bfda711b73a6dae9cdc9b8be3b69b2f5e88cc..5b494db9f95c90aba642c44f8af58910c71b1711 100644 (file)
@@ -593,10 +593,9 @@ static int pmic_probe(struct spi_device *spi)
        }
 
        hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL);
-       if (!hw) {
-               dev_err(dev, "cannot allocate regulator private data\n");
+       if (!hw)
                return -ENOMEM;
-       }
+
        spi_set_drvdata(spi, hw);
 
        memset(hw, 0, sizeof(struct tps6524x));
index 0485d47f0d8a82d9de595a8df5bd73c16111d4f2..32f38a63d944eaaf148a5a1f7c4034ab372e7f0d 100644 (file)
@@ -363,10 +363,8 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(
        }
 
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata) {
-               dev_err(&pdev->dev, "Memory alloction failed\n");
+       if (!pdata)
                return NULL;
-       }
 
        for (i = 0; i < num; i++) {
                int id;
@@ -398,7 +396,7 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
 {
        struct tps6586x_regulator *ri = NULL;
        struct regulator_config config = { };
-       struct regulator_dev **rdev;
+       struct regulator_dev *rdev;
        struct regulator_init_data *reg_data;
        struct tps6586x_platform_data *pdata;
        struct of_regulator_match *tps6586x_reg_matches = NULL;
@@ -418,13 +416,6 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR *
-                               sizeof(*rdev), GFP_KERNEL);
-       if (!rdev) {
-               dev_err(&pdev->dev, "Mmemory alloc failed\n");
-               return -ENOMEM;
-       }
-
        version = tps6586x_get_version(pdev->dev.parent);
 
        for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) {
@@ -451,12 +442,11 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
                if (tps6586x_reg_matches)
                        config.of_node = tps6586x_reg_matches[id].of_node;
 
-               rdev[id] = devm_regulator_register(&pdev->dev, &ri->desc,
-                                                  &config);
-               if (IS_ERR(rdev[id])) {
+               rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
+               if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev, "failed to register regulator %s\n",
                                        ri->desc.name);
-                       return PTR_ERR(rdev[id]);
+                       return PTR_ERR(rdev);
                }
 
                if (reg_data) {
index f50dd847eebc9f1e38508ee1ab67ba0be5e6bdd2..fa7db8847578abd61787d0820661e675c3cd80b0 100644 (file)
@@ -1011,11 +1011,8 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
 
        pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data),
                                        GFP_KERNEL);
-
-       if (!pmic_plat_data) {
-               dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+       if (!pmic_plat_data)
                return NULL;
-       }
 
        np = of_node_get(pdev->dev.parent->of_node);
        regulators = of_get_child_by_name(np, "regulators");
@@ -1098,10 +1095,8 @@ static int tps65910_probe(struct platform_device *pdev)
        }
 
        pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
-       if (!pmic) {
-               dev_err(&pdev->dev, "Memory allocation failed for pmic\n");
+       if (!pmic)
                return -ENOMEM;
-       }
 
        pmic->mfd = tps65910;
        platform_set_drvdata(pdev, pmic);
@@ -1130,24 +1125,18 @@ static int tps65910_probe(struct platform_device *pdev)
 
        pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators *
                        sizeof(struct regulator_desc), GFP_KERNEL);
-       if (!pmic->desc) {
-               dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+       if (!pmic->desc)
                return -ENOMEM;
-       }
 
        pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators *
                        sizeof(struct tps_info *), GFP_KERNEL);
-       if (!pmic->info) {
-               dev_err(&pdev->dev, "Memory alloc fails for info\n");
+       if (!pmic->info)
                return -ENOMEM;
-       }
 
        pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators *
                        sizeof(struct regulator_dev *), GFP_KERNEL);
-       if (!pmic->rdev) {
-               dev_err(&pdev->dev, "Memory alloc fails for rdev\n");
+       if (!pmic->rdev)
                return -ENOMEM;
-       }
 
        for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
                        i++, info++) {
index 71f457a42623f602541ae5d69b90521d673c9e2b..26aa6d9c308fdf1415f55a20f6d987b4260f92f8 100644 (file)
@@ -115,7 +115,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev)
                        ri->rinfo->state_reg, ret);
                return ret;
        }
-       return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON);
+       return (reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON;
 }
 
 static int tps80031_reg_enable(struct regulator_dev *rdev)
@@ -693,10 +693,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev)
 
        pmic = devm_kzalloc(&pdev->dev,
                        TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL);
-       if (!pmic) {
-               dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+       if (!pmic)
                return -ENOMEM;
-       }
 
        for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) {
                tps_pdata = pdata->regulator_pdata[num];
index 04cf9c16ef233eae69fbdf209d09e0865f947a67..0d88a82ab2a227f835fa7d6b2b318b939e9e8737 100644 (file)
@@ -469,10 +469,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev)
 
        dcdc = devm_kzalloc(&pdev->dev,  sizeof(struct wm831x_dcdc),
                            GFP_KERNEL);
-       if (dcdc == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!dcdc)
                return -ENOMEM;
-       }
 
        dcdc->wm831x = wm831x;
 
@@ -622,10 +620,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev)
 
        dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
                            GFP_KERNEL);
-       if (dcdc == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!dcdc)
                return -ENOMEM;
-       }
 
        dcdc->wm831x = wm831x;
 
@@ -752,10 +748,8 @@ static int wm831x_boostp_probe(struct platform_device *pdev)
                return -ENODEV;
 
        dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
-       if (dcdc == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!dcdc)
                return -ENOMEM;
-       }
 
        dcdc->wm831x = wm831x;
 
@@ -842,10 +836,8 @@ static int wm831x_epe_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1);
 
        dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
-       if (dcdc == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!dcdc)
                return -ENOMEM;
-       }
 
        dcdc->wm831x = wm831x;
 
index 0339b886df5dbf2a6bde26111a0a4c6a60f58732..72e385e76a9d75df7146e0bb42589d32c034f28b 100644 (file)
@@ -165,10 +165,8 @@ static int wm831x_isink_probe(struct platform_device *pdev)
 
        isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink),
                             GFP_KERNEL);
-       if (isink == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!isink)
                return -ENOMEM;
-       }
 
        isink->wm831x = wm831x;
 
index 46d6700467b57007fbb277283207cfbbc4456fc0..eca0eeb78acd66209dcb39ca94ac5aeb3937f3bf 100644 (file)
@@ -235,10 +235,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
-       if (ldo == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!ldo)
                return -ENOMEM;
-       }
 
        ldo->wm831x = wm831x;
 
@@ -447,10 +445,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
-       if (ldo == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!ldo)
                return -ENOMEM;
-       }
 
        ldo->wm831x = wm831x;
 
@@ -594,10 +590,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
-       if (ldo == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!ldo)
                return -ENOMEM;
-       }
 
        ldo->wm831x = wm831x;
 
index de7b9c73e3fa09f3b14db1c5d8949ca99a37c352..7ec7c390eedaa1085eeb03d4adfce33f7f1b4531 100644 (file)
@@ -361,7 +361,7 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 
        sel = regulator_map_voltage_linear(rdev, uV, uV);
        if (sel < 0)
-               return -EINVAL;
+               return sel;
 
        /* all DCDCs have same mV bits */
        val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
@@ -574,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 
        sel = regulator_map_voltage_linear_range(rdev, uV, uV);
        if (sel < 0)
-               return -EINVAL;
+               return sel;
 
        /* all LDOs have same mV bits */
        val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
index 71c5911f2e7130b2114d19b7619a30e69672a94a..c24346db8a71139e202c60464317e4fc03123253 100644 (file)
@@ -134,10 +134,8 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
 
        ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL);
-       if (ldo == NULL) {
-               dev_err(&pdev->dev, "Unable to allocate private data\n");
+       if (!ldo)
                return -ENOMEM;
-       }
 
        ldo->wm8994 = wm8994;
        ldo->supply = wm8994_ldo_consumer[id];
index 7afd373b9595ff68b16238fc37688102dbaa04f4..c4cde9c08f1ffa9ed5c7c1d91a10b745ef7fdb3e 100644 (file)
@@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev)
 
        clk_enable(rtc_clk);
        /* save TICNT for anyone using periodic interrupts */
-       ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
        if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
                ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
                ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+               ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
+       } else {
+               ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
        }
        s3c_rtc_enable(pdev, 0);
 
@@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev)
 
        clk_enable(rtc_clk);
        s3c_rtc_enable(pdev, 1);
-       writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
-               tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
-               writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+               if (ticnt_en_save) {
+                       tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+                       writew(tmp | ticnt_en_save,
+                                       s3c_rtc_base + S3C2410_RTCCON);
+               }
+       } else {
+               writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
        }
 
        if (device_may_wakeup(dev) && wake_en) {
index eb5d22795c47a55744381ee3f9e70c1666701835..5af7f0bd6125702358cb1fbab5830c5a77506e7b 100644 (file)
@@ -922,7 +922,7 @@ static int __init con3215_init(void)
                raw3215_freelist = req;
        }
 
-       cdev = ccw_device_probe_console();
+       cdev = ccw_device_create_console(&raw3215_ccw_driver);
        if (IS_ERR(cdev))
                return -ENODEV;
 
@@ -932,6 +932,12 @@ static int __init con3215_init(void)
        cdev->handler = raw3215_irq;
 
        raw->flags |= RAW3215_FIXED;
+       if (ccw_device_enable_console(cdev)) {
+               ccw_device_destroy_console(cdev);
+               raw3215_free_info(raw);
+               raw3215[0] = NULL;
+               return -ENODEV;
+       }
 
        /* Request the console irq */
        if (raw3215_startup(raw) != 0) {
index 699fd3e363dfba2f7b0fe8dbab3f43961ec1a108..75ffe9980c3e1cb8e141c6e29d01cef98aaf862f 100644 (file)
@@ -7,6 +7,7 @@
  *     Copyright IBM Corp. 2003, 2009
  */
 
+#include <linux/module.h>
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -30,6 +31,9 @@
 
 static struct raw3270_fn con3270_fn;
 
+static bool auto_update = 1;
+module_param(auto_update, bool, 0);
+
 /*
  * Main 3270 console view data structure.
  */
@@ -204,6 +208,8 @@ con3270_update(struct con3270 *cp)
        struct string *s, *n;
        int rc;
 
+       if (!auto_update && !raw3270_view_active(&cp->view))
+               return;
        if (cp->view.dev)
                raw3270_activate_view(&cp->view);
 
@@ -529,6 +535,7 @@ con3270_flush(void)
        if (!cp->view.dev)
                return;
        raw3270_pm_unfreeze(&cp->view);
+       raw3270_activate_view(&cp->view);
        spin_lock_irqsave(&cp->view.lock, flags);
        con3270_wait_write(cp);
        cp->nr_up = 0;
@@ -576,7 +583,6 @@ static struct console con3270 = {
 static int __init
 con3270_init(void)
 {
-       struct ccw_device *cdev;
        struct raw3270 *rp;
        void *cbuf;
        int i;
@@ -591,10 +597,7 @@ con3270_init(void)
                cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
        }
 
-       cdev = ccw_device_probe_console();
-       if (IS_ERR(cdev))
-               return -ENODEV;
-       rp = raw3270_setup_console(cdev);
+       rp = raw3270_setup_console();
        if (IS_ERR(rp))
                return PTR_ERR(rp);
 
index 2cdec21e8924ea7b0403aafd1b0bae172a76416e..9f849df4381e1388c87b89bfc33f2b350ce54dda 100644 (file)
@@ -275,6 +275,15 @@ __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
        return 0;
 }
 
+int
+raw3270_view_active(struct raw3270_view *view)
+{
+       struct raw3270 *rp = view->dev;
+
+       return rp && rp->view == view &&
+               !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+}
+
 int
 raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
 {
@@ -776,22 +785,37 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
 }
 
 #ifdef CONFIG_TN3270_CONSOLE
+/* Tentative definition - see below for actual definition. */
+static struct ccw_driver raw3270_ccw_driver;
+
 /*
  * Setup 3270 device configured as console.
  */
-struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(void)
 {
+       struct ccw_device *cdev;
        unsigned long flags;
        struct raw3270 *rp;
        char *ascebc;
        int rc;
 
+       cdev = ccw_device_create_console(&raw3270_ccw_driver);
+       if (IS_ERR(cdev))
+               return ERR_CAST(cdev);
+
        rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
        ascebc = kzalloc(256, GFP_KERNEL);
        rc = raw3270_setup_device(cdev, rp, ascebc);
        if (rc)
                return ERR_PTR(rc);
        set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
+
+       rc = ccw_device_enable_console(cdev);
+       if (rc) {
+               ccw_device_destroy_console(cdev);
+               return ERR_PTR(rc);
+       }
+
        spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
        do {
                __raw3270_reset_device(rp);
index 7b73ff8c1bd7a59a5c60fe9d7886371c48d4d2c4..e1e41c2861fbb34db1d035b4f51965cb39b41aa7 100644 (file)
@@ -173,6 +173,7 @@ int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *);
 int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
 int raw3270_reset(struct raw3270_view *);
 struct raw3270_view *raw3270_view(struct raw3270_view *);
+int raw3270_view_active(struct raw3270_view *);
 
 /* Reference count inliner for view structures. */
 static inline void
@@ -190,7 +191,7 @@ raw3270_put_view(struct raw3270_view *view)
                wake_up(&raw3270_wait_queue);
 }
 
-struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
+struct raw3270 *raw3270_setup_console(void);
 void raw3270_wait_cons_dev(struct raw3270 *);
 
 /* Notifier for device addition/removal */
index 82f2c389b4d1f51e882de45cd5e0fadfa3405f3e..14196ea0fdf3ad878b6fe527733d8390f0ba6a25 100644 (file)
@@ -20,7 +20,9 @@ struct read_info_sccb {
        struct  sccb_header header;     /* 0-7 */
        u16     rnmax;                  /* 8-9 */
        u8      rnsize;                 /* 10 */
-       u8      _reserved0[24 - 11];    /* 11-15 */
+       u8      _reserved0[16 - 11];    /* 11-15 */
+       u16     ncpurl;                 /* 16-17 */
+       u8      _reserved7[24 - 18];    /* 18-23 */
        u8      loadparm[8];            /* 24-31 */
        u8      _reserved1[48 - 32];    /* 32-47 */
        u64     facilities;             /* 48-55 */
@@ -32,13 +34,16 @@ struct read_info_sccb {
        u8      _reserved4[100 - 92];   /* 92-99 */
        u32     rnsize2;                /* 100-103 */
        u64     rnmax2;                 /* 104-111 */
-       u8      _reserved5[4096 - 112]; /* 112-4095 */
+       u8      _reserved5[120 - 112];  /* 112-119 */
+       u16     hcpua;                  /* 120-121 */
+       u8      _reserved6[4096 - 122]; /* 122-4095 */
 } __packed __aligned(PAGE_SIZE);
 
 static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
 static unsigned int sclp_con_has_vt220 __initdata;
 static unsigned int sclp_con_has_linemode __initdata;
 static unsigned long sclp_hsa_size;
+static unsigned int sclp_max_cpu;
 static struct sclp_ipl_info sclp_ipl_info;
 
 u64 sclp_facilities;
@@ -102,6 +107,15 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
        sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
        sclp_rzm <<= 20;
 
+       if (!sccb->hcpua) {
+               if (MACHINE_IS_VM)
+                       sclp_max_cpu = 64;
+               else
+                       sclp_max_cpu = sccb->ncpurl;
+       } else {
+               sclp_max_cpu = sccb->hcpua + 1;
+       }
+
        /* Save IPL information */
        sclp_ipl_info.is_valid = 1;
        if (sccb->flags & 0x2)
@@ -129,6 +143,11 @@ unsigned long long sclp_get_rzm(void)
        return sclp_rzm;
 }
 
+unsigned int sclp_get_max_cpu(void)
+{
+       return sclp_max_cpu;
+}
+
 /*
  * This function will be called after sclp_facilities_detect(), which gets
  * called from early.c code. The sclp_facilities_detect() function retrieves
@@ -184,9 +203,9 @@ static long __init sclp_hsa_size_init(struct sdias_sccb *sccb)
        sccb_init_eq_size(sccb);
        if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
                return -EIO;
-       if (sccb->evbuf.blk_cnt != 0)
-               return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
-       return 0;
+       if (sccb->evbuf.blk_cnt == 0)
+               return 0;
+       return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
 }
 
 static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
@@ -195,6 +214,8 @@ static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
        sccb->length = PAGE_SIZE;
        if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
                return -EIO;
+       if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0)
+               return 0;
        return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
 }
 
index f055df0b167fc83e1f2f6f17e0aef47e129007b4..445564c790f65ddc587d2a8185468c28b9e711a7 100644 (file)
@@ -186,55 +186,71 @@ void airq_iv_release(struct airq_iv *iv)
 EXPORT_SYMBOL(airq_iv_release);
 
 /**
- * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector
+ * airq_iv_alloc - allocate irq bits from an interrupt vector
  * @iv: pointer to an interrupt vector structure
+ * @num: number of consecutive irq bits to allocate
  *
- * Returns the bit number of the allocated irq, or -1UL if no bit
- * is available or the AIRQ_IV_ALLOC flag has not been specified
+ * Returns the bit number of the first irq in the allocated block of irqs,
+ * or -1UL if no bit is available or the AIRQ_IV_ALLOC flag has not been
+ * specified
  */
-unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
 {
-       unsigned long bit;
+       unsigned long bit, i;
 
-       if (!iv->avail)
+       if (!iv->avail || num == 0)
                return -1UL;
        spin_lock(&iv->lock);
        bit = find_first_bit_inv(iv->avail, iv->bits);
-       if (bit < iv->bits) {
-               clear_bit_inv(bit, iv->avail);
-               if (bit >= iv->end)
-                       iv->end = bit + 1;
-       } else
+       while (bit + num <= iv->bits) {
+               for (i = 1; i < num; i++)
+                       if (!test_bit_inv(bit + i, iv->avail))
+                               break;
+               if (i >= num) {
+                       /* Found a suitable block of irqs */
+                       for (i = 0; i < num; i++)
+                               clear_bit_inv(bit + i, iv->avail);
+                       if (bit + num >= iv->end)
+                               iv->end = bit + num + 1;
+                       break;
+               }
+               bit = find_next_bit_inv(iv->avail, iv->bits, bit + i + 1);
+       }
+       if (bit + num > iv->bits)
                bit = -1UL;
        spin_unlock(&iv->lock);
        return bit;
 
 }
-EXPORT_SYMBOL(airq_iv_alloc_bit);
+EXPORT_SYMBOL(airq_iv_alloc);
 
 /**
- * airq_iv_free_bit - free an irq bit of an interrupt vector
+ * airq_iv_free - free irq bits of an interrupt vector
  * @iv: pointer to interrupt vector structure
- * @bit: number of the irq bit to free
+ * @bit: number of the first irq bit to free
+ * @num: number of consecutive irq bits to free
  */
-void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
 {
-       if (!iv->avail)
+       unsigned long i;
+
+       if (!iv->avail || num == 0)
                return;
        spin_lock(&iv->lock);
-       /* Clear (possibly left over) interrupt bit */
-       clear_bit_inv(bit, iv->vector);
-       /* Make the bit position available again */
-       set_bit_inv(bit, iv->avail);
-       if (bit == iv->end - 1) {
+       for (i = 0; i < num; i++) {
+               /* Clear (possibly left over) interrupt bit */
+               clear_bit_inv(bit + i, iv->vector);
+               /* Make the bit positions available again */
+               set_bit_inv(bit + i, iv->avail);
+       }
+       if (bit + num >= iv->end) {
                /* Find new end of bit-field */
-               while (--iv->end > 0)
-                       if (!test_bit_inv(iv->end - 1, iv->avail))
-                               break;
+               while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail))
+                       iv->end--;
        }
        spin_unlock(&iv->lock);
 }
-EXPORT_SYMBOL(airq_iv_free_bit);
+EXPORT_SYMBOL(airq_iv_free);
 
 /**
  * airq_iv_scan - scan interrupt vector for non-zero bits
index 7b29d0be0ca33b610443a2059374a54fb0802f26..1d3661af7bd83c47afc4a468446278f121df056c 100644 (file)
@@ -173,8 +173,7 @@ static struct css_driver chsc_subchannel_driver = {
 
 static int __init chsc_init_dbfs(void)
 {
-       chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
-                                          16 * sizeof(long));
+       chsc_debug_msg_id = debug_register("chsc_msg", 8, 1, 4 * sizeof(long));
        if (!chsc_debug_msg_id)
                goto out;
        debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
index 8ee88c4ebd83e8dcdd78f45a2adc8500205e850b..9e058c4657a3fdef34a26f00f3e1fc3601d23841 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/device.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/cio.h>
 #include <asm/delay.h>
 #include <asm/irq.h>
@@ -28,7 +29,7 @@
 #include <asm/chpid.h>
 #include <asm/airq.h>
 #include <asm/isc.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
 #include <asm/fcx.h>
 #include <asm/nmi.h>
 #include <asm/crw.h>
@@ -54,7 +55,7 @@ debug_info_t *cio_debug_crw_id;
  */
 static int __init cio_debug_init(void)
 {
-       cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
+       cio_debug_msg_id = debug_register("cio_msg", 16, 1, 11 * sizeof(long));
        if (!cio_debug_msg_id)
                goto out_unregister;
        debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
@@ -64,7 +65,7 @@ static int __init cio_debug_init(void)
                goto out_unregister;
        debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
        debug_set_level(cio_debug_trace_id, 2);
-       cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
+       cio_debug_crw_id = debug_register("cio_crw", 8, 1, 8 * sizeof(long));
        if (!cio_debug_crw_id)
                goto out_unregister;
        debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
@@ -584,8 +585,6 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
        return IRQ_HANDLED;
 }
 
-static struct irq_desc *irq_desc_io;
-
 static struct irqaction io_interrupt = {
        .name    = "IO",
        .handler = do_cio_interrupt,
@@ -596,7 +595,6 @@ void __init init_cio_interrupts(void)
        irq_set_chip_and_handler(IO_INTERRUPT,
                                 &dummy_irq_chip, handle_percpu_irq);
        setup_irq(IO_INTERRUPT, &io_interrupt);
-       irq_desc_io = irq_to_desc(IO_INTERRUPT);
 }
 
 #ifdef CONFIG_CCW_CONSOLE
@@ -623,7 +621,7 @@ void cio_tsch(struct subchannel *sch)
                local_bh_disable();
                irq_enter();
        }
-       kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io);
+       kstat_incr_irq_this_cpu(IO_INTERRUPT);
        if (sch->driver && sch->driver->irq)
                sch->driver->irq(sch);
        else
index e9d783563cbb8894182efcfde40376eb731d286b..d8d9b5b5cc56f9508cd9bae511c592867775a3cc 100644 (file)
@@ -1571,12 +1571,27 @@ out:
        return rc;
 }
 
+static void ccw_device_set_int_class(struct ccw_device *cdev)
+{
+       struct ccw_driver *cdrv = cdev->drv;
+
+       /* Note: we interpret class 0 in this context as an uninitialized
+        * field since it translates to a non-I/O interrupt class. */
+       if (cdrv->int_class != 0)
+               cdev->private->int_class = cdrv->int_class;
+       else
+               cdev->private->int_class = IRQIO_CIO;
+}
+
 #ifdef CONFIG_CCW_CONSOLE
-static int ccw_device_console_enable(struct ccw_device *cdev,
-                                    struct subchannel *sch)
+int __init ccw_device_enable_console(struct ccw_device *cdev)
 {
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
        int rc;
 
+       if (!cdev->drv || !cdev->handler)
+               return -EINVAL;
+
        io_subchannel_init_fields(sch);
        rc = cio_commit_config(sch);
        if (rc)
@@ -1609,12 +1624,11 @@ out_unlock:
        return rc;
 }
 
-struct ccw_device *ccw_device_probe_console(void)
+struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv)
 {
        struct io_subchannel_private *io_priv;
        struct ccw_device *cdev;
        struct subchannel *sch;
-       int ret;
 
        sch = cio_probe_console();
        if (IS_ERR(sch))
@@ -1631,18 +1645,23 @@ struct ccw_device *ccw_device_probe_console(void)
                kfree(io_priv);
                return cdev;
        }
+       cdev->drv = drv;
        set_io_private(sch, io_priv);
-       ret = ccw_device_console_enable(cdev, sch);
-       if (ret) {
-               set_io_private(sch, NULL);
-               put_device(&sch->dev);
-               put_device(&cdev->dev);
-               kfree(io_priv);
-               return ERR_PTR(ret);
-       }
+       ccw_device_set_int_class(cdev);
        return cdev;
 }
 
+void __init ccw_device_destroy_console(struct ccw_device *cdev)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       struct io_subchannel_private *io_priv = to_io_private(sch);
+
+       set_io_private(sch, NULL);
+       put_device(&sch->dev);
+       put_device(&cdev->dev);
+       kfree(io_priv);
+}
+
 /**
  * ccw_device_wait_idle() - busy wait for device to become idle
  * @cdev: ccw device
@@ -1726,15 +1745,8 @@ ccw_device_probe (struct device *dev)
        int ret;
 
        cdev->drv = cdrv; /* to let the driver call _set_online */
-       /* Note: we interpret class 0 in this context as an uninitialized
-        * field since it translates to a non-I/O interrupt class. */
-       if (cdrv->int_class != 0)
-               cdev->private->int_class = cdrv->int_class;
-       else
-               cdev->private->int_class = IRQIO_CIO;
-
+       ccw_device_set_int_class(cdev);
        ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
-
        if (ret) {
                cdev->drv = NULL;
                cdev->private->int_class = IRQIO_CIO;
index c3a83df07894e51195d914111c15be2c615f09c1..a0aff2eb247c2fb9657aff821299404aa2d20ddc 100644 (file)
@@ -33,8 +33,8 @@ struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
        /*                   N  P  A    M  L  V                      H  */
        [QETH_DBF_SETUP] = {"qeth_setup",
                                8, 1,   8, 5, &debug_hex_ascii_view, NULL},
-       [QETH_DBF_MSG]   = {"qeth_msg",
-                               8, 1, 128, 3, &debug_sprintf_view,   NULL},
+       [QETH_DBF_MSG]   = {"qeth_msg", 8, 1, 11 * sizeof(long), 3,
+                           &debug_sprintf_view, NULL},
        [QETH_DBF_CTRL]  = {"qeth_control",
                8, 1, QETH_DBF_CTRL_LEN, 5, &debug_hex_ascii_view, NULL},
 };
@@ -1660,7 +1660,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
                                QDIO_FLAG_CLEANUP_USING_CLEAR);
                if (rc)
                        QETH_CARD_TEXT_(card, 3, "1err%d", rc);
-               qdio_free(CARD_DDEV(card));
                atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                break;
        case QETH_QDIO_CLEANING:
@@ -2605,6 +2604,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
        return 0;
 out_qdio:
        qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
+       qdio_free(CARD_DDEV(card));
        return rc;
 }
 
@@ -4906,9 +4906,11 @@ retry:
        if (retries < 3)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
                        dev_name(&card->gdev->dev));
+       rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        rc = ccw_device_set_online(CARD_RDEV(card));
        if (rc)
                goto retriable;
@@ -4918,7 +4920,6 @@ retry:
        rc = ccw_device_set_online(CARD_DDEV(card));
        if (rc)
                goto retriable;
-       rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
 retriable:
        if (rc == -ERESTARTSYS) {
                QETH_DBF_TEXT(SETUP, 2, "break1");
index 0710550093ce6ac5fea8ddbf80f8409bbc1186f6..908d82529ee9c3e04a42caf92b9e0787836ef7d0 100644 (file)
@@ -1091,6 +1091,7 @@ out_remove:
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_RECOVER)
                card->state = CARD_STATE_RECOVER;
        else
@@ -1132,6 +1133,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
                rc = (rc2) ? rc2 : rc3;
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_UP)
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
@@ -1194,6 +1196,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
        qeth_qdio_clear_card(card, 0);
        qeth_clear_qdio_buffers(card);
+       qdio_free(CARD_DDEV(card));
 }
 
 static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
index 0f430424c3b8b0aec231c3e2ca69d739c0c29701..3524d34ff694c273afefc7d85bfa17b6bce38af9 100644 (file)
@@ -3447,6 +3447,7 @@ out_remove:
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_RECOVER)
                card->state = CARD_STATE_RECOVER;
        else
@@ -3493,6 +3494,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
                rc = (rc2) ? rc2 : rc3;
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_UP)
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
@@ -3545,6 +3547,7 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
        qeth_qdio_clear_card(card, 0);
        qeth_clear_qdio_buffers(card);
+       qdio_free(CARD_DDEV(card));
 }
 
 static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
index a3e6c8a3ff0faa852f163185c46e98d80fb49a43..296c936cc03cc43397ba4905d53ac1fd7b050f89 100644 (file)
@@ -90,6 +90,7 @@
 #include <linux/init.h>
 #include <linux/nvram.h>
 #include <linux/bitops.h>
+#include <linux/wait.h>
 
 #include <asm/setup.h>
 #include <asm/atarihw.h>
@@ -549,8 +550,10 @@ static void falcon_get_lock(void)
 
        local_irq_save(flags);
 
-       while (!in_irq() && falcon_got_lock && stdma_others_waiting())
-               sleep_on(&falcon_fairness_wait);
+       wait_event_cmd(falcon_fairness_wait,
+               in_interrupt() || !falcon_got_lock || !stdma_others_waiting(),
+               local_irq_restore(flags),
+               local_irq_save(flags));
 
        while (!falcon_got_lock) {
                if (in_irq())
@@ -562,7 +565,10 @@ static void falcon_get_lock(void)
                        falcon_trying_lock = 0;
                        wake_up(&falcon_try_wait);
                } else {
-                       sleep_on(&falcon_try_wait);
+                       wait_event_cmd(falcon_try_wait,
+                               falcon_got_lock && !falcon_trying_lock,
+                               local_irq_restore(flags),
+                               local_irq_save(flags));
                }
        }
 
index 1f375051483a428d24c63c206fb24a40cda06211..5642a9b250c2fe11201510460563ec576c70461c 100644 (file)
@@ -325,7 +325,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
                if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
                        continue;
 
-               if (abrt_task->sc->device->lun != abrt_task->sc->device->lun)
+               if (sc->device->lun != abrt_task->sc->device->lun)
                        continue;
 
                /* Invalidate WRB Posted for this Task */
index ed880891cb7c4b7c038ee73aac032b77108377d4..e9279a8c1e1c31ecb33daba06dceed4273eadd11 100644 (file)
@@ -594,13 +594,13 @@ static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
                mp_req->mp_resp_bd = NULL;
        }
        if (mp_req->req_buf) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                     mp_req->req_buf,
                                     mp_req->req_buf_dma);
                mp_req->req_buf = NULL;
        }
        if (mp_req->resp_buf) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                     mp_req->resp_buf,
                                     mp_req->resp_buf_dma);
                mp_req->resp_buf = NULL;
@@ -622,7 +622,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
 
        mp_req->req_len = sizeof(struct fcp_cmnd);
        io_req->data_xfer_len = mp_req->req_len;
-       mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                             &mp_req->req_buf_dma,
                                             GFP_ATOMIC);
        if (!mp_req->req_buf) {
@@ -631,7 +631,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
                return FAILED;
        }
 
-       mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                              &mp_req->resp_buf_dma,
                                              GFP_ATOMIC);
        if (!mp_req->resp_buf) {
@@ -639,8 +639,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
                bnx2fc_free_mp_resc(io_req);
                return FAILED;
        }
-       memset(mp_req->req_buf, 0, PAGE_SIZE);
-       memset(mp_req->resp_buf, 0, PAGE_SIZE);
+       memset(mp_req->req_buf, 0, CNIC_PAGE_SIZE);
+       memset(mp_req->resp_buf, 0, CNIC_PAGE_SIZE);
 
        /* Allocate and map mp_req_bd and mp_resp_bd */
        sz = sizeof(struct fcoe_bd_ctx);
@@ -665,7 +665,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
        mp_req_bd = mp_req->mp_req_bd;
        mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff;
        mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32);
-       mp_req_bd->buf_len = PAGE_SIZE;
+       mp_req_bd->buf_len = CNIC_PAGE_SIZE;
        mp_req_bd->flags = 0;
 
        /*
@@ -677,7 +677,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
        addr = mp_req->resp_buf_dma;
        mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff;
        mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32);
-       mp_resp_bd->buf_len = PAGE_SIZE;
+       mp_resp_bd->buf_len = CNIC_PAGE_SIZE;
        mp_resp_bd->flags = 0;
 
        return SUCCESS;
index 4d93177dfb530c4446d959bd97fb71cd5dee86d1..d9bae5672273762dba7d183b4bedcc5206c1f9fe 100644 (file)
@@ -673,7 +673,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map SQ */
        tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
-       tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->sq_mem_size = (tgt->sq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
                                     &tgt->sq_dma, GFP_KERNEL);
@@ -686,7 +687,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map CQ */
        tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
-       tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->cq_mem_size = (tgt->cq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
                                     &tgt->cq_dma, GFP_KERNEL);
@@ -699,7 +701,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map RQ and RQ PBL */
        tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
-       tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->rq_mem_size = (tgt->rq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
                                        &tgt->rq_dma, GFP_KERNEL);
@@ -710,8 +713,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        }
        memset(tgt->rq, 0, tgt->rq_mem_size);
 
-       tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
-       tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->rq_pbl_size = (tgt->rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
+       tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
                                         &tgt->rq_pbl_dma, GFP_KERNEL);
@@ -722,7 +726,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        }
 
        memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
-       num_pages = tgt->rq_mem_size / PAGE_SIZE;
+       num_pages = tgt->rq_mem_size / CNIC_PAGE_SIZE;
        page = tgt->rq_dma;
        pbl = (u32 *)tgt->rq_pbl;
 
@@ -731,13 +735,13 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                pbl++;
                *pbl = (u32)((u64)page >> 32);
                pbl++;
-               page += PAGE_SIZE;
+               page += CNIC_PAGE_SIZE;
        }
 
        /* Allocate and map XFERQ */
        tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
-       tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) &
-                              PAGE_MASK;
+       tgt->xferq_mem_size = (tgt->xferq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                              CNIC_PAGE_MASK;
 
        tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
                                        &tgt->xferq_dma, GFP_KERNEL);
@@ -750,8 +754,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map CONFQ & CONFQ PBL */
        tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
-       tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) &
-                              PAGE_MASK;
+       tgt->confq_mem_size = (tgt->confq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                              CNIC_PAGE_MASK;
 
        tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
                                        &tgt->confq_dma, GFP_KERNEL);
@@ -763,9 +767,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        memset(tgt->confq, 0, tgt->confq_mem_size);
 
        tgt->confq_pbl_size =
-               (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (tgt->confq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        tgt->confq_pbl_size =
-               (tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
                                            tgt->confq_pbl_size,
@@ -777,7 +781,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        }
 
        memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
-       num_pages = tgt->confq_mem_size / PAGE_SIZE;
+       num_pages = tgt->confq_mem_size / CNIC_PAGE_SIZE;
        page = tgt->confq_dma;
        pbl = (u32 *)tgt->confq_pbl;
 
@@ -786,7 +790,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                pbl++;
                *pbl = (u32)((u64)page >> 32);
                pbl++;
-               page += PAGE_SIZE;
+               page += CNIC_PAGE_SIZE;
        }
 
        /* Allocate and map ConnDB */
@@ -805,8 +809,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map LCQ */
        tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
-       tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) &
-                            PAGE_MASK;
+       tgt->lcq_mem_size = (tgt->lcq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                            CNIC_PAGE_MASK;
 
        tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
                                      &tgt->lcq_dma, GFP_KERNEL);
index e4cf23df4b4f094d64a40332c81facd39da4097c..b87a1933f8809381d974392e6e7b3e7f208b86aa 100644 (file)
@@ -61,7 +61,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
         * yield integral num of page buffers
         */
        /* adjust SQ */
-       num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+       num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
        if (hba->max_sqes < num_elements_per_pg)
                hba->max_sqes = num_elements_per_pg;
        else if (hba->max_sqes % num_elements_per_pg)
@@ -69,7 +69,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
                                 ~(num_elements_per_pg - 1);
 
        /* adjust CQ */
-       num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+       num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
        if (hba->max_cqes < num_elements_per_pg)
                hba->max_cqes = num_elements_per_pg;
        else if (hba->max_cqes % num_elements_per_pg)
@@ -77,7 +77,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
                                 ~(num_elements_per_pg - 1);
 
        /* adjust RQ */
-       num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+       num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
        if (hba->max_rqes < num_elements_per_pg)
                hba->max_rqes = num_elements_per_pg;
        else if (hba->max_rqes % num_elements_per_pg)
@@ -959,7 +959,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
 
        /* SQ page table */
        memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
-       num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+       num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
        page = ep->qp.sq_phys;
 
        if (cnic_dev_10g)
@@ -973,7 +973,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) ((u64) page >> 32);
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                } else {
                        /* PTE is written in big endian format for
                         * 5706/5708/5709 devices */
@@ -981,13 +981,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) page;
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                }
        }
 
        /* RQ page table */
        memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
-       num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+       num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
        page = ep->qp.rq_phys;
 
        if (cnic_dev_10g)
@@ -1001,7 +1001,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) ((u64) page >> 32);
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                } else {
                        /* PTE is written in big endian format for
                         * 5706/5708/5709 devices */
@@ -1009,13 +1009,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) page;
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                }
        }
 
        /* CQ page table */
        memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
-       num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+       num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
        page = ep->qp.cq_phys;
 
        if (cnic_dev_10g)
@@ -1029,7 +1029,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) ((u64) page >> 32);
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                } else {
                        /* PTE is written in big endian format for
                         * 5706/5708/5709 devices */
@@ -1037,7 +1037,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) page;
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                }
        }
 }
@@ -1064,11 +1064,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
        /* Allocate page table memory for SQ which is page aligned */
        ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
        ep->qp.sq_mem_size =
-               (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
        ep->qp.sq_pgtbl_size =
-               (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        ep->qp.sq_pgtbl_size =
-               (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        ep->qp.sq_pgtbl_virt =
                dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
@@ -1101,11 +1101,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
        /* Allocate page table memory for CQ which is page aligned */
        ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
        ep->qp.cq_mem_size =
-               (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
        ep->qp.cq_pgtbl_size =
-               (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        ep->qp.cq_pgtbl_size =
-               (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        ep->qp.cq_pgtbl_virt =
                dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
@@ -1144,11 +1144,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
        /* Allocate page table memory for RQ which is page aligned */
        ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
        ep->qp.rq_mem_size =
-               (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
        ep->qp.rq_pgtbl_size =
-               (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        ep->qp.rq_pgtbl_size =
-               (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        ep->qp.rq_pgtbl_virt =
                dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
@@ -1270,7 +1270,7 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
        bnx2i_adjust_qp_size(hba);
 
        iscsi_init.flags =
-               ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+               (CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
        if (en_tcp_dack)
                iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
        iscsi_init.reserved0 = 0;
@@ -1288,15 +1288,15 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
                        ((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
        iscsi_init.num_ccells_per_conn = hba->num_ccell;
        iscsi_init.num_tasks_per_conn = hba->max_sqes;
-       iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+       iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
        iscsi_init.sq_num_wqes = hba->max_sqes;
        iscsi_init.cq_log_wqes_per_page =
-               (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+               (u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
        iscsi_init.cq_num_wqes = hba->max_cqes;
        iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
-                                  (PAGE_SIZE - 1)) / PAGE_SIZE;
+                                  (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
        iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
-                                  (PAGE_SIZE - 1)) / PAGE_SIZE;
+                                  (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
        iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
        iscsi_init.rq_num_wqes = hba->max_rqes;
 
index 854dad7d5b03318d10077d2e367eeb6ca8242dc6..c8b0aff5bbd4aa86d79b64516acf87d97c8894bd 100644 (file)
@@ -525,7 +525,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
        struct iscsi_bd *mp_bdt;
        u64 addr;
 
-       hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                            &hba->mp_bd_dma, GFP_KERNEL);
        if (!hba->mp_bd_tbl) {
                printk(KERN_ERR "unable to allocate Middle Path BDT\n");
@@ -533,11 +533,12 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
                goto out;
        }
 
-       hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+                                              CNIC_PAGE_SIZE,
                                               &hba->dummy_buf_dma, GFP_KERNEL);
        if (!hba->dummy_buffer) {
                printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  hba->mp_bd_tbl, hba->mp_bd_dma);
                hba->mp_bd_tbl = NULL;
                rc = -1;
@@ -548,7 +549,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
        addr = (unsigned long) hba->dummy_buf_dma;
        mp_bdt->buffer_addr_lo = addr & 0xffffffff;
        mp_bdt->buffer_addr_hi = addr >> 32;
-       mp_bdt->buffer_length = PAGE_SIZE;
+       mp_bdt->buffer_length = CNIC_PAGE_SIZE;
        mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
                        ISCSI_BD_FIRST_IN_BD_CHAIN;
 out:
@@ -565,12 +566,12 @@ out:
 static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
 {
        if (hba->mp_bd_tbl) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  hba->mp_bd_tbl, hba->mp_bd_dma);
                hba->mp_bd_tbl = NULL;
        }
        if (hba->dummy_buffer) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  hba->dummy_buffer, hba->dummy_buf_dma);
                hba->dummy_buffer = NULL;
        }
@@ -934,14 +935,14 @@ static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
                                            struct bnx2i_conn *bnx2i_conn)
 {
        if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  bnx2i_conn->gen_pdu.resp_bd_tbl,
                                  bnx2i_conn->gen_pdu.resp_bd_dma);
                bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
        }
 
        if (bnx2i_conn->gen_pdu.req_bd_tbl) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  bnx2i_conn->gen_pdu.req_bd_tbl,
                                  bnx2i_conn->gen_pdu.req_bd_dma);
                bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -998,13 +999,13 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
        bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
 
        bnx2i_conn->gen_pdu.req_bd_tbl =
-               dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                   &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
        if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
                goto login_req_bd_tbl_failure;
 
        bnx2i_conn->gen_pdu.resp_bd_tbl =
-               dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                   &bnx2i_conn->gen_pdu.resp_bd_dma,
                                   GFP_KERNEL);
        if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
@@ -1013,7 +1014,7 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
        return 0;
 
 login_resp_bd_tbl_failure:
-       dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                          bnx2i_conn->gen_pdu.req_bd_tbl,
                          bnx2i_conn->gen_pdu.req_bd_dma);
        bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
index 4911310a38f5e42fd9d292b89de93b57369c7419..22a9bb1abae1473062b06031494bb38b2cc11576 100644 (file)
@@ -311,9 +311,8 @@ static inline struct Scsi_Host *to_shost(struct isci_host *ihost)
 }
 
 #define for_each_isci_host(id, ihost, pdev) \
-       for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
-            id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
-            ihost = to_pci_info(pdev)->hosts[++id])
+       for (id = 0; id < SCI_MAX_CONTROLLERS && \
+            (ihost = to_pci_info(pdev)->hosts[id]); id++)
 
 static inline void wait_for_start(struct isci_host *ihost)
 {
index 85c77f6b802bdcba5795ced971a39e29f39ae8b9..ac879745ef8007ab2a4973aff26e3c950e8f1dba 100644 (file)
@@ -615,13 +615,6 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
                                          SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
        } else {
                /* the phy is already the part of the port */
-               u32 port_state = iport->sm.current_state_id;
-
-               /* if the PORT'S state is resetting then the link up is from
-                * port hard reset in this case, we need to tell the port
-                * that link up is recieved
-                */
-               BUG_ON(port_state != SCI_PORT_RESETTING);
                port_agent->phy_ready_mask |= 1 << phy_index;
                sci_port_link_up(iport, iphy);
        }
index 0d30ca849e8f71502c9ecddfa9aa539e4e59af0f..5d6fda72d659770d080e2c4201c4d3e6c7af1adc 100644 (file)
@@ -801,7 +801,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
                /* XXX: need to cleanup any ireqs targeting this
                 * domain_device
                 */
-               ret = TMF_RESP_FUNC_COMPLETE;
+               ret = -ENODEV;
                goto out;
        }
 
index d2895836f9fa4c00fec1a46d993074ecb3edeaea..766098af4eb79aebf8f080b6906db8aeade896e7 100644 (file)
@@ -700,46 +700,26 @@ void sas_probe_sata(struct asd_sas_port *port)
 
 }
 
-static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
 {
        struct domain_device *dev, *n;
-       bool retry = false;
 
        list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
-               int rc;
-
                if (!dev_is_sata(dev))
                        continue;
 
                sas_ata_wait_eh(dev);
-               rc = dev->sata_dev.pm_result;
-               if (rc == -EAGAIN)
-                       retry = true;
-               else if (rc) {
-                       /* since we don't have a
-                        * ->port_{suspend|resume} routine in our
-                        *  ata_port ops, and no entanglements with
-                        *  acpi, suspend should just be mechanical trip
-                        *  through eh, catch cases where these
-                        *  assumptions are invalidated
-                        */
-                       WARN_ONCE(1, "failed %s %s error: %d\n", func,
-                                dev_name(&dev->rphy->dev), rc);
-               }
 
                /* if libata failed to power manage the device, tear it down */
                if (ata_dev_disabled(sas_to_ata_dev(dev)))
                        sas_fail_probe(dev, func, -ENODEV);
        }
-
-       return retry;
 }
 
 void sas_suspend_sata(struct asd_sas_port *port)
 {
        struct domain_device *dev;
 
- retry:
        mutex_lock(&port->ha->disco_mutex);
        list_for_each_entry(dev, &port->dev_list, dev_list_node) {
                struct sata_device *sata;
@@ -751,20 +731,17 @@ void sas_suspend_sata(struct asd_sas_port *port)
                if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
                        continue;
 
-               sata->pm_result = -EIO;
-               ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+               ata_sas_port_suspend(sata->ap);
        }
        mutex_unlock(&port->ha->disco_mutex);
 
-       if (sas_ata_flush_pm_eh(port, __func__))
-               goto retry;
+       sas_ata_flush_pm_eh(port, __func__);
 }
 
 void sas_resume_sata(struct asd_sas_port *port)
 {
        struct domain_device *dev;
 
- retry:
        mutex_lock(&port->ha->disco_mutex);
        list_for_each_entry(dev, &port->dev_list, dev_list_node) {
                struct sata_device *sata;
@@ -776,13 +753,11 @@ void sas_resume_sata(struct asd_sas_port *port)
                if (sata->ap->pm_mesg.event == PM_EVENT_ON)
                        continue;
 
-               sata->pm_result = -EIO;
-               ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+               ata_sas_port_resume(sata->ap);
        }
        mutex_unlock(&port->ha->disco_mutex);
 
-       if (sas_ata_flush_pm_eh(port, __func__))
-               goto retry;
+       sas_ata_flush_pm_eh(port, __func__);
 }
 
 /**
index e1fe95ef23e11353aed91a8da9dd1d1f8ef2a9c3..266724b6b8996d451c4bf81c2ff5f0dbee5c1de5 100644 (file)
@@ -2996,8 +2996,7 @@ struct qla_hw_data {
                                IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
                                IS_QLA8044(ha))
 #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
-#define IS_NOPOLLING_TYPE(ha)  ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
-                       IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
+#define IS_NOPOLLING_TYPE(ha)  (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
 #define IS_FAC_REQUIRED(ha)    (IS_QLA81XX(ha) || IS_QLA83XX(ha))
 #define IS_NOCACHE_VPD_TYPE(ha)        (IS_QLA81XX(ha) || IS_QLA83XX(ha))
 #define IS_ALOGIO_CAPABLE(ha)  (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
index 9bc86b9e86b172145443d161e0715658df6acdc7..0a1dcb43d18bdb6b4c734e0ad38ac956ddeb5fe7 100644 (file)
@@ -2880,6 +2880,7 @@ static int
 qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
 #define MIN_MSIX_COUNT 2
+#define ATIO_VECTOR    2
        int i, ret;
        struct msix_entry *entries;
        struct qla_msix_entry *qentry;
@@ -2936,34 +2937,47 @@ msix_failed:
        }
 
        /* Enable MSI-X vectors for the base queue */
-       for (i = 0; i < ha->msix_count; i++) {
+       for (i = 0; i < 2; i++) {
                qentry = &ha->msix_entries[i];
-               if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
-                       ret = request_irq(qentry->vector,
-                               qla83xx_msix_entries[i].handler,
-                               0, qla83xx_msix_entries[i].name, rsp);
-               } else if (IS_P3P_TYPE(ha)) {
+               if (IS_P3P_TYPE(ha))
                        ret = request_irq(qentry->vector,
                                qla82xx_msix_entries[i].handler,
                                0, qla82xx_msix_entries[i].name, rsp);
-               } else {
+               else
                        ret = request_irq(qentry->vector,
                                msix_entries[i].handler,
                                0, msix_entries[i].name, rsp);
-               }
-               if (ret) {
-                       ql_log(ql_log_fatal, vha, 0x00cb,
-                           "MSI-X: unable to register handler -- %x/%d.\n",
-                           qentry->vector, ret);
-                       qla24xx_disable_msix(ha);
-                       ha->mqenable = 0;
-                       goto msix_out;
-               }
+               if (ret)
+                       goto msix_register_fail;
                qentry->have_irq = 1;
                qentry->rsp = rsp;
                rsp->msix = qentry;
        }
 
+       /*
+        * If target mode is enable, also request the vector for the ATIO
+        * queue.
+        */
+       if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
+               qentry = &ha->msix_entries[ATIO_VECTOR];
+               ret = request_irq(qentry->vector,
+                       qla83xx_msix_entries[ATIO_VECTOR].handler,
+                       0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
+               qentry->have_irq = 1;
+               qentry->rsp = rsp;
+               rsp->msix = qentry;
+       }
+
+msix_register_fail:
+       if (ret) {
+               ql_log(ql_log_fatal, vha, 0x00cb,
+                   "MSI-X: unable to register handler -- %x/%d.\n",
+                   qentry->vector, ret);
+               qla24xx_disable_msix(ha);
+               ha->mqenable = 0;
+               goto msix_out;
+       }
+
        /* Enable MSI-X vector for response queue update for queue 0 */
        if (IS_QLA83XX(ha)) {
                if (ha->msixbase && ha->mqiobase &&
index 17d7404272400dd1a76989a3965e0c4b85343036..9969fa1ef7c4ef09ac4fc72c942c5ef72703ae49 100644 (file)
@@ -1419,6 +1419,9 @@ static void storvsc_device_destroy(struct scsi_device *sdevice)
 {
        struct stor_mem_pools *memp = sdevice->hostdata;
 
+       if (!memp)
+               return;
+
        mempool_destroy(memp->request_mempool);
        kmem_cache_destroy(memp->request_pool);
        kfree(memp);
index 581ee2a8856b157641eb5a6b2c13389241b4ea90..efe1960af2b315704c39290617dbc2215f8aec48 100644 (file)
@@ -150,7 +150,7 @@ config SPI_BUTTERFLY
 
 config SPI_CLPS711X
        tristate "CLPS711X host SPI controller"
-       depends on ARCH_CLPS711X
+       depends on ARCH_CLPS711X || COMPILE_TEST
        help
          This enables dedicated general purpose SPI/Microwire1-compatible
          master mode interface (SSI1) for CLPS711X-based CPUs.
@@ -212,7 +212,6 @@ config SPI_IMX
        tristate "Freescale i.MX SPI controllers"
        depends on ARCH_MXC || COMPILE_TEST
        select SPI_BITBANG
-       default m if IMX_HAVE_PLATFORM_SPI_IMX
        help
          This enables using the Freescale i.MX SPI controllers in master
          mode.
@@ -270,6 +269,7 @@ config SPI_FSL_SPI
 config SPI_FSL_DSPI
        tristate "Freescale DSPI controller"
        select SPI_BITBANG
+       select REGMAP_MMIO
        depends on SOC_VF610 || COMPILE_TEST
        help
          This enables support for the Freescale DSPI controller in master
@@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE
 
 config SPI_OMAP24XX
        tristate "McSPI driver for OMAP"
-       depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH
+       depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
        depends on ARCH_OMAP2PLUS || COMPILE_TEST
        help
          SPI master controller for OMAP24XX and later Multichannel SPI
@@ -381,6 +381,19 @@ config SPI_RSPI
        help
          SPI driver for Renesas RSPI and QSPI blocks.
 
+config SPI_QUP
+       tristate "Qualcomm SPI controller with QUP interface"
+       depends on ARCH_MSM_DT || (ARM && COMPILE_TEST)
+       help
+         Qualcomm Universal Peripheral (QUP) core is an AHB slave that
+         provides a common data path (an output FIFO and an input FIFO)
+         for serial peripheral interface (SPI) mini-core. SPI in master
+         mode supports up to 50MHz, up to four chip selects, programmable
+         data path from 4 bits to 32 bits and numerous protocol variants.
+
+         This driver can also be built as a module.  If so, the module
+         will be called spi_qup.
+
 config SPI_S3C24XX
        tristate "Samsung S3C24XX series SPI"
        depends on ARCH_S3C24XX
@@ -416,7 +429,6 @@ config SPI_SH_MSIOF
        tristate "SuperH MSIOF SPI controller"
        depends on HAVE_CLK
        depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
-       select SPI_BITBANG
        help
          SPI driver for SuperH and SH Mobile MSIOF blocks.
 
@@ -446,6 +458,19 @@ config SPI_SIRF
        help
          SPI driver for CSR SiRFprimaII SoCs
 
+config SPI_SUN4I
+       tristate "Allwinner A10 SoCs SPI controller"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       help
+         SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
+
+config SPI_SUN6I
+       tristate "Allwinner A31 SPI controller"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       depends on RESET_CONTROLLER
+       help
+         This enables using the SPI controller on the Allwinner A31 SoCs.
+
 config SPI_MXS
        tristate "Freescale MXS SPI controller"
        depends on ARCH_MXS
@@ -478,13 +503,6 @@ config SPI_TEGRA20_SLINK
        help
          SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
 
-config SPI_TI_SSP
-       tristate "TI Sequencer Serial Port - SPI Support"
-       depends on MFD_TI_SSP
-       help
-         This selects an SPI master implementation using a TI sequencer
-         serial port.
-
 config SPI_TOPCLIFF_PCH
        tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
        depends on PCI
@@ -520,6 +538,19 @@ config SPI_XILINX
 
          Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
 
+config SPI_XTENSA_XTFPGA
+       tristate "Xtensa SPI controller for xtfpga"
+       depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
+       select SPI_BITBANG
+       help
+         SPI driver for xtfpga SPI master controller.
+
+         This simple SPI master controller is built into xtfpga bitstreams
+         and is used to control daughterboard audio codec. It always transfers
+         16 bit words in SPI mode 0, automatically asserting CS on transfer
+         start and deasserting on end.
+
+
 config SPI_NUC900
        tristate "Nuvoton NUC900 series SPI"
        depends on ARCH_W90X900
@@ -546,7 +577,7 @@ config SPI_DW_MID_DMA
 
 config SPI_DW_MMIO
        tristate "Memory-mapped io interface driver for DW SPI core"
-       depends on SPI_DESIGNWARE && HAVE_CLK
+       depends on SPI_DESIGNWARE
 
 #
 # There are lots of SPI device types, with sensors and memory
index 95af48d2d360d694e25012c80fa0cf127222db16..bd792669e56395525cfa3aba6c3542cb54fc6dad 100644 (file)
@@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA)       += spi-pxa2xx-pxadma.o
 spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)   += spi-pxa2xx-dma.o
 obj-$(CONFIG_SPI_PXA2XX)               += spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)           += spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QUP)                  += spi-qup.o
 obj-$(CONFIG_SPI_RSPI)                 += spi-rspi.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi-s3c24xx-hw.o
 spi-s3c24xx-hw-y                       := spi-s3c24xx.o
@@ -70,12 +71,14 @@ obj-$(CONFIG_SPI_SH_HSPI)           += spi-sh-hspi.o
 obj-$(CONFIG_SPI_SH_MSIOF)             += spi-sh-msiof.o
 obj-$(CONFIG_SPI_SH_SCI)               += spi-sh-sci.o
 obj-$(CONFIG_SPI_SIRF)         += spi-sirf.o
+obj-$(CONFIG_SPI_SUN4I)                        += spi-sun4i.o
+obj-$(CONFIG_SPI_SUN6I)                        += spi-sun6i.o
 obj-$(CONFIG_SPI_TEGRA114)             += spi-tegra114.o
 obj-$(CONFIG_SPI_TEGRA20_SFLASH)       += spi-tegra20-sflash.o
 obj-$(CONFIG_SPI_TEGRA20_SLINK)                += spi-tegra20-slink.o
-obj-$(CONFIG_SPI_TI_SSP)               += spi-ti-ssp.o
 obj-$(CONFIG_SPI_TLE62X0)              += spi-tle62x0.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH)         += spi-topcliff-pch.o
 obj-$(CONFIG_SPI_TXX9)                 += spi-txx9.o
 obj-$(CONFIG_SPI_XCOMM)                += spi-xcomm.o
 obj-$(CONFIG_SPI_XILINX)               += spi-xilinx.o
+obj-$(CONFIG_SPI_XTENSA_XTFPGA)                += spi-xtensa-xtfpga.o
index 5d7deaf628670b1cfad9c92b21d66c03a7c8d805..5b5709a5c95725276a3942745e9edbf6dc2fb53e 100644 (file)
@@ -13,7 +13,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -200,7 +199,6 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
 
 static int altera_spi_probe(struct platform_device *pdev)
 {
-       struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
        struct altera_spi *hw;
        struct spi_master *master;
        struct resource *res;
@@ -214,6 +212,8 @@ 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->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+       master->dev.of_node = pdev->dev.of_node;
 
        hw = spi_master_get_devdata(master);
        platform_set_drvdata(pdev, hw);
@@ -245,9 +245,6 @@ static int altera_spi_probe(struct platform_device *pdev)
                if (err)
                        goto exit;
        }
-       /* find platform data */
-       if (!platp)
-               hw->bitbang.master->dev.of_node = pdev->dev.of_node;
 
        /* register our spi controller */
        err = spi_bitbang_start(&hw->bitbang);
index 31534b51715aa95e29664cc80d44d71b5131d0ab..3898b0b9ee77cf2f0115c815a26dba9106cccf4a 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
@@ -132,9 +131,9 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
 
                flags = GPIOF_DIR_OUT;
                if (spi->mode & SPI_CS_HIGH)
-                       flags |= GPIOF_INIT_HIGH;
-               else
                        flags |= GPIOF_INIT_LOW;
+               else
+                       flags |= GPIOF_INIT_HIGH;
 
                status = gpio_request_one(cdata->gpio, flags,
                                          dev_name(&spi->dev));
index b0842f75101647616ada3a3db4f545a57b519be0..8005f986948173e55d5bc5a5387da80c8a5b9185 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -26,6 +25,7 @@
 
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
 
 /* SPI register offsets */
 #define SPI_CR                                 0x0000
@@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi)
 
        as = spi_master_get_devdata(spi->master);
 
-       if (spi->chip_select > spi->master->num_chipselect) {
-               dev_dbg(&spi->dev,
-                               "setup: invalid chipselect %u (%u defined)\n",
-                               spi->chip_select, spi->master->num_chipselect);
-               return -EINVAL;
-       }
-
        /* see notes above re chipselect */
        if (!atmel_spi_is_v2(as)
                        && spi->chip_select == 0
@@ -1087,14 +1080,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                }
        }
 
-       if (xfer->bits_per_word > 8) {
-               if (xfer->len % 2) {
-                       dev_dbg(&spi->dev,
-                       "buffer len should be 16 bits aligned\n");
-                       return -EINVAL;
-               }
-       }
-
        /*
         * DMA map early, for performance (empties dcache ASAP) and
         * better fault reporting.
@@ -1221,9 +1206,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
        dev_dbg(&spi->dev, "new message %p submitted for %s\n",
                                        msg, dev_name(&spi->dev));
 
-       if (unlikely(list_empty(&msg->transfers)))
-               return -EINVAL;
-
        atmel_spi_lock(as);
        cs_activate(as, spi);
 
@@ -1244,10 +1226,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                dev_dbg(&spi->dev,
-                       "  xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+                       "  xfer %p: len %u tx %p/%pad rx %p/%pad\n",
                        xfer, xfer->len,
-                       xfer->tx_buf, xfer->tx_dma,
-                       xfer->rx_buf, xfer->rx_dma);
+                       xfer->tx_buf, &xfer->tx_dma,
+                       xfer->rx_buf, &xfer->rx_dma);
        }
 
 msg_done:
@@ -1303,6 +1285,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
        struct spi_master       *master;
        struct atmel_spi        *as;
 
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(&pdev->dev);
+
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
                return -ENXIO;
@@ -1455,8 +1440,19 @@ static int atmel_spi_suspend(struct device *dev)
 {
        struct spi_master       *master = dev_get_drvdata(dev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
+       int ret;
+
+       /* Stop the queue running */
+       ret = spi_master_suspend(master);
+       if (ret) {
+               dev_warn(dev, "cannot suspend master\n");
+               return ret;
+       }
 
        clk_disable_unprepare(as->clk);
+
+       pinctrl_pm_select_sleep_state(dev);
+
        return 0;
 }
 
@@ -1464,9 +1460,18 @@ static int atmel_spi_resume(struct device *dev)
 {
        struct spi_master       *master = dev_get_drvdata(dev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
+       int ret;
+
+       pinctrl_pm_select_default_state(dev);
 
        clk_prepare_enable(as->clk);
-       return 0;
+
+       /* Start the queue running */
+       ret = spi_master_resume(master);
+       if (ret)
+               dev_err(dev, "problem starting queue (%d)\n", ret);
+
+       return ret;
 }
 
 static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
index c4141c92bcff5734c4f228e94c5ce38a665c0d94..aafb812d7ea605b9b2b3fab468029d6fea022a5a 100644 (file)
@@ -55,8 +55,6 @@ struct au1550_spi {
 
        volatile psc_spi_t __iomem *regs;
        int irq;
-       unsigned freq_max;
-       unsigned freq_min;
 
        unsigned len;
        unsigned tx_count;
@@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
                        hz = t->speed_hz;
        }
 
-       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);
+       if (!hz)
                return -EINVAL;
-       }
 
        au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
 
@@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
        return 0;
 }
 
-static int au1550_spi_setup(struct spi_device *spi)
-{
-       struct au1550_spi *hw = spi_master_get_devdata(spi->master);
-
-       if (spi->max_speed_hz == 0)
-               spi->max_speed_hz = hw->freq_max;
-       if (spi->max_speed_hz > hw->freq_max
-                       || spi->max_speed_hz < hw->freq_min)
-               return -EINVAL;
-       /*
-        * NOTE: cannot change speed and other hw settings immediately,
-        *       otherwise sharing of spi bus is not possible,
-        *       so do not call setupxfer(spi, NULL) here
-        */
-       return 0;
-}
-
 /*
  * for dma spi transfers, we have to setup rx channel, otherwise there is
  * no reliable way how to recognize that spi transfer is done
@@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev)
        hw->bitbang.master = hw->master;
        hw->bitbang.setup_transfer = au1550_spi_setupxfer;
        hw->bitbang.chipselect = au1550_spi_chipsel;
-       hw->bitbang.master->setup = au1550_spi_setup;
        hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
 
        if (hw->usedma) {
@@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
        {
                int min_div = (2 << 0) * (2 * (4 + 1));
                int max_div = (2 << 3) * (2 * (63 + 1));
-               hw->freq_max = hw->pdata->mainclk_hz / min_div;
-               hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
+               master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
+               master->min_speed_hz =
+                               hw->pdata->mainclk_hz / (max_div + 1) + 1;
        }
 
        au1550_spi_setup_psc_as_spi(hw);
index 8a89dd1f265427da19089824d284432451c7537c..69167456ec1e6a7c6de0a3cd68003bafbc8c78ed 100644 (file)
@@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 
        master->mode_bits = BCM2835_SPI_MODE_BITS;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
-       master->bus_num = -1;
        master->num_chipselect = 3;
        master->transfer_one_message = bcm2835_spi_transfer_one;
        master->dev.of_node = pdev->dev.of_node;
index b528f9fc8bc01959a4746f4a239b8c43b31e0577..5a211e98383bacc7e315240e2e5adf29e5668de9 100644 (file)
@@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
        while (pending > 0) {
                int curr_step = min_t(int, step_size, pending);
 
-               init_completion(&bs->done);
+               reinit_completion(&bs->done);
                if (tx) {
                        memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
                        tx += curr_step;
@@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
        bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
 
        mutex_init(&bs->bus_mutex);
+       init_completion(&bs->done);
 
        master->bus_num = HSSPI_BUS_NUM;
        master->num_chipselect = 8;
@@ -453,9 +454,8 @@ static int bcm63xx_hsspi_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume)
-};
+static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
+                        bcm63xx_hsspi_resume);
 
 static struct platform_driver bcm63xx_hsspi_driver = {
        .driver = {
index 77286aef2adfc9e5495704405f4c76f45855b1a0..0250fa721cea89277ef7843979ceaf95e7e4400a 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -35,8 +34,6 @@
 
 #include <bcm63xx_dev_spi.h>
 
-#define PFX            KBUILD_MODNAME
-
 #define BCM63XX_SPI_MAX_PREPEND                15
 
 struct bcm63xx_spi {
@@ -169,7 +166,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
                               transfer_list);
        }
 
-       init_completion(&bs->done);
+       reinit_completion(&bs->done);
 
        /* Fill in the Message control register */
        msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
@@ -353,6 +350,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
        }
 
        bs = spi_master_get_devdata(master);
+       init_completion(&bs->done);
 
        platform_set_drvdata(pdev, master);
        bs->pdev = pdev;
index 38941e5920b50fe2bb9455cc9392fe6803db6355..f515c5e9db5723babdf9f15ba808185011459948 100644 (file)
@@ -8,7 +8,6 @@
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/device.h>
index 8f8598834b30d0831ed08e6711a3528994f6df58..4089d0e0d84ee62deee2ed25d5d2f12b5ba65687 100644 (file)
@@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev)
        master->cleanup = bfin_spi_cleanup;
        master->setup = bfin_spi_setup;
        master->transfer_one_message = bfin_spi_transfer_one_message;
-       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);
 
        drv_data = spi_master_get_devdata(master);
        drv_data->master = master;
index f0f195af75d4d67815e6d550d54c5cf990d6813f..55e57c3eb9bd051bc7fcca7d5090a2d999bf688b 100644 (file)
@@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
 static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
 {
        struct bfin_spi_slave_data *chip = drv_data->cur_chip;
-       struct spi_transfer *last_transfer;
        unsigned long flags;
        struct spi_message *msg;
 
@@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
        queue_work(drv_data->workqueue, &drv_data->pump_messages);
        spin_unlock_irqrestore(&drv_data->lock, flags);
 
-       last_transfer = list_entry(msg->transfers.prev,
-                                  struct spi_transfer, transfer_list);
-
        msg->state = NULL;
 
        if (!drv_data->cs_change)
@@ -1030,10 +1026,6 @@ static int bfin_spi_setup(struct spi_device *spi)
        }
 
        /* 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");
-               goto error;
-       }
        if (spi->mode & SPI_CPOL)
                chip->ctl_reg |= BIT_CTL_CPOL;
        if (spi->mode & SPI_CPHA)
index bd222f6b677d0c775dbd608a66356554adefa660..dc7d2c2d643e80e3b6fa65564cc76b435d76ce50 100644 (file)
@@ -16,7 +16,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
@@ -467,11 +466,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start);
 /**
  * spi_bitbang_stop - stops the task providing spi communication
  */
-int spi_bitbang_stop(struct spi_bitbang *bitbang)
+void spi_bitbang_stop(struct spi_bitbang *bitbang)
 {
        spi_unregister_master(bitbang->master);
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_stop);
 
index 8081f96bd1d5add797eb482446f55850cbc248f1..ee4f91ccd8fd53bac3c77a04de9e898d690085bc 100644 (file)
@@ -309,7 +309,6 @@ done:
 static void butterfly_detach(struct parport *p)
 {
        struct butterfly        *pp;
-       int                     status;
 
        /* FIXME this global is ugly ... but, how to quickly get from
         * the parport to the "struct butterfly" associated with it?
@@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p)
        butterfly = NULL;
 
        /* stop() unregisters child devices too */
-       status = spi_bitbang_stop(&pp->bitbang);
+       spi_bitbang_stop(&pp->bitbang);
 
        /* turn off VCC */
        parport_write_data(pp->port, 0);
index 374ba4a48a9e1450dba5c46c062c71a3de6f00df..4cd62f63654741010a70fa7d45a4aae820a87e32 100644 (file)
 
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/init.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
 #include <linux/spi/spi.h>
 #include <linux/platform_data/spi-clps711x.h>
 
-#include <mach/hardware.h>
-
 #define DRIVER_NAME    "spi-clps711x"
 
-struct spi_clps711x_data {
-       struct completion       done;
+#define SYNCIO_FRMLEN(x)       ((x) << 8)
+#define SYNCIO_TXFRMEN         (1 << 14)
 
+struct spi_clps711x_data {
+       void __iomem            *syncio;
+       struct regmap           *syscon;
+       struct regmap           *syscon1;
        struct clk              *spi_clk;
-       u32                     max_speed_hz;
 
        u8                      *tx_buf;
        u8                      *rx_buf;
-       int                     count;
+       unsigned int            bpw;
        int                     len;
-
-       int                     chipselect[0];
 };
 
 static int spi_clps711x_setup(struct spi_device *spi)
 {
-       struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
        /* We are expect that SPI-device is not selected */
-       gpio_direction_output(hw->chipselect[spi->chip_select],
-                             !(spi->mode & SPI_CS_HIGH));
+       gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
 
        return 0;
 }
 
-static void spi_clps711x_setup_mode(struct spi_device *spi)
-{
-       /* Setup edge for transfer */
-       if (spi->mode & SPI_CPHA)
-               clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
-       else
-               clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
-}
-
-static int spi_clps711x_setup_xfer(struct spi_device *spi,
-                                  struct spi_transfer *xfer)
+static void spi_clps711x_setup_xfer(struct spi_device *spi,
+                                   struct spi_transfer *xfer)
 {
-       u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
-       u8 bpw = xfer->bits_per_word;
-       struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
-       if (bpw != 8) {
-               dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
-               return -EINVAL;
-       }
+       struct spi_master *master = spi->master;
+       struct spi_clps711x_data *hw = spi_master_get_devdata(master);
 
        /* Setup SPI frequency divider */
-       if (!speed || (speed >= hw->max_speed_hz))
-               clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
-                           SYSCON1_ADCKSEL(3), SYSCON1);
-       else if (speed >= (hw->max_speed_hz / 2))
-               clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
-                           SYSCON1_ADCKSEL(2), SYSCON1);
-       else if (speed >= (hw->max_speed_hz / 8))
-               clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
-                           SYSCON1_ADCKSEL(1), SYSCON1);
+       if (xfer->speed_hz >= master->max_speed_hz)
+               regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+                                  SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
+       else if (xfer->speed_hz >= (master->max_speed_hz / 2))
+               regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+                                  SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
+       else if (xfer->speed_hz >= (master->max_speed_hz / 8))
+               regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+                                  SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
        else
-               clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
-                           SYSCON1_ADCKSEL(0), SYSCON1);
-
-       return 0;
+               regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+                                  SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
 }
 
-static int spi_clps711x_transfer_one_message(struct spi_master *master,
-                                            struct spi_message *msg)
+static int spi_clps711x_prepare_message(struct spi_master *master,
+                                       struct spi_message *msg)
 {
        struct spi_clps711x_data *hw = spi_master_get_devdata(master);
-       struct spi_transfer *xfer;
-       int status = 0, cs = hw->chipselect[msg->spi->chip_select];
-       u32 data;
-
-       spi_clps711x_setup_mode(msg->spi);
-
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
-                       status = -EINVAL;
-                       goto out_xfr;
-               }
+       struct spi_device *spi = msg->spi;
 
-               gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
-
-               reinit_completion(&hw->done);
-
-               hw->count = 0;
-               hw->len = xfer->len;
-               hw->tx_buf = (u8 *)xfer->tx_buf;
-               hw->rx_buf = (u8 *)xfer->rx_buf;
-
-               /* Initiate transfer */
-               data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
-               clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
-
-               wait_for_completion(&hw->done);
+       /* Setup mode for transfer */
+       return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN,
+                                 (spi->mode & SPI_CPHA) ?
+                                 SYSCON3_ADCCKNSEN : 0);
+}
 
-               if (xfer->delay_usecs)
-                       udelay(xfer->delay_usecs);
+static int spi_clps711x_transfer_one(struct spi_master *master,
+                                    struct spi_device *spi,
+                                    struct spi_transfer *xfer)
+{
+       struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+       u8 data;
 
-               if (xfer->cs_change ||
-                   list_is_last(&xfer->transfer_list, &msg->transfers))
-                       gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
+       spi_clps711x_setup_xfer(spi, xfer);
 
-               msg->actual_length += xfer->len;
-       }
+       hw->len = xfer->len;
+       hw->bpw = xfer->bits_per_word;
+       hw->tx_buf = (u8 *)xfer->tx_buf;
+       hw->rx_buf = (u8 *)xfer->rx_buf;
 
-out_xfr:
-       msg->status = status;
-       spi_finalize_current_message(master);
+       /* Initiate transfer */
+       data = hw->tx_buf ? *hw->tx_buf++ : 0;
+       writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio);
 
-       return 0;
+       return 1;
 }
 
 static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
 {
-       struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
-       u32 data;
+       struct spi_master *master = dev_id;
+       struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+       u8 data;
 
        /* Handle RX */
-       data = clps_readb(SYNCIO);
+       data = readb(hw->syncio);
        if (hw->rx_buf)
-               hw->rx_buf[hw->count] = (u8)data;
-
-       hw->count++;
+               *hw->rx_buf++ = data;
 
        /* Handle TX */
-       if (hw->count < hw->len) {
-               data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
-               clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
+       if (--hw->len > 0) {
+               data = hw->tx_buf ? *hw->tx_buf++ : 0;
+               writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
+                      hw->syncio);
        } else
-               complete(&hw->done);
+               spi_finalize_current_transfer(master);
 
        return IRQ_HANDLED;
 }
 
 static int spi_clps711x_probe(struct platform_device *pdev)
 {
-       int i, ret;
-       struct spi_master *master;
        struct spi_clps711x_data *hw;
        struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
+       struct spi_master *master;
+       struct resource *res;
+       int i, irq, ret;
 
        if (!pdata) {
                dev_err(&pdev->dev, "No platform data supplied\n");
@@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       master = spi_alloc_master(&pdev->dev,
-                                 sizeof(struct spi_clps711x_data) +
-                                 sizeof(int) * pdata->num_chipselect);
-       if (!master) {
-               dev_err(&pdev->dev, "SPI allocating memory error\n");
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*hw));
+       if (!master)
                return -ENOMEM;
+
+       master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) *
+                                       pdata->num_chipselect, GFP_KERNEL);
+       if (!master->cs_gpios) {
+               ret = -ENOMEM;
+               goto err_out;
        }
 
        master->bus_num = pdev->id;
        master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
-       master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->bits_per_word_mask =  SPI_BPW_RANGE_MASK(1, 8);
        master->num_chipselect = pdata->num_chipselect;
        master->setup = spi_clps711x_setup;
-       master->transfer_one_message = spi_clps711x_transfer_one_message;
+       master->prepare_message = spi_clps711x_prepare_message;
+       master->transfer_one = spi_clps711x_transfer_one;
 
        hw = spi_master_get_devdata(master);
 
        for (i = 0; i < master->num_chipselect; i++) {
-               hw->chipselect[i] = pdata->chipselect[i];
-               if (!gpio_is_valid(hw->chipselect[i])) {
-                       dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
-                       ret = -EINVAL;
-                       goto err_out;
-               }
-               if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
+               master->cs_gpios[i] = pdata->chipselect[i];
+               ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
+                                       DRIVER_NAME);
+               if (ret) {
                        dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
-                       ret = -EINVAL;
                        goto err_out;
                }
        }
@@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev)
                ret = PTR_ERR(hw->spi_clk);
                goto err_out;
        }
-       hw->max_speed_hz = clk_get_rate(hw->spi_clk);
+       master->max_speed_hz = clk_get_rate(hw->spi_clk);
 
-       init_completion(&hw->done);
        platform_set_drvdata(pdev, master);
 
+       hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
+       if (IS_ERR(hw->syscon)) {
+               ret = PTR_ERR(hw->syscon);
+               goto err_out;
+       }
+
+       hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
+       if (IS_ERR(hw->syscon1)) {
+               ret = PTR_ERR(hw->syscon1);
+               goto err_out;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hw->syncio = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(hw->syncio)) {
+               ret = PTR_ERR(hw->syncio);
+               goto err_out;
+       }
+
        /* Disable extended mode due hardware problems */
-       clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
+       regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0);
 
        /* Clear possible pending interrupt */
-       clps_readl(SYNCIO);
+       readl(hw->syncio);
 
-       ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
-                              dev_name(&pdev->dev), hw);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't request IRQ\n");
+       ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
+                              dev_name(&pdev->dev), master);
+       if (ret)
                goto err_out;
-       }
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (!ret) {
                dev_info(&pdev->dev,
                         "SPI bus driver initialized. Master clock %u Hz\n",
-                        hw->max_speed_hz);
+                        master->max_speed_hz);
                return 0;
        }
 
index cabed8f9119e1af30d80766420d548b94567c91c..e2fa628e55e7b86478cf08de8f48b78c56cf75f1 100644 (file)
@@ -77,8 +77,6 @@ struct mcfqspi {
        struct mcfqspi_cs_control *cs_control;
 
        wait_queue_head_t waitq;
-
-       struct device *dev;
 };
 
 static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@@ -135,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
 
 static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
 {
-       return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
+       return (mcfqspi->cs_control->setup) ?
                mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
 }
 
 static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
 {
-       if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
+       if (mcfqspi->cs_control->teardown)
                mcfqspi->cs_control->teardown(mcfqspi->cs_control);
 }
 
@@ -300,68 +298,45 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
        }
 }
 
-static int mcfqspi_transfer_one_message(struct spi_master *master,
-                                        struct spi_message *msg)
+static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
 {
-       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-       struct spi_device *spi = msg->spi;
-       struct spi_transfer *t;
-       int status = 0;
-
-       list_for_each_entry(t, &msg->transfers, transfer_list) {
-               bool cs_high = spi->mode & SPI_CS_HIGH;
-               u16 qmr = MCFQSPI_QMR_MSTR;
-
-               qmr |= t->bits_per_word << 10;
-               if (spi->mode & SPI_CPHA)
-                       qmr |= MCFQSPI_QMR_CPHA;
-               if (spi->mode & SPI_CPOL)
-                       qmr |= MCFQSPI_QMR_CPOL;
-               if (t->speed_hz)
-                       qmr |= mcfqspi_qmr_baud(t->speed_hz);
-               else
-                       qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
-               mcfqspi_wr_qmr(mcfqspi, qmr);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
+       bool cs_high = spi->mode & SPI_CS_HIGH;
 
+       if (enable)
                mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+       else
+               mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high);
+}
 
-               mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
-               if (t->bits_per_word == 8)
-                       mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
-                                       t->rx_buf);
-               else
-                       mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
-                                       t->rx_buf);
-               mcfqspi_wr_qir(mcfqspi, 0);
-
-               if (t->delay_usecs)
-                       udelay(t->delay_usecs);
-               if (t->cs_change) {
-                       if (!list_is_last(&t->transfer_list, &msg->transfers))
-                               mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
-                                               cs_high);
-               } else {
-                       if (list_is_last(&t->transfer_list, &msg->transfers))
-                               mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
-                                               cs_high);
-               }
-               msg->actual_length += t->len;
-       }
-       msg->status = status;
-       spi_finalize_current_message(master);
-
-       return status;
+static int mcfqspi_transfer_one(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *t)
+{
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+       u16 qmr = MCFQSPI_QMR_MSTR;
+
+       qmr |= t->bits_per_word << 10;
+       if (spi->mode & SPI_CPHA)
+               qmr |= MCFQSPI_QMR_CPHA;
+       if (spi->mode & SPI_CPOL)
+               qmr |= MCFQSPI_QMR_CPOL;
+       qmr |= mcfqspi_qmr_baud(t->speed_hz);
+       mcfqspi_wr_qmr(mcfqspi, qmr);
+
+       mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+       if (t->bits_per_word == 8)
+               mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);
+       else
+               mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
+                                      t->rx_buf);
+       mcfqspi_wr_qir(mcfqspi, 0);
 
+       return 0;
 }
 
 static int mcfqspi_setup(struct spi_device *spi)
 {
-       if (spi->chip_select >= spi->master->num_chipselect) {
-               dev_dbg(&spi->dev, "%d chip select is out of range\n",
-                       spi->chip_select);
-               return -EINVAL;
-       }
-
        mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
                            spi->chip_select, spi->mode & SPI_CS_HIGH);
 
@@ -388,6 +363,11 @@ static int mcfqspi_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
+       if (!pdata->cs_control) {
+               dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");
+               return -EINVAL;
+       }
+
        master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
        if (master == NULL) {
                dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
@@ -436,12 +416,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
        }
 
        init_waitqueue_head(&mcfqspi->waitq);
-       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->set_cs = mcfqspi_set_cs;
+       master->transfer_one = mcfqspi_transfer_one;
        master->auto_runtime_pm = true;
 
        platform_set_drvdata(pdev, master);
@@ -451,7 +431,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
                dev_dbg(&pdev->dev, "spi_register_master failed\n");
                goto fail2;
        }
-       pm_runtime_enable(mcfqspi->dev);
+       pm_runtime_enable(&pdev->dev);
 
        dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
 
@@ -473,9 +453,8 @@ static int mcfqspi_remove(struct platform_device *pdev)
 {
        struct spi_master *master = platform_get_drvdata(pdev);
        struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       pm_runtime_disable(mcfqspi->dev);
+       pm_runtime_disable(&pdev->dev);
        /* disable the hardware (set the baud rate to 0) */
        mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
 
@@ -490,8 +469,11 @@ static int mcfqspi_suspend(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
        struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+       int ret;
 
-       spi_master_suspend(master);
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
 
        clk_disable(mcfqspi->clk);
 
@@ -503,18 +485,17 @@ static int mcfqspi_resume(struct device *dev)
        struct spi_master *master = dev_get_drvdata(dev);
        struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
-       spi_master_resume(master);
-
        clk_enable(mcfqspi->clk);
 
-       return 0;
+       return spi_master_resume(master);
 }
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
 static int mcfqspi_runtime_suspend(struct device *dev)
 {
-       struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        clk_disable(mcfqspi->clk);
 
@@ -523,7 +504,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
 
 static int mcfqspi_runtime_resume(struct device *dev)
 {
-       struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        clk_enable(mcfqspi->clk);
 
index 5e7389faa2a0189472d71fedcba95ae8ecd1cf35..50f750989258110a1099a9eb08a482a36020fd52 100644 (file)
@@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
        pdata = &dspi->pdata;
 
        pdata->version = SPI_VERSION_1;
-       match = of_match_device(of_match_ptr(davinci_spi_of_match),
-                               &pdev->dev);
+       match = of_match_device(davinci_spi_of_match, &pdev->dev);
        if (!match)
                return -ENODEV;
 
@@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
        return 0;
 }
 #else
-#define davinci_spi_of_match NULL
 static struct davinci_spi_platform_data
        *spi_davinci_get_pdata(struct platform_device *pdev,
                struct davinci_spi *dspi)
@@ -864,10 +862,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
 
        dspi = spi_master_get_devdata(master);
-       if (dspi == NULL) {
-               ret = -ENOENT;
-               goto free_master;
-       }
 
        if (dev_get_platdata(&pdev->dev)) {
                pdata = dev_get_platdata(&pdev->dev);
@@ -908,10 +902,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
                goto free_master;
 
        dspi->bitbang.master = master;
-       if (dspi->bitbang.master == NULL) {
-               ret = -ENODEV;
-               goto free_master;
-       }
 
        dspi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dspi->clk)) {
@@ -1040,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = {
        .driver = {
                .name = "spi_davinci",
                .owner = THIS_MODULE,
-               .of_match_table = davinci_spi_of_match,
+               .of_match_table = of_match_ptr(davinci_spi_of_match),
        },
        .probe = davinci_spi_probe,
        .remove = davinci_spi_remove,
index 9af56cdf1540551d595409efc47533cf45c5e5c5..1492f5ee9aaad702b1f6c490be4d38c1ac6091a0 100644 (file)
@@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       dws->bus_num = 0;
+       dws->bus_num = pdev->id;
        dws->num_cs = 4;
        dws->max_freq = clk_get_rate(dwsmmio->clk);
 
index bf98d63d92b3eabbd80ea49d125421069139c535..712ac5629cd46cea34fa6713a5a0462186aa6de0 100644 (file)
@@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws)
        queue_work(dws->workqueue, &dws->pump_messages);
        spin_unlock_irqrestore(&dws->lock, flags);
 
-       last_transfer = list_entry(msg->transfers.prev,
-                                       struct spi_transfer,
+       last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
                                        transfer_list);
 
        if (!last_transfer->cs_change && dws->cs_control)
@@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data)
 
                if (transfer->speed_hz != speed) {
                        speed = transfer->speed_hz;
-                       if (speed > dws->max_freq) {
-                               printk(KERN_ERR "MRST SPI0: unsupported"
-                                       "freq: %dHz\n", speed);
-                               message->status = -EIO;
-                               goto early_exit;
-                       }
 
                        /* clk_div doesn't support odd number */
                        clk_div = dws->max_freq / speed;
@@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-static void dw_spi_cleanup(struct spi_device *spi)
-{
-       struct chip_data *chip = spi_get_ctldata(spi);
-       kfree(chip);
-}
-
 static int init_queue(struct dw_spi *dws)
 {
        INIT_LIST_HEAD(&dws->queue);
@@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        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;
        master->setup = dw_spi_setup;
        master->transfer = dw_spi_transfer;
+       master->max_speed_hz = dws->max_freq;
 
        /* Basic HW init */
        spi_hw_init(dws);
index d4d3cc534792ad024d9680f8e52025460f26e7b3..be44a3eeb5e8b2b244704a48a4c2fc4184b45aa0 100644 (file)
@@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
 
        efm32_spi_filltx(ddata);
 
-       init_completion(&ddata->done);
+       reinit_completion(&ddata->done);
 
        efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
 
@@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
        return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
 }
 
-static int efm32_spi_probe_dt(struct platform_device *pdev,
+static void efm32_spi_probe_dt(struct platform_device *pdev,
                struct spi_master *master, struct efm32_spi_ddata *ddata)
 {
        struct device_node *np = pdev->dev.of_node;
        u32 location;
        int ret;
 
-       if (!np)
-               return 1;
-
-       ret = of_property_read_u32(np, "location", &location);
+       ret = of_property_read_u32(np, "efm32,location", &location);
+       if (ret)
+               /* fall back to old and (wrongly) generic property "location" */
+               ret = of_property_read_u32(np, "location", &location);
        if (!ret) {
                dev_dbg(&pdev->dev, "using location %u\n", location);
        } else {
@@ -308,11 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev,
        }
 
        ddata->pdata.location = location;
-
-       /* spi core takes care about the bus number using an alias */
-       master->bus_num = -1;
-
-       return 0;
 }
 
 static int efm32_spi_probe(struct platform_device *pdev)
@@ -322,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev)
        int ret;
        struct spi_master *master;
        struct device_node *np = pdev->dev.of_node;
-       unsigned int num_cs, i;
+       int num_cs, i;
+
+       if (!np)
+               return -EINVAL;
 
        num_cs = of_gpio_named_count(np, "cs-gpios");
+       if (num_cs < 0)
+               return num_cs;
 
        master = spi_alloc_master(&pdev->dev,
                        sizeof(*ddata) + num_cs * sizeof(unsigned));
@@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
        ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
 
        spin_lock_init(&ddata->lock);
+       init_completion(&ddata->done);
 
        ddata->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ddata->clk)) {
@@ -415,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
                goto err;
        }
 
-       ret = efm32_spi_probe_dt(pdev, master, ddata);
-       if (ret > 0) {
-               /* not created by device tree */
-               const struct efm32_spi_pdata *pdata =
-                       dev_get_platdata(&pdev->dev);
-
-               if (pdata)
-                       ddata->pdata = *pdata;
-               else
-                       ddata->pdata.location =
-                               efm32_spi_get_configured_location(ddata);
-
-               master->bus_num = pdev->id;
-
-       } else if (ret < 0) {
-               goto err_disable_clk;
-       }
+       efm32_spi_probe_dt(pdev, master, ddata);
 
        efm32_spi_write32(ddata, 0, REG_IEN);
        efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
@@ -487,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev)
 
 static const struct of_device_id efm32_spi_dt_ids[] = {
        {
+               .compatible = "energymicro,efm32-spi",
+       }, {
+               /* doesn't follow the "vendor,device" scheme, don't use */
                .compatible = "efm32,spi",
        }, {
                /* sentinel */
index 1bfaed6e4073cb3d536a9d1baf5be2227324a555..2f675d32df0ea0ef0d4d94df14d1f6be8d422b02 100644 (file)
@@ -73,8 +73,6 @@
  * @clk: clock for the controller
  * @regs_base: pointer to ioremap()'d registers
  * @sspdr_phys: physical address of the SSPDR register
- * @min_rate: minimum clock rate (in Hz) supported by the controller
- * @max_rate: maximum clock rate (in Hz) supported by the controller
  * @wait: wait here until given transfer is completed
  * @current_msg: message that is currently processed (or %NULL if none)
  * @tx: current byte in transfer to transmit
@@ -95,8 +93,6 @@ struct ep93xx_spi {
        struct clk                      *clk;
        void __iomem                    *regs_base;
        unsigned long                   sspdr_phys;
-       unsigned long                   min_rate;
-       unsigned long                   max_rate;
        struct completion               wait;
        struct spi_message              *current_msg;
        size_t                          tx;
@@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
  * @div_scr: pointer to return the scr divider
  */
 static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
-                                   unsigned long rate,
-                                   u8 *div_cpsr, u8 *div_scr)
+                                   u32 rate, u8 *div_cpsr, u8 *div_scr)
 {
+       struct spi_master *master = platform_get_drvdata(espi->pdev);
        unsigned long spi_clk_rate = clk_get_rate(espi->clk);
        int cpsr, scr;
 
@@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
         * controller. Note that minimum value is already checked in
         * ep93xx_spi_transfer_one_message().
         */
-       rate = clamp(rate, espi->min_rate, espi->max_rate);
+       rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
 
        /*
         * Calculate divisors so that we can get speed according the
@@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master,
                                           struct spi_message *msg)
 {
        struct ep93xx_spi *espi = spi_master_get_devdata(master);
-       struct spi_transfer *t;
-
-       /* first validate each transfer */
-       list_for_each_entry(t, &msg->transfers, transfer_list) {
-               if (t->speed_hz < espi->min_rate)
-                       return -EINVAL;
-       }
 
        msg->state = NULL;
        msg->status = 0;
@@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
         * Calculate maximum and minimum supported clock rates
         * for the controller.
         */
-       espi->max_rate = clk_get_rate(espi->clk) / 2;
-       espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+       master->max_speed_hz = clk_get_rate(espi->clk) / 2;
+       master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
        espi->pdev = pdev;
 
        espi->sspdr_phys = res->start + SSPDR;
index dd5bd468e9621698c7a130418d5a74994c474cbe..09965f069a1c9710c300a8a2f96334ecb1f513e9 100644 (file)
@@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi)
        unsigned int i;
        unsigned long flags;
 
-       if (spi->chip_select > 0)
-               return -ENODEV;
-
        spin_lock_irqsave(&ebu_lock, flags);
 
        if (spi->max_speed_hz >= CLOCK_100M) {
@@ -422,9 +419,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
        priv->master = master;
 
        master->mode_bits = SPI_MODE_3;
-       master->num_chipselect = 1;
        master->flags = SPI_MASTER_HALF_DUPLEX;
-       master->bus_num = -1;
        master->setup = falcon_sflash_setup;
        master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
        master->transfer_one_message = falcon_sflash_xfer_one;
index ec79f726672a14f7644810101afe59e82322976c..d565eeee3bd8dc38085d84d5ab5d7b606ef232f2 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -108,11 +109,11 @@ struct fsl_dspi {
        struct spi_bitbang      bitbang;
        struct platform_device  *pdev;
 
-       void __iomem            *base;
+       struct regmap           *regmap;
        int                     irq;
-       struct clk              *clk;
+       struct clk              *clk;
 
-       struct spi_transfer     *cur_transfer;
+       struct spi_transfer     *cur_transfer;
        struct chip_data        *cur_chip;
        size_t                  len;
        void                    *tx;
@@ -123,24 +124,17 @@ struct fsl_dspi {
        u8                      cs;
        u16                     void_write_data;
 
-       wait_queue_head_t       waitq;
-       u32                     waitflags;
+       wait_queue_head_t       waitq;
+       u32                     waitflags;
 };
 
 static inline int is_double_byte_mode(struct fsl_dspi *dspi)
 {
-       return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
-                       == SPI_FRAME_BITS(8)) ? 0 : 1;
-}
+       unsigned int val;
 
-static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
-{
-       u32 temp;
+       regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
 
-       temp = readl(dspi->base + SPI_CTAR(dspi->cs));
-       temp &= ~SPI_FRAME_BITS_MASK;
-       temp |= SPI_FRAME_BITS(bits);
-       writel(temp, dspi->base + SPI_CTAR(dspi->cs));
+       return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
 }
 
 static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
@@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
         */
        if (tx_word && (dspi->len == 1)) {
                dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-               set_bit_mode(dspi, 8);
+               regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+                               SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
                tx_word = 0;
        }
 
@@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
                        dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
                }
 
-               writel(dspi_pushr, dspi->base + SPI_PUSHR);
+               regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+
                tx_count++;
        }
 
@@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
        while ((dspi->rx < dspi->rx_end)
                        && (rx_count < DSPI_FIFO_SIZE)) {
                if (rx_word) {
+                       unsigned int val;
+
                        if ((dspi->rx_end - dspi->rx) == 1)
                                break;
 
-                       d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+                       regmap_read(dspi->regmap, SPI_POPR, &val);
+                       d = SPI_POPR_RXDATA(val);
 
                        if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
                                *(u16 *)dspi->rx = d;
                        dspi->rx += 2;
 
                } else {
-                       d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+                       unsigned int val;
+
+                       regmap_read(dspi->regmap, SPI_POPR, &val);
+                       d = SPI_POPR_RXDATA(val);
                        if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
                                *(u8 *)dspi->rx = d;
                        dspi->rx++;
@@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
        if (!dspi->tx)
                dspi->dataflags |= TRAN_STATE_TX_VOID;
 
-       writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
-       writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
-       writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
+       regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
+       regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
+       regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
 
        if (t->speed_hz)
-               writel(dspi->cur_chip->ctar_val,
-                               dspi->base + SPI_CTAR(dspi->cs));
+               regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+                               dspi->cur_chip->ctar_val);
 
        dspi_transfer_write(dspi);
 
@@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
 static void dspi_chipselect(struct spi_device *spi, int value)
 {
        struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
-       u32 pushr = readl(dspi->base + SPI_PUSHR);
+       unsigned int pushr;
+
+       regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
 
        switch (value) {
        case BITBANG_CS_ACTIVE:
@@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
                break;
        }
 
-       writel(pushr, dspi->base + SPI_PUSHR);
+       regmap_write(dspi->regmap, SPI_PUSHR, pushr);
 }
 
 static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
@@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
        if (chip == NULL) {
-               chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
+               chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
+                                   GFP_KERNEL);
                if (!chip)
                        return -ENOMEM;
        }
@@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                fmsz = spi->bits_per_word - 1;
        } else {
                pr_err("Invalid wordsize\n");
-               kfree(chip);
                return -ENODEV;
        }
 
@@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
 {
        struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
 
-       writel(SPI_SR_EOQF, dspi->base + SPI_SR);
+       regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
 
        dspi_transfer_read(dspi);
 
        if (!dspi->len) {
                if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
-                       set_bit_mode(dspi, 16);
+                       regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+                               SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
+
                dspi->waitflags = 1;
                wake_up_interruptible(&dspi->waitq);
        } else {
@@ -420,7 +426,6 @@ static int dspi_suspend(struct device *dev)
 
 static int dspi_resume(struct device *dev)
 {
-
        struct spi_master *master = dev_get_drvdata(dev);
        struct fsl_dspi *dspi = spi_master_get_devdata(master);
 
@@ -431,8 +436,13 @@ static int dspi_resume(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-static const struct dev_pm_ops dspi_pm = {
-       SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
+static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
+
+static struct regmap_config dspi_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = 0x88,
 };
 
 static int dspi_probe(struct platform_device *pdev)
@@ -441,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct fsl_dspi *dspi;
        struct resource *res;
+       void __iomem *base;
        int ret = 0, cs_num, bus_num;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@@ -475,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
        master->bus_num = bus_num;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dspi->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dspi->base)) {
-               ret = PTR_ERR(dspi->base);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base)) {
+               ret = PTR_ERR(base);
                goto out_master_put;
        }
 
+       dspi_regmap_config.lock_arg = dspi;
+       dspi_regmap_config.val_format_endian =
+               of_property_read_bool(np, "big-endian")
+                       ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
+       dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
+                                               &dspi_regmap_config);
+       if (IS_ERR(dspi->regmap)) {
+               dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+                               PTR_ERR(dspi->regmap));
+               return PTR_ERR(dspi->regmap);
+       }
+
        dspi->irq = platform_get_irq(pdev, 0);
        if (dspi->irq < 0) {
                dev_err(&pdev->dev, "can't get platform irq\n");
@@ -504,7 +527,7 @@ static int dspi_probe(struct platform_device *pdev)
        clk_prepare_enable(dspi->clk);
 
        init_waitqueue_head(&dspi->waitq);
-       platform_set_drvdata(pdev, dspi);
+       platform_set_drvdata(pdev, master);
 
        ret = spi_bitbang_start(&dspi->bitbang);
        if (ret != 0) {
@@ -525,7 +548,8 @@ out_master_put:
 
 static int dspi_remove(struct platform_device *pdev)
 {
-       struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct fsl_dspi *dspi = spi_master_get_devdata(master);
 
        /* Disconnect from the SPI framework */
        spi_bitbang_stop(&dspi->bitbang);
index 428dc7a6b62e7c173fb9a1dd8b9028ab9ded01b3..6fb2b75df821e78f80a0f6c1bf4c64e45e4292d5 100644 (file)
@@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
        struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
        unsigned int len = t->len;
-       u8 bits_per_word;
        int ret;
 
-       bits_per_word = spi->bits_per_word;
-       if (t->bits_per_word)
-               bits_per_word = t->bits_per_word;
-
        mpc8xxx_spi->len = t->len;
        len = roundup(len, 4) / 4;
 
index 0b75f26158abbf00b5c781585a28a82e70a31eff..e5d45fca355182809ea9c3f66c63c1beef44ffdd 100644 (file)
@@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
        const void *prop;
        int ret = -ENOMEM;
 
-       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+       pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL);
        if (!pinfo)
                return -ENOMEM;
 
@@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
        pdata->sysclk = get_brgfreq();
        if (pdata->sysclk == -1) {
                pdata->sysclk = fsl_get_sys_freq();
-               if (pdata->sysclk == -1) {
-                       ret = -ENODEV;
-                       goto err;
-               }
+               if (pdata->sysclk == -1)
+                       return -ENODEV;
        }
 #else
        ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
        if (ret)
-               goto err;
+               return ret;
 #endif
 
        prop = of_get_property(np, "mode", NULL);
@@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
                pdata->flags = SPI_CPM_MODE | SPI_CPM1;
 
        return 0;
-
-err:
-       kfree(pinfo);
-       return ret;
 }
index 119f7af945374f43a7e1547efbb2f5aa1d9517b0..f35488ed62a9eaca3c353401d9bf7b935bf4a00c 100644 (file)
@@ -239,12 +239,6 @@ static int fsl_spi_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, 32] */
-       if ((bits_per_word < 4)
-           || ((bits_per_word > 16) && (bits_per_word != 32))
-           || (bits_per_word > mpc8xxx_spi->max_bits_per_word))
-               return -EINVAL;
-
        if (!hz)
                hz = spi->max_speed_hz;
 
@@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
 static void fsl_spi_do_one_msg(struct spi_message *m)
 {
        struct spi_device *spi = m->spi;
-       struct spi_transfer *t;
+       struct spi_transfer *t, *first;
        unsigned int cs_change;
        const int nsecs = 50;
        int status;
 
-       cs_change = 1;
-       status = 0;
+       /* Don't allow changes if CS is active */
+       first = list_first_entry(&m->transfers, struct spi_transfer,
+                       transfer_list);
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               if (t->bits_per_word || t->speed_hz) {
-                       /* Don't allow changes if CS is active */
+               if ((first->bits_per_word != t->bits_per_word) ||
+                       (first->speed_hz != t->speed_hz)) {
                        status = -EINVAL;
+                       dev_err(&spi->dev,
+                               "bits_per_word/speed_hz should be same for the same SPI transfer\n");
+                       return;
+               }
+       }
 
+       cs_change = 1;
+       status = -EINVAL;
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->bits_per_word || t->speed_hz) {
                        if (cs_change)
                                status = fsl_spi_setup_transfer(spi, t);
                        if (status < 0)
@@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
        if (mpc8xxx_spi->type == TYPE_GRLIB)
                fsl_spi_grlib_probe(dev);
 
+       master->bits_per_word_mask =
+               (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
+               SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
+
        if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
                mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
 
index 7beeb29472ac73f59fcf0e92e04c9c31ef88a75a..09823076df889d8b3a2928304713c7faa72651af 100644 (file)
@@ -19,7 +19,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
@@ -250,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi)
                /*
                 * ... otherwise, take it from spi->controller_data
                 */
-               cs = (unsigned int) spi->controller_data;
+               cs = (unsigned int)(uintptr_t) spi->controller_data;
        }
 
        if (!spi->controller_state) {
@@ -503,13 +502,12 @@ static int spi_gpio_remove(struct platform_device *pdev)
 {
        struct spi_gpio                 *spi_gpio;
        struct spi_gpio_platform_data   *pdata;
-       int                             status;
 
        spi_gpio = platform_get_drvdata(pdev);
        pdata = dev_get_platdata(&pdev->dev);
 
        /* stop() unregisters child devices too */
-       status = spi_bitbang_stop(&spi_gpio->bitbang);
+       spi_bitbang_stop(&spi_gpio->bitbang);
 
        if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
                gpio_free(SPI_MISO_GPIO);
@@ -518,7 +516,7 @@ static int spi_gpio_remove(struct platform_device *pdev)
        gpio_free(SPI_SCK_GPIO);
        spi_master_put(spi_gpio->bitbang.master);
 
-       return status;
+       return 0;
 }
 
 MODULE_ALIAS("platform:" DRIVER_NAME);
index a5474ef9d2a0cf4ad7367ee1e0399fae2e982145..5daff2054ae49ffa3810c29def0e3cd0db8822fe 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -741,7 +740,7 @@ static int spi_imx_transfer(struct spi_device *spi,
        spi_imx->count = transfer->len;
        spi_imx->txfifo = 0;
 
-       init_completion(&spi_imx->xfer_done);
+       reinit_completion(&spi_imx->xfer_done);
 
        spi_imx_push(spi_imx);
 
@@ -880,12 +879,12 @@ static int spi_imx_probe(struct platform_device *pdev)
 
        spi_imx->irq = platform_get_irq(pdev, 0);
        if (spi_imx->irq < 0) {
-               ret = -EINVAL;
+               ret = spi_imx->irq;
                goto out_master_put;
        }
 
        ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
-                              DRIVER_NAME, spi_imx);
+                              dev_name(&pdev->dev), spi_imx);
        if (ret) {
                dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
                goto out_master_put;
@@ -948,8 +947,8 @@ static int spi_imx_remove(struct platform_device *pdev)
        spi_bitbang_stop(&spi_imx->bitbang);
 
        writel(0, spi_imx->base + MXC_CSPICTRL);
-       clk_disable_unprepare(spi_imx->clk_ipg);
-       clk_disable_unprepare(spi_imx->clk_per);
+       clk_unprepare(spi_imx->clk_ipg);
+       clk_unprepare(spi_imx->clk_per);
        spi_master_put(master);
 
        return 0;
index 5032141eeeec4ee0cbb46b7d7af7c8a65e76212c..3822eef2ef9dacebd723ee2472a33dc04e1865a5 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/of_address.h>
@@ -466,10 +465,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff)
        gpio_set_value(spi->cs_gpio, onoff);
 }
 
-/* bus_num is used only for the case dev->platform_data == NULL */
 static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
-                                             u32 size, unsigned int irq,
-                                             s16 bus_num)
+                                             u32 size, unsigned int irq)
 {
        struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
        struct mpc512x_psc_spi *mps;
@@ -488,7 +485,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 
        if (pdata == NULL) {
                mps->cs_control = mpc512x_spi_cs_control;
-               master->bus_num = bus_num;
        } else {
                mps->cs_control = pdata->cs_control;
                master->bus_num = pdata->bus_num;
@@ -574,7 +570,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
 {
        const u32 *regaddr_p;
        u64 regaddr64, size64;
-       s16 id = -1;
 
        regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
        if (!regaddr_p) {
@@ -583,16 +578,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
        }
        regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
 
-       /* get PSC id (0..11, used by port_config) */
-       id = of_alias_get_id(op->dev.of_node, "spi");
-       if (id < 0) {
-               dev_err(&op->dev, "no alias id for %s\n",
-                       op->dev.of_node->full_name);
-               return id;
-       }
-
        return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
-                               irq_of_parse_and_map(op->dev.of_node, 0), id);
+                               irq_of_parse_and_map(op->dev.of_node, 0));
 }
 
 static int mpc512x_psc_spi_of_remove(struct platform_device *op)
index 00ba910ab3023a2587bc54a700e25e9f4a561438..3d18d93511854c1aa56fd6b5ebe6d10c65157242 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
index 7c675fe8310105d255f6f10afc7a2f1c5e576b32..aac2a5ddd964efcf1086263fa1231235aa065141 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
@@ -357,20 +356,6 @@ static void mpc52xx_spi_wq(struct work_struct *work)
  * spi_master ops
  */
 
-static int mpc52xx_spi_setup(struct spi_device *spi)
-{
-       if (spi->bits_per_word % 8)
-               return -EINVAL;
-
-       if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST))
-               return -EINVAL;
-
-       if (spi->chip_select >= spi->master->num_chipselect)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
 {
        struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
@@ -433,9 +418,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
                goto err_alloc;
        }
 
-       master->setup = mpc52xx_spi_setup;
        master->transfer = mpc52xx_spi_transfer;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->dev.of_node = op->dev.of_node;
 
        platform_set_drvdata(op, master);
index 79e5aa2250c89d48541d8d9eb263410c2aa66ac6..2884f0c2f5f05a086621102e847c2bfbefcb215e 100644 (file)
@@ -29,7 +29,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -371,7 +370,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
 {
        struct mxs_spi *spi = spi_master_get_devdata(master);
        struct mxs_ssp *ssp = &spi->ssp;
-       struct spi_transfer *t, *tmp_t;
+       struct spi_transfer *t;
        unsigned int flag;
        int status = 0;
 
@@ -381,7 +380,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
        writel(mxs_spi_cs_to_reg(m->spi->chip_select),
               ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
 
-       list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
+       list_for_each_entry(t, &m->transfers, transfer_list) {
 
                status = mxs_spi_setup_transfer(m->spi, t);
                if (status)
@@ -473,7 +472,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq_err = platform_get_irq(pdev, 0);
        if (irq_err < 0)
-               return -EINVAL;
+               return irq_err;
 
        base = devm_ioremap_resource(&pdev->dev, iores);
        if (IS_ERR(base))
index bae97ffec4b9952f10a1affc3ca3741d537e91af..16e30de650b02a7bdbada7b00be5d8eb7e0deaff 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
@@ -38,7 +37,9 @@
 /* usi register bit */
 #define ENINT          (0x01 << 17)
 #define ENFLG          (0x01 << 16)
+#define SLEEP          (0x0f << 12)
 #define TXNUM          (0x03 << 8)
+#define TXBITLEN       (0x1f << 3)
 #define TXNEG          (0x01 << 2)
 #define RXNEG          (0x01 << 1)
 #define LSB            (0x01 << 10)
@@ -58,11 +59,8 @@ struct nuc900_spi {
        unsigned char           *rx;
        struct clk              *clk;
        struct spi_master       *master;
-       struct spi_device       *curdev;
-       struct device           *dev;
        struct nuc900_spi_info *pdata;
        spinlock_t              lock;
-       struct resource         *res;
 };
 
 static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
@@ -119,19 +117,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value)
        }
 }
 
-static void nuc900_spi_setup_txnum(struct nuc900_spi *hw,
-                                                       unsigned int txnum)
+static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
 {
        unsigned int val;
        unsigned long flags;
 
        spin_lock_irqsave(&hw->lock, flags);
 
-       val = __raw_readl(hw->regs + USI_CNT);
+       val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
 
-       if (!txnum)
-               val &= ~TXNUM;
-       else
+       if (txnum)
                val |= txnum << 0x08;
 
        __raw_writel(val, hw->regs + USI_CNT);
@@ -148,7 +143,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
 
        spin_lock_irqsave(&hw->lock, flags);
 
-       val = __raw_readl(hw->regs + USI_CNT);
+       val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
 
        val |= (txbitlen << 0x03);
 
@@ -287,12 +282,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
 
        spin_lock_irqsave(&hw->lock, flags);
 
-       val = __raw_readl(hw->regs + USI_CNT);
+       val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
 
        if (sleep)
                val |= (sleep << 12);
-       else
-               val &= ~(0x0f << 12);
+
        __raw_writel(val, hw->regs + USI_CNT);
 
        spin_unlock_irqrestore(&hw->lock, flags);
@@ -338,6 +332,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
 {
        struct nuc900_spi *hw;
        struct spi_master *master;
+       struct resource *res;
        int err = 0;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
@@ -349,7 +344,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
        hw = spi_master_get_devdata(master);
        hw->master = master;
        hw->pdata  = dev_get_platdata(&pdev->dev);
-       hw->dev = &pdev->dev;
 
        if (hw->pdata == NULL) {
                dev_err(&pdev->dev, "No platform data supplied\n");
@@ -369,8 +363,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
        hw->bitbang.chipselect     = nuc900_spi_chipsel;
        hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
 
-       hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hw->regs = devm_ioremap_resource(&pdev->dev, hw->res);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hw->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(hw->regs)) {
                err = PTR_ERR(hw->regs);
                goto err_pdata;
index f7c896e2981ef684d339f8e97f2b021ff468c35d..8998d11c72386d78811328590038be63ce34f3f9 100644 (file)
@@ -15,7 +15,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -267,8 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
 
        /* setup the state for the bitbang driver */
        hw->bitbang.master = master;
-       if (!hw->bitbang.master)
-               return err;
        hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
        hw->bitbang.chipselect = tiny_spi_chipselect;
        hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
index 67249a48b391b601a7e069ff566015e5a3872773..c5e2f718eebda3f2c5da42266b7769e4aa8ca407 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/of.h>
 
@@ -33,13 +32,6 @@ struct octeon_spi {
        u64 cs_enax;
 };
 
-struct octeon_spi_setup {
-       u32 max_speed_hz;
-       u8 chip_select;
-       u8 mode;
-       u8 bits_per_word;
-};
-
 static void octeon_spi_wait_ready(struct octeon_spi *p)
 {
        union cvmx_mpi_sts mpi_sts;
@@ -57,6 +49,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
                                  struct spi_transfer *xfer,
                                  bool last_xfer)
 {
+       struct spi_device *spi = msg->spi;
        union cvmx_mpi_cfg mpi_cfg;
        union cvmx_mpi_tx mpi_tx;
        unsigned int clkdiv;
@@ -68,18 +61,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
        int len;
        int i;
 
-       struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi);
-
-       speed_hz = msg_setup->max_speed_hz;
-       mode = msg_setup->mode;
+       mode = spi->mode;
        cpha = mode & SPI_CPHA;
        cpol = mode & SPI_CPOL;
 
-       if (xfer->speed_hz)
-               speed_hz = xfer->speed_hz;
-
-       if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
-               speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+       speed_hz = xfer->speed_hz ? : spi->max_speed_hz;
 
        clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
 
@@ -93,8 +79,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
        mpi_cfg.s.cslate = cpha ? 1 : 0;
        mpi_cfg.s.enable = 1;
 
-       if (msg_setup->chip_select < 4)
-               p->cs_enax |= 1ull << (12 + msg_setup->chip_select);
+       if (spi->chip_select < 4)
+               p->cs_enax |= 1ull << (12 + spi->chip_select);
        mpi_cfg.u64 |= p->cs_enax;
 
        if (mpi_cfg.u64 != p->last_cfg) {
@@ -114,7 +100,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
                        cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
                }
                mpi_tx.u64 = 0;
-               mpi_tx.s.csid = msg_setup->chip_select;
+               mpi_tx.s.csid = spi->chip_select;
                mpi_tx.s.leavecs = 1;
                mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
                mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
@@ -139,7 +125,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
        }
 
        mpi_tx.u64 = 0;
-       mpi_tx.s.csid = msg_setup->chip_select;
+       mpi_tx.s.csid = spi->chip_select;
        if (last_xfer)
                mpi_tx.s.leavecs = xfer->cs_change;
        else
@@ -169,17 +155,9 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
        int status = 0;
        struct spi_transfer *xfer;
 
-       /*
-        * We better have set the configuration via a call to .setup
-        * before we get here.
-        */
-       if (spi_get_ctldata(msg->spi) == NULL) {
-               status = -EINVAL;
-               goto err;
-       }
-
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
+               bool last_xfer = list_is_last(&xfer->transfer_list,
+                                             &msg->transfers);
                int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
                if (r < 0) {
                        status = r;
@@ -194,41 +172,6 @@ err:
        return status;
 }
 
-static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi)
-{
-       struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL);
-       if (!setup)
-               return NULL;
-
-       setup->max_speed_hz = spi->max_speed_hz;
-       setup->chip_select = spi->chip_select;
-       setup->mode = spi->mode;
-       setup->bits_per_word = spi->bits_per_word;
-       return setup;
-}
-
-static int octeon_spi_setup(struct spi_device *spi)
-{
-       struct octeon_spi_setup *new_setup;
-       struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
-
-       new_setup = octeon_spi_new_setup(spi);
-       if (!new_setup)
-               return -ENOMEM;
-
-       spi_set_ctldata(spi, new_setup);
-       kfree(old_setup);
-
-       return 0;
-}
-
-static void octeon_spi_cleanup(struct spi_device *spi)
-{
-       struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
-       spi_set_ctldata(spi, NULL);
-       kfree(old_setup);
-}
-
 static int octeon_spi_probe(struct platform_device *pdev)
 {
        struct resource *res_mem;
@@ -257,8 +200,6 @@ static int octeon_spi_probe(struct platform_device *pdev)
        p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
                                             resource_size(res_mem));
 
-       /* Dynamic bus numbering */
-       master->bus_num = -1;
        master->num_chipselect = 4;
        master->mode_bits = SPI_CPHA |
                            SPI_CPOL |
@@ -266,10 +207,9 @@ static int octeon_spi_probe(struct platform_device *pdev)
                            SPI_LSB_FIRST |
                            SPI_3WIRE;
 
-       master->setup = octeon_spi_setup;
-       master->cleanup = octeon_spi_cleanup;
        master->transfer_one_message = octeon_spi_transfer_one_message;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
 
        master->dev.of_node = pdev->dev.of_node;
        err = devm_spi_register_master(&pdev->dev, master);
index 0d32054bfc0dd624c1d99ec37f47f6c8244b3ab2..e7ffcded4e14b84d28cef21e0c8f321690d49e94 100644 (file)
 #define SPI_SHUTDOWN   1
 
 struct omap1_spi100k {
-       struct spi_master       *master;
        struct clk              *ick;
        struct clk              *fck;
 
        /* Virtual base address of the controller */
        void __iomem            *base;
-
-       /* State of the SPI */
-       unsigned int            state;
 };
 
 struct omap1_spi100k_cs {
@@ -99,13 +95,6 @@ struct omap1_spi100k_cs {
        int                     word_len;
 };
 
-#define MOD_REG_BIT(val, mask, set) do { \
-       if (set) \
-               val |= mask; \
-       else \
-               val &= ~mask; \
-} while (0)
-
 static void spi100k_enable_clock(struct spi_master *master)
 {
        unsigned int val;
@@ -139,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
        }
 
        spi100k_enable_clock(master);
-       writew( data , spi100k->base + SPI_TX_MSB);
+       writew(data , spi100k->base + SPI_TX_MSB);
 
        writew(SPI_CTRL_SEN(0) |
               SPI_CTRL_WORD_SIZE(len) |
@@ -147,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
               spi100k->base + SPI_CTRL);
 
        /* Wait for bit ack send change */
-       while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
+       while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE)
+               ;
        udelay(1000);
 
        spi100k_disable_clock(master);
@@ -155,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
 
 static int spi100k_read_data(struct spi_master *master, int len)
 {
-       int dataH,dataL;
+       int dataH, dataL;
        struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
 
        /* Always do at least 16 bits */
@@ -168,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len)
               SPI_CTRL_RD,
               spi100k->base + SPI_CTRL);
 
-       while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
+       while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD)
+               ;
        udelay(1000);
 
        dataL = readw(spi100k->base + SPI_RX_LSB);
@@ -204,12 +195,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
 static unsigned
 omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 {
-       struct omap1_spi100k    *spi100k;
        struct omap1_spi100k_cs *cs = spi->controller_state;
        unsigned int            count, c;
        int                     word_len;
 
-       spi100k = spi_master_get_devdata(spi->master);
        count = xfer->len;
        c = count;
        word_len = cs->word_len;
@@ -221,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
-                       c-=1;
+                       c -= 1;
                        if (xfer->tx_buf != NULL)
                                spi100k_write_data(spi->master, word_len, *tx++);
                        if (xfer->rx_buf != NULL)
                                *rx++ = spi100k_read_data(spi->master, word_len);
-               } while(c);
+               } while (c);
        } else if (word_len <= 16) {
                u16             *rx;
                const u16       *tx;
@@ -234,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
-                       c-=2;
+                       c -= 2;
                        if (xfer->tx_buf != NULL)
-                               spi100k_write_data(spi->master,word_len, *tx++);
+                               spi100k_write_data(spi->master, word_len, *tx++);
                        if (xfer->rx_buf != NULL)
-                               *rx++ = spi100k_read_data(spi->master,word_len);
-               } while(c);
+                               *rx++ = spi100k_read_data(spi->master, word_len);
+               } while (c);
        } else if (word_len <= 32) {
                u32             *rx;
                const u32       *tx;
@@ -247,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
-                       c-=4;
+                       c -= 4;
                        if (xfer->tx_buf != NULL)
-                               spi100k_write_data(spi->master,word_len, *tx);
+                               spi100k_write_data(spi->master, word_len, *tx);
                        if (xfer->rx_buf != NULL)
-                               *rx = spi100k_read_data(spi->master,word_len);
-               } while(c);
+                               *rx = spi100k_read_data(spi->master, word_len);
+               } while (c);
        }
        return count - c;
 }
@@ -294,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi)
        spi100k = spi_master_get_devdata(spi->master);
 
        if (!cs) {
-               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
                if (!cs)
                        return -ENOMEM;
                cs->base = spi100k->base + spi->chip_select * 0x14;
@@ -411,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
        if (!pdev->id)
                return -EINVAL;
 
-       master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+       master = spi_alloc_master(&pdev->dev, sizeof(*spi100k));
        if (master == NULL) {
                dev_dbg(&pdev->dev, "master allocation failed\n");
                return -ENOMEM;
        }
 
        if (pdev->id != -1)
-              master->bus_num = pdev->id;
+               master->bus_num = pdev->id;
 
        master->setup = omap1_spi100k_setup;
        master->transfer_one_message = omap1_spi100k_transfer_one_message;
@@ -434,7 +423,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
 
        spi100k = spi_master_get_devdata(master);
-       spi100k->master = master;
 
        /*
         * The memory region base address is taken as the platform_data.
@@ -461,8 +449,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
        if (status < 0)
                goto err;
 
-       spi100k->state = SPI_RUNNING;
-
        return status;
 
 err:
index 9313fd3b413dfd6eed5e1d8e14dc42a0e32f1e3d..be2a2e108e2fc29878d5266fb5fdbcfd43bae357 100644 (file)
@@ -99,7 +99,6 @@ struct uwire_spi {
 };
 
 struct uwire_state {
-       unsigned        bits_per_word;
        unsigned        div1_idx;
 };
 
@@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value)
 
 static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
 {
-       struct uwire_state *ust = spi->controller_state;
        unsigned        len = t->len;
-       unsigned        bits = ust->bits_per_word;
+       unsigned        bits = t->bits_per_word ? : spi->bits_per_word;
        unsigned        bytes;
        u16             val, w;
        int             status = 0;
@@ -220,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
        if (!t->tx_buf && !t->rx_buf)
                return 0;
 
-       /* Microwire doesn't read and write concurrently */
-       if (t->tx_buf && t->rx_buf)
-               return -EPERM;
-
        w = spi->chip_select << 10;
        w |= CS_CMD;
 
@@ -322,7 +316,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        struct uwire_state      *ust = spi->controller_state;
        struct uwire_spi        *uwire;
        unsigned                flags = 0;
-       unsigned                bits;
        unsigned                hz;
        unsigned long           rate;
        int                     div1_idx;
@@ -332,23 +325,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 
        uwire = spi_master_get_devdata(spi->master);
 
-       if (spi->chip_select > 3) {
-               pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
-               status = -ENODEV;
-               goto done;
-       }
-
-       bits = spi->bits_per_word;
-       if (t != NULL && t->bits_per_word)
-               bits = t->bits_per_word;
-
-       if (bits > 16) {
-               pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
-               status = -ENODEV;
-               goto done;
-       }
-       ust->bits_per_word = bits;
-
        /* mode 0..3, clock inverted separately;
         * standard nCS signaling;
         * don't treat DI=high as "not ready"
@@ -502,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev)
                status = PTR_ERR(uwire->ck);
                dev_dbg(&pdev->dev, "no functional clock?\n");
                spi_master_put(master);
+               iounmap(uwire_base);
                return status;
        }
        clk_enable(uwire->ck);
@@ -515,7 +492,7 @@ static int uwire_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(1, 16);
        master->flags = SPI_MASTER_HALF_DUPLEX;
 
        master->bus_num = 2;    /* "official" */
@@ -539,14 +516,13 @@ static int uwire_probe(struct platform_device *pdev)
 static int uwire_remove(struct platform_device *pdev)
 {
        struct uwire_spi        *uwire = platform_get_drvdata(pdev);
-       int                     status;
 
        // FIXME remove all child devices, somewhere ...
 
-       status = spi_bitbang_stop(&uwire->bitbang);
+       spi_bitbang_stop(&uwire->bitbang);
        uwire_off(uwire);
        iounmap(uwire_base);
-       return status;
+       return 0;
 }
 
 /* work with hotplug and coldplug */
index a72127f08e39faa04d1433094590094ea1ac357d..2941c5b96ebc2e063c22a4b2fcfea946d55b8849 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/device.h>
@@ -45,6 +44,7 @@
 #include <linux/platform_data/spi-omap2-mcspi.h>
 
 #define OMAP2_MCSPI_MAX_FREQ           48000000
+#define OMAP2_MCSPI_MAX_DIVIDER                4096
 #define OMAP2_MCSPI_MAX_FIFODEPTH      64
 #define OMAP2_MCSPI_MAX_FIFOWCNT       0xFFFF
 #define SPI_AUTOSUSPEND_TIMEOUT                2000
@@ -89,6 +89,7 @@
 #define OMAP2_MCSPI_CHCONF_FORCE       BIT(20)
 #define OMAP2_MCSPI_CHCONF_FFET                BIT(27)
 #define OMAP2_MCSPI_CHCONF_FFER                BIT(28)
+#define OMAP2_MCSPI_CHCONF_CLKG                BIT(29)
 
 #define OMAP2_MCSPI_CHSTAT_RXS         BIT(0)
 #define OMAP2_MCSPI_CHSTAT_TXS         BIT(1)
@@ -96,6 +97,7 @@
 #define OMAP2_MCSPI_CHSTAT_TXFFE       BIT(3)
 
 #define OMAP2_MCSPI_CHCTRL_EN          BIT(0)
+#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8)
 
 #define OMAP2_MCSPI_WAKEUPENABLE_WKEN  BIT(0)
 
@@ -149,7 +151,7 @@ struct omap2_mcspi_cs {
        int                     word_len;
        struct list_head        node;
        /* Context save and restore shadow register */
-       u32                     chconf0;
+       u32                     chconf0, chctrl0;
 };
 
 static inline void mcspi_write_reg(struct spi_master *master,
@@ -230,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
 
 static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
 {
+       struct omap2_mcspi_cs *cs = spi->controller_state;
        u32 l;
 
-       l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
-       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+       l = cs->chctrl0;
+       if (enable)
+               l |= OMAP2_MCSPI_CHCTRL_EN;
+       else
+               l &= ~OMAP2_MCSPI_CHCTRL_EN;
+       cs->chctrl0 = l;
+       mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
        /* Flash post-writes */
        mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
 }
@@ -840,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
        struct omap2_mcspi_cs *cs = spi->controller_state;
        struct omap2_mcspi *mcspi;
        struct spi_master *spi_cntrl;
-       u32 l = 0, div = 0;
+       u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
        u8 word_len = spi->bits_per_word;
        u32 speed_hz = spi->max_speed_hz;
 
@@ -856,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
                speed_hz = t->speed_hz;
 
        speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
-       div = omap2_mcspi_calc_divisor(speed_hz);
+       if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
+               clkd = omap2_mcspi_calc_divisor(speed_hz);
+               speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
+               clkg = 0;
+       } else {
+               div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
+               speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
+               clkd = (div - 1) & 0xf;
+               extclk = (div - 1) >> 4;
+               clkg = OMAP2_MCSPI_CHCONF_CLKG;
+       }
 
        l = mcspi_cached_chconf0(spi);
 
@@ -885,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
 
        /* set clock divisor */
        l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
-       l |= div << 2;
+       l |= clkd << 2;
+
+       /* set clock granularity */
+       l &= ~OMAP2_MCSPI_CHCONF_CLKG;
+       l |= clkg;
+       if (clkg) {
+               cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
+               cs->chctrl0 |= extclk << 8;
+               mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
+       }
 
        /* set SPI mode 0..3 */
        if (spi->mode & SPI_CPOL)
@@ -900,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
        mcspi_write_chconf0(spi, l);
 
        dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
-                       OMAP2_MCSPI_MAX_FREQ >> div,
+                       speed_hz,
                        (spi->mode & SPI_CPHA) ? "trailing" : "leading",
                        (spi->mode & SPI_CPOL) ? "inverted" : "normal");
 
@@ -972,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                cs->base = mcspi->base + spi->chip_select * 0x14;
                cs->phys = mcspi->phys + spi->chip_select * 0x14;
                cs->chconf0 = 0;
+               cs->chctrl0 = 0;
                spi->controller_state = cs;
                /* Link this to context save list */
                list_add_tail(&cs->node, &ctx->cs);
@@ -1057,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
                        status = -EINVAL;
                        break;
                }
-               if (par_override || t->speed_hz || t->bits_per_word) {
+               if (par_override ||
+                   (t->speed_hz != spi->max_speed_hz) ||
+                   (t->bits_per_word != spi->bits_per_word)) {
                        par_override = 1;
                        status = omap2_mcspi_setup_transfer(spi, t);
                        if (status < 0)
                                break;
-                       if (!t->speed_hz && !t->bits_per_word)
+                       if (t->speed_hz == spi->max_speed_hz &&
+                           t->bits_per_word == spi->bits_per_word)
                                par_override = 0;
                }
                if (cd && cd->cs_per_word) {
@@ -1176,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
        m->actual_length = 0;
        m->status = 0;
 
-       /* reject invalid messages and transfers */
-       if (list_empty(&m->transfers))
-               return -EINVAL;
        list_for_each_entry(t, &m->transfers, transfer_list) {
                const void      *tx_buf = t->tx_buf;
                void            *rx_buf = t->rx_buf;
                unsigned        len = t->len;
 
-               if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
-                               || (len && !(rx_buf || tx_buf))) {
+               if ((len && !(rx_buf || tx_buf))) {
                        dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
                                        t->speed_hz,
                                        len,
@@ -1194,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
                                        t->bits_per_word);
                        return -EINVAL;
                }
-               if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
-                       dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
-                                       t->speed_hz,
-                                       OMAP2_MCSPI_MAX_FREQ >> 15);
-                       return -EINVAL;
-               }
 
                if (m->is_dma_mapped || len < DMA_MIN_BYTES)
                        continue;
@@ -1311,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        master->transfer_one_message = omap2_mcspi_transfer_one_message;
        master->cleanup = omap2_mcspi_cleanup;
        master->dev.of_node = node;
+       master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
+       master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
 
        platform_set_drvdata(pdev, master);
 
index 7f2121fe262223391185bfc458be0ced703463a6..d018a4aac3a18f818921a6d04226f1bf2fd703b1 100644 (file)
@@ -9,7 +9,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
@@ -43,8 +42,6 @@
 struct orion_spi {
        struct spi_master       *master;
        void __iomem            *base;
-       unsigned int            max_speed;
-       unsigned int            min_speed;
        struct clk              *clk;
 };
 
@@ -75,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
        writel(val, reg_addr);
 }
 
-static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
-{
-       if (size == 16) {
-               orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
-                                 ORION_SPI_IF_8_16_BIT_MODE);
-       } else if (size == 8) {
-               orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
-                                 ORION_SPI_IF_8_16_BIT_MODE);
-       } else {
-               pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n",
-                       size);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
 {
        u32 tclk_hz;
@@ -170,7 +150,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        if (rc)
                return rc;
 
-       return orion_spi_set_transfer_size(orion_spi, bits_per_word);
+       if (bits_per_word == 16)
+               orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+                                 ORION_SPI_IF_8_16_BIT_MODE);
+       else
+               orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+                                 ORION_SPI_IF_8_16_BIT_MODE);
+
+       return 0;
 }
 
 static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
@@ -260,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi,
 static unsigned int
 orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
 {
-       struct orion_spi *orion_spi;
        unsigned int count;
        int word_len;
 
-       orion_spi = spi_master_get_devdata(spi->master);
        word_len = spi->bits_per_word;
        count = xfer->len;
 
@@ -310,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master,
                goto msg_done;
 
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               /* make sure buffer length is even when working in 16
-                * bit mode*/
-               if ((t->bits_per_word == 16) && (t->len & 1)) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "odd data length %d while in 16 bit mode\n",
-                               t->len);
-                       status = -EIO;
-                       goto msg_done;
-               }
-
-               if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "device min speed (%d Hz) exceeds "
-                               "required transfer speed (%d Hz)\n",
-                               orion_spi->min_speed, t->speed_hz);
-                       status = -EIO;
-                       goto msg_done;
-               }
-
                if (par_override || t->speed_hz || t->bits_per_word) {
                        par_override = 1;
                        status = orion_spi_setup_transfer(spi, t);
@@ -375,28 +339,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
        return 0;
 }
 
-static int orion_spi_setup(struct spi_device *spi)
-{
-       struct orion_spi *orion_spi;
-
-       orion_spi = spi_master_get_devdata(spi->master);
-
-       if ((spi->max_speed_hz == 0)
-                       || (spi->max_speed_hz > orion_spi->max_speed))
-               spi->max_speed_hz = orion_spi->max_speed;
-
-       if (spi->max_speed_hz < orion_spi->min_speed) {
-               dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
-                       spi->max_speed_hz);
-               return -EINVAL;
-       }
-
-       /*
-        * baudrate & width will be set orion_spi_setup_transfer
-        */
-       return 0;
-}
-
 static int orion_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
@@ -425,9 +367,9 @@ static int orion_spi_probe(struct platform_device *pdev)
        /* we support only mode 0, and no options */
        master->mode_bits = SPI_CPHA | SPI_CPOL;
 
-       master->setup = orion_spi_setup;
        master->transfer_one_message = orion_spi_transfer_one_message;
        master->num_chipselect = ORION_NUM_CHIPSELECTS;
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
 
        platform_set_drvdata(pdev, master);
 
@@ -443,8 +385,8 @@ static int orion_spi_probe(struct platform_device *pdev)
        clk_prepare(spi->clk);
        clk_enable(spi->clk);
        tclk_hz = clk_get_rate(spi->clk);
-       spi->max_speed = DIV_ROUND_UP(tclk_hz, 4);
-       spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
+       master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
+       master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        spi->base = devm_ioremap_resource(&pdev->dev, r);
index 2789b452e71159a86164ff752ef2c1e06a6da411..51d99779682fc14933b0e93575748a7755f2d328 100644 (file)
@@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022)
        struct spi_transfer *last_transfer;
        pl022->next_msg_cs_active = false;
 
-       last_transfer = list_entry(pl022->cur_msg->transfers.prev,
-                                       struct spi_transfer,
-                                       transfer_list);
+       last_transfer = list_last_entry(&pl022->cur_msg->transfers,
+                                       struct spi_transfer, transfer_list);
 
        /* Delay if requested before any change in chip select */
        if (last_transfer->delay_usecs)
@@ -2109,8 +2108,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
        pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
                                          GFP_KERNEL);
 
-       pinctrl_pm_select_default_state(dev);
-
        /*
         * Bus Number Which has been Assigned to this SSP controller
         * on this board
@@ -2183,13 +2180,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
                goto err_no_clk;
        }
 
-       status = clk_prepare(pl022->clk);
-       if (status) {
-               dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n");
-               goto  err_clk_prep;
-       }
-
-       status = clk_enable(pl022->clk);
+       status = clk_prepare_enable(pl022->clk);
        if (status) {
                dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
                goto err_no_clk_en;
@@ -2250,10 +2241,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
        if (platform_info->enable_dma)
                pl022_dma_remove(pl022);
  err_no_irq:
-       clk_disable(pl022->clk);
+       clk_disable_unprepare(pl022->clk);
  err_no_clk_en:
-       clk_unprepare(pl022->clk);
- err_clk_prep:
  err_no_clk:
  err_no_ioremap:
        amba_release_regions(adev);
@@ -2281,42 +2270,13 @@ pl022_remove(struct amba_device *adev)
        if (pl022->master_info->enable_dma)
                pl022_dma_remove(pl022);
 
-       clk_disable(pl022->clk);
-       clk_unprepare(pl022->clk);
+       clk_disable_unprepare(pl022->clk);
        amba_release_regions(adev);
        tasklet_disable(&pl022->pump_transfers);
        return 0;
 }
 
-#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
-/*
- * These two functions are used from both suspend/resume and
- * the runtime counterparts to handle external resources like
- * clocks, pins and regulators when going to sleep.
- */
-static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
-{
-       clk_disable(pl022->clk);
-
-       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)
-{
-       /* First go to the default state */
-       pinctrl_pm_select_default_state(&pl022->adev->dev);
-       if (!runtime)
-               /* Then let's idle the pins until the next transfer happens */
-               pinctrl_pm_select_idle_state(&pl022->adev->dev);
-
-       clk_enable(pl022->clk);
-}
-#endif
-
-#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_PM_SLEEP
 static int pl022_suspend(struct device *dev)
 {
        struct pl022 *pl022 = dev_get_drvdata(dev);
@@ -2328,8 +2288,13 @@ static int pl022_suspend(struct device *dev)
                return ret;
        }
 
-       pm_runtime_get_sync(dev);
-       pl022_suspend_resources(pl022, false);
+       ret = pm_runtime_force_suspend(dev);
+       if (ret) {
+               spi_master_resume(pl022->master);
+               return ret;
+       }
+
+       pinctrl_pm_select_sleep_state(dev);
 
        dev_dbg(dev, "suspended\n");
        return 0;
@@ -2340,8 +2305,9 @@ static int pl022_resume(struct device *dev)
        struct pl022 *pl022 = dev_get_drvdata(dev);
        int ret;
 
-       pl022_resume_resources(pl022, false);
-       pm_runtime_put(dev);
+       ret = pm_runtime_force_resume(dev);
+       if (ret)
+               dev_err(dev, "problem resuming\n");
 
        /* Start the queue running */
        ret = spi_master_resume(pl022->master);
@@ -2352,14 +2318,16 @@ static int pl022_resume(struct device *dev)
 
        return ret;
 }
-#endif /* CONFIG_PM */
+#endif
 
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
 static int pl022_runtime_suspend(struct device *dev)
 {
        struct pl022 *pl022 = dev_get_drvdata(dev);
 
-       pl022_suspend_resources(pl022, true);
+       clk_disable_unprepare(pl022->clk);
+       pinctrl_pm_select_idle_state(dev);
+
        return 0;
 }
 
@@ -2367,14 +2335,16 @@ static int pl022_runtime_resume(struct device *dev)
 {
        struct pl022 *pl022 = dev_get_drvdata(dev);
 
-       pl022_resume_resources(pl022, true);
+       pinctrl_pm_select_default_state(dev);
+       clk_prepare_enable(pl022->clk);
+
        return 0;
 }
 #endif
 
 static const struct dev_pm_ops pl022_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
-       SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
+       SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
 };
 
 static struct vendor_data vendor_arm = {
index 5ee56726f8d080faaf052289a89c667fc425d85c..80b8408ac3e3c89e05ff8c30fd8b99f0ced01601 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
index 3c0b55125f1eb6b85989a549fc50c51f114b9b0d..713af4806f265e10b87dcfade6b6989055c2f283 100644 (file)
@@ -9,7 +9,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
index 2916efc7cfe59eed5734304b5022c150902298fe..e8a26f25d5c0a1464ab259c545e2b1d2031a9741 100644 (file)
@@ -18,7 +18,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
index c702fc536a775c8400cfa64a1b208c71e2953c15..41185d0557fa5575531d6da9318b7c135198a681 100644 (file)
@@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data)
        drv_data->cur_msg = NULL;
        drv_data->cur_transfer = NULL;
 
-       last_transfer = list_entry(msg->transfers.prev,
-                                       struct spi_transfer,
+       last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
                                        transfer_list);
 
        /* Delay if requested before any change in chip select */
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
new file mode 100644 (file)
index 0000000..b032e88
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2008-2014, The Linux foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License rev 2 and
+ * only rev 2 as published by the free Software foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define QUP_CONFIG                     0x0000
+#define QUP_STATE                      0x0004
+#define QUP_IO_M_MODES                 0x0008
+#define QUP_SW_RESET                   0x000c
+#define QUP_OPERATIONAL                        0x0018
+#define QUP_ERROR_FLAGS                        0x001c
+#define QUP_ERROR_FLAGS_EN             0x0020
+#define QUP_OPERATIONAL_MASK           0x0028
+#define QUP_HW_VERSION                 0x0030
+#define QUP_MX_OUTPUT_CNT              0x0100
+#define QUP_OUTPUT_FIFO                        0x0110
+#define QUP_MX_WRITE_CNT               0x0150
+#define QUP_MX_INPUT_CNT               0x0200
+#define QUP_MX_READ_CNT                        0x0208
+#define QUP_INPUT_FIFO                 0x0218
+
+#define SPI_CONFIG                     0x0300
+#define SPI_IO_CONTROL                 0x0304
+#define SPI_ERROR_FLAGS                        0x0308
+#define SPI_ERROR_FLAGS_EN             0x030c
+
+/* QUP_CONFIG fields */
+#define QUP_CONFIG_SPI_MODE            (1 << 8)
+#define QUP_CONFIG_CLOCK_AUTO_GATE     BIT(13)
+#define QUP_CONFIG_NO_INPUT            BIT(7)
+#define QUP_CONFIG_NO_OUTPUT           BIT(6)
+#define QUP_CONFIG_N                   0x001f
+
+/* QUP_STATE fields */
+#define QUP_STATE_VALID                        BIT(2)
+#define QUP_STATE_RESET                        0
+#define QUP_STATE_RUN                  1
+#define QUP_STATE_PAUSE                        3
+#define QUP_STATE_MASK                 3
+#define QUP_STATE_CLEAR                        2
+
+#define QUP_HW_VERSION_2_1_1           0x20010001
+
+/* QUP_IO_M_MODES fields */
+#define QUP_IO_M_PACK_EN               BIT(15)
+#define QUP_IO_M_UNPACK_EN             BIT(14)
+#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12
+#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT        10
+#define QUP_IO_M_INPUT_MODE_MASK       (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT)
+#define QUP_IO_M_OUTPUT_MODE_MASK      (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT)
+
+#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x)  (((x) & (0x03 << 0)) >> 0)
+#define QUP_IO_M_OUTPUT_FIFO_SIZE(x)   (((x) & (0x07 << 2)) >> 2)
+#define QUP_IO_M_INPUT_BLOCK_SIZE(x)   (((x) & (0x03 << 5)) >> 5)
+#define QUP_IO_M_INPUT_FIFO_SIZE(x)    (((x) & (0x07 << 7)) >> 7)
+
+#define QUP_IO_M_MODE_FIFO             0
+#define QUP_IO_M_MODE_BLOCK            1
+#define QUP_IO_M_MODE_DMOV             2
+#define QUP_IO_M_MODE_BAM              3
+
+/* QUP_OPERATIONAL fields */
+#define QUP_OP_MAX_INPUT_DONE_FLAG     BIT(11)
+#define QUP_OP_MAX_OUTPUT_DONE_FLAG    BIT(10)
+#define QUP_OP_IN_SERVICE_FLAG         BIT(9)
+#define QUP_OP_OUT_SERVICE_FLAG                BIT(8)
+#define QUP_OP_IN_FIFO_FULL            BIT(7)
+#define QUP_OP_OUT_FIFO_FULL           BIT(6)
+#define QUP_OP_IN_FIFO_NOT_EMPTY       BIT(5)
+#define QUP_OP_OUT_FIFO_NOT_EMPTY      BIT(4)
+
+/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */
+#define QUP_ERROR_OUTPUT_OVER_RUN      BIT(5)
+#define QUP_ERROR_INPUT_UNDER_RUN      BIT(4)
+#define QUP_ERROR_OUTPUT_UNDER_RUN     BIT(3)
+#define QUP_ERROR_INPUT_OVER_RUN       BIT(2)
+
+/* SPI_CONFIG fields */
+#define SPI_CONFIG_HS_MODE             BIT(10)
+#define SPI_CONFIG_INPUT_FIRST         BIT(9)
+#define SPI_CONFIG_LOOPBACK            BIT(8)
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS              BIT(11)
+#define SPI_IO_C_CLK_IDLE_HIGH         BIT(10)
+#define SPI_IO_C_MX_CS_MODE            BIT(8)
+#define SPI_IO_C_CS_N_POLARITY_0       BIT(4)
+#define SPI_IO_C_CS_SELECT(x)          (((x) & 3) << 2)
+#define SPI_IO_C_CS_SELECT_MASK                0x000c
+#define SPI_IO_C_TRISTATE_CS           BIT(1)
+#define SPI_IO_C_NO_TRI_STATE          BIT(0)
+
+/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
+#define SPI_ERROR_CLK_OVER_RUN         BIT(1)
+#define SPI_ERROR_CLK_UNDER_RUN                BIT(0)
+
+#define SPI_NUM_CHIPSELECTS            4
+
+/* high speed mode is when bus rate is greater then 26MHz */
+#define SPI_HS_MIN_RATE                        26000000
+#define SPI_MAX_RATE                   50000000
+
+#define SPI_DELAY_THRESHOLD            1
+#define SPI_DELAY_RETRY                        10
+
+struct spi_qup {
+       void __iomem            *base;
+       struct device           *dev;
+       struct clk              *cclk;  /* core clock */
+       struct clk              *iclk;  /* interface clock */
+       int                     irq;
+       spinlock_t              lock;
+
+       int                     in_fifo_sz;
+       int                     out_fifo_sz;
+       int                     in_blk_sz;
+       int                     out_blk_sz;
+
+       struct spi_transfer     *xfer;
+       struct completion       done;
+       int                     error;
+       int                     w_size; /* bytes per SPI word */
+       int                     tx_bytes;
+       int                     rx_bytes;
+};
+
+
+static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
+{
+       u32 opstate = readl_relaxed(controller->base + QUP_STATE);
+
+       return opstate & QUP_STATE_VALID;
+}
+
+static int spi_qup_set_state(struct spi_qup *controller, u32 state)
+{
+       unsigned long loop;
+       u32 cur_state;
+
+       loop = 0;
+       while (!spi_qup_is_valid_state(controller)) {
+
+               usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+               if (++loop > SPI_DELAY_RETRY)
+                       return -EIO;
+       }
+
+       if (loop)
+               dev_dbg(controller->dev, "invalid state for %ld,us %d\n",
+                       loop, state);
+
+       cur_state = readl_relaxed(controller->base + QUP_STATE);
+       /*
+        * Per spec: for PAUSE_STATE to RESET_STATE, two writes
+        * of (b10) are required
+        */
+       if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) &&
+           (state == QUP_STATE_RESET)) {
+               writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+               writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+       } else {
+               cur_state &= ~QUP_STATE_MASK;
+               cur_state |= state;
+               writel_relaxed(cur_state, controller->base + QUP_STATE);
+       }
+
+       loop = 0;
+       while (!spi_qup_is_valid_state(controller)) {
+
+               usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+               if (++loop > SPI_DELAY_RETRY)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+
+static void spi_qup_fifo_read(struct spi_qup *controller,
+                           struct spi_transfer *xfer)
+{
+       u8 *rx_buf = xfer->rx_buf;
+       u32 word, state;
+       int idx, shift, w_size;
+
+       w_size = controller->w_size;
+
+       while (controller->rx_bytes < xfer->len) {
+
+               state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+               if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
+                       break;
+
+               word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+
+               if (!rx_buf) {
+                       controller->rx_bytes += w_size;
+                       continue;
+               }
+
+               for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+                       /*
+                        * The data format depends on bytes per SPI word:
+                        *  4 bytes: 0x12345678
+                        *  2 bytes: 0x00001234
+                        *  1 byte : 0x00000012
+                        */
+                       shift = BITS_PER_BYTE;
+                       shift *= (w_size - idx - 1);
+                       rx_buf[controller->rx_bytes] = word >> shift;
+               }
+       }
+}
+
+static void spi_qup_fifo_write(struct spi_qup *controller,
+                           struct spi_transfer *xfer)
+{
+       const u8 *tx_buf = xfer->tx_buf;
+       u32 word, state, data;
+       int idx, w_size;
+
+       w_size = controller->w_size;
+
+       while (controller->tx_bytes < xfer->len) {
+
+               state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+               if (state & QUP_OP_OUT_FIFO_FULL)
+                       break;
+
+               word = 0;
+               for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
+
+                       if (!tx_buf) {
+                               controller->tx_bytes += w_size;
+                               break;
+                       }
+
+                       data = tx_buf[controller->tx_bytes];
+                       word |= data << (BITS_PER_BYTE * (3 - idx));
+               }
+
+               writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
+       }
+}
+
+static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
+{
+       struct spi_qup *controller = dev_id;
+       struct spi_transfer *xfer;
+       u32 opflags, qup_err, spi_err;
+       unsigned long flags;
+       int error = 0;
+
+       spin_lock_irqsave(&controller->lock, flags);
+       xfer = controller->xfer;
+       controller->xfer = NULL;
+       spin_unlock_irqrestore(&controller->lock, flags);
+
+       qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
+       spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
+       opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+       writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
+       writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
+       writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+
+       if (!xfer) {
+               dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n",
+                                   qup_err, spi_err, opflags);
+               return IRQ_HANDLED;
+       }
+
+       if (qup_err) {
+               if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
+                       dev_warn(controller->dev, "OUTPUT_OVER_RUN\n");
+               if (qup_err & QUP_ERROR_INPUT_UNDER_RUN)
+                       dev_warn(controller->dev, "INPUT_UNDER_RUN\n");
+               if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN)
+                       dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n");
+               if (qup_err & QUP_ERROR_INPUT_OVER_RUN)
+                       dev_warn(controller->dev, "INPUT_OVER_RUN\n");
+
+               error = -EIO;
+       }
+
+       if (spi_err) {
+               if (spi_err & SPI_ERROR_CLK_OVER_RUN)
+                       dev_warn(controller->dev, "CLK_OVER_RUN\n");
+               if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
+                       dev_warn(controller->dev, "CLK_UNDER_RUN\n");
+
+               error = -EIO;
+       }
+
+       if (opflags & QUP_OP_IN_SERVICE_FLAG)
+               spi_qup_fifo_read(controller, xfer);
+
+       if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+               spi_qup_fifo_write(controller, xfer);
+
+       spin_lock_irqsave(&controller->lock, flags);
+       controller->error = error;
+       controller->xfer = xfer;
+       spin_unlock_irqrestore(&controller->lock, flags);
+
+       if (controller->rx_bytes == xfer->len || error)
+               complete(&controller->done);
+
+       return IRQ_HANDLED;
+}
+
+
+/* set clock freq ... bits per word */
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+{
+       struct spi_qup *controller = spi_master_get_devdata(spi->master);
+       u32 config, iomode, mode;
+       int ret, n_words, w_size;
+
+       if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
+               dev_err(controller->dev, "too big size for loopback %d > %d\n",
+                       xfer->len, controller->in_fifo_sz);
+               return -EIO;
+       }
+
+       ret = clk_set_rate(controller->cclk, xfer->speed_hz);
+       if (ret) {
+               dev_err(controller->dev, "fail to set frequency %d",
+                       xfer->speed_hz);
+               return -EIO;
+       }
+
+       if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
+               dev_err(controller->dev, "cannot set RESET state\n");
+               return -EIO;
+       }
+
+       w_size = 4;
+       if (xfer->bits_per_word <= 8)
+               w_size = 1;
+       else if (xfer->bits_per_word <= 16)
+               w_size = 2;
+
+       n_words = xfer->len / w_size;
+       controller->w_size = w_size;
+
+       if (n_words <= controller->in_fifo_sz) {
+               mode = QUP_IO_M_MODE_FIFO;
+               writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+               writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+               /* must be zero for FIFO */
+               writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
+               writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+       } else {
+               mode = QUP_IO_M_MODE_BLOCK;
+               writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+               writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+               /* must be zero for BLOCK and BAM */
+               writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+               writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+       }
+
+       iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
+       /* Set input and output transfer mode */
+       iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
+       iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
+       iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+       iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+
+       writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+
+       config = readl_relaxed(controller->base + SPI_CONFIG);
+
+       if (spi->mode & SPI_LOOP)
+               config |= SPI_CONFIG_LOOPBACK;
+       else
+               config &= ~SPI_CONFIG_LOOPBACK;
+
+       if (spi->mode & SPI_CPHA)
+               config &= ~SPI_CONFIG_INPUT_FIRST;
+       else
+               config |= SPI_CONFIG_INPUT_FIRST;
+
+       /*
+        * HS_MODE improves signal stability for spi-clk high rates,
+        * but is invalid in loop back mode.
+        */
+       if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
+               config |= SPI_CONFIG_HS_MODE;
+       else
+               config &= ~SPI_CONFIG_HS_MODE;
+
+       writel_relaxed(config, controller->base + SPI_CONFIG);
+
+       config = readl_relaxed(controller->base + QUP_CONFIG);
+       config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
+       config |= xfer->bits_per_word - 1;
+       config |= QUP_CONFIG_SPI_MODE;
+       writel_relaxed(config, controller->base + QUP_CONFIG);
+
+       writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK);
+       return 0;
+}
+
+static void spi_qup_set_cs(struct spi_device *spi, bool enable)
+{
+       struct spi_qup *controller = spi_master_get_devdata(spi->master);
+
+       u32 iocontol, mask;
+
+       iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL);
+
+       /* Disable auto CS toggle and use manual */
+       iocontol &= ~SPI_IO_C_MX_CS_MODE;
+       iocontol |= SPI_IO_C_FORCE_CS;
+
+       iocontol &= ~SPI_IO_C_CS_SELECT_MASK;
+       iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select);
+
+       mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
+
+       if (enable)
+               iocontol |= mask;
+       else
+               iocontol &= ~mask;
+
+       writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL);
+}
+
+static int spi_qup_transfer_one(struct spi_master *master,
+                             struct spi_device *spi,
+                             struct spi_transfer *xfer)
+{
+       struct spi_qup *controller = spi_master_get_devdata(master);
+       unsigned long timeout, flags;
+       int ret = -EIO;
+
+       ret = spi_qup_io_config(spi, xfer);
+       if (ret)
+               return ret;
+
+       timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
+       timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+       timeout = 100 * msecs_to_jiffies(timeout);
+
+       reinit_completion(&controller->done);
+
+       spin_lock_irqsave(&controller->lock, flags);
+       controller->xfer     = xfer;
+       controller->error    = 0;
+       controller->rx_bytes = 0;
+       controller->tx_bytes = 0;
+       spin_unlock_irqrestore(&controller->lock, flags);
+
+       if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+               dev_warn(controller->dev, "cannot set RUN state\n");
+               goto exit;
+       }
+
+       if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
+               dev_warn(controller->dev, "cannot set PAUSE state\n");
+               goto exit;
+       }
+
+       spi_qup_fifo_write(controller, xfer);
+
+       if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+               dev_warn(controller->dev, "cannot set EXECUTE state\n");
+               goto exit;
+       }
+
+       if (!wait_for_completion_timeout(&controller->done, timeout))
+               ret = -ETIMEDOUT;
+exit:
+       spi_qup_set_state(controller, QUP_STATE_RESET);
+       spin_lock_irqsave(&controller->lock, flags);
+       controller->xfer = NULL;
+       if (!ret)
+               ret = controller->error;
+       spin_unlock_irqrestore(&controller->lock, flags);
+       return ret;
+}
+
+static int spi_qup_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct clk *iclk, *cclk;
+       struct spi_qup *controller;
+       struct resource *res;
+       struct device *dev;
+       void __iomem *base;
+       u32 data, max_freq, iomode;
+       int ret, irq, size;
+
+       dev = &pdev->dev;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       cclk = devm_clk_get(dev, "core");
+       if (IS_ERR(cclk))
+               return PTR_ERR(cclk);
+
+       iclk = devm_clk_get(dev, "iface");
+       if (IS_ERR(iclk))
+               return PTR_ERR(iclk);
+
+       /* This is optional parameter */
+       if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
+               max_freq = SPI_MAX_RATE;
+
+       if (!max_freq || max_freq > SPI_MAX_RATE) {
+               dev_err(dev, "invalid clock frequency %d\n", max_freq);
+               return -ENXIO;
+       }
+
+       ret = clk_prepare_enable(cclk);
+       if (ret) {
+               dev_err(dev, "cannot enable core clock\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(iclk);
+       if (ret) {
+               clk_disable_unprepare(cclk);
+               dev_err(dev, "cannot enable iface clock\n");
+               return ret;
+       }
+
+       data = readl_relaxed(base + QUP_HW_VERSION);
+
+       if (data < QUP_HW_VERSION_2_1_1) {
+               clk_disable_unprepare(cclk);
+               clk_disable_unprepare(iclk);
+               dev_err(dev, "v.%08x is not supported\n", data);
+               return -ENXIO;
+       }
+
+       master = spi_alloc_master(dev, sizeof(struct spi_qup));
+       if (!master) {
+               clk_disable_unprepare(cclk);
+               clk_disable_unprepare(iclk);
+               dev_err(dev, "cannot allocate master\n");
+               return -ENOMEM;
+       }
+
+       master->bus_num = pdev->id;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+       master->num_chipselect = SPI_NUM_CHIPSELECTS;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+       master->max_speed_hz = max_freq;
+       master->set_cs = spi_qup_set_cs;
+       master->transfer_one = spi_qup_transfer_one;
+       master->dev.of_node = pdev->dev.of_node;
+       master->auto_runtime_pm = true;
+
+       platform_set_drvdata(pdev, master);
+
+       controller = spi_master_get_devdata(master);
+
+       controller->dev = dev;
+       controller->base = base;
+       controller->iclk = iclk;
+       controller->cclk = cclk;
+       controller->irq = irq;
+
+       spin_lock_init(&controller->lock);
+       init_completion(&controller->done);
+
+       iomode = readl_relaxed(base + QUP_IO_M_MODES);
+
+       size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
+       if (size)
+               controller->out_blk_sz = size * 16;
+       else
+               controller->out_blk_sz = 4;
+
+       size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode);
+       if (size)
+               controller->in_blk_sz = size * 16;
+       else
+               controller->in_blk_sz = 4;
+
+       size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode);
+       controller->out_fifo_sz = controller->out_blk_sz * (2 << size);
+
+       size = QUP_IO_M_INPUT_FIFO_SIZE(iomode);
+       controller->in_fifo_sz = controller->in_blk_sz * (2 << size);
+
+       dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+                data, controller->in_blk_sz, controller->in_fifo_sz,
+                controller->out_blk_sz, controller->out_fifo_sz);
+
+       writel_relaxed(1, base + QUP_SW_RESET);
+
+       ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+       if (ret) {
+               dev_err(dev, "cannot set RESET state\n");
+               goto error;
+       }
+
+       writel_relaxed(0, base + QUP_OPERATIONAL);
+       writel_relaxed(0, base + QUP_IO_M_MODES);
+       writel_relaxed(0, base + QUP_OPERATIONAL_MASK);
+       writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN,
+                      base + SPI_ERROR_FLAGS_EN);
+
+       writel_relaxed(0, base + SPI_CONFIG);
+       writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
+
+       ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
+                              IRQF_TRIGGER_HIGH, pdev->name, controller);
+       if (ret)
+               goto error;
+
+       ret = devm_spi_register_master(dev, master);
+       if (ret)
+               goto error;
+
+       pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       return 0;
+
+error:
+       clk_disable_unprepare(cclk);
+       clk_disable_unprepare(iclk);
+       spi_master_put(master);
+       return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int spi_qup_pm_suspend_runtime(struct device *device)
+{
+       struct spi_master *master = dev_get_drvdata(device);
+       struct spi_qup *controller = spi_master_get_devdata(master);
+       u32 config;
+
+       /* Enable clocks auto gaiting */
+       config = readl(controller->base + QUP_CONFIG);
+       config |= QUP_CONFIG_CLOCK_AUTO_GATE;
+       writel_relaxed(config, controller->base + QUP_CONFIG);
+       return 0;
+}
+
+static int spi_qup_pm_resume_runtime(struct device *device)
+{
+       struct spi_master *master = dev_get_drvdata(device);
+       struct spi_qup *controller = spi_master_get_devdata(master);
+       u32 config;
+
+       /* Disable clocks auto gaiting */
+       config = readl_relaxed(controller->base + QUP_CONFIG);
+       config &= ~QUP_CONFIG_CLOCK_AUTO_GATE;
+       writel_relaxed(config, controller->base + QUP_CONFIG);
+       return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_SLEEP
+static int spi_qup_suspend(struct device *device)
+{
+       struct spi_master *master = dev_get_drvdata(device);
+       struct spi_qup *controller = spi_master_get_devdata(master);
+       int ret;
+
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
+
+       ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+       if (ret)
+               return ret;
+
+       clk_disable_unprepare(controller->cclk);
+       clk_disable_unprepare(controller->iclk);
+       return 0;
+}
+
+static int spi_qup_resume(struct device *device)
+{
+       struct spi_master *master = dev_get_drvdata(device);
+       struct spi_qup *controller = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(controller->iclk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(controller->cclk);
+       if (ret)
+               return ret;
+
+       ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+       if (ret)
+               return ret;
+
+       return spi_master_resume(master);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int spi_qup_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = dev_get_drvdata(&pdev->dev);
+       struct spi_qup *controller = spi_master_get_devdata(master);
+       int ret;
+
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret)
+               return ret;
+
+       ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+       if (ret)
+               return ret;
+
+       clk_disable_unprepare(controller->cclk);
+       clk_disable_unprepare(controller->iclk);
+
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       return 0;
+}
+
+static struct of_device_id spi_qup_dt_match[] = {
+       { .compatible = "qcom,spi-qup-v2.1.1", },
+       { .compatible = "qcom,spi-qup-v2.2.1", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, spi_qup_dt_match);
+
+static const struct dev_pm_ops spi_qup_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume)
+       SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime,
+                          spi_qup_pm_resume_runtime,
+                          NULL)
+};
+
+static struct platform_driver spi_qup_driver = {
+       .driver = {
+               .name           = "spi_qup",
+               .owner          = THIS_MODULE,
+               .pm             = &spi_qup_dev_pm_ops,
+               .of_match_table = spi_qup_dt_match,
+       },
+       .probe = spi_qup_probe,
+       .remove = spi_qup_remove,
+};
+module_platform_driver(spi_qup_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spi_qup");
index 28987d9fcfe5c9181f54d3b4e2afbbee0e47080c..1fb0ad213324eadd2ef2a9cd9088880c42e5e722 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * SH RSPI driver
  *
- * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012, 2013  Renesas Solutions Corp.
+ * Copyright (C) 2014 Glider bvba
  *
  * Based on spi-sh.c:
  * Copyright (C) 2011 Renesas Solutions Corp.
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/sh_dma.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/rspi.h>
@@ -49,7 +50,7 @@
 #define RSPI_SPCKD             0x0c    /* Clock Delay Register */
 #define RSPI_SSLND             0x0d    /* Slave Select Negation Delay Register */
 #define RSPI_SPND              0x0e    /* Next-Access Delay Register */
-#define RSPI_SPCR2             0x0f    /* Control Register 2 */
+#define RSPI_SPCR2             0x0f    /* Control Register 2 (SH only) */
 #define RSPI_SPCMD0            0x10    /* Command Register 0 */
 #define RSPI_SPCMD1            0x12    /* Command Register 1 */
 #define RSPI_SPCMD2            0x14    /* Command Register 2 */
 #define RSPI_SPCMD5            0x1a    /* Command Register 5 */
 #define RSPI_SPCMD6            0x1c    /* Command Register 6 */
 #define RSPI_SPCMD7            0x1e    /* Command Register 7 */
+#define RSPI_SPCMD(i)          (RSPI_SPCMD0 + (i) * 2)
+#define RSPI_NUM_SPCMD         8
+#define RSPI_RZ_NUM_SPCMD      4
+#define QSPI_NUM_SPCMD         4
+
+/* RSPI on RZ only */
 #define RSPI_SPBFCR            0x20    /* Buffer Control Register */
 #define RSPI_SPBFDR            0x22    /* Buffer Data Count Setting Register */
 
-/*qspi only */
+/* QSPI only */
 #define QSPI_SPBFCR            0x18    /* Buffer Control Register */
 #define QSPI_SPBDCR            0x1a    /* Buffer Data Count Register */
 #define QSPI_SPBMUL0           0x1c    /* Transfer Data Length Multiplier Setting Register 0 */
 #define QSPI_SPBMUL1           0x20    /* Transfer Data Length Multiplier Setting Register 1 */
 #define QSPI_SPBMUL2           0x24    /* Transfer Data Length Multiplier Setting Register 2 */
 #define QSPI_SPBMUL3           0x28    /* Transfer Data Length Multiplier Setting Register 3 */
+#define QSPI_SPBMUL(i)         (QSPI_SPBMUL0 + (i) * 4)
 
 /* SPCR - Control Register */
 #define SPCR_SPRIE             0x80    /* Receive Interrupt Enable */
 #define SPSR_PERF              0x08    /* Parity Error Flag */
 #define SPSR_MODF              0x04    /* Mode Fault Error Flag */
 #define SPSR_IDLNF             0x02    /* RSPI Idle Flag */
-#define SPSR_OVRF              0x01    /* Overrun Error Flag */
+#define SPSR_OVRF              0x01    /* Overrun Error Flag (RSPI only) */
 
 /* SPSCR - Sequence Control Register */
 #define SPSCR_SPSLN_MASK       0x07    /* Sequence Length Specification */
 #define SPDCR_SPLWORD          SPDCR_SPLW1
 #define SPDCR_SPLBYTE          SPDCR_SPLW0
 #define SPDCR_SPLW             0x20    /* Access Width Specification (SH) */
-#define SPDCR_SPRDTD           0x10    /* Receive Transmit Data Select */
+#define SPDCR_SPRDTD           0x10    /* Receive Transmit Data Select (SH) */
 #define SPDCR_SLSEL1           0x08
 #define SPDCR_SLSEL0           0x04
-#define SPDCR_SLSEL_MASK       0x0c    /* SSL1 Output Select */
+#define SPDCR_SLSEL_MASK       0x0c    /* SSL1 Output Select (SH) */
 #define SPDCR_SPFC1            0x02
 #define SPDCR_SPFC0            0x01
-#define SPDCR_SPFC_MASK                0x03    /* Frame Count Setting (1-4) */
+#define SPDCR_SPFC_MASK                0x03    /* Frame Count Setting (1-4) (SH) */
 
 /* SPCKD - Clock Delay Register */
 #define SPCKD_SCKDL_MASK       0x07    /* Clock Delay Setting (1-8) */
 #define SPCMD_LSBF             0x1000  /* LSB First */
 #define SPCMD_SPB_MASK         0x0f00  /* Data Length Setting */
 #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
-#define SPCMD_SPB_8BIT         0x0000  /* qspi only */
+#define SPCMD_SPB_8BIT         0x0000  /* QSPI only */
 #define SPCMD_SPB_16BIT                0x0100
 #define SPCMD_SPB_20BIT                0x0000
 #define SPCMD_SPB_24BIT                0x0100
 #define SPCMD_CPHA             0x0001  /* Clock Phase Setting */
 
 /* SPBFCR - Buffer Control Register */
-#define SPBFCR_TXRST           0x80    /* Transmit Buffer Data Reset (qspi only) */
-#define SPBFCR_RXRST           0x40    /* Receive Buffer Data Reset (qspi only) */
+#define SPBFCR_TXRST           0x80    /* Transmit Buffer Data Reset */
+#define SPBFCR_RXRST           0x40    /* Receive Buffer Data Reset */
 #define SPBFCR_TXTRG_MASK      0x30    /* Transmit Buffer Data Triggering Number */
 #define SPBFCR_RXTRG_MASK      0x07    /* Receive Buffer Data Triggering Number */
 
@@ -181,22 +189,21 @@ struct rspi_data {
        void __iomem *addr;
        u32 max_speed_hz;
        struct spi_master *master;
-       struct list_head queue;
-       struct work_struct ws;
        wait_queue_head_t wait;
-       spinlock_t lock;
        struct clk *clk;
-       u8 spsr;
        u16 spcmd;
+       u8 spsr;
+       u8 sppcr;
+       int rx_irq, tx_irq;
        const struct spi_ops *ops;
 
        /* for dmaengine */
        struct dma_chan *chan_tx;
        struct dma_chan *chan_rx;
-       int irq;
 
        unsigned dma_width_16bit:1;
        unsigned dma_callbacked:1;
+       unsigned byte_access:1;
 };
 
 static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset)
@@ -224,34 +231,47 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
        return ioread16(rspi->addr + offset);
 }
 
+static void rspi_write_data(const struct rspi_data *rspi, u16 data)
+{
+       if (rspi->byte_access)
+               rspi_write8(rspi, data, RSPI_SPDR);
+       else /* 16 bit */
+               rspi_write16(rspi, data, RSPI_SPDR);
+}
+
+static u16 rspi_read_data(const struct rspi_data *rspi)
+{
+       if (rspi->byte_access)
+               return rspi_read8(rspi, RSPI_SPDR);
+       else /* 16 bit */
+               return rspi_read16(rspi, RSPI_SPDR);
+}
+
 /* optional functions */
 struct spi_ops {
-       int (*set_config_register)(const struct rspi_data *rspi,
-                                  int access_size);
-       int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
-                       struct spi_transfer *t);
-       int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
-                          struct spi_transfer *t);
-
+       int (*set_config_register)(struct rspi_data *rspi, int access_size);
+       int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
+                           struct spi_transfer *xfer);
+       u16 mode_bits;
 };
 
 /*
- * functions for RSPI
+ * functions for RSPI on legacy SH
  */
-static int rspi_set_config_register(const struct rspi_data *rspi,
-                                   int access_size)
+static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
 {
        int spbr;
 
-       /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
-       rspi_write8(rspi, 0x00, RSPI_SPPCR);
+       /* Sets output mode, MOSI signal, and (optionally) loopback */
+       rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
 
        /* Sets transfer bit rate */
        spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
        rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
 
-       /* Sets number of frames to be used: 1 frame */
-       rspi_write8(rspi, 0x00, RSPI_SPDCR);
+       /* Disable dummy transmission, set 16-bit word access, 1 frame */
+       rspi_write8(rspi, 0, RSPI_SPDCR);
+       rspi->byte_access = 0;
 
        /* Sets RSPCK, SSL, next-access delay value */
        rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -262,8 +282,41 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
        rspi_write8(rspi, 0x00, RSPI_SPCR2);
 
        /* Sets SPCMD */
-       rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd,
-                    RSPI_SPCMD0);
+       rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+       rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+
+       /* Sets RSPI mode */
+       rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
+
+       return 0;
+}
+
+/*
+ * functions for RSPI on RZ
+ */
+static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
+{
+       int spbr;
+
+       /* Sets output mode, MOSI signal, and (optionally) loopback */
+       rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
+
+       /* Sets transfer bit rate */
+       spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
+       rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+       /* Disable dummy transmission, set byte access */
+       rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
+       rspi->byte_access = 1;
+
+       /* Sets RSPCK, SSL, next-access delay value */
+       rspi_write8(rspi, 0x00, RSPI_SPCKD);
+       rspi_write8(rspi, 0x00, RSPI_SSLND);
+       rspi_write8(rspi, 0x00, RSPI_SPND);
+
+       /* Sets SPCMD */
+       rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+       rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
 
        /* Sets RSPI mode */
        rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
@@ -274,21 +327,20 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
 /*
  * functions for QSPI
  */
-static int qspi_set_config_register(const struct rspi_data *rspi,
-                                   int access_size)
+static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
 {
-       u16 spcmd;
        int spbr;
 
-       /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
-       rspi_write8(rspi, 0x00, RSPI_SPPCR);
+       /* Sets output mode, MOSI signal, and (optionally) loopback */
+       rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
 
        /* Sets transfer bit rate */
        spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
        rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
 
-       /* Sets number of frames to be used: 1 frame */
-       rspi_write8(rspi, 0x00, RSPI_SPDCR);
+       /* Disable dummy transmission, set byte access */
+       rspi_write8(rspi, 0, RSPI_SPDCR);
+       rspi->byte_access = 1;
 
        /* Sets RSPCK, SSL, next-access delay value */
        rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -297,13 +349,13 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
 
        /* Data Length Setting */
        if (access_size == 8)
-               spcmd = SPCMD_SPB_8BIT;
+               rspi->spcmd |= SPCMD_SPB_8BIT;
        else if (access_size == 16)
-               spcmd = SPCMD_SPB_16BIT;
+               rspi->spcmd |= SPCMD_SPB_16BIT;
        else
-               spcmd = SPCMD_SPB_32BIT;
+               rspi->spcmd |= SPCMD_SPB_32BIT;
 
-       spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN;
+       rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN;
 
        /* Resets transfer data length */
        rspi_write32(rspi, 0, QSPI_SPBMUL0);
@@ -314,9 +366,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
        rspi_write8(rspi, 0x00, QSPI_SPBFCR);
 
        /* Sets SPCMD */
-       rspi_write16(rspi, spcmd, RSPI_SPCMD0);
+       rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
 
-       /* Enables SPI function in master mode */
+       /* Enables SPI function in master mode */
        rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
 
        return 0;
@@ -340,6 +392,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
        int ret;
 
        rspi->spsr = rspi_read8(rspi, RSPI_SPSR);
+       if (rspi->spsr & wait_mask)
+               return 0;
+
        rspi_enable_irq(rspi, enable_bit);
        ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ);
        if (ret == 0 && !(rspi->spsr & wait_mask))
@@ -348,78 +403,39 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
        return 0;
 }
 
-static void rspi_assert_ssl(const struct rspi_data *rspi)
-{
-       rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
-}
-
-static void rspi_negate_ssl(const struct rspi_data *rspi)
+static int rspi_data_out(struct rspi_data *rspi, u8 data)
 {
-       rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+       if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
+               dev_err(&rspi->master->dev, "transmit timeout\n");
+               return -ETIMEDOUT;
+       }
+       rspi_write_data(rspi, data);
+       return 0;
 }
 
-static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
-                        struct spi_transfer *t)
+static int rspi_data_in(struct rspi_data *rspi)
 {
-       int remain = t->len;
-       const u8 *data = t->tx_buf;
-       while (remain > 0) {
-               rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
-                           RSPI_SPCR);
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: tx empty timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
+       u8 data;
 
-               rspi_write16(rspi, *data, RSPI_SPDR);
-               data++;
-               remain--;
+       if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
+               dev_err(&rspi->master->dev, "receive timeout\n");
+               return -ETIMEDOUT;
        }
-
-       /* Waiting for the last transmission */
-       rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-
-       return 0;
+       data = rspi_read_data(rspi);
+       return data;
 }
 
-static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
-                        struct spi_transfer *t)
+static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
 {
-       int remain = t->len;
-       const u8 *data = t->tx_buf;
-
-       rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
-       rspi_write8(rspi, 0x00, QSPI_SPBFCR);
-
-       while (remain > 0) {
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: tx empty timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-               rspi_write8(rspi, *data++, RSPI_SPDR);
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: receive timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-               rspi_read8(rspi, RSPI_SPDR);
-
-               remain--;
-       }
+       int ret;
 
-       /* Waiting for the last transmission */
-       rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+       ret = rspi_data_out(rspi, data);
+       if (ret < 0)
+               return ret;
 
-       return 0;
+       return rspi_data_in(rspi);
 }
 
-#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
-
 static void rspi_dma_complete(void *arg)
 {
        struct rspi_data *rspi = arg;
@@ -471,7 +487,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
        struct scatterlist sg;
        const void *buf = NULL;
        struct dma_async_tx_descriptor *desc;
-       unsigned len;
+       unsigned int len;
        int ret = 0;
 
        if (rspi->dma_width_16bit) {
@@ -509,7 +525,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
         * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
         * called. So, this driver disables the IRQ while DMA transfer.
         */
-       disable_irq(rspi->irq);
+       disable_irq(rspi->tx_irq);
 
        rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
        rspi_enable_irq(rspi, SPCR_SPTIE);
@@ -528,7 +544,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
                ret = -ETIMEDOUT;
        rspi_disable_irq(rspi, SPCR_SPTIE);
 
-       enable_irq(rspi->irq);
+       enable_irq(rspi->tx_irq);
 
 end:
        rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
@@ -545,46 +561,17 @@ static void rspi_receive_init(const struct rspi_data *rspi)
 
        spsr = rspi_read8(rspi, RSPI_SPSR);
        if (spsr & SPSR_SPRF)
-               rspi_read16(rspi, RSPI_SPDR);   /* dummy read */
+               rspi_read_data(rspi);   /* dummy read */
        if (spsr & SPSR_OVRF)
                rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
                            RSPI_SPSR);
 }
 
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
-                           struct spi_transfer *t)
+static void rspi_rz_receive_init(const struct rspi_data *rspi)
 {
-       int remain = t->len;
-       u8 *data;
-
        rspi_receive_init(rspi);
-
-       data = t->rx_buf;
-       while (remain > 0) {
-               rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
-                           RSPI_SPCR);
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: tx empty timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-               /* dummy write for generate clock */
-               rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR);
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: receive timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-               /* SPDR allows 16 or 32-bit access only */
-               *data = (u8)rspi_read16(rspi, RSPI_SPDR);
-
-               data++;
-               remain--;
-       }
-
-       return 0;
+       rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR);
+       rspi_write8(rspi, 0, RSPI_SPBFCR);
 }
 
 static void qspi_receive_init(const struct rspi_data *rspi)
@@ -593,51 +580,17 @@ static void qspi_receive_init(const struct rspi_data *rspi)
 
        spsr = rspi_read8(rspi, RSPI_SPSR);
        if (spsr & SPSR_SPRF)
-               rspi_read8(rspi, RSPI_SPDR);   /* dummy read */
+               rspi_read_data(rspi);   /* dummy read */
        rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
-       rspi_write8(rspi, 0x00, QSPI_SPBFCR);
+       rspi_write8(rspi, 0, QSPI_SPBFCR);
 }
 
-static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
-                           struct spi_transfer *t)
-{
-       int remain = t->len;
-       u8 *data;
-
-       qspi_receive_init(rspi);
-
-       data = t->rx_buf;
-       while (remain > 0) {
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: tx empty timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-               /* dummy write for generate clock */
-               rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR);
-
-               if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
-                       dev_err(&rspi->master->dev,
-                               "%s: receive timeout\n", __func__);
-                       return -ETIMEDOUT;
-               }
-               /* SPDR allows 8, 16 or 32-bit access */
-               *data++ = rspi_read8(rspi, RSPI_SPDR);
-               remain--;
-       }
-
-       return 0;
-}
-
-#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
-
 static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
 {
        struct scatterlist sg, sg_dummy;
        void *dummy = NULL, *rx_buf = NULL;
        struct dma_async_tx_descriptor *desc, *desc_dummy;
-       unsigned len;
+       unsigned int len;
        int ret = 0;
 
        if (rspi->dma_width_16bit) {
@@ -695,7 +648,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
         * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
         * called. So, this driver disables the IRQ while DMA transfer.
         */
-       disable_irq(rspi->irq);
+       disable_irq(rspi->tx_irq);
+       if (rspi->rx_irq != rspi->tx_irq)
+               disable_irq(rspi->rx_irq);
 
        rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
        rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
@@ -718,7 +673,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
                ret = -ETIMEDOUT;
        rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
 
-       enable_irq(rspi->irq);
+       enable_irq(rspi->tx_irq);
+       if (rspi->rx_irq != rspi->tx_irq)
+               enable_irq(rspi->rx_irq);
 
 end:
        rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
@@ -746,56 +703,175 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t)
        return 0;
 }
 
-static void rspi_work(struct work_struct *work)
+static int rspi_transfer_out_in(struct rspi_data *rspi,
+                               struct spi_transfer *xfer)
 {
-       struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
-       struct spi_message *mesg;
-       struct spi_transfer *t;
-       unsigned long flags;
-       int ret;
+       int remain = xfer->len, ret;
+       const u8 *tx_buf = xfer->tx_buf;
+       u8 *rx_buf = xfer->rx_buf;
+       u8 spcr, data;
 
-       while (1) {
-               spin_lock_irqsave(&rspi->lock, flags);
-               if (list_empty(&rspi->queue)) {
-                       spin_unlock_irqrestore(&rspi->lock, flags);
-                       break;
-               }
-               mesg = list_entry(rspi->queue.next, struct spi_message, queue);
-               list_del_init(&mesg->queue);
-               spin_unlock_irqrestore(&rspi->lock, flags);
-
-               rspi_assert_ssl(rspi);
-
-               list_for_each_entry(t, &mesg->transfers, transfer_list) {
-                       if (t->tx_buf) {
-                               if (rspi_is_dma(rspi, t))
-                                       ret = rspi_send_dma(rspi, t);
-                               else
-                                       ret = send_pio(rspi, mesg, t);
-                               if (ret < 0)
-                                       goto error;
-                       }
-                       if (t->rx_buf) {
-                               if (rspi_is_dma(rspi, t))
-                                       ret = rspi_receive_dma(rspi, t);
-                               else
-                                       ret = receive_pio(rspi, mesg, t);
-                               if (ret < 0)
-                                       goto error;
-                       }
-                       mesg->actual_length += t->len;
+       rspi_receive_init(rspi);
+
+       spcr = rspi_read8(rspi, RSPI_SPCR);
+       if (rx_buf)
+               spcr &= ~SPCR_TXMD;
+       else
+               spcr |= SPCR_TXMD;
+       rspi_write8(rspi, spcr, RSPI_SPCR);
+
+       while (remain > 0) {
+               data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+               ret = rspi_data_out(rspi, data);
+               if (ret < 0)
+                       return ret;
+               if (rx_buf) {
+                       ret = rspi_data_in(rspi);
+                       if (ret < 0)
+                               return ret;
+                       *rx_buf++ = ret;
                }
-               rspi_negate_ssl(rspi);
+               remain--;
+       }
+
+       /* Wait for the last transmission */
+       rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+       return 0;
+}
+
+static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+                            struct spi_transfer *xfer)
+{
+       struct rspi_data *rspi = spi_master_get_devdata(master);
+       int ret;
+
+       if (!rspi_is_dma(rspi, xfer))
+               return rspi_transfer_out_in(rspi, xfer);
+
+       if (xfer->tx_buf) {
+               ret = rspi_send_dma(rspi, xfer);
+               if (ret < 0)
+                       return ret;
+       }
+       if (xfer->rx_buf)
+               return rspi_receive_dma(rspi, xfer);
+
+       return 0;
+}
+
+static int rspi_rz_transfer_out_in(struct rspi_data *rspi,
+                                  struct spi_transfer *xfer)
+{
+       int remain = xfer->len, ret;
+       const u8 *tx_buf = xfer->tx_buf;
+       u8 *rx_buf = xfer->rx_buf;
+       u8 data;
+
+       rspi_rz_receive_init(rspi);
+
+       while (remain > 0) {
+               data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+               ret = rspi_data_out_in(rspi, data);
+               if (ret < 0)
+                       return ret;
+               if (rx_buf)
+                       *rx_buf++ = ret;
+               remain--;
+       }
+
+       /* Wait for the last transmission */
+       rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+       return 0;
+}
+
+static int rspi_rz_transfer_one(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
+{
+       struct rspi_data *rspi = spi_master_get_devdata(master);
+
+       return rspi_rz_transfer_out_in(rspi, xfer);
+}
+
+static int qspi_transfer_out_in(struct rspi_data *rspi,
+                               struct spi_transfer *xfer)
+{
+       int remain = xfer->len, ret;
+       const u8 *tx_buf = xfer->tx_buf;
+       u8 *rx_buf = xfer->rx_buf;
+       u8 data;
 
-               mesg->status = 0;
-               mesg->complete(mesg->context);
+       qspi_receive_init(rspi);
+
+       while (remain > 0) {
+               data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+               ret = rspi_data_out_in(rspi, data);
+               if (ret < 0)
+                       return ret;
+               if (rx_buf)
+                       *rx_buf++ = ret;
+               remain--;
+       }
+
+       /* Wait for the last transmission */
+       rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+       return 0;
+}
+
+static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+       const u8 *buf = xfer->tx_buf;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < xfer->len; i++) {
+               ret = rspi_data_out(rspi, *buf++);
+               if (ret < 0)
+                       return ret;
        }
 
-       return;
+       /* Wait for the last transmission */
+       rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
 
-error:
-       mesg->status = ret;
-       mesg->complete(mesg->context);
+       return 0;
+}
+
+static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+       u8 *buf = xfer->rx_buf;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < xfer->len; i++) {
+               ret = rspi_data_in(rspi);
+               if (ret < 0)
+                       return ret;
+               *buf++ = ret;
+       }
+
+       return 0;
+}
+
+static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+                            struct spi_transfer *xfer)
+{
+       struct rspi_data *rspi = spi_master_get_devdata(master);
+
+       if (spi->mode & SPI_LOOP) {
+               return qspi_transfer_out_in(rspi, xfer);
+       } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) {
+               /* Quad or Dual SPI Write */
+               return qspi_transfer_out(rspi, xfer);
+       } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) {
+               /* Quad or Dual SPI Read */
+               return qspi_transfer_in(rspi, xfer);
+       } else {
+               /* Single SPI Transfer */
+               return qspi_transfer_out_in(rspi, xfer);
+       }
 }
 
 static int rspi_setup(struct spi_device *spi)
@@ -810,32 +886,115 @@ static int rspi_setup(struct spi_device *spi)
        if (spi->mode & SPI_CPHA)
                rspi->spcmd |= SPCMD_CPHA;
 
+       /* CMOS output mode and MOSI signal from previous transfer */
+       rspi->sppcr = 0;
+       if (spi->mode & SPI_LOOP)
+               rspi->sppcr |= SPPCR_SPLP;
+
        set_config_register(rspi, 8);
 
        return 0;
 }
 
-static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg)
+static u16 qspi_transfer_mode(const struct spi_transfer *xfer)
 {
-       struct rspi_data *rspi = spi_master_get_devdata(spi->master);
-       unsigned long flags;
+       if (xfer->tx_buf)
+               switch (xfer->tx_nbits) {
+               case SPI_NBITS_QUAD:
+                       return SPCMD_SPIMOD_QUAD;
+               case SPI_NBITS_DUAL:
+                       return SPCMD_SPIMOD_DUAL;
+               default:
+                       return 0;
+               }
+       if (xfer->rx_buf)
+               switch (xfer->rx_nbits) {
+               case SPI_NBITS_QUAD:
+                       return SPCMD_SPIMOD_QUAD | SPCMD_SPRW;
+               case SPI_NBITS_DUAL:
+                       return SPCMD_SPIMOD_DUAL | SPCMD_SPRW;
+               default:
+                       return 0;
+               }
+
+       return 0;
+}
 
-       mesg->actual_length = 0;
-       mesg->status = -EINPROGRESS;
+static int qspi_setup_sequencer(struct rspi_data *rspi,
+                               const struct spi_message *msg)
+{
+       const struct spi_transfer *xfer;
+       unsigned int i = 0, len = 0;
+       u16 current_mode = 0xffff, mode;
+
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               mode = qspi_transfer_mode(xfer);
+               if (mode == current_mode) {
+                       len += xfer->len;
+                       continue;
+               }
+
+               /* Transfer mode change */
+               if (i) {
+                       /* Set transfer data length of previous transfer */
+                       rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+               }
 
-       spin_lock_irqsave(&rspi->lock, flags);
-       list_add_tail(&mesg->queue, &rspi->queue);
-       schedule_work(&rspi->ws);
-       spin_unlock_irqrestore(&rspi->lock, flags);
+               if (i >= QSPI_NUM_SPCMD) {
+                       dev_err(&msg->spi->dev,
+                               "Too many different transfer modes");
+                       return -EINVAL;
+               }
+
+               /* Program transfer mode for this transfer */
+               rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i));
+               current_mode = mode;
+               len = xfer->len;
+               i++;
+       }
+       if (i) {
+               /* Set final transfer data length and sequence length */
+               rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+               rspi_write8(rspi, i - 1, RSPI_SPSCR);
+       }
 
        return 0;
 }
 
-static void rspi_cleanup(struct spi_device *spi)
+static int rspi_prepare_message(struct spi_master *master,
+                               struct spi_message *msg)
 {
+       struct rspi_data *rspi = spi_master_get_devdata(master);
+       int ret;
+
+       if (msg->spi->mode &
+           (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) {
+               /* Setup sequencer for messages with multiple transfer modes */
+               ret = qspi_setup_sequencer(rspi, msg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Enable SPI function in master mode */
+       rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
+       return 0;
 }
 
-static irqreturn_t rspi_irq(int irq, void *_sr)
+static int rspi_unprepare_message(struct spi_master *master,
+                                 struct spi_message *msg)
+{
+       struct rspi_data *rspi = spi_master_get_devdata(master);
+
+       /* Disable SPI function */
+       rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+
+       /* Reset sequencer for Single SPI Transfers */
+       rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+       rspi_write8(rspi, 0, RSPI_SPSCR);
+       return 0;
+}
+
+static irqreturn_t rspi_irq_mux(int irq, void *_sr)
 {
        struct rspi_data *rspi = _sr;
        u8 spsr;
@@ -857,6 +1016,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
        return ret;
 }
 
+static irqreturn_t rspi_irq_rx(int irq, void *_sr)
+{
+       struct rspi_data *rspi = _sr;
+       u8 spsr;
+
+       rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+       if (spsr & SPSR_SPRF) {
+               rspi_disable_irq(rspi, SPCR_SPRIE);
+               wake_up(&rspi->wait);
+               return IRQ_HANDLED;
+       }
+
+       return 0;
+}
+
+static irqreturn_t rspi_irq_tx(int irq, void *_sr)
+{
+       struct rspi_data *rspi = _sr;
+       u8 spsr;
+
+       rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+       if (spsr & SPSR_SPTEF) {
+               rspi_disable_irq(rspi, SPCR_SPTIE);
+               wake_up(&rspi->wait);
+               return IRQ_HANDLED;
+       }
+
+       return 0;
+}
+
 static int rspi_request_dma(struct rspi_data *rspi,
                                      struct platform_device *pdev)
 {
@@ -923,34 +1112,89 @@ static int rspi_remove(struct platform_device *pdev)
        struct rspi_data *rspi = platform_get_drvdata(pdev);
 
        rspi_release_dma(rspi);
-       clk_disable(rspi->clk);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
 
+static const struct spi_ops rspi_ops = {
+       .set_config_register =          rspi_set_config_register,
+       .transfer_one =                 rspi_transfer_one,
+       .mode_bits =                    SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops rspi_rz_ops = {
+       .set_config_register =          rspi_rz_set_config_register,
+       .transfer_one =                 rspi_rz_transfer_one,
+       .mode_bits =                    SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops qspi_ops = {
+       .set_config_register =          qspi_set_config_register,
+       .transfer_one =                 qspi_transfer_one,
+       .mode_bits =                    SPI_CPHA | SPI_CPOL | SPI_LOOP |
+                                       SPI_TX_DUAL | SPI_TX_QUAD |
+                                       SPI_RX_DUAL | SPI_RX_QUAD,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rspi_of_match[] = {
+       /* RSPI on legacy SH */
+       { .compatible = "renesas,rspi", .data = &rspi_ops },
+       /* RSPI on RZ/A1H */
+       { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops },
+       /* QSPI on R-Car Gen2 */
+       { .compatible = "renesas,qspi", .data = &qspi_ops },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rspi_of_match);
+
+static int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+       u32 num_cs;
+       int error;
+
+       /* Parse DT properties */
+       error = of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+       if (error) {
+               dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error);
+               return error;
+       }
+
+       master->num_chipselect = num_cs;
+       return 0;
+}
+#else
+#define rspi_of_match  NULL
+static inline int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+       return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
+static int rspi_request_irq(struct device *dev, unsigned int irq,
+                           irq_handler_t handler, const char *suffix,
+                           void *dev_id)
+{
+       const char *base = dev_name(dev);
+       size_t len = strlen(base) + strlen(suffix) + 2;
+       char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+       snprintf(name, len, "%s:%s", base, suffix);
+       return devm_request_irq(dev, irq, handler, 0, name, dev_id);
+}
+
 static int rspi_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct spi_master *master;
        struct rspi_data *rspi;
-       int ret, irq;
-       char clk_name[16];
-       const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+       int ret;
+       const struct of_device_id *of_id;
+       const struct rspi_plat_data *rspi_pd;
        const struct spi_ops *ops;
-       const struct platform_device_id *id_entry = pdev->id_entry;
-
-       ops = (struct spi_ops *)id_entry->driver_data;
-       /* ops parameter check */
-       if (!ops->set_config_register) {
-               dev_err(&pdev->dev, "there is no set_config_register\n");
-               return -ENODEV;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "platform_get_irq error\n");
-               return -ENODEV;
-       }
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
        if (master == NULL) {
@@ -958,6 +1202,28 @@ static int rspi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       of_id = of_match_device(rspi_of_match, &pdev->dev);
+       if (of_id) {
+               ops = of_id->data;
+               ret = rspi_parse_dt(&pdev->dev, master);
+               if (ret)
+                       goto error1;
+       } else {
+               ops = (struct spi_ops *)pdev->id_entry->driver_data;
+               rspi_pd = dev_get_platdata(&pdev->dev);
+               if (rspi_pd && rspi_pd->num_chipselect)
+                       master->num_chipselect = rspi_pd->num_chipselect;
+               else
+                       master->num_chipselect = 2; /* default */
+       };
+
+       /* ops parameter check */
+       if (!ops->set_config_register) {
+               dev_err(&pdev->dev, "there is no set_config_register\n");
+               ret = -ENODEV;
+               goto error1;
+       }
+
        rspi = spi_master_get_devdata(master);
        platform_set_drvdata(pdev, rspi);
        rspi->ops = ops;
@@ -970,39 +1236,61 @@ static int rspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
-       rspi->clk = devm_clk_get(&pdev->dev, clk_name);
+       rspi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(rspi->clk)) {
                dev_err(&pdev->dev, "cannot get clock\n");
                ret = PTR_ERR(rspi->clk);
                goto error1;
        }
-       clk_enable(rspi->clk);
 
-       INIT_LIST_HEAD(&rspi->queue);
-       spin_lock_init(&rspi->lock);
-       INIT_WORK(&rspi->ws, rspi_work);
-       init_waitqueue_head(&rspi->wait);
+       pm_runtime_enable(&pdev->dev);
 
-       if (rspi_pd && rspi_pd->num_chipselect)
-               master->num_chipselect = rspi_pd->num_chipselect;
-       else
-               master->num_chipselect = 2; /* default */
+       init_waitqueue_head(&rspi->wait);
 
        master->bus_num = pdev->id;
        master->setup = rspi_setup;
-       master->transfer = rspi_transfer;
-       master->cleanup = rspi_cleanup;
-       master->mode_bits = SPI_CPHA | SPI_CPOL;
+       master->auto_runtime_pm = true;
+       master->transfer_one = ops->transfer_one;
+       master->prepare_message = rspi_prepare_message;
+       master->unprepare_message = rspi_unprepare_message;
+       master->mode_bits = ops->mode_bits;
+       master->dev.of_node = pdev->dev.of_node;
+
+       ret = platform_get_irq_byname(pdev, "rx");
+       if (ret < 0) {
+               ret = platform_get_irq_byname(pdev, "mux");
+               if (ret < 0)
+                       ret = platform_get_irq(pdev, 0);
+               if (ret >= 0)
+                       rspi->rx_irq = rspi->tx_irq = ret;
+       } else {
+               rspi->rx_irq = ret;
+               ret = platform_get_irq_byname(pdev, "tx");
+               if (ret >= 0)
+                       rspi->tx_irq = ret;
+       }
+       if (ret < 0) {
+               dev_err(&pdev->dev, "platform_get_irq error\n");
+               goto error2;
+       }
 
-       ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0,
-                              dev_name(&pdev->dev), rspi);
+       if (rspi->rx_irq == rspi->tx_irq) {
+               /* Single multiplexed interrupt */
+               ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux,
+                                      "mux", rspi);
+       } else {
+               /* Multi-interrupt mode, only SPRI and SPTI are used */
+               ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx,
+                                      "rx", rspi);
+               if (!ret)
+                       ret = rspi_request_irq(&pdev->dev, rspi->tx_irq,
+                                              rspi_irq_tx, "tx", rspi);
+       }
        if (ret < 0) {
                dev_err(&pdev->dev, "request_irq error\n");
                goto error2;
        }
 
-       rspi->irq = irq;
        ret = rspi_request_dma(rspi, pdev);
        if (ret < 0) {
                dev_err(&pdev->dev, "rspi_request_dma failed.\n");
@@ -1022,27 +1310,16 @@ static int rspi_probe(struct platform_device *pdev)
 error3:
        rspi_release_dma(rspi);
 error2:
-       clk_disable(rspi->clk);
+       pm_runtime_disable(&pdev->dev);
 error1:
        spi_master_put(master);
 
        return ret;
 }
 
-static struct spi_ops rspi_ops = {
-       .set_config_register =          rspi_set_config_register,
-       .send_pio =                     rspi_send_pio,
-       .receive_pio =                  rspi_receive_pio,
-};
-
-static struct spi_ops qspi_ops = {
-       .set_config_register =          qspi_set_config_register,
-       .send_pio =                     qspi_send_pio,
-       .receive_pio =                  qspi_receive_pio,
-};
-
 static struct platform_device_id spi_driver_ids[] = {
        { "rspi",       (kernel_ulong_t)&rspi_ops },
+       { "rspi-rz",    (kernel_ulong_t)&rspi_rz_ops },
        { "qspi",       (kernel_ulong_t)&qspi_ops },
        {},
 };
@@ -1056,6 +1333,7 @@ static struct platform_driver rspi_driver = {
        .driver         = {
                .name = "renesas_spi",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(rspi_of_match),
        },
 };
 module_platform_driver(rspi_driver);
index 746424aa5353fb2a779b04c0fc93aae0163da0ea..bed23384dfab5858f91c612f352df3a7af7b4aed 100644 (file)
@@ -9,7 +9,6 @@
  *
 */
 
-#include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
@@ -123,25 +122,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
 {
        struct s3c24xx_spi *hw = to_hw(spi);
        struct s3c24xx_spi_devstate *cs = spi->controller_state;
-       unsigned int bpw;
        unsigned int hz;
        unsigned int div;
        unsigned long clk;
 
-       bpw = t ? t->bits_per_word : spi->bits_per_word;
        hz  = t ? t->speed_hz : spi->max_speed_hz;
 
-       if (!bpw)
-               bpw = 8;
-
        if (!hz)
                hz = spi->max_speed_hz;
 
-       if (bpw != 8) {
-               dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
-               return -EINVAL;
-       }
-
        if (spi->mode != cs->mode) {
                u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
 
@@ -544,6 +533,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
 
        master->num_chipselect = hw->pdata->num_cs;
        master->bus_num = pdata->bus_num;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
 
        /* setup the state for the bitbang driver */
 
@@ -643,6 +633,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
 static int s3c24xx_spi_suspend(struct device *dev)
 {
        struct s3c24xx_spi *hw = dev_get_drvdata(dev);
+       int ret;
+
+       ret = spi_master_suspend(hw->master);
+       if (ret)
+               return ret;
 
        if (hw->pdata && hw->pdata->gpio_setup)
                hw->pdata->gpio_setup(hw->pdata, 0);
@@ -656,7 +651,7 @@ static int s3c24xx_spi_resume(struct device *dev)
        struct s3c24xx_spi *hw = dev_get_drvdata(dev);
 
        s3c24xx_spi_initialsetup(hw);
-       return 0;
+       return spi_master_resume(hw->master);
 }
 
 static const struct dev_pm_ops s3c24xx_spi_pmops = {
index ae907dde1371c9133c526ad66daf16155d03fbe9..f19cd97855e8e76fc4bc90e8ac21853c58495d7d 100644 (file)
 
 #include <linux/platform_data/spi-s3c64xx.h>
 
-#ifdef CONFIG_S3C_DMA
-#include <mach/dma.h>
-#endif
-
 #define MAX_SPI_PORTS          3
 #define S3C64XX_SPI_QUIRK_POLL         (1 << 0)
 
@@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
        unsigned                        cur_speed;
        struct s3c64xx_spi_dma_data     rx_dma;
        struct s3c64xx_spi_dma_data     tx_dma;
-#ifdef CONFIG_S3C_DMA
-       struct samsung_dma_ops          *ops;
-#endif
        struct s3c64xx_spi_port_config  *port_conf;
        unsigned int                    port_id;
        bool                            cs_gpio;
@@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data)
        spin_unlock_irqrestore(&sdd->lock, flags);
 }
 
-#ifdef CONFIG_S3C_DMA
-/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
-
-static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
-       .name = "samsung-spi-dma",
-};
-
-static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
-                                       unsigned len, dma_addr_t buf)
-{
-       struct s3c64xx_spi_driver_data *sdd;
-       struct samsung_dma_prep info;
-       struct samsung_dma_config config;
-
-       if (dma->direction == DMA_DEV_TO_MEM) {
-               sdd = container_of((void *)dma,
-                       struct s3c64xx_spi_driver_data, rx_dma);
-               config.direction = sdd->rx_dma.direction;
-               config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
-               config.width = sdd->cur_bpw / 8;
-               sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
-       } else {
-               sdd = container_of((void *)dma,
-                       struct s3c64xx_spi_driver_data, tx_dma);
-               config.direction =  sdd->tx_dma.direction;
-               config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
-               config.width = sdd->cur_bpw / 8;
-               sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
-       }
-
-       info.cap = DMA_SLAVE;
-       info.len = len;
-       info.fp = s3c64xx_spi_dmacb;
-       info.fp_param = dma;
-       info.direction = dma->direction;
-       info.buf = buf;
-
-       sdd->ops->prepare((enum dma_ch)dma->ch, &info);
-       sdd->ops->trigger((enum dma_ch)dma->ch);
-}
-
-static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
-{
-       struct samsung_dma_req req;
-       struct device *dev = &sdd->pdev->dev;
-
-       sdd->ops = samsung_dma_get_ops();
-
-       req.cap = DMA_SLAVE;
-       req.client = &s3c64xx_spi_dma_client;
-
-       sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
-                                       sdd->rx_dma.dmach, &req, dev, "rx");
-       sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
-                                       sdd->tx_dma.dmach, &req, dev, "tx");
-
-       return 1;
-}
-
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
-       /*
-        * 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);
-
-       return 0;
-}
-
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
-       /* Free DMA channels */
-       if (!is_polling(sdd)) {
-               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);
-       }
-
-       return 0;
-}
-
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
-                                struct s3c64xx_spi_dma_data *dma)
-{
-       sdd->ops->stop((enum dma_ch)dma->ch);
-}
-#else
-
 static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
-                                       unsigned len, dma_addr_t buf)
+                       struct sg_table *sgt)
 {
        struct s3c64xx_spi_driver_data *sdd;
        struct dma_slave_config config;
@@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
                dmaengine_slave_config(dma->ch, &config);
        }
 
-       desc = dmaengine_prep_slave_single(dma->ch, buf, len,
-                                       dma->direction, DMA_PREP_INTERRUPT);
+       desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
+                                      dma->direction, DMA_PREP_INTERRUPT);
 
        desc->callback = s3c64xx_spi_dmacb;
        desc->callback_param = dma;
@@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
                        ret = -EBUSY;
                        goto out;
                }
+               spi->dma_rx = sdd->rx_dma.ch;
 
                sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
                                   (void *)sdd->tx_dma.dmach, dev, "tx");
@@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
                        ret = -EBUSY;
                        goto out_rx;
                }
+               spi->dma_tx = sdd->tx_dma.ch;
        }
 
        ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
        return 0;
 }
 
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
-                                struct s3c64xx_spi_dma_data *dma)
+static bool s3c64xx_spi_can_dma(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
 {
-       dmaengine_terminate_all(dma->ch);
+       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+
+       return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
 }
-#endif
 
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                                struct spi_device *spi,
@@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                chcfg |= S3C64XX_SPI_CH_TXCH_ON;
                if (dma_mode) {
                        modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-                       prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
+                       prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
                } else {
                        switch (sdd->cur_bpw) {
                        case 32:
@@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                        writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
                                        | S3C64XX_SPI_PACKET_CNT_EN,
                                        regs + S3C64XX_SPI_PACKET_CNT);
-                       prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
+                       prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
                }
        }
 
@@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
        writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
 }
 
-static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_device *spi)
-{
-       if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
-               if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
-                       /* Deselect the last toggled device */
-                       if (spi->cs_gpio >= 0)
-                               gpio_set_value(spi->cs_gpio,
-                                       spi->mode & SPI_CS_HIGH ? 0 : 1);
-               }
-               sdd->tgl_spi = NULL;
-       }
-
-       if (spi->cs_gpio >= 0)
-               gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
-}
-
 static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
                                        int timeout_ms)
 {
@@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
        return RX_FIFO_LVL(status, sdd);
 }
 
-static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
-                               struct spi_transfer *xfer, int dma_mode)
+static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
+                       struct spi_transfer *xfer)
 {
        void __iomem *regs = sdd->regs;
        unsigned long val;
+       u32 status;
        int ms;
 
        /* millisecs to xfer 'len' bytes @ 'cur_speed' */
        ms = xfer->len * 8 * 1000 / sdd->cur_speed;
        ms += 10; /* some tolerance */
 
-       if (dma_mode) {
-               val = msecs_to_jiffies(ms) + 10;
-               val = wait_for_completion_timeout(&sdd->xfer_completion, val);
-       } else {
-               u32 status;
-               val = msecs_to_loops(ms);
-               do {
+       val = msecs_to_jiffies(ms) + 10;
+       val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+
+       /*
+        * 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 (val && !xfer->rx_buf) {
+               val = msecs_to_loops(10);
+               status = readl(regs + S3C64XX_SPI_STATUS);
+               while ((TX_FIFO_LVL(status, sdd)
+                       || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
+                      && --val) {
+                       cpu_relax();
                        status = readl(regs + S3C64XX_SPI_STATUS);
-               } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
+               }
+
        }
 
-       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 (val && !xfer->rx_buf) {
-                       val = msecs_to_loops(10);
-                       status = readl(regs + S3C64XX_SPI_STATUS);
-                       while ((TX_FIFO_LVL(status, sdd)
-                               || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
-                                       && --val) {
-                               cpu_relax();
-                               status = readl(regs + S3C64XX_SPI_STATUS);
-                       }
+       /* If timed out while checking rx/tx status return error */
+       if (!val)
+               return -EIO;
 
-               }
+       return 0;
+}
 
-               /* 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) {
-                       sdd->state &= ~TXBUSY;
-                       return 0;
-               }
+static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
+                       struct spi_transfer *xfer)
+{
+       void __iomem *regs = sdd->regs;
+       unsigned long val;
+       u32 status;
+       int loops;
+       u32 cpy_len;
+       u8 *buf;
+       int ms;
 
-               /*
-                * 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));
+       /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+       ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+       ms += 10; /* some tolerance */
 
-                       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;
-                       }
+       val = msecs_to_loops(ms);
+       do {
+               status = readl(regs + S3C64XX_SPI_STATUS);
+       } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
 
-                       buf = buf + cpy_len;
-               } while (loops--);
-               sdd->state &= ~RXBUSY;
+
+       /* If it was only Tx */
+       if (!xfer->rx_buf) {
+               sdd->state &= ~TXBUSY;
+               return 0;
        }
 
-       return 0;
-}
+       /*
+        * 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;
+               }
 
-static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_device *spi)
-{
-       if (sdd->tgl_spi == spi)
-               sdd->tgl_spi = NULL;
+               buf = buf + cpy_len;
+       } while (loops--);
+       sdd->state &= ~RXBUSY;
 
-       if (spi->cs_gpio >= 0)
-               gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+       return 0;
 }
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 
 #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
 
-static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_message *msg)
-{
-       struct device *dev = &sdd->pdev->dev;
-       struct spi_transfer *xfer;
-
-       if (is_polling(sdd) || msg->is_dma_mapped)
-               return 0;
-
-       /* First mark all xfer unmapped */
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               xfer->rx_dma = XFER_DMAADDR_INVALID;
-               xfer->tx_dma = XFER_DMAADDR_INVALID;
-       }
-
-       /* Map until end or first fail */
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
-               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
-                       continue;
-
-               if (xfer->tx_buf != NULL) {
-                       xfer->tx_dma = dma_map_single(dev,
-                                       (void *)xfer->tx_buf, xfer->len,
-                                       DMA_TO_DEVICE);
-                       if (dma_mapping_error(dev, xfer->tx_dma)) {
-                               dev_err(dev, "dma_map_single Tx failed\n");
-                               xfer->tx_dma = XFER_DMAADDR_INVALID;
-                               return -ENOMEM;
-                       }
-               }
-
-               if (xfer->rx_buf != NULL) {
-                       xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
-                                               xfer->len, DMA_FROM_DEVICE);
-                       if (dma_mapping_error(dev, xfer->rx_dma)) {
-                               dev_err(dev, "dma_map_single Rx failed\n");
-                               dma_unmap_single(dev, xfer->tx_dma,
-                                               xfer->len, DMA_TO_DEVICE);
-                               xfer->tx_dma = XFER_DMAADDR_INVALID;
-                               xfer->rx_dma = XFER_DMAADDR_INVALID;
-                               return -ENOMEM;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_message *msg)
-{
-       struct device *dev = &sdd->pdev->dev;
-       struct spi_transfer *xfer;
-
-       if (is_polling(sdd) || msg->is_dma_mapped)
-               return;
-
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
-               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
-                       continue;
-
-               if (xfer->rx_buf != NULL
-                               && xfer->rx_dma != XFER_DMAADDR_INVALID)
-                       dma_unmap_single(dev, xfer->rx_dma,
-                                               xfer->len, DMA_FROM_DEVICE);
-
-               if (xfer->tx_buf != NULL
-                               && xfer->tx_dma != XFER_DMAADDR_INVALID)
-                       dma_unmap_single(dev, xfer->tx_dma,
-                                               xfer->len, DMA_TO_DEVICE);
-       }
-}
-
 static int s3c64xx_spi_prepare_message(struct spi_master *master,
                                       struct spi_message *msg)
 {
@@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
                s3c64xx_spi_config(sdd);
        }
 
-       /* Map all the transfers if needed */
-       if (s3c64xx_spi_map_mssg(sdd, msg)) {
-               dev_err(&spi->dev,
-                       "Xfer: Unable to map message buffers!\n");
-               return -ENOMEM;
-       }
-
        /* Configure feedback delay */
        writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
 
@@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
        bpw = xfer->bits_per_word;
        speed = xfer->speed_hz ? : spi->max_speed_hz;
 
-       if (xfer->len % (bpw / 8)) {
-               dev_err(&spi->dev,
-                       "Xfer length(%u) not a multiple of word size(%u)\n",
-                       xfer->len, bpw / 8);
-               return -EIO;
-       }
-
        if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
                sdd->cur_bpw = bpw;
                sdd->cur_speed = speed;
@@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
 
        spin_unlock_irqrestore(&sdd->lock, flags);
 
-       status = wait_for_xfer(sdd, xfer, use_dma);
+       if (use_dma)
+               status = wait_for_dma(sdd, xfer);
+       else
+               status = wait_for_pio(sdd, xfer);
 
        if (status) {
                dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
@@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
                if (use_dma) {
                        if (xfer->tx_buf != NULL
                            && (sdd->state & TXBUSY))
-                               s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
+                               dmaengine_terminate_all(sdd->tx_dma.ch);
                        if (xfer->rx_buf != NULL
                            && (sdd->state & RXBUSY))
-                               s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
+                               dmaengine_terminate_all(sdd->rx_dma.ch);
                }
        } else {
                flush_fifo(sdd);
@@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
        return status;
 }
 
-static int s3c64xx_spi_unprepare_message(struct spi_master *master,
-                                           struct spi_message *msg)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-
-       s3c64xx_spi_unmap_mssg(sdd, msg);
-
-       return 0;
-}
-
 static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
                                struct spi_device *spi)
 {
@@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 
        pm_runtime_put(&sdd->pdev->dev);
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-       disable_cs(sdd, spi);
        return 0;
 
 setup_exit:
        pm_runtime_put(&sdd->pdev->dev);
        /* setup() returns with device de-selected */
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-       disable_cs(sdd, spi);
 
        gpio_free(cs->line);
        spi_set_ctldata(spi, NULL);
@@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
        master->prepare_message = s3c64xx_spi_prepare_message;
        master->transfer_one = s3c64xx_spi_transfer_one;
-       master->unprepare_message = s3c64xx_spi_unprepare_message;
        master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
        master->num_chipselect = sci->num_cs;
        master->dma_alignment = 8;
@@ -1347,6 +1131,8 @@ static int s3c64xx_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->auto_runtime_pm = true;
+       if (!is_polling(sdd))
+               master->can_dma = s3c64xx_spi_can_dma;
 
        sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
        if (IS_ERR(sdd->regs)) {
index 121c2e1dea364f863cd4f66b832edfc367701eb8..237f2e7a717999087e464c41e329ad43e3ff3455 100644 (file)
@@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
 static int sc18is602_check_transfer(struct spi_device *spi,
                                    struct spi_transfer *t, int tlen)
 {
-       uint32_t hz;
-
        if (t && t->len + tlen > SC18IS602_BUFSIZ)
                return -EINVAL;
 
-       hz = spi->max_speed_hz;
-       if (t && t->speed_hz)
-               hz = t->speed_hz;
-       if (hz == 0)
-               return -EINVAL;
-
        return 0;
 }
 
@@ -205,22 +197,15 @@ static int sc18is602_transfer_one(struct spi_master *master,
        struct spi_transfer *t;
        int status = 0;
 
-       /* SC18IS602 does not support CS2 */
-       if (hw->id == sc18is602 && spi->chip_select == 2) {
-               status = -ENXIO;
-               goto error;
-       }
-
        hw->tlen = 0;
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               u32 hz = t->speed_hz ? : spi->max_speed_hz;
                bool do_transfer;
 
                status = sc18is602_check_transfer(spi, t, hw->tlen);
                if (status < 0)
                        break;
 
-               status = sc18is602_setup_transfer(hw, hz, spi->mode);
+               status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);
                if (status < 0)
                        break;
 
@@ -238,7 +223,6 @@ static int sc18is602_transfer_one(struct spi_master *master,
                if (t->delay_usecs)
                        udelay(t->delay_usecs);
        }
-error:
        m->status = status;
        spi_finalize_current_message(master);
 
@@ -247,10 +231,13 @@ error:
 
 static int sc18is602_setup(struct spi_device *spi)
 {
-       if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST))
-               return -EINVAL;
+       struct sc18is602 *hw = spi_master_get_devdata(spi->master);
 
-       return sc18is602_check_transfer(spi, NULL, 0);
+       /* SC18IS602 does not support CS2 */
+       if (hw->id == sc18is602 && spi->chip_select == 2)
+               return -ENXIO;
+
+       return 0;
 }
 
 static int sc18is602_probe(struct i2c_client *client,
@@ -309,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client,
        master->setup = sc18is602_setup;
        master->transfer_one_message = sc18is602_transfer_one;
        master->dev.of_node = np;
+       master->min_speed_hz = hw->freq / 128;
+       master->max_speed_hz = hw->freq / 4;
 
        error = devm_spi_register_master(dev, master);
        if (error)
index 82d2f922ffa0a830883fee3aafff2be4b86c1d50..9009456bdf4d29c6febf56b162113fa5e4bf78ef 100644 (file)
@@ -46,8 +46,6 @@
 /* SPSR */
 #define RXFL   (1 << 2)
 
-#define hspi2info(h)   (h->dev->platform_data)
-
 struct hspi_priv {
        void __iomem *addr;
        struct spi_master *master;
@@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
 {
        struct spi_device *spi = msg->spi;
        struct device *dev = hspi->dev;
-       u32 target_rate;
        u32 spcr, idiv_clk;
        u32 rate, best_rate, min, tmp;
 
-       target_rate = t ? t->speed_hz : 0;
-       if (!target_rate)
-               target_rate = spi->max_speed_hz;
-
        /*
         * find best IDIV/CLKCx settings
         */
@@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
                rate /= (((idiv_clk & 0x1F) + 1) * 2);
 
                /* save best settings */
-               tmp = abs(target_rate - rate);
+               tmp = abs(t->speed_hz - rate);
                if (tmp < min) {
                        min = tmp;
                        spcr = idiv_clk;
@@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
        if (spi->mode & SPI_CPOL)
                spcr |= 1 << 6;
 
-       dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate);
+       dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate);
 
        hspi_write(hspi, SPCR, spcr);
        hspi_write(hspi, SPSR, 0x0);
@@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master,
        return ret;
 }
 
-static int hspi_setup(struct spi_device *spi)
-{
-       struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
-       struct device *dev = hspi->dev;
-
-       if (8 != spi->bits_per_word) {
-               dev_err(dev, "bits_per_word should be 8\n");
-               return -EIO;
-       }
-
-       dev_dbg(dev, "%s setup\n", spi->modalias);
-
-       return 0;
-}
-
-static void hspi_cleanup(struct spi_device *spi)
-{
-       struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
-       struct device *dev = hspi->dev;
-
-       dev_dbg(dev, "%s cleanup\n", spi->modalias);
-}
-
 static int hspi_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -298,22 +268,23 @@ static int hspi_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       master->num_chipselect  = 1;
        master->bus_num         = pdev->id;
-       master->setup           = hspi_setup;
-       master->cleanup         = hspi_cleanup;
        master->mode_bits       = SPI_CPOL | SPI_CPHA;
        master->dev.of_node     = pdev->dev.of_node;
        master->auto_runtime_pm = true;
        master->transfer_one_message            = hspi_transfer_one_message;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
+
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret < 0) {
                dev_err(&pdev->dev, "spi_register_master error.\n");
-               goto error1;
+               goto error2;
        }
 
        return 0;
 
+ error2:
+       pm_runtime_disable(&pdev->dev);
  error1:
        clk_put(clk);
  error0:
index 81cc02f5f9b02494379bbc7cfb5547f17c48fb20..e850d03e719047638465916633981670da1b51a4 100644 (file)
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/spi/sh_msiof.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
 
 #include <asm/unaligned.h>
 
+
+struct sh_msiof_chipdata {
+       u16 tx_fifo_size;
+       u16 rx_fifo_size;
+       u16 master_flags;
+};
+
 struct sh_msiof_spi_priv {
-       struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
        void __iomem *mapbase;
        struct clk *clk;
        struct platform_device *pdev;
+       const struct sh_msiof_chipdata *chipdata;
        struct sh_msiof_spi_info *info;
        struct completion done;
-       unsigned long flags;
        int tx_fifo_size;
        int rx_fifo_size;
 };
 
-#define TMDR1  0x00
-#define TMDR2  0x04
-#define TMDR3  0x08
-#define RMDR1  0x10
-#define RMDR2  0x14
-#define RMDR3  0x18
-#define TSCR   0x20
-#define RSCR   0x22
-#define CTR    0x28
-#define FCTR   0x30
-#define STR    0x40
-#define IER    0x44
-#define TDR1   0x48
-#define TDR2   0x4c
-#define TFDR   0x50
-#define RDR1   0x58
-#define RDR2   0x5c
-#define RFDR   0x60
-
-#define CTR_TSCKE (1 << 15)
-#define CTR_TFSE  (1 << 14)
-#define CTR_TXE   (1 << 9)
-#define CTR_RXE   (1 << 8)
-
-#define STR_TEOF  (1 << 23)
-#define STR_REOF  (1 << 7)
+#define TMDR1  0x00    /* Transmit Mode Register 1 */
+#define TMDR2  0x04    /* Transmit Mode Register 2 */
+#define TMDR3  0x08    /* Transmit Mode Register 3 */
+#define RMDR1  0x10    /* Receive Mode Register 1 */
+#define RMDR2  0x14    /* Receive Mode Register 2 */
+#define RMDR3  0x18    /* Receive Mode Register 3 */
+#define TSCR   0x20    /* Transmit Clock Select Register */
+#define RSCR   0x22    /* Receive Clock Select Register (SH, A1, APE6) */
+#define CTR    0x28    /* Control Register */
+#define FCTR   0x30    /* FIFO Control Register */
+#define STR    0x40    /* Status Register */
+#define IER    0x44    /* Interrupt Enable Register */
+#define TDR1   0x48    /* Transmit Control Data Register 1 (SH, A1) */
+#define TDR2   0x4c    /* Transmit Control Data Register 2 (SH, A1) */
+#define TFDR   0x50    /* Transmit FIFO Data Register */
+#define RDR1   0x58    /* Receive Control Data Register 1 (SH, A1) */
+#define RDR2   0x5c    /* Receive Control Data Register 2 (SH, A1) */
+#define RFDR   0x60    /* Receive FIFO Data Register */
+
+/* TMDR1 and RMDR1 */
+#define MDR1_TRMD       0x80000000 /* Transfer Mode (1 = Master mode) */
+#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */
+#define MDR1_SYNCMD_SPI         0x20000000 /*   Level mode/SPI */
+#define MDR1_SYNCMD_LR  0x30000000 /*   L/R mode */
+#define MDR1_SYNCAC_SHIFT       25 /* Sync Polarity (1 = Active-low) */
+#define MDR1_BITLSB_SHIFT       24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_FLD_MASK   0x000000c0 /* Frame Sync Signal Interval (0-3) */
+#define MDR1_FLD_SHIFT           2
+#define MDR1_XXSTP      0x00000001 /* Transmission/Reception Stop on FIFO */
+/* TMDR1 */
+#define TMDR1_PCON      0x40000000 /* Transfer Signal Connection */
+
+/* TMDR2 and RMDR2 */
+#define MDR2_BITLEN1(i)        (((i) - 1) << 24) /* Data Size (8-32 bits) */
+#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
+#define MDR2_GRPMASK1  0x00000001 /* Group Output Mask 1 (SH, A1) */
+
+/* TSCR and RSCR */
+#define SCR_BRPS_MASK      0x1f00 /* Prescaler Setting (1-32) */
+#define SCR_BRPS(i)    (((i) - 1) << 8)
+#define SCR_BRDV_MASK      0x0007 /* Baud Rate Generator's Division Ratio */
+#define SCR_BRDV_DIV_2     0x0000
+#define SCR_BRDV_DIV_4     0x0001
+#define SCR_BRDV_DIV_8     0x0002
+#define SCR_BRDV_DIV_16            0x0003
+#define SCR_BRDV_DIV_32            0x0004
+#define SCR_BRDV_DIV_1     0x0007
+
+/* CTR */
+#define CTR_TSCKIZ_MASK        0xc0000000 /* Transmit Clock I/O Polarity Select */
+#define CTR_TSCKIZ_SCK 0x80000000 /*   Disable SCK when TX disabled */
+#define CTR_TSCKIZ_POL_SHIFT   30 /*   Transmit Clock Polarity */
+#define CTR_RSCKIZ_MASK        0x30000000 /* Receive Clock Polarity Select */
+#define CTR_RSCKIZ_SCK 0x20000000 /*   Must match CTR_TSCKIZ_SCK */
+#define CTR_RSCKIZ_POL_SHIFT   28 /*   Receive Clock Polarity */
+#define CTR_TEDG_SHIFT         27 /* Transmit Timing (1 = falling edge) */
+#define CTR_REDG_SHIFT         26 /* Receive Timing (1 = falling edge) */
+#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */
+#define CTR_TXDIZ_LOW  0x00000000 /*   0 */
+#define CTR_TXDIZ_HIGH 0x00400000 /*   1 */
+#define CTR_TXDIZ_HIZ  0x00800000 /*   High-impedance */
+#define CTR_TSCKE      0x00008000 /* Transmit Serial Clock Output Enable */
+#define CTR_TFSE       0x00004000 /* Transmit Frame Sync Signal Output Enable */
+#define CTR_TXE                0x00000200 /* Transmit Enable */
+#define CTR_RXE                0x00000100 /* Receive Enable */
+
+/* STR and IER */
+#define STR_TEOF       0x00800000 /* Frame Transmission End */
+#define STR_REOF       0x00000080 /* Frame Reception End */
+
 
 static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
 {
@@ -131,22 +180,21 @@ static struct {
        unsigned short div;
        unsigned short scr;
 } const sh_msiof_spi_clk_table[] = {
-       { 1, 0x0007 },
-       { 2, 0x0000 },
-       { 4, 0x0001 },
-       { 8, 0x0002 },
-       { 16, 0x0003 },
-       { 32, 0x0004 },
-       { 64, 0x1f00 },
-       { 128, 0x1f01 },
-       { 256, 0x1f02 },
-       { 512, 0x1f03 },
-       { 1024, 0x1f04 },
+       { 1,    SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
+       { 2,    SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
+       { 4,    SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
+       { 8,    SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
+       { 16,   SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
+       { 32,   SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
+       { 64,   SCR_BRPS(32) | SCR_BRDV_DIV_2 },
+       { 128,  SCR_BRPS(32) | SCR_BRDV_DIV_4 },
+       { 256,  SCR_BRPS(32) | SCR_BRDV_DIV_8 },
+       { 512,  SCR_BRPS(32) | SCR_BRDV_DIV_16 },
+       { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
 };
 
 static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
-                                     unsigned long parent_rate,
-                                     unsigned long spi_hz)
+                                     unsigned long parent_rate, u32 spi_hz)
 {
        unsigned long div = 1024;
        size_t k;
@@ -164,7 +212,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
        k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
 
        sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
-       sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
+       if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
+               sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
 }
 
 static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
@@ -183,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
         */
        sh_msiof_write(p, FCTR, 0);
 
-       tmp = 0;
-       tmp |= !cs_high << 25;
-       tmp |= lsb_first << 24;
-       sh_msiof_write(p, TMDR1, 0xe0000005 | tmp);
-       sh_msiof_write(p, RMDR1, 0x20000005 | tmp);
+       tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
+       tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
+       tmp |= lsb_first << MDR1_BITLSB_SHIFT;
+       sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+       if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
+               /* These bits are reserved if RX needs TX */
+               tmp &= ~0x0000ffff;
+       }
+       sh_msiof_write(p, RMDR1, tmp);
 
-       tmp = 0xa0000000;
-       tmp |= cpol << 30; /* TSCKIZ */
-       tmp |= cpol << 28; /* RSCKIZ */
+       tmp = 0;
+       tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+       tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
 
        edge = cpol ^ !cpha;
 
-       tmp |= edge << 27; /* TEDG */
-       tmp |= edge << 26; /* REDG */
-       tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
+       tmp |= edge << CTR_TEDG_SHIFT;
+       tmp |= edge << CTR_REDG_SHIFT;
+       tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW;
        sh_msiof_write(p, CTR, tmp);
 }
 
@@ -205,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
                                       const void *tx_buf, void *rx_buf,
                                       u32 bits, u32 words)
 {
-       u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
+       u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
 
-       if (tx_buf)
+       if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
                sh_msiof_write(p, TMDR2, dr2);
        else
-               sh_msiof_write(p, TMDR2, dr2 | 1);
+               sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
 
        if (rx_buf)
                sh_msiof_write(p, RMDR2, dr2);
@@ -363,77 +416,45 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
                put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
 }
 
-static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_spi_setup(struct spi_device *spi)
 {
-       int bits;
-
-       bits = t ? t->bits_per_word : 0;
-       if (!bits)
-               bits = spi->bits_per_word;
-       return bits;
-}
-
-static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
-                                    struct spi_transfer *t)
-{
-       unsigned long hz;
-
-       hz = t ? t->speed_hz : 0;
-       if (!hz)
-               hz = spi->max_speed_hz;
-       return hz;
-}
+       struct device_node      *np = spi->master->dev.of_node;
+       struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
 
-static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
-                                      struct spi_transfer *t)
-{
-       int bits;
+       if (!np) {
+               /*
+                * Use spi->controller_data for CS (same strategy as spi_gpio),
+                * if any. otherwise let HW control CS
+                */
+               spi->cs_gpio = (uintptr_t)spi->controller_data;
+       }
 
-       /* noting to check hz values against since parent clock is disabled */
+       /* Configure pins before deasserting CS */
+       sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+                                 !!(spi->mode & SPI_CPHA),
+                                 !!(spi->mode & SPI_3WIRE),
+                                 !!(spi->mode & SPI_LSB_FIRST),
+                                 !!(spi->mode & SPI_CS_HIGH));
 
-       bits = sh_msiof_spi_bits(spi, t);
-       if (bits < 8)
-               return -EINVAL;
-       if (bits > 32)
-               return -EINVAL;
+       if (spi->cs_gpio >= 0)
+               gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
 
-       return spi_bitbang_setup_transfer(spi, t);
+       return 0;
 }
 
-static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
+static int sh_msiof_prepare_message(struct spi_master *master,
+                                   struct spi_message *msg)
 {
-       struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
-       int value;
-
-       /* chip select is active low unless SPI_CS_HIGH is set */
-       if (spi->mode & SPI_CS_HIGH)
-               value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
-       else
-               value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
-
-       if (is_on == BITBANG_CS_ACTIVE) {
-               if (!test_and_set_bit(0, &p->flags)) {
-                       pm_runtime_get_sync(&p->pdev->dev);
-                       clk_enable(p->clk);
-               }
-
-               /* Configure pins before asserting CS */
-               sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
-                                         !!(spi->mode & SPI_CPHA),
-                                         !!(spi->mode & SPI_3WIRE),
-                                         !!(spi->mode & SPI_LSB_FIRST),
-                                         !!(spi->mode & SPI_CS_HIGH));
-       }
+       struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
+       const struct spi_device *spi = msg->spi;
 
-       /* use spi->controller data for CS (same strategy as spi_gpio) */
-       gpio_set_value((uintptr_t)spi->controller_data, value);
-
-       if (is_on == BITBANG_CS_INACTIVE) {
-               if (test_and_clear_bit(0, &p->flags)) {
-                       clk_disable(p->clk);
-                       pm_runtime_put(&p->pdev->dev);
-               }
-       }
+       /* Configure pins before asserting CS */
+       sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+                                 !!(spi->mode & SPI_CPHA),
+                                 !!(spi->mode & SPI_3WIRE),
+                                 !!(spi->mode & SPI_LSB_FIRST),
+                                 !!(spi->mode & SPI_CS_HIGH));
+       return 0;
 }
 
 static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
@@ -487,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
        /* clear status bits */
        sh_msiof_reset_str(p);
 
-       /* shut down frame, tx/tx and clock signals */
+       /* shut down frame, rx/tx and clock signals */
        ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
        ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
        if (rx_buf)
@@ -505,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
        return ret;
 }
 
-static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_transfer_one(struct spi_master *master,
+                                struct spi_device *spi,
+                                struct spi_transfer *t)
 {
-       struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
+       struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
        void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
        void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
        int bits;
@@ -517,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
        int n;
        bool swab;
 
-       bits = sh_msiof_spi_bits(spi, t);
+       bits = t->bits_per_word;
 
        if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
                bits = 32;
@@ -567,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
        }
 
        /* setup clocks (clock already enabled in chipselect()) */
-       sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
-                                 sh_msiof_spi_hz(spi, t));
+       sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
 
        /* transfer in fifo sized chunks */
        words = t->len / bytes_per_word;
@@ -588,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
                words -= n;
        }
 
-       return bytes_done;
-}
-
-static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
-                                 u32 word, u8 bits)
-{
-       BUG(); /* unused but needed by bitbang code */
        return 0;
 }
 
+static const struct sh_msiof_chipdata sh_data = {
+       .tx_fifo_size = 64,
+       .rx_fifo_size = 64,
+       .master_flags = 0,
+};
+
+static const struct sh_msiof_chipdata r8a779x_data = {
+       .tx_fifo_size = 64,
+       .rx_fifo_size = 256,
+       .master_flags = SPI_MASTER_MUST_TX,
+};
+
+static const struct of_device_id sh_msiof_match[] = {
+       { .compatible = "renesas,sh-msiof",        .data = &sh_data },
+       { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
+       { .compatible = "renesas,msiof-r8a7790",   .data = &r8a779x_data },
+       { .compatible = "renesas,msiof-r8a7791",   .data = &r8a779x_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sh_msiof_match);
+
 #ifdef CONFIG_OF
 static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
 {
        struct sh_msiof_spi_info *info;
        struct device_node *np = dev->of_node;
-       u32 num_cs = 0;
+       u32 num_cs = 1;
 
        info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
        if (!info) {
@@ -633,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
 {
        struct resource *r;
        struct spi_master *master;
+       const struct of_device_id *of_id;
        struct sh_msiof_spi_priv *p;
        int i;
        int ret;
@@ -646,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
        p = spi_master_get_devdata(master);
 
        platform_set_drvdata(pdev, p);
-       if (pdev->dev.of_node)
+
+       of_id = of_match_device(sh_msiof_match, &pdev->dev);
+       if (of_id) {
+               p->chipdata = of_id->data;
                p->info = sh_msiof_spi_parse_dt(&pdev->dev);
-       else
+       } else {
+               p->chipdata = (const void *)pdev->id_entry->driver_data;
                p->info = dev_get_platdata(&pdev->dev);
+       }
 
        if (!p->info) {
                dev_err(&pdev->dev, "failed to obtain device info\n");
@@ -687,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       ret = clk_prepare(p->clk);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "unable to prepare clock\n");
-               goto err1;
-       }
-
        p->pdev = pdev;
        pm_runtime_enable(&pdev->dev);
 
-       /* The standard version of MSIOF use 64 word FIFOs */
-       p->tx_fifo_size = 64;
-       p->rx_fifo_size = 64;
-
        /* Platform data may override FIFO sizes */
+       p->tx_fifo_size = p->chipdata->tx_fifo_size;
+       p->rx_fifo_size = p->chipdata->rx_fifo_size;
        if (p->info->tx_fifo_override)
                p->tx_fifo_size = p->info->tx_fifo_override;
        if (p->info->rx_fifo_override)
                p->rx_fifo_size = p->info->rx_fifo_override;
 
-       /* init master and bitbang code */
+       /* init master code */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
-       master->flags = 0;
+       master->flags = p->chipdata->master_flags;
        master->bus_num = pdev->id;
+       master->dev.of_node = pdev->dev.of_node;
        master->num_chipselect = p->info->num_chipselect;
-       master->setup = spi_bitbang_setup;
-       master->cleanup = spi_bitbang_cleanup;
-
-       p->bitbang.master = master;
-       p->bitbang.chipselect = sh_msiof_spi_chipselect;
-       p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
-       p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
-       p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word;
-       p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
-       p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
-       p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
-
-       ret = spi_bitbang_start(&p->bitbang);
-       if (ret == 0)
-               return 0;
+       master->setup = sh_msiof_spi_setup;
+       master->prepare_message = sh_msiof_prepare_message;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+       master->auto_runtime_pm = true;
+       master->transfer_one = sh_msiof_transfer_one;
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "spi_register_master error.\n");
+               goto err2;
+       }
 
+       return 0;
+
+ err2:
        pm_runtime_disable(&pdev->dev);
-       clk_unprepare(p->clk);
  err1:
        spi_master_put(master);
        return ret;
@@ -737,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
 
 static int sh_msiof_spi_remove(struct platform_device *pdev)
 {
-       struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
-       int ret;
-
-       ret = spi_bitbang_stop(&p->bitbang);
-       if (!ret) {
-               pm_runtime_disable(&pdev->dev);
-               clk_unprepare(p->clk);
-               spi_master_put(p->bitbang.master);
-       }
-       return ret;
+       pm_runtime_disable(&pdev->dev);
+       return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id sh_msiof_match[] = {
-       { .compatible = "renesas,sh-msiof", },
-       { .compatible = "renesas,sh-mobile-msiof", },
+static struct platform_device_id spi_driver_ids[] = {
+       { "spi_sh_msiof",       (kernel_ulong_t)&sh_data },
+       { "spi_r8a7790_msiof",  (kernel_ulong_t)&r8a779x_data },
+       { "spi_r8a7791_msiof",  (kernel_ulong_t)&r8a779x_data },
        {},
 };
-MODULE_DEVICE_TABLE(of, sh_msiof_match);
-#endif
+MODULE_DEVICE_TABLE(platform, spi_driver_ids);
 
 static struct platform_driver sh_msiof_spi_drv = {
        .probe          = sh_msiof_spi_probe,
        .remove         = sh_msiof_spi_remove,
+       .id_table       = spi_driver_ids,
        .driver         = {
                .name           = "spi_sh_msiof",
                .owner          = THIS_MODULE,
index 38eb24df796c58ebdef65d2c5ada2e90aff036d0..8b44b71f502445c0efee94e8b2d2ea750886caad 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
@@ -109,7 +108,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
 {
        struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
 
-       if (sp->info && sp->info->chip_select)
+       if (sp->info->chip_select)
                (sp->info->chip_select)(sp->info, dev->chip_select, value);
 }
 
@@ -131,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev)
 
        platform_set_drvdata(dev, sp);
        sp->info = dev_get_platdata(&dev->dev);
+       if (!sp->info) {
+               dev_err(&dev->dev, "platform data is missing\n");
+               ret = -ENOENT;
+               goto err1;
+       }
 
        /* setup spi bitbang adaptor */
        sp->bitbang.master = master;
index e430689c3837360f02e5e6d7e70a40ceae712777..1a77ad52812fd79d3a2524264e7a2a8678ca1464 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/dmaengine.h>
 #include <linux/dma-direction.h>
 #include <linux/dma-mapping.h>
-#include <linux/sirfsoc_dma.h>
 
 #define DRIVER_NAME "sirfsoc_spi"
 
 #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
        ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
 
+#define SIRFSOC_MAX_CMD_BYTES  4
+
 struct sirfsoc_spi {
        struct spi_bitbang bitbang;
        struct completion rx_done;
@@ -162,6 +163,12 @@ struct sirfsoc_spi {
        void *dummypage;
        int word_width; /* in bytes */
 
+       /*
+        * if tx size is not more than 4 and rx size is NULL, use
+        * command model
+        */
+       bool    tx_by_cmd;
+
        int chipselect[0];
 };
 
@@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
 
        writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
 
+       if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
+               complete(&sspi->tx_done);
+               writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+               return IRQ_HANDLED;
+       }
+
        /* Error Conditions */
        if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
                        spi_stat & SIRFSOC_SPI_TX_UFLOW) {
@@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
 
        writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
 
+       /*
+        * fill tx_buf into command register and wait for its completion
+        */
+       if (sspi->tx_by_cmd) {
+               u32 cmd;
+               memcpy(&cmd, sspi->tx, t->len);
+
+               if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
+                       cmd = cpu_to_be32(cmd) >>
+                               ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
+               if (sspi->word_width == 2 && t->len == 4 &&
+                               (!(spi->mode & SPI_LSB_FIRST)))
+                       cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);
+
+               writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
+               writel(SIRFSOC_SPI_FRM_END_INT_EN,
+                       sspi->base + SIRFSOC_SPI_INT_EN);
+               writel(SIRFSOC_SPI_CMD_TX_EN,
+                       sspi->base + SIRFSOC_SPI_TX_RX_EN);
+
+               if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+                       dev_err(&spi->dev, "transfer timeout\n");
+                       return 0;
+               }
+
+               return t->len;
+       }
+
        if (sspi->left_tx_word == 1) {
                writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
                        SIRFSOC_SPI_ENA_AUTO_CLR,
@@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;
                sspi->rx_word = spi_sirfsoc_rx_word_u8;
                sspi->tx_word = spi_sirfsoc_tx_word_u8;
-               txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                       SIRFSOC_SPI_FIFO_WIDTH_BYTE;
-               rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                       SIRFSOC_SPI_FIFO_WIDTH_BYTE;
-               sspi->word_width = 1;
                break;
        case 12:
        case 16:
@@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                        SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
                sspi->rx_word = spi_sirfsoc_rx_word_u16;
                sspi->tx_word = spi_sirfsoc_tx_word_u16;
-               txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                       SIRFSOC_SPI_FIFO_WIDTH_WORD;
-               rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                       SIRFSOC_SPI_FIFO_WIDTH_WORD;
-               sspi->word_width = 2;
                break;
        case 32:
                regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
                sspi->rx_word = spi_sirfsoc_rx_word_u32;
                sspi->tx_word = spi_sirfsoc_tx_word_u32;
-               txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                       SIRFSOC_SPI_FIFO_WIDTH_DWORD;
-               rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                       SIRFSOC_SPI_FIFO_WIDTH_DWORD;
-               sspi->word_width = 4;
                break;
        default:
                BUG();
        }
 
+       sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
+       txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+                                          sspi->word_width;
+       rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+                                          sspi->word_width;
+
        if (!(spi->mode & SPI_CS_HIGH))
                regval |= SIRFSOC_SPI_CS_IDLE_STAT;
        if (!(spi->mode & SPI_LSB_FIRST))
@@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
        writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
 
+       if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
+               regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
+                               SIRFSOC_SPI_CMD_MODE);
+               sspi->tx_by_cmd = true;
+       } else {
+               regval &= ~SIRFSOC_SPI_CMD_MODE;
+               sspi->tx_by_cmd = false;
+       }
        writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
 
        if (IS_DMA_VALID(t)) {
@@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct resource *mem_res;
        int num_cs, cs_gpio, irq;
-       u32 rx_dma_ch, tx_dma_ch;
-       dma_cap_mask_t dma_cap_mask;
        int i;
        int ret;
 
@@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
                goto err_cs;
        }
 
-       ret = of_property_read_u32(pdev->dev.of_node,
-                       "sirf,spi-dma-rx-channel", &rx_dma_ch);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Unable to get rx dma channel\n");
-               goto err_cs;
-       }
-
-       ret = of_property_read_u32(pdev->dev.of_node,
-                       "sirf,spi-dma-tx-channel", &tx_dma_ch);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Unable to get tx dma channel\n");
-               goto err_cs;
-       }
-
        master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
        if (!master) {
                dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
 
        /* request DMA channels */
-       dma_cap_zero(dma_cap_mask);
-       dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
-
-       sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
-               (void *)rx_dma_ch);
+       sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
        if (!sspi->rx_chan) {
                dev_err(&pdev->dev, "can not allocate rx dma channel\n");
                ret = -ENODEV;
                goto free_master;
        }
-       sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
-               (void *)tx_dma_ch);
+       sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
        if (!sspi->tx_chan) {
                dev_err(&pdev->dev, "can not allocate tx dma channel\n");
                ret = -ENODEV;
@@ -724,11 +743,16 @@ static int  spi_sirfsoc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int spi_sirfsoc_suspend(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
        struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
 
        clk_disable(sspi->clk);
        return 0;
@@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev)
        writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
        writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
 
-       return 0;
+       return spi_master_resume(master);
 }
-
-static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
-       .suspend = spi_sirfsoc_suspend,
-       .resume = spi_sirfsoc_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
+                        spi_sirfsoc_resume);
+
 static const struct of_device_id spi_sirfsoc_of_match[] = {
        { .compatible = "sirf,prima2-spi", },
        { .compatible = "sirf,marco-spi", },
@@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm     = &spi_sirfsoc_pm_ops,
-#endif
                .of_match_table = spi_sirfsoc_of_match,
        },
        .probe = spi_sirfsoc_probe,
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
new file mode 100644 (file)
index 0000000..d266a87
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN4I_FIFO_DEPTH               64
+
+#define SUN4I_RXDATA_REG               0x00
+
+#define SUN4I_TXDATA_REG               0x04
+
+#define SUN4I_CTL_REG                  0x08
+#define SUN4I_CTL_ENABLE                       BIT(0)
+#define SUN4I_CTL_MASTER                       BIT(1)
+#define SUN4I_CTL_CPHA                         BIT(2)
+#define SUN4I_CTL_CPOL                         BIT(3)
+#define SUN4I_CTL_CS_ACTIVE_LOW                        BIT(4)
+#define SUN4I_CTL_LMTF                         BIT(6)
+#define SUN4I_CTL_TF_RST                       BIT(8)
+#define SUN4I_CTL_RF_RST                       BIT(9)
+#define SUN4I_CTL_XCH                          BIT(10)
+#define SUN4I_CTL_CS_MASK                      0x3000
+#define SUN4I_CTL_CS(cs)                       (((cs) << 12) & SUN4I_CTL_CS_MASK)
+#define SUN4I_CTL_DHB                          BIT(15)
+#define SUN4I_CTL_CS_MANUAL                    BIT(16)
+#define SUN4I_CTL_CS_LEVEL                     BIT(17)
+#define SUN4I_CTL_TP                           BIT(18)
+
+#define SUN4I_INT_CTL_REG              0x0c
+#define SUN4I_INT_CTL_TC                       BIT(16)
+
+#define SUN4I_INT_STA_REG              0x10
+
+#define SUN4I_DMA_CTL_REG              0x14
+
+#define SUN4I_WAIT_REG                 0x18
+
+#define SUN4I_CLK_CTL_REG              0x1c
+#define SUN4I_CLK_CTL_CDR2_MASK                        0xff
+#define SUN4I_CLK_CTL_CDR2(div)                        ((div) & SUN4I_CLK_CTL_CDR2_MASK)
+#define SUN4I_CLK_CTL_CDR1_MASK                        0xf
+#define SUN4I_CLK_CTL_CDR1(div)                        (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN4I_CLK_CTL_DRS                      BIT(12)
+
+#define SUN4I_BURST_CNT_REG            0x20
+#define SUN4I_BURST_CNT(cnt)                   ((cnt) & 0xffffff)
+
+#define SUN4I_XMIT_CNT_REG             0x24
+#define SUN4I_XMIT_CNT(cnt)                    ((cnt) & 0xffffff)
+
+#define SUN4I_FIFO_STA_REG             0x28
+#define SUN4I_FIFO_STA_RF_CNT_MASK             0x7f
+#define SUN4I_FIFO_STA_RF_CNT_BITS             0
+#define SUN4I_FIFO_STA_TF_CNT_MASK             0x7f
+#define SUN4I_FIFO_STA_TF_CNT_BITS             16
+
+struct sun4i_spi {
+       struct spi_master       *master;
+       void __iomem            *base_addr;
+       struct clk              *hclk;
+       struct clk              *mclk;
+
+       struct completion       done;
+
+       const u8                *tx_buf;
+       u8                      *rx_buf;
+       int                     len;
+};
+
+static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
+{
+       return readl(sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
+{
+       writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
+{
+       u32 reg, cnt;
+       u8 byte;
+
+       /* See how much data is available */
+       reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
+       reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
+       cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
+
+       if (len > cnt)
+               len = cnt;
+
+       while (len--) {
+               byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
+               if (sspi->rx_buf)
+                       *sspi->rx_buf++ = byte;
+       }
+}
+
+static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
+{
+       u8 byte;
+
+       if (len > sspi->len)
+               len = sspi->len;
+
+       while (len--) {
+               byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+               writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
+               sspi->len--;
+       }
+}
+
+static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
+       u32 reg;
+
+       reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+       reg &= ~SUN4I_CTL_CS_MASK;
+       reg |= SUN4I_CTL_CS(spi->chip_select);
+
+       if (enable)
+               reg |= SUN4I_CTL_CS_LEVEL;
+       else
+               reg &= ~SUN4I_CTL_CS_LEVEL;
+
+       /*
+        * Even though this looks irrelevant since we are supposed to
+        * be controlling the chip select manually, this bit also
+        * controls the levels of the chip select for inactive
+        * devices.
+        *
+        * If we don't set it, the chip select level will go low by
+        * default when the device is idle, which is not really
+        * expected in the common case where the chip select is active
+        * low.
+        */
+       if (spi->mode & SPI_CS_HIGH)
+               reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
+       else
+               reg |= SUN4I_CTL_CS_ACTIVE_LOW;
+
+       sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+}
+
+static int sun4i_spi_transfer_one(struct spi_master *master,
+                                 struct spi_device *spi,
+                                 struct spi_transfer *tfr)
+{
+       struct sun4i_spi *sspi = spi_master_get_devdata(master);
+       unsigned int mclk_rate, div, timeout;
+       unsigned int tx_len = 0;
+       int ret = 0;
+       u32 reg;
+
+       /* We don't support transfer larger than the FIFO */
+       if (tfr->len > SUN4I_FIFO_DEPTH)
+               return -EINVAL;
+
+       reinit_completion(&sspi->done);
+       sspi->tx_buf = tfr->tx_buf;
+       sspi->rx_buf = tfr->rx_buf;
+       sspi->len = tfr->len;
+
+       /* Clear pending interrupts */
+       sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
+
+
+       reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+       /* Reset FIFOs */
+       sun4i_spi_write(sspi, SUN4I_CTL_REG,
+                       reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
+
+       /*
+        * Setup the transfer control register: Chip Select,
+        * polarities, etc.
+        */
+       if (spi->mode & SPI_CPOL)
+               reg |= SUN4I_CTL_CPOL;
+       else
+               reg &= ~SUN4I_CTL_CPOL;
+
+       if (spi->mode & SPI_CPHA)
+               reg |= SUN4I_CTL_CPHA;
+       else
+               reg &= ~SUN4I_CTL_CPHA;
+
+       if (spi->mode & SPI_LSB_FIRST)
+               reg |= SUN4I_CTL_LMTF;
+       else
+               reg &= ~SUN4I_CTL_LMTF;
+
+
+       /*
+        * If it's a TX only transfer, we don't want to fill the RX
+        * FIFO with bogus data
+        */
+       if (sspi->rx_buf)
+               reg &= ~SUN4I_CTL_DHB;
+       else
+               reg |= SUN4I_CTL_DHB;
+
+       /* We want to control the chip select manually */
+       reg |= SUN4I_CTL_CS_MANUAL;
+
+       sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+
+       /* Ensure that we have a parent clock fast enough */
+       mclk_rate = clk_get_rate(sspi->mclk);
+       if (mclk_rate < (2 * spi->max_speed_hz)) {
+               clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+               mclk_rate = clk_get_rate(sspi->mclk);
+       }
+
+       /*
+        * Setup clock divider.
+        *
+        * We have two choices there. Either we can use the clock
+        * divide rate 1, which is calculated thanks to this formula:
+        * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
+        * Or we can use CDR2, which is calculated with the formula:
+        * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+        * Wether we use the former or the latter is set through the
+        * DRS bit.
+        *
+        * First try CDR2, and if we can't reach the expected
+        * frequency, fall back to CDR1.
+        */
+       div = mclk_rate / (2 * spi->max_speed_hz);
+       if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
+               if (div > 0)
+                       div--;
+
+               reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
+       } else {
+               div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+               reg = SUN4I_CLK_CTL_CDR1(div);
+       }
+
+       sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
+
+       /* Setup the transfer now... */
+       if (sspi->tx_buf)
+               tx_len = tfr->len;
+
+       /* Setup the counters */
+       sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
+       sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
+
+       /* Fill the TX FIFO */
+       sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+       /* Enable the interrupts */
+       sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
+
+       /* Start the transfer */
+       reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+       sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
+
+       timeout = wait_for_completion_timeout(&sspi->done,
+                                             msecs_to_jiffies(1000));
+       if (!timeout) {
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+out:
+       sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
+
+       return ret;
+}
+
+static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
+{
+       struct sun4i_spi *sspi = dev_id;
+       u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
+
+       /* Transfer complete */
+       if (status & SUN4I_INT_CTL_TC) {
+               sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
+               complete(&sspi->done);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static int sun4i_spi_runtime_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sun4i_spi *sspi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(sspi->hclk);
+       if (ret) {
+               dev_err(dev, "Couldn't enable AHB clock\n");
+               goto out;
+       }
+
+       ret = clk_prepare_enable(sspi->mclk);
+       if (ret) {
+               dev_err(dev, "Couldn't enable module clock\n");
+               goto err;
+       }
+
+       sun4i_spi_write(sspi, SUN4I_CTL_REG,
+                       SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
+
+       return 0;
+
+err:
+       clk_disable_unprepare(sspi->hclk);
+out:
+       return ret;
+}
+
+static int sun4i_spi_runtime_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sun4i_spi *sspi = spi_master_get_devdata(master);
+
+       clk_disable_unprepare(sspi->mclk);
+       clk_disable_unprepare(sspi->hclk);
+
+       return 0;
+}
+
+static int sun4i_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct sun4i_spi *sspi;
+       struct resource *res;
+       int ret = 0, irq;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
+       if (!master) {
+               dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, master);
+       sspi = spi_master_get_devdata(master);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(sspi->base_addr)) {
+               ret = PTR_ERR(sspi->base_addr);
+               goto err_free_master;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "No spi IRQ specified\n");
+               ret = -ENXIO;
+               goto err_free_master;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
+                              0, "sun4i-spi", sspi);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot request IRQ\n");
+               goto err_free_master;
+       }
+
+       sspi->master = master;
+       master->set_cs = sun4i_spi_set_cs;
+       master->transfer_one = sun4i_spi_transfer_one;
+       master->num_chipselect = 4;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->dev.of_node = pdev->dev.of_node;
+       master->auto_runtime_pm = true;
+
+       sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(sspi->hclk)) {
+               dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+               ret = PTR_ERR(sspi->hclk);
+               goto err_free_master;
+       }
+
+       sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+       if (IS_ERR(sspi->mclk)) {
+               dev_err(&pdev->dev, "Unable to acquire module clock\n");
+               ret = PTR_ERR(sspi->mclk);
+               goto err_free_master;
+       }
+
+       init_completion(&sspi->done);
+
+       /*
+        * This wake-up/shutdown pattern is to be able to have the
+        * device woken up, even if runtime_pm is disabled
+        */
+       ret = sun4i_spi_runtime_resume(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Couldn't resume the device\n");
+               goto err_free_master;
+       }
+
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               goto err_pm_disable;
+       }
+
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       sun4i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+       spi_master_put(master);
+       return ret;
+}
+
+static int sun4i_spi_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id sun4i_spi_match[] = {
+       { .compatible = "allwinner,sun4i-a10-spi", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_spi_match);
+
+static const struct dev_pm_ops sun4i_spi_pm_ops = {
+       .runtime_resume         = sun4i_spi_runtime_resume,
+       .runtime_suspend        = sun4i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun4i_spi_driver = {
+       .probe  = sun4i_spi_probe,
+       .remove = sun4i_spi_remove,
+       .driver = {
+               .name           = "sun4i-spi",
+               .owner          = THIS_MODULE,
+               .of_match_table = sun4i_spi_match,
+               .pm             = &sun4i_spi_pm_ops,
+       },
+};
+module_platform_driver(sun4i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
new file mode 100644 (file)
index 0000000..b3e3498
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN6I_FIFO_DEPTH               128
+
+#define SUN6I_GBL_CTL_REG              0x04
+#define SUN6I_GBL_CTL_BUS_ENABLE               BIT(0)
+#define SUN6I_GBL_CTL_MASTER                   BIT(1)
+#define SUN6I_GBL_CTL_TP                       BIT(7)
+#define SUN6I_GBL_CTL_RST                      BIT(31)
+
+#define SUN6I_TFR_CTL_REG              0x08
+#define SUN6I_TFR_CTL_CPHA                     BIT(0)
+#define SUN6I_TFR_CTL_CPOL                     BIT(1)
+#define SUN6I_TFR_CTL_SPOL                     BIT(2)
+#define SUN6I_TFR_CTL_CS_MASK                  0x30
+#define SUN6I_TFR_CTL_CS(cs)                   (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK)
+#define SUN6I_TFR_CTL_CS_MANUAL                        BIT(6)
+#define SUN6I_TFR_CTL_CS_LEVEL                 BIT(7)
+#define SUN6I_TFR_CTL_DHB                      BIT(8)
+#define SUN6I_TFR_CTL_FBS                      BIT(12)
+#define SUN6I_TFR_CTL_XCH                      BIT(31)
+
+#define SUN6I_INT_CTL_REG              0x10
+#define SUN6I_INT_CTL_RF_OVF                   BIT(8)
+#define SUN6I_INT_CTL_TC                       BIT(12)
+
+#define SUN6I_INT_STA_REG              0x14
+
+#define SUN6I_FIFO_CTL_REG             0x18
+#define SUN6I_FIFO_CTL_RF_RST                  BIT(15)
+#define SUN6I_FIFO_CTL_TF_RST                  BIT(31)
+
+#define SUN6I_FIFO_STA_REG             0x1c
+#define SUN6I_FIFO_STA_RF_CNT_MASK             0x7f
+#define SUN6I_FIFO_STA_RF_CNT_BITS             0
+#define SUN6I_FIFO_STA_TF_CNT_MASK             0x7f
+#define SUN6I_FIFO_STA_TF_CNT_BITS             16
+
+#define SUN6I_CLK_CTL_REG              0x24
+#define SUN6I_CLK_CTL_CDR2_MASK                        0xff
+#define SUN6I_CLK_CTL_CDR2(div)                        (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
+#define SUN6I_CLK_CTL_CDR1_MASK                        0xf
+#define SUN6I_CLK_CTL_CDR1(div)                        (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN6I_CLK_CTL_DRS                      BIT(12)
+
+#define SUN6I_BURST_CNT_REG            0x30
+#define SUN6I_BURST_CNT(cnt)                   ((cnt) & 0xffffff)
+
+#define SUN6I_XMIT_CNT_REG             0x34
+#define SUN6I_XMIT_CNT(cnt)                    ((cnt) & 0xffffff)
+
+#define SUN6I_BURST_CTL_CNT_REG                0x38
+#define SUN6I_BURST_CTL_CNT_STC(cnt)           ((cnt) & 0xffffff)
+
+#define SUN6I_TXDATA_REG               0x200
+#define SUN6I_RXDATA_REG               0x300
+
+struct sun6i_spi {
+       struct spi_master       *master;
+       void __iomem            *base_addr;
+       struct clk              *hclk;
+       struct clk              *mclk;
+       struct reset_control    *rstc;
+
+       struct completion       done;
+
+       const u8                *tx_buf;
+       u8                      *rx_buf;
+       int                     len;
+};
+
+static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
+{
+       return readl(sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
+{
+       writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
+{
+       u32 reg, cnt;
+       u8 byte;
+
+       /* See how much data is available */
+       reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
+       reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
+       cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
+
+       if (len > cnt)
+               len = cnt;
+
+       while (len--) {
+               byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
+               if (sspi->rx_buf)
+                       *sspi->rx_buf++ = byte;
+       }
+}
+
+static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
+{
+       u8 byte;
+
+       if (len > sspi->len)
+               len = sspi->len;
+
+       while (len--) {
+               byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+               writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
+               sspi->len--;
+       }
+}
+
+static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+       u32 reg;
+
+       reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+       reg &= ~SUN6I_TFR_CTL_CS_MASK;
+       reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
+
+       if (enable)
+               reg |= SUN6I_TFR_CTL_CS_LEVEL;
+       else
+               reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
+
+       sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+}
+
+
+static int sun6i_spi_transfer_one(struct spi_master *master,
+                                 struct spi_device *spi,
+                                 struct spi_transfer *tfr)
+{
+       struct sun6i_spi *sspi = spi_master_get_devdata(master);
+       unsigned int mclk_rate, div, timeout;
+       unsigned int tx_len = 0;
+       int ret = 0;
+       u32 reg;
+
+       /* We don't support transfer larger than the FIFO */
+       if (tfr->len > SUN6I_FIFO_DEPTH)
+               return -EINVAL;
+
+       reinit_completion(&sspi->done);
+       sspi->tx_buf = tfr->tx_buf;
+       sspi->rx_buf = tfr->rx_buf;
+       sspi->len = tfr->len;
+
+       /* Clear pending interrupts */
+       sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
+
+       /* Reset FIFO */
+       sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
+                       SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
+
+       /*
+        * Setup the transfer control register: Chip Select,
+        * polarities, etc.
+        */
+       reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+       if (spi->mode & SPI_CPOL)
+               reg |= SUN6I_TFR_CTL_CPOL;
+       else
+               reg &= ~SUN6I_TFR_CTL_CPOL;
+
+       if (spi->mode & SPI_CPHA)
+               reg |= SUN6I_TFR_CTL_CPHA;
+       else
+               reg &= ~SUN6I_TFR_CTL_CPHA;
+
+       if (spi->mode & SPI_LSB_FIRST)
+               reg |= SUN6I_TFR_CTL_FBS;
+       else
+               reg &= ~SUN6I_TFR_CTL_FBS;
+
+       /*
+        * If it's a TX only transfer, we don't want to fill the RX
+        * FIFO with bogus data
+        */
+       if (sspi->rx_buf)
+               reg &= ~SUN6I_TFR_CTL_DHB;
+       else
+               reg |= SUN6I_TFR_CTL_DHB;
+
+       /* We want to control the chip select manually */
+       reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
+       sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+       /* Ensure that we have a parent clock fast enough */
+       mclk_rate = clk_get_rate(sspi->mclk);
+       if (mclk_rate < (2 * spi->max_speed_hz)) {
+               clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+               mclk_rate = clk_get_rate(sspi->mclk);
+       }
+
+       /*
+        * Setup clock divider.
+        *
+        * We have two choices there. Either we can use the clock
+        * divide rate 1, which is calculated thanks to this formula:
+        * SPI_CLK = MOD_CLK / (2 ^ cdr)
+        * Or we can use CDR2, which is calculated with the formula:
+        * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+        * Wether we use the former or the latter is set through the
+        * DRS bit.
+        *
+        * First try CDR2, and if we can't reach the expected
+        * frequency, fall back to CDR1.
+        */
+       div = mclk_rate / (2 * spi->max_speed_hz);
+       if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+               if (div > 0)
+                       div--;
+
+               reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
+       } else {
+               div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+               reg = SUN6I_CLK_CTL_CDR1(div);
+       }
+
+       sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+
+       /* Setup the transfer now... */
+       if (sspi->tx_buf)
+               tx_len = tfr->len;
+
+       /* Setup the counters */
+       sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
+       sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
+       sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
+                       SUN6I_BURST_CTL_CNT_STC(tx_len));
+
+       /* Fill the TX FIFO */
+       sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+       /* Enable the interrupts */
+       sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
+
+       /* Start the transfer */
+       reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+       sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+
+       timeout = wait_for_completion_timeout(&sspi->done,
+                                             msecs_to_jiffies(1000));
+       if (!timeout) {
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+out:
+       sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+       return ret;
+}
+
+static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
+{
+       struct sun6i_spi *sspi = dev_id;
+       u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+
+       /* Transfer complete */
+       if (status & SUN6I_INT_CTL_TC) {
+               sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
+               complete(&sspi->done);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static int sun6i_spi_runtime_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sun6i_spi *sspi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(sspi->hclk);
+       if (ret) {
+               dev_err(dev, "Couldn't enable AHB clock\n");
+               goto out;
+       }
+
+       ret = clk_prepare_enable(sspi->mclk);
+       if (ret) {
+               dev_err(dev, "Couldn't enable module clock\n");
+               goto err;
+       }
+
+       ret = reset_control_deassert(sspi->rstc);
+       if (ret) {
+               dev_err(dev, "Couldn't deassert the device from reset\n");
+               goto err2;
+       }
+
+       sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
+                       SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+
+       return 0;
+
+err2:
+       clk_disable_unprepare(sspi->mclk);
+err:
+       clk_disable_unprepare(sspi->hclk);
+out:
+       return ret;
+}
+
+static int sun6i_spi_runtime_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+       reset_control_assert(sspi->rstc);
+       clk_disable_unprepare(sspi->mclk);
+       clk_disable_unprepare(sspi->hclk);
+
+       return 0;
+}
+
+static int sun6i_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct sun6i_spi *sspi;
+       struct resource *res;
+       int ret = 0, irq;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+       if (!master) {
+               dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, master);
+       sspi = spi_master_get_devdata(master);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(sspi->base_addr)) {
+               ret = PTR_ERR(sspi->base_addr);
+               goto err_free_master;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "No spi IRQ specified\n");
+               ret = -ENXIO;
+               goto err_free_master;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
+                              0, "sun6i-spi", sspi);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot request IRQ\n");
+               goto err_free_master;
+       }
+
+       sspi->master = master;
+       master->set_cs = sun6i_spi_set_cs;
+       master->transfer_one = sun6i_spi_transfer_one;
+       master->num_chipselect = 4;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->dev.of_node = pdev->dev.of_node;
+       master->auto_runtime_pm = true;
+
+       sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(sspi->hclk)) {
+               dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+               ret = PTR_ERR(sspi->hclk);
+               goto err_free_master;
+       }
+
+       sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+       if (IS_ERR(sspi->mclk)) {
+               dev_err(&pdev->dev, "Unable to acquire module clock\n");
+               ret = PTR_ERR(sspi->mclk);
+               goto err_free_master;
+       }
+
+       init_completion(&sspi->done);
+
+       sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(sspi->rstc)) {
+               dev_err(&pdev->dev, "Couldn't get reset controller\n");
+               ret = PTR_ERR(sspi->rstc);
+               goto err_free_master;
+       }
+
+       /*
+        * This wake-up/shutdown pattern is to be able to have the
+        * device woken up, even if runtime_pm is disabled
+        */
+       ret = sun6i_spi_runtime_resume(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Couldn't resume the device\n");
+               goto err_free_master;
+       }
+
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register SPI master\n");
+               goto err_pm_disable;
+       }
+
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+       sun6i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+       spi_master_put(master);
+       return ret;
+}
+
+static int sun6i_spi_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id sun6i_spi_match[] = {
+       { .compatible = "allwinner,sun6i-a31-spi", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+
+static const struct dev_pm_ops sun6i_spi_pm_ops = {
+       .runtime_resume         = sun6i_spi_runtime_resume,
+       .runtime_suspend        = sun6i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun6i_spi_driver = {
+       .probe  = sun6i_spi_probe,
+       .remove = sun6i_spi_remove,
+       .driver = {
+               .name           = "sun6i-spi",
+               .owner          = THIS_MODULE,
+               .of_match_table = sun6i_spi_match,
+               .pm             = &sun6i_spi_pm_ops,
+       },
+};
+module_platform_driver(sun6i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
+MODULE_LICENSE("GPL");
index 413c718434927f0d3278c051d15040639a68237a..400649595505e874e2b8873e1561a9e33310da56 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -172,7 +171,6 @@ struct tegra_spi_data {
        void __iomem                            *base;
        phys_addr_t                             phys;
        unsigned                                irq;
-       u32                                     spi_max_frequency;
        u32                                     cur_speed;
 
        struct spi_device                       *cur_spi;
@@ -761,11 +759,6 @@ static int tegra_spi_setup(struct spi_device *spi)
                spi->mode & SPI_CPHA ? "" : "~",
                spi->max_speed_hz);
 
-       BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
-       /* Set speed to the spi max fequency if spi device has not set */
-       spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
-
        ret = pm_runtime_get_sync(tspi->dev);
        if (ret < 0) {
                dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -853,8 +846,8 @@ complete_xfer:
                                        SPI_COMMAND1);
                        tegra_spi_transfer_delay(xfer->delay_usecs);
                        goto exit;
-               } else if (msg->transfers.prev == &xfer->transfer_list) {
-                       /* This is the last transfer in message */
+               } else if (list_is_last(&xfer->transfer_list,
+                                       &msg->transfers)) {
                        if (xfer->cs_change)
                                tspi->cs_control = spi;
                        else {
@@ -1019,16 +1012,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
        return IRQ_WAKE_THREAD;
 }
 
-static void tegra_spi_parse_dt(struct platform_device *pdev,
-       struct tegra_spi_data *tspi)
-{
-       struct device_node *np = pdev->dev.of_node;
-
-       if (of_property_read_u32(np, "spi-max-frequency",
-                               &tspi->spi_max_frequency))
-               tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
 static struct of_device_id tegra_spi_of_match[] = {
        { .compatible = "nvidia,tegra114-spi", },
        {}
@@ -1050,15 +1033,15 @@ static int tegra_spi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
        tspi = spi_master_get_devdata(master);
 
-       /* Parse DT */
-       tegra_spi_parse_dt(pdev, tspi);
+       if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
+                                &master->max_speed_hz))
+               master->max_speed_hz = 25000000; /* 25MHz */
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->setup = tegra_spi_setup;
        master->transfer_one_message = tegra_spi_transfer_one_message;
        master->num_chipselect = MAX_CHIP_SELECT;
-       master->bus_num = -1;
        master->auto_runtime_pm = true;
 
        tspi->master = master;
index 08794977f21ae38e35186e5347d40d8bb7bdcb7d..47869ea636e16189cbe651ad3426b338a670d1b7 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -121,7 +120,6 @@ struct tegra_sflash_data {
        struct reset_control                    *rst;
        void __iomem                            *base;
        unsigned                                irq;
-       u32                                     spi_max_frequency;
        u32                                     cur_speed;
 
        struct spi_device                       *cur_spi;
@@ -315,15 +313,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
        return tegra_sflash_start_cpu_based_transfer(tsd, t);
 }
 
-static int tegra_sflash_setup(struct spi_device *spi)
-{
-       struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
-
-       /* Set speed to the spi max fequency if spi device has not set */
-       spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
-       return 0;
-}
-
 static int tegra_sflash_transfer_one_message(struct spi_master *master,
                        struct spi_message *msg)
 {
@@ -430,15 +419,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
        return handle_cpu_based_xfer(tsd);
 }
 
-static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd)
-{
-       struct device_node *np = tsd->dev->of_node;
-
-       if (of_property_read_u32(np, "spi-max-frequency",
-                                       &tsd->spi_max_frequency))
-               tsd->spi_max_frequency = 25000000; /* 25MHz */
-}
-
 static struct of_device_id tegra_sflash_of_match[] = {
        { .compatible = "nvidia,tegra20-sflash", },
        {}
@@ -467,11 +447,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA;
-       master->setup = tegra_sflash_setup;
        master->transfer_one_message = tegra_sflash_transfer_one_message;
        master->auto_runtime_pm = true;
        master->num_chipselect = MAX_CHIP_SELECT;
-       master->bus_num = -1;
 
        platform_set_drvdata(pdev, master);
        tsd = spi_master_get_devdata(master);
@@ -479,7 +457,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
        tsd->dev = &pdev->dev;
        spin_lock_init(&tsd->lock);
 
-       tegra_sflash_parse_dt(tsd);
+       if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency",
+                                &master->max_speed_hz))
+               master->max_speed_hz = 25000000; /* 25MHz */
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        tsd->base = devm_ioremap_resource(&pdev->dev, r);
index be3a069879c3d42bfb482771bc83733318c2273d..e3c1b93e45d19abf610e7566405c3ad434a4bfbf 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -171,7 +170,6 @@ struct tegra_slink_data {
        void __iomem                            *base;
        phys_addr_t                             phys;
        unsigned                                irq;
-       u32                                     spi_max_frequency;
        u32                                     cur_speed;
 
        struct spi_device                       *cur_spi;
@@ -761,10 +759,6 @@ static int tegra_slink_setup(struct spi_device *spi)
                spi->mode & SPI_CPHA ? "" : "~",
                spi->max_speed_hz);
 
-       BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
-       /* Set speed to the spi max fequency if spi device has not set */
-       spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
        ret = pm_runtime_get_sync(tspi->dev);
        if (ret < 0) {
                dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -999,15 +993,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data)
        return IRQ_WAKE_THREAD;
 }
 
-static void tegra_slink_parse_dt(struct tegra_slink_data *tspi)
-{
-       struct device_node *np = tspi->dev->of_node;
-
-       if (of_property_read_u32(np, "spi-max-frequency",
-                                       &tspi->spi_max_frequency))
-               tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
 static const struct tegra_slink_chip_data tegra30_spi_cdata = {
        .cs_hold_time = true,
 };
@@ -1053,7 +1038,6 @@ static int tegra_slink_probe(struct platform_device *pdev)
        master->unprepare_message = tegra_slink_unprepare_message;
        master->auto_runtime_pm = true;
        master->num_chipselect = MAX_CHIP_SELECT;
-       master->bus_num = -1;
 
        platform_set_drvdata(pdev, master);
        tspi = spi_master_get_devdata(master);
@@ -1062,7 +1046,9 @@ static int tegra_slink_probe(struct platform_device *pdev)
        tspi->chip_data = cdata;
        spin_lock_init(&tspi->lock);
 
-       tegra_slink_parse_dt(tspi);
+       if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency",
+                                &master->max_speed_hz))
+               master->max_speed_hz = 25000000; /* 25MHz */
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
index 3d09265b51335e2cefdf3d098ce177826b150674..6c211d1910b084645d19d6eaa8cdcc3aa2f7c1c9 100644 (file)
@@ -429,13 +429,13 @@ static int ti_qspi_probe(struct platform_device *pdev)
 
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
 
-       master->bus_num = -1;
        master->flags = SPI_MASTER_HALF_DUPLEX;
        master->setup = ti_qspi_setup;
        master->auto_runtime_pm = true;
        master->transfer_one_message = ti_qspi_start_transfer_one;
        master->dev.of_node = pdev->dev.of_node;
-       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);
 
        if (!of_property_read_u32(np, "num-cs", &num_cs))
                master->num_chipselect = num_cs;
@@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
                if (res_mmap == NULL) {
                        dev_err(&pdev->dev,
                                "memory mapped resource not required\n");
-                       return -ENODEV;
                }
        }
 
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
deleted file mode 100644 (file)
index 7d20e12..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Sequencer Serial Port (SSP) based SPI master driver
- *
- * Copyright (C) 2010 Texas Instruments 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ti_ssp.h>
-
-#define MODE_BITS      (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
-
-struct ti_ssp_spi {
-       struct spi_master               *master;
-       struct device                   *dev;
-       spinlock_t                      lock;
-       struct list_head                msg_queue;
-       struct completion               complete;
-       bool                            shutdown;
-       struct workqueue_struct         *workqueue;
-       struct work_struct              work;
-       u8                              mode, bpw;
-       int                             cs_active;
-       u32                             pc_en, pc_dis, pc_wr, pc_rd;
-       void                            (*select)(int cs);
-};
-
-static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
-{
-       u32 ret;
-
-       ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
-       return ret;
-}
-
-static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
-{
-       ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
-}
-
-static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
-                      struct spi_transfer *t)
-{
-       int count;
-
-       if (hw->bpw <= 8) {
-               u8              *rx = t->rx_buf;
-               const u8        *tx = t->tx_buf;
-
-               for (count = 0; count < t->len; count += 1) {
-                       if (t->tx_buf)
-                               ti_ssp_spi_tx(hw, *tx++);
-                       if (t->rx_buf)
-                               *rx++ = ti_ssp_spi_rx(hw);
-               }
-       } else if (hw->bpw <= 16) {
-               u16             *rx = t->rx_buf;
-               const u16       *tx = t->tx_buf;
-
-               for (count = 0; count < t->len; count += 2) {
-                       if (t->tx_buf)
-                               ti_ssp_spi_tx(hw, *tx++);
-                       if (t->rx_buf)
-                               *rx++ = ti_ssp_spi_rx(hw);
-               }
-       } else {
-               u32             *rx = t->rx_buf;
-               const u32       *tx = t->tx_buf;
-
-               for (count = 0; count < t->len; count += 4) {
-                       if (t->tx_buf)
-                               ti_ssp_spi_tx(hw, *tx++);
-                       if (t->rx_buf)
-                               *rx++ = ti_ssp_spi_rx(hw);
-               }
-       }
-
-       msg->actual_length += count; /* bytes transferred */
-
-       dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
-               t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
-               hw->bpw, count, (count < t->len) ? " (under)" : "");
-
-       return (count < t->len) ? -EIO : 0; /* left over data */
-}
-
-static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
-{
-       cs_active = !!cs_active;
-       if (cs_active == hw->cs_active)
-               return;
-       ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
-       hw->cs_active = cs_active;
-}
-
-#define __SHIFT_OUT(bits)      (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
-                                cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-#define __SHIFT_IN(bits)       (SSP_OPCODE_SHIFT | SSP_IN_MODE  | \
-                                cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-
-static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
-{
-       int error, idx = 0;
-       u32 seqram[16];
-       u32 cs_en, cs_dis, clk;
-       u32 topbits, botbits;
-
-       mode &= MODE_BITS;
-       if (mode == hw->mode && bpw == hw->bpw)
-               return 0;
-
-       cs_en  = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
-       cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW  : SSP_CS_HIGH;
-       clk    = (mode & SPI_CPOL)    ? SSP_CLK_HIGH : SSP_CLK_LOW;
-
-       /* Construct instructions */
-
-       /* Disable Chip Select */
-       hw->pc_dis = idx;
-       seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
-       seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_dis | clk;
-
-       /* Enable Chip Select */
-       hw->pc_en = idx;
-       seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
-       seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_en | clk;
-
-       /* Reads and writes need to be split for bpw > 16 */
-       topbits = (bpw > 16) ? 16 : bpw;
-       botbits = bpw - topbits;
-
-       /* Write */
-       hw->pc_wr = idx;
-       seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
-       if (botbits)
-               seqram[idx++] = __SHIFT_OUT(botbits)  | SSP_DATA_REG;
-       seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
-       /* Read */
-       hw->pc_rd = idx;
-       if (botbits)
-               seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
-       seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
-       seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
-       error = ti_ssp_load(hw->dev, 0, seqram, idx);
-       if (error < 0)
-               return error;
-
-       error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
-                                         0 : SSP_EARLY_DIN));
-       if (error < 0)
-               return error;
-
-       hw->bpw = bpw;
-       hw->mode = mode;
-
-       return error;
-}
-
-static void ti_ssp_spi_work(struct work_struct *work)
-{
-       struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
-
-       spin_lock(&hw->lock);
-
-        while (!list_empty(&hw->msg_queue)) {
-               struct spi_message      *m;
-               struct spi_device       *spi;
-               struct spi_transfer     *t = NULL;
-               int                     status = 0;
-
-               m = container_of(hw->msg_queue.next, struct spi_message,
-                                queue);
-
-               list_del_init(&m->queue);
-
-               spin_unlock(&hw->lock);
-
-               spi = m->spi;
-
-               if (hw->select)
-                       hw->select(spi->chip_select);
-
-               list_for_each_entry(t, &m->transfers, transfer_list) {
-                       int bpw = spi->bits_per_word;
-                       int xfer_status;
-
-                       if (t->bits_per_word)
-                               bpw = t->bits_per_word;
-
-                       if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
-                               break;
-
-                       ti_ssp_spi_chip_select(hw, 1);
-
-                       xfer_status = ti_ssp_spi_txrx(hw, m, t);
-                       if (xfer_status < 0)
-                               status = xfer_status;
-
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
-
-                       if (t->cs_change)
-                               ti_ssp_spi_chip_select(hw, 0);
-               }
-
-               ti_ssp_spi_chip_select(hw, 0);
-               m->status = status;
-               m->complete(m->context);
-
-               spin_lock(&hw->lock);
-       }
-
-       if (hw->shutdown)
-               complete(&hw->complete);
-
-       spin_unlock(&hw->lock);
-}
-
-static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
-       struct ti_ssp_spi       *hw;
-       struct spi_transfer     *t;
-       int                     error = 0;
-
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
-
-       hw = spi_master_get_devdata(spi->master);
-
-       if (list_empty(&m->transfers) || !m->complete)
-               return -EINVAL;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               if (t->len && !(t->rx_buf || t->tx_buf)) {
-                       dev_err(&spi->dev, "invalid xfer, no buffer\n");
-                       return -EINVAL;
-               }
-
-               if (t->len && t->rx_buf && t->tx_buf) {
-                       dev_err(&spi->dev, "invalid xfer, full duplex\n");
-                       return -EINVAL;
-               }
-       }
-
-       spin_lock(&hw->lock);
-       if (hw->shutdown) {
-               error = -ESHUTDOWN;
-               goto error_unlock;
-       }
-       list_add_tail(&m->queue, &hw->msg_queue);
-       queue_work(hw->workqueue, &hw->work);
-error_unlock:
-       spin_unlock(&hw->lock);
-       return error;
-}
-
-static int ti_ssp_spi_probe(struct platform_device *pdev)
-{
-       const struct ti_ssp_spi_data *pdata;
-       struct ti_ssp_spi *hw;
-       struct spi_master *master;
-       struct device *dev = &pdev->dev;
-       int error = 0;
-
-       pdata = dev_get_platdata(dev);
-       if (!pdata) {
-               dev_err(dev, "platform data not found\n");
-               return -EINVAL;
-       }
-
-       master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
-       if (!master) {
-               dev_err(dev, "cannot allocate SPI master\n");
-               return -ENOMEM;
-       }
-
-       hw = spi_master_get_devdata(master);
-       platform_set_drvdata(pdev, hw);
-
-       hw->master = master;
-       hw->dev = dev;
-       hw->select = pdata->select;
-
-       spin_lock_init(&hw->lock);
-       init_completion(&hw->complete);
-       INIT_LIST_HEAD(&hw->msg_queue);
-       INIT_WORK(&hw->work, ti_ssp_spi_work);
-
-       hw->workqueue = create_singlethread_workqueue(dev_name(dev));
-       if (!hw->workqueue) {
-               error = -ENOMEM;
-               dev_err(dev, "work queue creation failed\n");
-               goto error_wq;
-       }
-
-       error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
-       if (error < 0) {
-               dev_err(dev, "io setup failed\n");
-               goto error_iosel;
-       }
-
-       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->transfer        = ti_ssp_spi_transfer;
-
-       error = spi_register_master(master);
-       if (error) {
-               dev_err(dev, "master registration failed\n");
-               goto error_reg;
-       }
-
-       return 0;
-
-error_reg:
-error_iosel:
-       destroy_workqueue(hw->workqueue);
-error_wq:
-       spi_master_put(master);
-       return error;
-}
-
-static int ti_ssp_spi_remove(struct platform_device *pdev)
-{
-       struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
-       int error;
-
-       hw->shutdown = 1;
-       while (!list_empty(&hw->msg_queue)) {
-               error = wait_for_completion_interruptible(&hw->complete);
-               if (error < 0) {
-                       hw->shutdown = 0;
-                       return error;
-               }
-       }
-       destroy_workqueue(hw->workqueue);
-       spi_unregister_master(hw->master);
-
-       return 0;
-}
-
-static struct platform_driver ti_ssp_spi_driver = {
-       .probe          = ti_ssp_spi_probe,
-       .remove         = ti_ssp_spi_remove,
-       .driver         = {
-               .name   = "ti-ssp-spi",
-               .owner  = THIS_MODULE,
-       },
-};
-module_platform_driver(ti_ssp_spi_driver);
-
-MODULE_DESCRIPTION("SSP SPI Master");
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ti-ssp-spi");
index 2e7f38c7a9610b11f63fd36c816f311b3372d66d..f406b30af961fd8f52e969a665ce46fb7b46352c 100644 (file)
@@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
                                data->transfer_active = false;
                                wake_up(&data->wait);
                        } else {
-                               dev_err(&data->master->dev,
+                               dev_vdbg(&data->master->dev,
                                        "%s : Transfer is not completed",
                                        __func__);
                        }
@@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master)
        pch_spi_writereg(master, PCH_SRST, 0x0);
 }
 
-static int pch_spi_setup(struct spi_device *pspi)
-{
-       /* Check baud rate setting */
-       /* if baud rate of chip is greater than
-          max we can support,return error */
-       if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
-               pspi->max_speed_hz = PCH_MAX_BAUDRATE;
-
-       dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
-               (pspi->mode) & (SPI_CPOL | SPI_CPHA));
-
-       return 0;
-}
-
 static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
 {
 
@@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
        int retval;
        unsigned long flags;
 
-       /* validate spi message and baud rate */
-       if (unlikely(list_empty(&pmsg->transfers) == 1)) {
-               dev_err(&pspi->dev, "%s list empty\n", __func__);
-               retval = -EINVAL;
-               goto err_out;
-       }
-
-       if (unlikely(pspi->max_speed_hz == 0)) {
-               dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
-                       __func__, pspi->max_speed_hz);
-               retval = -EINVAL;
-               goto err_out;
-       }
-
-       dev_dbg(&pspi->dev,
-               "%s Transfer List not empty. Transfer Speed is set.\n", __func__);
-
        spin_lock_irqsave(&data->lock, flags);
        /* validate Tx/Rx buffers and Transfer length */
        list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
@@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
                dev_dbg(&pspi->dev,
                        "%s Tx/Rx buffer valid. Transfer length valid\n",
                        __func__);
-
-               /* if baud rate has been specified validate the same */
-               if (transfer->speed_hz > PCH_MAX_BAUDRATE)
-                       transfer->speed_hz = PCH_MAX_BAUDRATE;
        }
        spin_unlock_irqrestore(&data->lock, flags);
 
@@ -915,7 +880,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
        /* Set Tx DMA */
        param = &dma->param_tx;
        param->dma_dev = &dma_dev->dev;
-       param->chan_id = data->master->bus_num * 2; /* Tx = 0, 2 */
+       param->chan_id = data->ch * 2; /* Tx = 0, 2 */;
        param->tx_reg = data->io_base_addr + PCH_SPDWR;
        param->width = width;
        chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -930,7 +895,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
        /* Set Rx DMA */
        param = &dma->param_rx;
        param->dma_dev = &dma_dev->dev;
-       param->chan_id = data->master->bus_num * 2 + 1; /* Rx = Tx + 1 */
+       param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */;
        param->rx_reg = data->io_base_addr + PCH_SPDRR;
        param->width = width;
        chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        dma->nent = num;
        dma->desc_tx = desc_tx;
 
-       dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
-               "0x2 to SSNXCR\n", __func__);
+       dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
 
        spin_lock_irqsave(&data->lock, flags);
        pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
@@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
 
        /* initialize members of SPI master */
        master->num_chipselect = PCH_MAX_CS;
-       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);
+       master->max_speed_hz = PCH_MAX_BAUDRATE;
 
        data->board_dat = board_dat;
        data->plat_dev = plat_dev;
@@ -1452,6 +1416,11 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
 
        pch_spi_set_master_mode(master);
 
+       if (use_dma) {
+               dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
+               pch_alloc_dma_buf(board_dat, data);
+       }
+
        ret = spi_register_master(master);
        if (ret != 0) {
                dev_err(&plat_dev->dev,
@@ -1459,14 +1428,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
                goto err_spi_register_master;
        }
 
-       if (use_dma) {
-               dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
-               pch_alloc_dma_buf(board_dat, data);
-       }
-
        return 0;
 
 err_spi_register_master:
+       pch_free_dma_buf(board_dat, data);
        free_irq(board_dat->pdev->irq, data);
 err_request_irq:
        pch_spi_free_resources(board_dat, data);
@@ -1604,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = {
        .resume = pch_spi_pd_resume
 };
 
-static int pch_spi_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *id)
+static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct pch_spi_board_data *board_dat;
        struct platform_device *pd_dev = NULL;
@@ -1675,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev,
        return 0;
 
 err_platform_device:
+       while (--i >= 0)
+               platform_device_unregister(pd_dev_save->pd_save[i]);
        pci_disable_device(pdev);
 pci_enable_device:
        pci_release_regions(pdev);
index 6191ced514b2e71538926983ecc341ce7be75718..820b499816f8ebfb6bc45a56026dbe05b9b4311f 100644 (file)
@@ -80,7 +80,6 @@ struct txx9spi {
        void __iomem *membase;
        int baseclk;
        struct clk *clk;
-       u32 max_speed_hz, min_speed_hz;
        int last_chipselect;
        int last_chipselect_val;
 };
@@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi)
 {
        struct txx9spi *c = spi_master_get_devdata(spi->master);
 
-       if (!spi->max_speed_hz
-                       || spi->max_speed_hz > c->max_speed_hz
-                       || spi->max_speed_hz < c->min_speed_hz)
+       if (!spi->max_speed_hz)
                return -EINVAL;
 
        if (gpio_direction_output(spi->chip_select,
@@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
 
        /* check each transfer's parameters */
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
-               u8 bits_per_word = t->bits_per_word;
-
                if (!t->tx_buf && !t->rx_buf && t->len)
                        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)
-                       return -EINVAL;
        }
 
        spin_lock_irqsave(&c->lock, flags);
@@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev)
                goto exit;
        }
        c->baseclk = clk_get_rate(c->clk);
-       c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
-       c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
+       master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
+       master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
 
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               goto exit_busy;
-       if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
-                                    "spi_txx9"))
-               goto exit_busy;
-       c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
-       if (!c->membase)
+       c->membase = devm_ioremap_resource(&dev->dev, res);
+       if (IS_ERR(c->membase))
                goto exit_busy;
 
        /* enter config mode */
index 24c40b13dab1596edb6756e4f6311523393b418a..bb478dccf1d82dd5d9fb1316bd04cf1755f08f0a 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -74,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
 static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
        struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
 {
-       unsigned int speed;
-
        if (t->len > 62)
                return -EINVAL;
 
-       speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
+       if (t->speed_hz != spi_xcomm->current_speed) {
+               unsigned int divider;
 
-       if (speed != spi_xcomm->current_speed) {
-               unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed);
+               divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
                if (divider >= 64)
                        *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64;
                else if (divider >= 16)
@@ -90,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
                else
                        *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4;
 
-               spi_xcomm->current_speed = speed;
+               spi_xcomm->current_speed = t->speed_hz;
        }
 
        if (spi->mode & SPI_CPOL)
@@ -148,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
        int status = 0;
        bool is_last;
 
-       is_first = true;
-
        spi_xcomm_chipselect(spi_xcomm, spi, true);
 
        list_for_each_entry(t, &msg->transfers, transfer_list) {
index 6d4ce4615163ddb8efbdfc798cec36341b6baa1b..a3b0b9944bf000c7b69afd868a1c8eed71308489 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -88,10 +87,10 @@ struct xilinx_spi {
        const u8 *tx_ptr;       /* pointer in the Rx buffer */
        int remaining_bytes;    /* the number of bytes left to transfer */
        u8 bits_per_word;
-       unsigned int (*read_fn) (void __iomem *);
-       void (*write_fn) (u32, void __iomem *);
-       void (*tx_fn) (struct xilinx_spi *);
-       void (*rx_fn) (struct xilinx_spi *);
+       unsigned int (*read_fn)(void __iomem *);
+       void (*write_fn)(u32, void __iomem *);
+       void (*tx_fn)(struct xilinx_spi *);
+       void (*rx_fn)(struct xilinx_spi *);
 };
 
 static void xspi_write32(u32 val, void __iomem *addr)
@@ -209,26 +208,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
 }
 
 /* spi_bitbang requires custom setup_transfer() to be defined if there is a
- * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
- * supports 8 or 16 bits per word which cannot be changed in software.
- * SPI clock can't be changed in software either.
- * Check for correct bits per word. Chip select delay calculations could be
- * added here as soon as bitbang_work() can be made aware of the delay value.
+ * custom txrx_bufs().
  */
 static int xilinx_spi_setup_transfer(struct spi_device *spi,
                struct spi_transfer *t)
 {
-       struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
-       u8 bits_per_word;
-
-       bits_per_word = (t && t->bits_per_word)
-                        ? t->bits_per_word : spi->bits_per_word;
-       if (bits_per_word != xspi->bits_per_word) {
-               dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
-                       __func__, bits_per_word);
-               return -EINVAL;
-       }
-
        return 0;
 }
 
@@ -407,6 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
                xspi->write_fn = xspi_write32_be;
        }
 
+       master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
        xspi->bits_per_word = bits_per_word;
        if (xspi->bits_per_word == 8) {
                xspi->tx_fn = xspi_tx8;
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
new file mode 100644 (file)
index 0000000..41e1581
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Xtensa xtfpga SPI controller driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#define XTFPGA_SPI_NAME "xtfpga_spi"
+
+#define XTFPGA_SPI_START       0x0
+#define XTFPGA_SPI_BUSY                0x4
+#define XTFPGA_SPI_DATA                0x8
+
+#define BUSY_WAIT_US           100
+
+struct xtfpga_spi {
+       struct spi_bitbang bitbang;
+       void __iomem *regs;
+       u32 data;
+       unsigned data_sz;
+};
+
+static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi,
+                                     unsigned addr, u32 val)
+{
+       iowrite32(val, spi->regs + addr);
+}
+
+static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
+                                            unsigned addr)
+{
+       return ioread32(spi->regs + addr);
+}
+
+static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
+{
+       unsigned i;
+       for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
+            i < BUSY_WAIT_US; ++i)
+               udelay(1);
+       WARN_ON_ONCE(i == BUSY_WAIT_US);
+}
+
+static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
+                               u32 v, u8 bits)
+{
+       struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+
+       xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0));
+       xspi->data_sz += bits;
+       if (xspi->data_sz >= 16) {
+               xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA,
+                                  xspi->data >> (xspi->data_sz - 16));
+               xspi->data_sz -= 16;
+               xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1);
+               xtfpga_spi_wait_busy(xspi);
+               xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
+       }
+
+       return 0;
+}
+
+static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
+{
+       struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+
+       WARN_ON(xspi->data_sz != 0);
+       xspi->data_sz = 0;
+}
+
+static int xtfpga_spi_probe(struct platform_device *pdev)
+{
+       struct xtfpga_spi *xspi;
+       struct resource *mem;
+       int ret;
+       struct spi_master *master;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
+       if (!master)
+               return -ENOMEM;
+
+       master->flags = SPI_MASTER_NO_RX;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+       master->bus_num = pdev->dev.id;
+       master->dev.of_node = pdev->dev.of_node;
+
+       xspi = spi_master_get_devdata(master);
+       xspi->bitbang.master = master;
+       xspi->bitbang.chipselect = xtfpga_spi_chipselect;
+       xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "No memory resource\n");
+               ret = -ENODEV;
+               goto err;
+       }
+       xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(xspi->regs)) {
+               ret = PTR_ERR(xspi->regs);
+               goto err;
+       }
+
+       xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
+       usleep_range(1000, 2000);
+       if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) {
+               dev_err(&pdev->dev, "Device stuck in busy state\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       ret = spi_bitbang_start(&xspi->bitbang);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "spi_bitbang_start failed\n");
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, master);
+       return 0;
+err:
+       spi_master_put(master);
+       return ret;
+}
+
+static int xtfpga_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct xtfpga_spi *xspi = spi_master_get_devdata(master);
+
+       spi_bitbang_stop(&xspi->bitbang);
+       spi_master_put(master);
+
+       return 0;
+}
+
+MODULE_ALIAS("platform:" XTFPGA_SPI_NAME);
+
+#ifdef CONFIG_OF
+static const struct of_device_id xtfpga_spi_of_match[] = {
+       { .compatible = "cdns,xtfpga-spi", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match);
+#endif
+
+static struct platform_driver xtfpga_spi_driver = {
+       .probe = xtfpga_spi_probe,
+       .remove = xtfpga_spi_remove,
+       .driver = {
+               .name = XTFPGA_SPI_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(xtfpga_spi_of_match),
+       },
+};
+module_platform_driver(xtfpga_spi_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("xtensa xtfpga SPI driver");
+MODULE_LICENSE("GPL");
index d0b28bba38be6bfff2a420e9fc2850e5c84c690b..4eb9bf02996cf179cf3e6365421867aaf8a10593 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/cache.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
@@ -255,13 +257,12 @@ EXPORT_SYMBOL_GPL(spi_bus_type);
 static int spi_drv_probe(struct device *dev)
 {
        const struct spi_driver         *sdrv = to_spi_driver(dev->driver);
-       struct spi_device               *spi = to_spi_device(dev);
        int ret;
 
-       acpi_dev_pm_attach(&spi->dev, true);
-       ret = sdrv->probe(spi);
+       acpi_dev_pm_attach(dev, true);
+       ret = sdrv->probe(to_spi_device(dev));
        if (ret)
-               acpi_dev_pm_detach(&spi->dev, true);
+               acpi_dev_pm_detach(dev, true);
 
        return ret;
 }
@@ -269,11 +270,10 @@ static int spi_drv_probe(struct device *dev)
 static int spi_drv_remove(struct device *dev)
 {
        const struct spi_driver         *sdrv = to_spi_driver(dev->driver);
-       struct spi_device               *spi = to_spi_device(dev);
        int ret;
 
-       ret = sdrv->remove(spi);
-       acpi_dev_pm_detach(&spi->dev, true);
+       ret = sdrv->remove(to_spi_device(dev));
+       acpi_dev_pm_detach(dev, true);
 
        return ret;
 }
@@ -580,6 +580,169 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
                spi->master->set_cs(spi, !enable);
 }
 
+static int spi_map_buf(struct spi_master *master, struct device *dev,
+                      struct sg_table *sgt, void *buf, size_t len,
+                      enum dma_data_direction dir)
+{
+       const bool vmalloced_buf = is_vmalloc_addr(buf);
+       const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len;
+       const int sgs = DIV_ROUND_UP(len, desc_len);
+       struct page *vm_page;
+       void *sg_buf;
+       size_t min;
+       int i, ret;
+
+       ret = sg_alloc_table(sgt, sgs, GFP_KERNEL);
+       if (ret != 0)
+               return ret;
+
+       for (i = 0; i < sgs; i++) {
+               min = min_t(size_t, len, desc_len);
+
+               if (vmalloced_buf) {
+                       vm_page = vmalloc_to_page(buf);
+                       if (!vm_page) {
+                               sg_free_table(sgt);
+                               return -ENOMEM;
+                       }
+                       sg_buf = page_address(vm_page) +
+                               ((size_t)buf & ~PAGE_MASK);
+               } else {
+                       sg_buf = buf;
+               }
+
+               sg_set_buf(&sgt->sgl[i], sg_buf, min);
+
+               buf += min;
+               len -= min;
+       }
+
+       ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
+       if (ret < 0) {
+               sg_free_table(sgt);
+               return ret;
+       }
+
+       sgt->nents = ret;
+
+       return 0;
+}
+
+static void spi_unmap_buf(struct spi_master *master, struct device *dev,
+                         struct sg_table *sgt, enum dma_data_direction dir)
+{
+       if (sgt->orig_nents) {
+               dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+               sg_free_table(sgt);
+       }
+}
+
+static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
+{
+       struct device *tx_dev, *rx_dev;
+       struct spi_transfer *xfer;
+       void *tmp;
+       unsigned int max_tx, max_rx;
+       int ret;
+
+       if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
+               max_tx = 0;
+               max_rx = 0;
+
+               list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+                       if ((master->flags & SPI_MASTER_MUST_TX) &&
+                           !xfer->tx_buf)
+                               max_tx = max(xfer->len, max_tx);
+                       if ((master->flags & SPI_MASTER_MUST_RX) &&
+                           !xfer->rx_buf)
+                               max_rx = max(xfer->len, max_rx);
+               }
+
+               if (max_tx) {
+                       tmp = krealloc(master->dummy_tx, max_tx,
+                                      GFP_KERNEL | GFP_DMA);
+                       if (!tmp)
+                               return -ENOMEM;
+                       master->dummy_tx = tmp;
+                       memset(tmp, 0, max_tx);
+               }
+
+               if (max_rx) {
+                       tmp = krealloc(master->dummy_rx, max_rx,
+                                      GFP_KERNEL | GFP_DMA);
+                       if (!tmp)
+                               return -ENOMEM;
+                       master->dummy_rx = tmp;
+               }
+
+               if (max_tx || max_rx) {
+                       list_for_each_entry(xfer, &msg->transfers,
+                                           transfer_list) {
+                               if (!xfer->tx_buf)
+                                       xfer->tx_buf = master->dummy_tx;
+                               if (!xfer->rx_buf)
+                                       xfer->rx_buf = master->dummy_rx;
+                       }
+               }
+       }
+
+       if (!master->can_dma)
+               return 0;
+
+       tx_dev = &master->dma_tx->dev->device;
+       rx_dev = &master->dma_rx->dev->device;
+
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               if (!master->can_dma(master, msg->spi, xfer))
+                       continue;
+
+               if (xfer->tx_buf != NULL) {
+                       ret = spi_map_buf(master, tx_dev, &xfer->tx_sg,
+                                         (void *)xfer->tx_buf, xfer->len,
+                                         DMA_TO_DEVICE);
+                       if (ret != 0)
+                               return ret;
+               }
+
+               if (xfer->rx_buf != NULL) {
+                       ret = spi_map_buf(master, rx_dev, &xfer->rx_sg,
+                                         xfer->rx_buf, xfer->len,
+                                         DMA_FROM_DEVICE);
+                       if (ret != 0) {
+                               spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
+                                             DMA_TO_DEVICE);
+                               return ret;
+                       }
+               }
+       }
+
+       master->cur_msg_mapped = true;
+
+       return 0;
+}
+
+static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
+{
+       struct spi_transfer *xfer;
+       struct device *tx_dev, *rx_dev;
+
+       if (!master->cur_msg_mapped || !master->can_dma)
+               return 0;
+
+       tx_dev = &master->dma_tx->dev->device;
+       rx_dev = &master->dma_rx->dev->device;
+
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               if (!master->can_dma(master, msg->spi, xfer))
+                       continue;
+
+               spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
+               spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+       }
+
+       return 0;
+}
+
 /*
  * spi_transfer_one_message - Default implementation of transfer_one_message()
  *
@@ -591,9 +754,9 @@ static int spi_transfer_one_message(struct spi_master *master,
                                    struct spi_message *msg)
 {
        struct spi_transfer *xfer;
-       bool cur_cs = true;
        bool keep_cs = false;
        int ret = 0;
+       int ms = 1;
 
        spi_set_cs(msg->spi, true);
 
@@ -611,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master,
 
                if (ret > 0) {
                        ret = 0;
-                       wait_for_completion(&master->xfer_completion);
+                       ms = xfer->len * 8 * 1000 / xfer->speed_hz;
+                       ms += 10; /* some tolerance */
+
+                       ms = wait_for_completion_timeout(&master->xfer_completion,
+                                                        msecs_to_jiffies(ms));
+               }
+
+               if (ms == 0) {
+                       dev_err(&msg->spi->dev, "SPI transfer timed out\n");
+                       msg->status = -ETIMEDOUT;
                }
 
                trace_spi_transfer_stop(msg, xfer);
@@ -627,8 +799,9 @@ static int spi_transfer_one_message(struct spi_master *master,
                                         &msg->transfers)) {
                                keep_cs = true;
                        } else {
-                               cur_cs = !cur_cs;
-                               spi_set_cs(msg->spi, cur_cs);
+                               spi_set_cs(msg->spi, false);
+                               udelay(10);
+                               spi_set_cs(msg->spi, true);
                        }
                }
 
@@ -686,6 +859,10 @@ static void spi_pump_messages(struct kthread_work *work)
                }
                master->busy = false;
                spin_unlock_irqrestore(&master->queue_lock, flags);
+               kfree(master->dummy_rx);
+               master->dummy_rx = NULL;
+               kfree(master->dummy_tx);
+               master->dummy_tx = NULL;
                if (master->unprepare_transfer_hardware &&
                    master->unprepare_transfer_hardware(master))
                        dev_err(&master->dev,
@@ -752,6 +929,13 @@ static void spi_pump_messages(struct kthread_work *work)
                master->cur_msg_prepared = true;
        }
 
+       ret = spi_map_msg(master, master->cur_msg);
+       if (ret) {
+               master->cur_msg->status = ret;
+               spi_finalize_current_message(master);
+               return;
+       }
+
        ret = master->transfer_one_message(master, master->cur_msg);
        if (ret) {
                dev_err(&master->dev,
@@ -839,6 +1023,8 @@ void spi_finalize_current_message(struct spi_master *master)
        queue_kthread_work(&master->kworker, &master->pump_messages);
        spin_unlock_irqrestore(&master->queue_lock, flags);
 
+       spi_unmap_msg(master, mesg);
+
        if (master->cur_msg_prepared && master->unprepare_message) {
                ret = master->unprepare_message(master, mesg);
                if (ret) {
@@ -892,7 +1078,7 @@ static int spi_stop_queue(struct spi_master *master)
         */
        while ((!list_empty(&master->queue) || master->busy) && limit--) {
                spin_unlock_irqrestore(&master->queue_lock, flags);
-               msleep(10);
+               usleep_range(10000, 11000);
                spin_lock_irqsave(&master->queue_lock, flags);
        }
 
@@ -1372,6 +1558,8 @@ int spi_register_master(struct spi_master *master)
        mutex_init(&master->bus_lock_mutex);
        master->bus_lock_flag = 0;
        init_completion(&master->xfer_completion);
+       if (!master->max_dma_len)
+               master->max_dma_len = INT_MAX;
 
        /* register the device, then userspace will see it.
         * registration fails if the bus ID is in use.
@@ -1597,6 +1785,9 @@ int spi_setup(struct spi_device *spi)
        if (!spi->bits_per_word)
                spi->bits_per_word = 8;
 
+       if (!spi->max_speed_hz)
+               spi->max_speed_hz = spi->master->max_speed_hz;
+
        if (spi->master->setup)
                status = spi->master->setup(spi);
 
@@ -1617,11 +1808,10 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 {
        struct spi_master *master = spi->master;
        struct spi_transfer *xfer;
+       int w_size;
 
        if (list_empty(&message->transfers))
                return -EINVAL;
-       if (!message->complete)
-               return -EINVAL;
 
        /* Half-duplex links include original MicroWire, and ones with
         * only one data pin like SPI_3WIRE (switches direction) or where
@@ -1652,12 +1842,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
                message->frame_length += xfer->len;
                if (!xfer->bits_per_word)
                        xfer->bits_per_word = spi->bits_per_word;
-               if (!xfer->speed_hz) {
+
+               if (!xfer->speed_hz)
                        xfer->speed_hz = spi->max_speed_hz;
-                       if (master->max_speed_hz &&
-                           xfer->speed_hz > master->max_speed_hz)
-                               xfer->speed_hz = master->max_speed_hz;
-               }
+
+               if (master->max_speed_hz &&
+                   xfer->speed_hz > master->max_speed_hz)
+                       xfer->speed_hz = master->max_speed_hz;
 
                if (master->bits_per_word_mask) {
                        /* Only 32 bits fit in the mask */
@@ -1668,12 +1859,24 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
                                return -EINVAL;
                }
 
+               /*
+                * SPI transfer length should be multiple of SPI word size
+                * where SPI word size should be power-of-two multiple
+                */
+               if (xfer->bits_per_word <= 8)
+                       w_size = 1;
+               else if (xfer->bits_per_word <= 16)
+                       w_size = 2;
+               else
+                       w_size = 4;
+
+               /* No partial transfers accepted */
+               if (xfer->len % w_size)
+                       return -EINVAL;
+
                if (xfer->speed_hz && master->min_speed_hz &&
                    xfer->speed_hz < master->min_speed_hz)
                        return -EINVAL;
-               if (xfer->speed_hz && master->max_speed_hz &&
-                   xfer->speed_hz > master->max_speed_hz)
-                       return -EINVAL;
 
                if (xfer->tx_buf && !xfer->tx_nbits)
                        xfer->tx_nbits = SPI_NBITS_SINGLE;
index d7c6e36021e884727f9bd0a7fc858d83824d441a..e3bc23bb588340f6856efe33e2d26fc4f6156ea4 100644 (file)
@@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
  */
 #define SPI_MODE_MASK          (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
                                | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
-                               | SPI_NO_CS | SPI_READY)
+                               | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
+                               | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
 
 struct spidev_data {
        dev_t                   devt;
@@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev,
                buf += k_tmp->len;
 
                k_tmp->cs_change = !!u_tmp->cs_change;
+               k_tmp->tx_nbits = u_tmp->tx_nbits;
+               k_tmp->rx_nbits = u_tmp->rx_nbits;
                k_tmp->bits_per_word = u_tmp->bits_per_word;
                k_tmp->delay_usecs = u_tmp->delay_usecs;
                k_tmp->speed_hz = u_tmp->speed_hz;
@@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                retval = __put_user(spi->mode & SPI_MODE_MASK,
                                        (__u8 __user *)arg);
                break;
+       case SPI_IOC_RD_MODE32:
+               retval = __put_user(spi->mode & SPI_MODE_MASK,
+                                       (__u32 __user *)arg);
+               break;
        case SPI_IOC_RD_LSB_FIRST:
                retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,
                                        (__u8 __user *)arg);
@@ -372,9 +379,13 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
        /* write requests */
        case SPI_IOC_WR_MODE:
-               retval = __get_user(tmp, (u8 __user *)arg);
+       case SPI_IOC_WR_MODE32:
+               if (cmd == SPI_IOC_WR_MODE)
+                       retval = __get_user(tmp, (u8 __user *)arg);
+               else
+                       retval = __get_user(tmp, (u32 __user *)arg);
                if (retval == 0) {
-                       u     save = spi->mode;
+                       u32     save = spi->mode;
 
                        if (tmp & ~SPI_MODE_MASK) {
                                retval = -EINVAL;
@@ -382,18 +393,18 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                        }
 
                        tmp |= spi->mode & ~SPI_MODE_MASK;
-                       spi->mode = (u8)tmp;
+                       spi->mode = (u16)tmp;
                        retval = spi_setup(spi);
                        if (retval < 0)
                                spi->mode = save;
                        else
-                               dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
+                               dev_dbg(&spi->dev, "spi mode %x\n", tmp);
                }
                break;
        case SPI_IOC_WR_LSB_FIRST:
                retval = __get_user(tmp, (__u8 __user *)arg);
                if (retval == 0) {
-                       u     save = spi->mode;
+                       u32     save = spi->mode;
 
                        if (tmp)
                                spi->mode |= SPI_LSB_FIRST;
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
new file mode 100644 (file)
index 0000000..bf1295e
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# SPMI driver configuration
+#
+menuconfig SPMI
+       tristate "SPMI support"
+       help
+         SPMI (System Power Management Interface) is a two-wire
+         serial interface between baseband and application processors
+         and Power Management Integrated Circuits (PMIC).
+
+if SPMI
+
+config SPMI_MSM_PMIC_ARB
+       tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
+       depends on ARM
+       depends on IRQ_DOMAIN
+       depends on ARCH_QCOM || COMPILE_TEST
+       default ARCH_QCOM
+       help
+         If you say yes to this option, support will be included for the
+         built-in SPMI PMIC Arbiter interface on Qualcomm MSM family
+         processors.
+
+         This is required for communicating with Qualcomm PMICs and
+         other devices that have the SPMI interface.
+
+endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
new file mode 100644 (file)
index 0000000..fc75104
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for kernel SPMI framework.
+#
+obj-$(CONFIG_SPMI)     += spmi.o
+
+obj-$(CONFIG_SPMI_MSM_PMIC_ARB)        += spmi-pmic-arb.o
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
new file mode 100644 (file)
index 0000000..246e03a
--- /dev/null
@@ -0,0 +1,778 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/* PMIC Arbiter configuration registers */
+#define PMIC_ARB_VERSION               0x0000
+#define PMIC_ARB_INT_EN                        0x0004
+
+/* PMIC Arbiter channel registers */
+#define PMIC_ARB_CMD(N)                        (0x0800 + (0x80 * (N)))
+#define PMIC_ARB_CONFIG(N)             (0x0804 + (0x80 * (N)))
+#define PMIC_ARB_STATUS(N)             (0x0808 + (0x80 * (N)))
+#define PMIC_ARB_WDATA0(N)             (0x0810 + (0x80 * (N)))
+#define PMIC_ARB_WDATA1(N)             (0x0814 + (0x80 * (N)))
+#define PMIC_ARB_RDATA0(N)             (0x0818 + (0x80 * (N)))
+#define PMIC_ARB_RDATA1(N)             (0x081C + (0x80 * (N)))
+
+/* Interrupt Controller */
+#define SPMI_PIC_OWNER_ACC_STATUS(M, N)        (0x0000 + ((32 * (M)) + (4 * (N))))
+#define SPMI_PIC_ACC_ENABLE(N)         (0x0200 + (4 * (N)))
+#define SPMI_PIC_IRQ_STATUS(N)         (0x0600 + (4 * (N)))
+#define SPMI_PIC_IRQ_CLEAR(N)          (0x0A00 + (4 * (N)))
+
+/* Mapping Table */
+#define SPMI_MAPPING_TABLE_REG(N)      (0x0B00 + (4 * (N)))
+#define SPMI_MAPPING_BIT_INDEX(X)      (((X) >> 18) & 0xF)
+#define SPMI_MAPPING_BIT_IS_0_FLAG(X)  (((X) >> 17) & 0x1)
+#define SPMI_MAPPING_BIT_IS_0_RESULT(X)        (((X) >> 9) & 0xFF)
+#define SPMI_MAPPING_BIT_IS_1_FLAG(X)  (((X) >> 8) & 0x1)
+#define SPMI_MAPPING_BIT_IS_1_RESULT(X)        (((X) >> 0) & 0xFF)
+
+#define SPMI_MAPPING_TABLE_LEN         255
+#define SPMI_MAPPING_TABLE_TREE_DEPTH  16      /* Maximum of 16-bits */
+
+/* Ownership Table */
+#define SPMI_OWNERSHIP_TABLE_REG(N)    (0x0700 + (4 * (N)))
+#define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
+
+/* Channel Status fields */
+enum pmic_arb_chnl_status {
+       PMIC_ARB_STATUS_DONE    = (1 << 0),
+       PMIC_ARB_STATUS_FAILURE = (1 << 1),
+       PMIC_ARB_STATUS_DENIED  = (1 << 2),
+       PMIC_ARB_STATUS_DROPPED = (1 << 3),
+};
+
+/* Command register fields */
+#define PMIC_ARB_CMD_MAX_BYTE_COUNT    8
+
+/* Command Opcodes */
+enum pmic_arb_cmd_op_code {
+       PMIC_ARB_OP_EXT_WRITEL = 0,
+       PMIC_ARB_OP_EXT_READL = 1,
+       PMIC_ARB_OP_EXT_WRITE = 2,
+       PMIC_ARB_OP_RESET = 3,
+       PMIC_ARB_OP_SLEEP = 4,
+       PMIC_ARB_OP_SHUTDOWN = 5,
+       PMIC_ARB_OP_WAKEUP = 6,
+       PMIC_ARB_OP_AUTHENTICATE = 7,
+       PMIC_ARB_OP_MSTR_READ = 8,
+       PMIC_ARB_OP_MSTR_WRITE = 9,
+       PMIC_ARB_OP_EXT_READ = 13,
+       PMIC_ARB_OP_WRITE = 14,
+       PMIC_ARB_OP_READ = 15,
+       PMIC_ARB_OP_ZERO_WRITE = 16,
+};
+
+/* Maximum number of support PMIC peripherals */
+#define PMIC_ARB_MAX_PERIPHS           256
+#define PMIC_ARB_PERIPH_ID_VALID       (1 << 15)
+#define PMIC_ARB_TIMEOUT_US            100
+#define PMIC_ARB_MAX_TRANS_BYTES       (8)
+
+#define PMIC_ARB_APID_MASK             0xFF
+#define PMIC_ARB_PPID_MASK             0xFFF
+
+/* interrupt enable bit */
+#define SPMI_PIC_ACC_ENABLE_BIT                BIT(0)
+
+/**
+ * spmi_pmic_arb_dev - SPMI PMIC Arbiter object
+ *
+ * @base:              address of the PMIC Arbiter core registers.
+ * @intr:              address of the SPMI interrupt control registers.
+ * @cnfg:              address of the PMIC Arbiter configuration registers.
+ * @lock:              lock to synchronize accesses.
+ * @channel:           which channel to use for accesses.
+ * @irq:               PMIC ARB interrupt.
+ * @ee:                        the current Execution Environment
+ * @min_apid:          minimum APID (used for bounding IRQ search)
+ * @max_apid:          maximum APID
+ * @mapping_table:     in-memory copy of PPID -> APID mapping table.
+ * @domain:            irq domain object for PMIC IRQ domain
+ * @spmic:             SPMI controller object
+ * @apid_to_ppid:      cached mapping from APID to PPID
+ */
+struct spmi_pmic_arb_dev {
+       void __iomem            *base;
+       void __iomem            *intr;
+       void __iomem            *cnfg;
+       raw_spinlock_t          lock;
+       u8                      channel;
+       int                     irq;
+       u8                      ee;
+       u8                      min_apid;
+       u8                      max_apid;
+       u32                     mapping_table[SPMI_MAPPING_TABLE_LEN];
+       struct irq_domain       *domain;
+       struct spmi_controller  *spmic;
+       u16                     apid_to_ppid[256];
+};
+
+static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)
+{
+       return readl_relaxed(dev->base + offset);
+}
+
+static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev,
+                                      u32 offset, u32 val)
+{
+       writel_relaxed(val, dev->base + offset);
+}
+
+/**
+ * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
+ * @bc:                byte count -1. range: 0..3
+ * @reg:       register's address
+ * @buf:       output parameter, length must be bc + 1
+ */
+static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
+{
+       u32 data = pmic_arb_base_read(dev, reg);
+       memcpy(buf, &data, (bc & 3) + 1);
+}
+
+/**
+ * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @bc:                byte-count -1. range: 0..3.
+ * @reg:       register's address.
+ * @buf:       buffer to write. length must be bc + 1.
+ */
+static void
+pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+{
+       u32 data = 0;
+       memcpy(&data, buf, (bc & 3) + 1);
+       pmic_arb_base_write(dev, reg, data);
+}
+
+static int pmic_arb_wait_for_done(struct spmi_controller *ctrl)
+{
+       struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl);
+       u32 status = 0;
+       u32 timeout = PMIC_ARB_TIMEOUT_US;
+       u32 offset = PMIC_ARB_STATUS(dev->channel);
+
+       while (timeout--) {
+               status = pmic_arb_base_read(dev, offset);
+
+               if (status & PMIC_ARB_STATUS_DONE) {
+                       if (status & PMIC_ARB_STATUS_DENIED) {
+                               dev_err(&ctrl->dev,
+                                       "%s: transaction denied (0x%x)\n",
+                                       __func__, status);
+                               return -EPERM;
+                       }
+
+                       if (status & PMIC_ARB_STATUS_FAILURE) {
+                               dev_err(&ctrl->dev,
+                                       "%s: transaction failed (0x%x)\n",
+                                       __func__, status);
+                               return -EIO;
+                       }
+
+                       if (status & PMIC_ARB_STATUS_DROPPED) {
+                               dev_err(&ctrl->dev,
+                                       "%s: transaction dropped (0x%x)\n",
+                                       __func__, status);
+                               return -EIO;
+                       }
+
+                       return 0;
+               }
+               udelay(1);
+       }
+
+       dev_err(&ctrl->dev,
+               "%s: timeout, status 0x%x\n",
+               __func__, status);
+       return -ETIMEDOUT;
+}
+
+/* Non-data command */
+static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
+{
+       struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+       unsigned long flags;
+       u32 cmd;
+       int rc;
+
+       /* Check for valid non-data command */
+       if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
+               return -EINVAL;
+
+       cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
+
+       raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+       pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+       rc = pmic_arb_wait_for_done(ctrl);
+       raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+
+       return rc;
+}
+
+static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+                            u16 addr, u8 *buf, size_t len)
+{
+       struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+       unsigned long flags;
+       u8 bc = len - 1;
+       u32 cmd;
+       int rc;
+
+       if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+               dev_err(&ctrl->dev,
+                       "pmic-arb supports 1..%d bytes per trans, but %d requested",
+                       PMIC_ARB_MAX_TRANS_BYTES, len);
+               return  -EINVAL;
+       }
+
+       /* Check the opcode */
+       if (opc >= 0x60 && opc <= 0x7F)
+               opc = PMIC_ARB_OP_READ;
+       else if (opc >= 0x20 && opc <= 0x2F)
+               opc = PMIC_ARB_OP_EXT_READ;
+       else if (opc >= 0x38 && opc <= 0x3F)
+               opc = PMIC_ARB_OP_EXT_READL;
+       else
+               return -EINVAL;
+
+       cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
+
+       raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+       pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+       rc = pmic_arb_wait_for_done(ctrl);
+       if (rc)
+               goto done;
+
+       pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel),
+                    min_t(u8, bc, 3));
+
+       if (bc > 3)
+               pa_read_data(pmic_arb, buf + 4,
+                               PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4);
+
+done:
+       raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+       return rc;
+}
+
+static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+                             u16 addr, const u8 *buf, size_t len)
+{
+       struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+       unsigned long flags;
+       u8 bc = len - 1;
+       u32 cmd;
+       int rc;
+
+       if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+               dev_err(&ctrl->dev,
+                       "pmic-arb supports 1..%d bytes per trans, but:%d requested",
+                       PMIC_ARB_MAX_TRANS_BYTES, len);
+               return  -EINVAL;
+       }
+
+       /* Check the opcode */
+       if (opc >= 0x40 && opc <= 0x5F)
+               opc = PMIC_ARB_OP_WRITE;
+       else if (opc >= 0x00 && opc <= 0x0F)
+               opc = PMIC_ARB_OP_EXT_WRITE;
+       else if (opc >= 0x30 && opc <= 0x37)
+               opc = PMIC_ARB_OP_EXT_WRITEL;
+       else if (opc >= 0x80 && opc <= 0xFF)
+               opc = PMIC_ARB_OP_ZERO_WRITE;
+       else
+               return -EINVAL;
+
+       cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
+
+       /* Write data to FIFOs */
+       raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+       pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel)
+                                                       , min_t(u8, bc, 3));
+       if (bc > 3)
+               pa_write_data(pmic_arb, buf + 4,
+                               PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4);
+
+       /* Start the transaction */
+       pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+       rc = pmic_arb_wait_for_done(ctrl);
+       raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+
+       return rc;
+}
+
+enum qpnpint_regs {
+       QPNPINT_REG_RT_STS              = 0x10,
+       QPNPINT_REG_SET_TYPE            = 0x11,
+       QPNPINT_REG_POLARITY_HIGH       = 0x12,
+       QPNPINT_REG_POLARITY_LOW        = 0x13,
+       QPNPINT_REG_LATCHED_CLR         = 0x14,
+       QPNPINT_REG_EN_SET              = 0x15,
+       QPNPINT_REG_EN_CLR              = 0x16,
+       QPNPINT_REG_LATCHED_STS         = 0x18,
+};
+
+struct spmi_pmic_arb_qpnpint_type {
+       u8 type; /* 1 -> edge */
+       u8 polarity_high;
+       u8 polarity_low;
+} __packed;
+
+/* Simplified accessor functions for irqchip callbacks */
+static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
+                              size_t len)
+{
+       struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+       u8 sid = d->hwirq >> 24;
+       u8 per = d->hwirq >> 16;
+
+       if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+                              (per << 8) + reg, buf, len))
+               dev_err_ratelimited(&pa->spmic->dev,
+                               "failed irqchip transaction on %x\n",
+                                   d->irq);
+}
+
+static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
+{
+       struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+       u8 sid = d->hwirq >> 24;
+       u8 per = d->hwirq >> 16;
+
+       if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid,
+                             (per << 8) + reg, buf, len))
+               dev_err_ratelimited(&pa->spmic->dev,
+                               "failed irqchip transaction on %x\n",
+                                   d->irq);
+}
+
+static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
+{
+       unsigned int irq;
+       u32 status;
+       int id;
+
+       status = readl_relaxed(pa->intr + SPMI_PIC_IRQ_STATUS(apid));
+       while (status) {
+               id = ffs(status) - 1;
+               status &= ~(1 << id);
+               irq = irq_find_mapping(pa->domain,
+                                      pa->apid_to_ppid[apid] << 16
+                                    | id << 8
+                                    | apid);
+               generic_handle_irq(irq);
+       }
+}
+
+static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq);
+       struct irq_chip *chip = irq_get_chip(irq);
+       void __iomem *intr = pa->intr;
+       int first = pa->min_apid >> 5;
+       int last = pa->max_apid >> 5;
+       u32 status;
+       int i, id;
+
+       chained_irq_enter(chip, desc);
+
+       for (i = first; i <= last; ++i) {
+               status = readl_relaxed(intr +
+                                      SPMI_PIC_OWNER_ACC_STATUS(pa->ee, i));
+               while (status) {
+                       id = ffs(status) - 1;
+                       status &= ~(1 << id);
+                       periph_interrupt(pa, id + i * 32);
+               }
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void qpnpint_irq_ack(struct irq_data *d)
+{
+       struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+       u8 irq  = d->hwirq >> 8;
+       u8 apid = d->hwirq;
+       unsigned long flags;
+       u8 data;
+
+       raw_spin_lock_irqsave(&pa->lock, flags);
+       writel_relaxed(1 << irq, pa->intr + SPMI_PIC_IRQ_CLEAR(apid));
+       raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+       data = 1 << irq;
+       qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
+}
+
+static void qpnpint_irq_mask(struct irq_data *d)
+{
+       struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+       u8 irq  = d->hwirq >> 8;
+       u8 apid = d->hwirq;
+       unsigned long flags;
+       u32 status;
+       u8 data;
+
+       raw_spin_lock_irqsave(&pa->lock, flags);
+       status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+       if (status & SPMI_PIC_ACC_ENABLE_BIT) {
+               status = status & ~SPMI_PIC_ACC_ENABLE_BIT;
+               writel_relaxed(status, pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+       }
+       raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+       data = 1 << irq;
+       qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
+}
+
+static void qpnpint_irq_unmask(struct irq_data *d)
+{
+       struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+       u8 irq  = d->hwirq >> 8;
+       u8 apid = d->hwirq;
+       unsigned long flags;
+       u32 status;
+       u8 data;
+
+       raw_spin_lock_irqsave(&pa->lock, flags);
+       status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+       if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
+               writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT,
+                               pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+       }
+       raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+       data = 1 << irq;
+       qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
+}
+
+static void qpnpint_irq_enable(struct irq_data *d)
+{
+       u8 irq  = d->hwirq >> 8;
+       u8 data;
+
+       qpnpint_irq_unmask(d);
+
+       data = 1 << irq;
+       qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
+}
+
+static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       struct spmi_pmic_arb_qpnpint_type type;
+       u8 irq = d->hwirq >> 8;
+
+       qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+
+       if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+               type.type |= 1 << irq;
+               if (flow_type & IRQF_TRIGGER_RISING)
+                       type.polarity_high |= 1 << irq;
+               if (flow_type & IRQF_TRIGGER_FALLING)
+                       type.polarity_low  |= 1 << irq;
+       } else {
+               if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
+                   (flow_type & (IRQF_TRIGGER_LOW)))
+                       return -EINVAL;
+
+               type.type &= ~(1 << irq); /* level trig */
+               if (flow_type & IRQF_TRIGGER_HIGH)
+                       type.polarity_high |= 1 << irq;
+               else
+                       type.polarity_low  |= 1 << irq;
+       }
+
+       qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+       return 0;
+}
+
+static struct irq_chip pmic_arb_irqchip = {
+       .name           = "pmic_arb",
+       .irq_enable     = qpnpint_irq_enable,
+       .irq_ack        = qpnpint_irq_ack,
+       .irq_mask       = qpnpint_irq_mask,
+       .irq_unmask     = qpnpint_irq_unmask,
+       .irq_set_type   = qpnpint_irq_set_type,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND
+                       | IRQCHIP_SKIP_SET_WAKE,
+};
+
+struct spmi_pmic_arb_irq_spec {
+       unsigned slave:4;
+       unsigned per:8;
+       unsigned irq:3;
+};
+
+static int search_mapping_table(struct spmi_pmic_arb_dev *pa,
+                               struct spmi_pmic_arb_irq_spec *spec,
+                               u8 *apid)
+{
+       u16 ppid = spec->slave << 8 | spec->per;
+       u32 *mapping_table = pa->mapping_table;
+       int index = 0, i;
+       u32 data;
+
+       for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+               data = mapping_table[index];
+
+               if (ppid & (1 << SPMI_MAPPING_BIT_INDEX(data))) {
+                       if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
+                               index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+                       } else {
+                               *apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+                               return 0;
+                       }
+               } else {
+                       if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
+                               index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+                       } else {
+                               *apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+                               return 0;
+                       }
+               }
+       }
+
+       return -ENODEV;
+}
+
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+                                          struct device_node *controller,
+                                          const u32 *intspec,
+                                          unsigned int intsize,
+                                          unsigned long *out_hwirq,
+                                          unsigned int *out_type)
+{
+       struct spmi_pmic_arb_dev *pa = d->host_data;
+       struct spmi_pmic_arb_irq_spec spec;
+       int err;
+       u8 apid;
+
+       dev_dbg(&pa->spmic->dev,
+               "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
+               intspec[0], intspec[1], intspec[2]);
+
+       if (d->of_node != controller)
+               return -EINVAL;
+       if (intsize != 4)
+               return -EINVAL;
+       if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
+               return -EINVAL;
+
+       spec.slave = intspec[0];
+       spec.per   = intspec[1];
+       spec.irq   = intspec[2];
+
+       err = search_mapping_table(pa, &spec, &apid);
+       if (err)
+               return err;
+
+       pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+
+       /* Keep track of {max,min}_apid for bounding search during interrupt */
+       if (apid > pa->max_apid)
+               pa->max_apid = apid;
+       if (apid < pa->min_apid)
+               pa->min_apid = apid;
+
+       *out_hwirq = spec.slave << 24
+                  | spec.per   << 16
+                  | spec.irq   << 8
+                  | apid;
+       *out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
+
+       dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
+
+       return 0;
+}
+
+static int qpnpint_irq_domain_map(struct irq_domain *d,
+                                 unsigned int virq,
+                                 irq_hw_number_t hwirq)
+{
+       struct spmi_pmic_arb_dev *pa = d->host_data;
+
+       dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq);
+
+       irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq);
+       irq_set_chip_data(virq, d->host_data);
+       irq_set_noprobe(virq);
+       return 0;
+}
+
+static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
+       .map    = qpnpint_irq_domain_map,
+       .xlate  = qpnpint_irq_domain_dt_translate,
+};
+
+static int spmi_pmic_arb_probe(struct platform_device *pdev)
+{
+       struct spmi_pmic_arb_dev *pa;
+       struct spmi_controller *ctrl;
+       struct resource *res;
+       u32 channel, ee;
+       int err, i;
+
+       ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
+       if (!ctrl)
+               return -ENOMEM;
+
+       pa = spmi_controller_get_drvdata(ctrl);
+       pa->spmic = ctrl;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+       pa->base = devm_ioremap_resource(&ctrl->dev, res);
+       if (IS_ERR(pa->base)) {
+               err = PTR_ERR(pa->base);
+               goto err_put_ctrl;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
+       pa->intr = devm_ioremap_resource(&ctrl->dev, res);
+       if (IS_ERR(pa->intr)) {
+               err = PTR_ERR(pa->intr);
+               goto err_put_ctrl;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
+       pa->cnfg = devm_ioremap_resource(&ctrl->dev, res);
+       if (IS_ERR(pa->cnfg)) {
+               err = PTR_ERR(pa->cnfg);
+               goto err_put_ctrl;
+       }
+
+       pa->irq = platform_get_irq_byname(pdev, "periph_irq");
+       if (pa->irq < 0) {
+               err = pa->irq;
+               goto err_put_ctrl;
+       }
+
+       err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
+       if (err) {
+               dev_err(&pdev->dev, "channel unspecified.\n");
+               goto err_put_ctrl;
+       }
+
+       if (channel > 5) {
+               dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
+                       channel);
+               goto err_put_ctrl;
+       }
+
+       pa->channel = channel;
+
+       err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee);
+       if (err) {
+               dev_err(&pdev->dev, "EE unspecified.\n");
+               goto err_put_ctrl;
+       }
+
+       if (ee > 5) {
+               dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee);
+               err = -EINVAL;
+               goto err_put_ctrl;
+       }
+
+       pa->ee = ee;
+
+       for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
+               pa->mapping_table[i] = readl_relaxed(
+                               pa->cnfg + SPMI_MAPPING_TABLE_REG(i));
+
+       /* Initialize max_apid/min_apid to the opposite bounds, during
+        * the irq domain translation, we are sure to update these */
+       pa->max_apid = 0;
+       pa->min_apid = PMIC_ARB_MAX_PERIPHS - 1;
+
+       platform_set_drvdata(pdev, ctrl);
+       raw_spin_lock_init(&pa->lock);
+
+       ctrl->cmd = pmic_arb_cmd;
+       ctrl->read_cmd = pmic_arb_read_cmd;
+       ctrl->write_cmd = pmic_arb_write_cmd;
+
+       dev_dbg(&pdev->dev, "adding irq domain\n");
+       pa->domain = irq_domain_add_tree(pdev->dev.of_node,
+                                        &pmic_arb_irq_domain_ops, pa);
+       if (!pa->domain) {
+               dev_err(&pdev->dev, "unable to create irq_domain\n");
+               err = -ENOMEM;
+               goto err_put_ctrl;
+       }
+
+       irq_set_handler_data(pa->irq, pa);
+       irq_set_chained_handler(pa->irq, pmic_arb_chained_irq);
+
+       err = spmi_controller_add(ctrl);
+       if (err)
+               goto err_domain_remove;
+
+       dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n",
+               pmic_arb_base_read(pa, PMIC_ARB_VERSION));
+
+       return 0;
+
+err_domain_remove:
+       irq_set_chained_handler(pa->irq, NULL);
+       irq_set_handler_data(pa->irq, NULL);
+       irq_domain_remove(pa->domain);
+err_put_ctrl:
+       spmi_controller_put(ctrl);
+       return err;
+}
+
+static int spmi_pmic_arb_remove(struct platform_device *pdev)
+{
+       struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+       struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl);
+       spmi_controller_remove(ctrl);
+       irq_set_chained_handler(pa->irq, NULL);
+       irq_set_handler_data(pa->irq, NULL);
+       irq_domain_remove(pa->domain);
+       spmi_controller_put(ctrl);
+       return 0;
+}
+
+static const struct of_device_id spmi_pmic_arb_match_table[] = {
+       { .compatible = "qcom,spmi-pmic-arb", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
+
+static struct platform_driver spmi_pmic_arb_driver = {
+       .probe          = spmi_pmic_arb_probe,
+       .remove         = spmi_pmic_arb_remove,
+       .driver         = {
+               .name   = "spmi_pmic_arb",
+               .owner  = THIS_MODULE,
+               .of_match_table = spmi_pmic_arb_match_table,
+       },
+};
+module_platform_driver(spmi_pmic_arb_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spmi_pmic_arb");
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
new file mode 100644 (file)
index 0000000..3b57807
--- /dev/null
@@ -0,0 +1,574 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/spmi/spmi.h>
+
+static DEFINE_IDA(ctrl_ida);
+
+static void spmi_dev_release(struct device *dev)
+{
+       struct spmi_device *sdev = to_spmi_device(dev);
+       kfree(sdev);
+}
+
+static const struct device_type spmi_dev_type = {
+       .release        = spmi_dev_release,
+};
+
+static void spmi_ctrl_release(struct device *dev)
+{
+       struct spmi_controller *ctrl = to_spmi_controller(dev);
+       ida_simple_remove(&ctrl_ida, ctrl->nr);
+       kfree(ctrl);
+}
+
+static const struct device_type spmi_ctrl_type = {
+       .release        = spmi_ctrl_release,
+};
+
+static int spmi_device_match(struct device *dev, struct device_driver *drv)
+{
+       if (of_driver_match_device(dev, drv))
+               return 1;
+
+       if (drv->name)
+               return strncmp(dev_name(dev), drv->name,
+                              SPMI_NAME_SIZE) == 0;
+
+       return 0;
+}
+
+/**
+ * spmi_device_add() - add a device previously constructed via spmi_device_alloc()
+ * @sdev:      spmi_device to be added
+ */
+int spmi_device_add(struct spmi_device *sdev)
+{
+       struct spmi_controller *ctrl = sdev->ctrl;
+       int err;
+
+       dev_set_name(&sdev->dev, "%d-%02x", ctrl->nr, sdev->usid);
+
+       err = device_add(&sdev->dev);
+       if (err < 0) {
+               dev_err(&sdev->dev, "Can't add %s, status %d\n",
+                       dev_name(&sdev->dev), err);
+               goto err_device_add;
+       }
+
+       dev_dbg(&sdev->dev, "device %s registered\n", dev_name(&sdev->dev));
+
+err_device_add:
+       return err;
+}
+EXPORT_SYMBOL_GPL(spmi_device_add);
+
+/**
+ * spmi_device_remove(): remove an SPMI device
+ * @sdev:      spmi_device to be removed
+ */
+void spmi_device_remove(struct spmi_device *sdev)
+{
+       device_unregister(&sdev->dev);
+}
+EXPORT_SYMBOL_GPL(spmi_device_remove);
+
+static inline int
+spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid)
+{
+       if (!ctrl || !ctrl->cmd || ctrl->dev.type != &spmi_ctrl_type)
+               return -EINVAL;
+
+       return ctrl->cmd(ctrl, opcode, sid);
+}
+
+static inline int spmi_read_cmd(struct spmi_controller *ctrl, u8 opcode,
+                               u8 sid, u16 addr, u8 *buf, size_t len)
+{
+       if (!ctrl || !ctrl->read_cmd || ctrl->dev.type != &spmi_ctrl_type)
+               return -EINVAL;
+
+       return ctrl->read_cmd(ctrl, opcode, sid, addr, buf, len);
+}
+
+static inline int spmi_write_cmd(struct spmi_controller *ctrl, u8 opcode,
+                                u8 sid, u16 addr, const u8 *buf, size_t len)
+{
+       if (!ctrl || !ctrl->write_cmd || ctrl->dev.type != &spmi_ctrl_type)
+               return -EINVAL;
+
+       return ctrl->write_cmd(ctrl, opcode, sid, addr, buf, len);
+}
+
+/**
+ * spmi_register_read() - register read
+ * @sdev:      SPMI device.
+ * @addr:      slave register address (5-bit address).
+ * @buf:       buffer to be populated with data from the Slave.
+ *
+ * Reads 1 byte of data from a Slave device register.
+ */
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf)
+{
+       /* 5-bit register address */
+       if (addr > 0x1F)
+               return -EINVAL;
+
+       return spmi_read_cmd(sdev->ctrl, SPMI_CMD_READ, sdev->usid, addr,
+                            buf, 1);
+}
+EXPORT_SYMBOL_GPL(spmi_register_read);
+
+/**
+ * spmi_ext_register_read() - extended register read
+ * @sdev:      SPMI device.
+ * @addr:      slave register address (8-bit address).
+ * @buf:       buffer to be populated with data from the Slave.
+ * @len:       the request number of bytes to read (up to 16 bytes).
+ *
+ * Reads up to 16 bytes of data from the extended register space on a
+ * Slave device.
+ */
+int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf,
+                          size_t len)
+{
+       /* 8-bit register address, up to 16 bytes */
+       if (len == 0 || len > 16)
+               return -EINVAL;
+
+       return spmi_read_cmd(sdev->ctrl, SPMI_CMD_EXT_READ, sdev->usid, addr,
+                            buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_read);
+
+/**
+ * spmi_ext_register_readl() - extended register read long
+ * @sdev:      SPMI device.
+ * @addr:      slave register address (16-bit address).
+ * @buf:       buffer to be populated with data from the Slave.
+ * @len:       the request number of bytes to read (up to 8 bytes).
+ *
+ * Reads up to 8 bytes of data from the extended register space on a
+ * Slave device using 16-bit address.
+ */
+int spmi_ext_register_readl(struct spmi_device *sdev, u16 addr, u8 *buf,
+                           size_t len)
+{
+       /* 16-bit register address, up to 8 bytes */
+       if (len == 0 || len > 8)
+               return -EINVAL;
+
+       return spmi_read_cmd(sdev->ctrl, SPMI_CMD_EXT_READL, sdev->usid, addr,
+                            buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_readl);
+
+/**
+ * spmi_register_write() - register write
+ * @sdev:      SPMI device
+ * @addr:      slave register address (5-bit address).
+ * @data:      buffer containing the data to be transferred to the Slave.
+ *
+ * Writes 1 byte of data to a Slave device register.
+ */
+int spmi_register_write(struct spmi_device *sdev, u8 addr, u8 data)
+{
+       /* 5-bit register address */
+       if (addr > 0x1F)
+               return -EINVAL;
+
+       return spmi_write_cmd(sdev->ctrl, SPMI_CMD_WRITE, sdev->usid, addr,
+                             &data, 1);
+}
+EXPORT_SYMBOL_GPL(spmi_register_write);
+
+/**
+ * spmi_register_zero_write() - register zero write
+ * @sdev:      SPMI device.
+ * @data:      the data to be written to register 0 (7-bits).
+ *
+ * Writes data to register 0 of the Slave device.
+ */
+int spmi_register_zero_write(struct spmi_device *sdev, u8 data)
+{
+       return spmi_write_cmd(sdev->ctrl, SPMI_CMD_ZERO_WRITE, sdev->usid, 0,
+                             &data, 1);
+}
+EXPORT_SYMBOL_GPL(spmi_register_zero_write);
+
+/**
+ * spmi_ext_register_write() - extended register write
+ * @sdev:      SPMI device.
+ * @addr:      slave register address (8-bit address).
+ * @buf:       buffer containing the data to be transferred to the Slave.
+ * @len:       the request number of bytes to read (up to 16 bytes).
+ *
+ * Writes up to 16 bytes of data to the extended register space of a
+ * Slave device.
+ */
+int spmi_ext_register_write(struct spmi_device *sdev, u8 addr, const u8 *buf,
+                           size_t len)
+{
+       /* 8-bit register address, up to 16 bytes */
+       if (len == 0 || len > 16)
+               return -EINVAL;
+
+       return spmi_write_cmd(sdev->ctrl, SPMI_CMD_EXT_WRITE, sdev->usid, addr,
+                             buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_write);
+
+/**
+ * spmi_ext_register_writel() - extended register write long
+ * @sdev:      SPMI device.
+ * @addr:      slave register address (16-bit address).
+ * @buf:       buffer containing the data to be transferred to the Slave.
+ * @len:       the request number of bytes to read (up to 8 bytes).
+ *
+ * Writes up to 8 bytes of data to the extended register space of a
+ * Slave device using 16-bit address.
+ */
+int spmi_ext_register_writel(struct spmi_device *sdev, u16 addr, const u8 *buf,
+                            size_t len)
+{
+       /* 4-bit Slave Identifier, 16-bit register address, up to 8 bytes */
+       if (len == 0 || len > 8)
+               return -EINVAL;
+
+       return spmi_write_cmd(sdev->ctrl, SPMI_CMD_EXT_WRITEL, sdev->usid,
+                             addr, buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_writel);
+
+/**
+ * spmi_command_reset() - sends RESET command to the specified slave
+ * @sdev:      SPMI device.
+ *
+ * The Reset command initializes the Slave and forces all registers to
+ * their reset values. The Slave shall enter the STARTUP state after
+ * receiving a Reset command.
+ */
+int spmi_command_reset(struct spmi_device *sdev)
+{
+       return spmi_cmd(sdev->ctrl, SPMI_CMD_RESET, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_reset);
+
+/**
+ * spmi_command_sleep() - sends SLEEP command to the specified SPMI device
+ * @sdev:      SPMI device.
+ *
+ * The Sleep command causes the Slave to enter the user defined SLEEP state.
+ */
+int spmi_command_sleep(struct spmi_device *sdev)
+{
+       return spmi_cmd(sdev->ctrl, SPMI_CMD_SLEEP, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_sleep);
+
+/**
+ * spmi_command_wakeup() - sends WAKEUP command to the specified SPMI device
+ * @sdev:      SPMI device.
+ *
+ * The Wakeup command causes the Slave to move from the SLEEP state to
+ * the ACTIVE state.
+ */
+int spmi_command_wakeup(struct spmi_device *sdev)
+{
+       return spmi_cmd(sdev->ctrl, SPMI_CMD_WAKEUP, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_wakeup);
+
+/**
+ * spmi_command_shutdown() - sends SHUTDOWN command to the specified SPMI device
+ * @sdev:      SPMI device.
+ *
+ * The Shutdown command causes the Slave to enter the SHUTDOWN state.
+ */
+int spmi_command_shutdown(struct spmi_device *sdev)
+{
+       return spmi_cmd(sdev->ctrl, SPMI_CMD_SHUTDOWN, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_shutdown);
+
+static int spmi_drv_probe(struct device *dev)
+{
+       const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+       struct spmi_device *sdev = to_spmi_device(dev);
+       int err;
+
+       /* Ensure the slave is in ACTIVE state */
+       err = spmi_command_wakeup(sdev);
+       if (err)
+               goto fail_wakeup;
+
+       pm_runtime_get_noresume(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       err = sdrv->probe(sdev);
+       if (err)
+               goto fail_probe;
+
+       return 0;
+
+fail_probe:
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_put_noidle(dev);
+fail_wakeup:
+       return err;
+}
+
+static int spmi_drv_remove(struct device *dev)
+{
+       const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+
+       pm_runtime_get_sync(dev);
+       sdrv->remove(to_spmi_device(dev));
+       pm_runtime_put_noidle(dev);
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_put_noidle(dev);
+       return 0;
+}
+
+static struct bus_type spmi_bus_type = {
+       .name           = "spmi",
+       .match          = spmi_device_match,
+       .probe          = spmi_drv_probe,
+       .remove         = spmi_drv_remove,
+};
+
+/**
+ * spmi_controller_alloc() - Allocate a new SPMI device
+ * @ctrl:      associated controller
+ *
+ * Caller is responsible for either calling spmi_device_add() to add the
+ * newly allocated controller, or calling spmi_device_put() to discard it.
+ */
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl)
+{
+       struct spmi_device *sdev;
+
+       sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+       if (!sdev)
+               return NULL;
+
+       sdev->ctrl = ctrl;
+       device_initialize(&sdev->dev);
+       sdev->dev.parent = &ctrl->dev;
+       sdev->dev.bus = &spmi_bus_type;
+       sdev->dev.type = &spmi_dev_type;
+       return sdev;
+}
+EXPORT_SYMBOL_GPL(spmi_device_alloc);
+
+/**
+ * spmi_controller_alloc() - Allocate a new SPMI controller
+ * @parent:    parent device
+ * @size:      size of private data
+ *
+ * Caller is responsible for either calling spmi_controller_add() to add the
+ * newly allocated controller, or calling spmi_controller_put() to discard it.
+ * The allocated private data region may be accessed via
+ * spmi_controller_get_drvdata()
+ */
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+                                             size_t size)
+{
+       struct spmi_controller *ctrl;
+       int id;
+
+       if (WARN_ON(!parent))
+               return NULL;
+
+       ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
+       if (!ctrl)
+               return NULL;
+
+       device_initialize(&ctrl->dev);
+       ctrl->dev.type = &spmi_ctrl_type;
+       ctrl->dev.bus = &spmi_bus_type;
+       ctrl->dev.parent = parent;
+       ctrl->dev.of_node = parent->of_node;
+       spmi_controller_set_drvdata(ctrl, &ctrl[1]);
+
+       id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
+       if (id < 0) {
+               dev_err(parent,
+                       "unable to allocate SPMI controller identifier.\n");
+               spmi_controller_put(ctrl);
+               return NULL;
+       }
+
+       ctrl->nr = id;
+       dev_set_name(&ctrl->dev, "spmi-%d", id);
+
+       dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);
+       return ctrl;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_alloc);
+
+static void of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+       struct device_node *node;
+       int err;
+
+       if (!ctrl->dev.of_node)
+               return;
+
+       for_each_available_child_of_node(ctrl->dev.of_node, node) {
+               struct spmi_device *sdev;
+               u32 reg[2];
+
+               dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
+               err = of_property_read_u32_array(node, "reg", reg, 2);
+               if (err) {
+                       dev_err(&ctrl->dev,
+                               "node %s err (%d) does not have 'reg' property\n",
+                               node->full_name, err);
+                       continue;
+               }
+
+               if (reg[1] != SPMI_USID) {
+                       dev_err(&ctrl->dev,
+                               "node %s contains unsupported 'reg' entry\n",
+                               node->full_name);
+                       continue;
+               }
+
+               if (reg[0] >= SPMI_MAX_SLAVE_ID) {
+                       dev_err(&ctrl->dev,
+                               "invalid usid on node %s\n",
+                               node->full_name);
+                       continue;
+               }
+
+               dev_dbg(&ctrl->dev, "read usid %02x\n", reg[0]);
+
+               sdev = spmi_device_alloc(ctrl);
+               if (!sdev)
+                       continue;
+
+               sdev->dev.of_node = node;
+               sdev->usid = (u8) reg[0];
+
+               err = spmi_device_add(sdev);
+               if (err) {
+                       dev_err(&sdev->dev,
+                               "failure adding device. status %d\n", err);
+                       spmi_device_put(sdev);
+               }
+       }
+}
+
+/**
+ * spmi_controller_add() - Add an SPMI controller
+ * @ctrl:      controller to be registered.
+ *
+ * Register a controller previously allocated via spmi_controller_alloc() with
+ * the SPMI core.
+ */
+int spmi_controller_add(struct spmi_controller *ctrl)
+{
+       int ret;
+
+       /* Can't register until after driver model init */
+       if (WARN_ON(!spmi_bus_type.p))
+               return -EAGAIN;
+
+       ret = device_add(&ctrl->dev);
+       if (ret)
+               return ret;
+
+       if (IS_ENABLED(CONFIG_OF))
+               of_spmi_register_devices(ctrl);
+
+       dev_dbg(&ctrl->dev, "spmi-%d registered: dev:%p\n",
+               ctrl->nr, &ctrl->dev);
+
+       return 0;
+};
+EXPORT_SYMBOL_GPL(spmi_controller_add);
+
+/* Remove a device associated with a controller */
+static int spmi_ctrl_remove_device(struct device *dev, void *data)
+{
+       struct spmi_device *spmidev = to_spmi_device(dev);
+       if (dev->type == &spmi_dev_type)
+               spmi_device_remove(spmidev);
+       return 0;
+}
+
+/**
+ * spmi_controller_remove(): remove an SPMI controller
+ * @ctrl:      controller to remove
+ *
+ * Remove a SPMI controller.  Caller is responsible for calling
+ * spmi_controller_put() to discard the allocated controller.
+ */
+void spmi_controller_remove(struct spmi_controller *ctrl)
+{
+       int dummy;
+
+       if (!ctrl)
+               return;
+
+       dummy = device_for_each_child(&ctrl->dev, NULL,
+                                     spmi_ctrl_remove_device);
+       device_del(&ctrl->dev);
+}
+EXPORT_SYMBOL_GPL(spmi_controller_remove);
+
+/**
+ * spmi_driver_register() - Register client driver with SPMI core
+ * @sdrv:      client driver to be associated with client-device.
+ *
+ * This API will register the client driver with the SPMI framework.
+ * It is typically called from the driver's module-init function.
+ */
+int spmi_driver_register(struct spmi_driver *sdrv)
+{
+       sdrv->driver.bus = &spmi_bus_type;
+       return driver_register(&sdrv->driver);
+}
+EXPORT_SYMBOL_GPL(spmi_driver_register);
+
+static void __exit spmi_exit(void)
+{
+       bus_unregister(&spmi_bus_type);
+}
+module_exit(spmi_exit);
+
+static int __init spmi_init(void)
+{
+       return bus_register(&spmi_bus_type);
+}
+postcore_initcall(spmi_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SPMI module");
+MODULE_ALIAS("platform:spmi");
index 4a08e16e42f719470cd9a0b63de557d2b3ff704b..79206cb3fb946e785021607c7b12474bff9d73a5 100644 (file)
@@ -866,6 +866,8 @@ c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd)
             _IOC_SIZE (iocmd));
 #endif
     iolen = _IOC_SIZE (iocmd);
+    if (iolen > sizeof(arg))
+        return -EFAULT;
     data = ifr->ifr_data + sizeof (iocmd);
     if (copy_from_user (&arg, data, iolen))
         return -EFAULT;
index 8af136e9c9dc16e1ab5f5f5cecf7dfe1579c528b..b22142ee52625c8bce4130b24cf0e9046544a050 100644 (file)
@@ -2036,6 +2036,13 @@ static void fwserial_auto_connect(struct work_struct *work)
                schedule_delayed_work(&peer->connect, CONNECT_RETRY_DELAY);
 }
 
+static void fwserial_peer_workfn(struct work_struct *work)
+{
+       struct fwtty_peer *peer = to_peer(work, work);
+
+       peer->workfn(work);
+}
+
 /**
  * fwserial_add_peer - add a newly probed 'serial' unit device as a 'peer'
  * @serial: aggregate representing the specific fw_card to add the peer to
@@ -2100,7 +2107,7 @@ static int fwserial_add_peer(struct fw_serial *serial, struct fw_unit *unit)
        peer->port = NULL;
 
        init_timer(&peer->timer);
-       INIT_WORK(&peer->work, NULL);
+       INIT_WORK(&peer->work, fwserial_peer_workfn);
        INIT_DELAYED_WORK(&peer->connect, fwserial_auto_connect);
 
        /* associate peer with specific fw_card */
@@ -2702,7 +2709,7 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer,
 
                } else {
                        peer->work_params.plug_req = pkt->plug_req;
-                       PREPARE_WORK(&peer->work, fwserial_handle_plug_req);
+                       peer->workfn = fwserial_handle_plug_req;
                        queue_work(system_unbound_wq, &peer->work);
                }
                break;
@@ -2731,7 +2738,7 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer,
                        fwtty_err(&peer->unit, "unplug req: busy\n");
                        rcode = RCODE_CONFLICT_ERROR;
                } else {
-                       PREPARE_WORK(&peer->work, fwserial_handle_unplug_req);
+                       peer->workfn = fwserial_handle_unplug_req;
                        queue_work(system_unbound_wq, &peer->work);
                }
                break;
index 54f7f9b9b2123a120a48595a878723b5d89d465e..98b853d4acbcf16181984bf3f529c24f4bab3a1c 100644 (file)
@@ -91,6 +91,7 @@ struct fwtty_peer {
        struct rcu_head         rcu;
 
        spinlock_t              lock;
+       work_func_t             workfn;
        struct work_struct      work;
        struct peer_work_params work_params;
        struct timer_list       timer;
index a92e21f7d55b83bb1b537e48259b1202271699fa..171d80c1b02071fdadc2e7111e34b0cde49565a6 100644 (file)
@@ -24,8 +24,9 @@ int line6_init_audio(struct usb_line6 *line6)
        struct snd_card *card;
        int err;
 
-       err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                             THIS_MODULE, 0, &card);
+       err = snd_card_new(line6->ifcdev,
+                          SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                          THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index 3f6d78c585fb925d75bb630e07dab6f67c124b95..c61cd0515baf299a244c9c44ff393dfcc0cf0cda 100644 (file)
@@ -307,8 +307,6 @@ int line6_init_midi(struct usb_line6 *line6)
        if (err < 0)
                return err;
 
-       snd_card_set_dev(line6->card, line6->ifcdev);
-
        err = snd_line6_new_midi(line6midi);
        if (err < 0)
                return err;
index df8331bce1754a71206d86d426209ba2fab33075..661080b3c39df8c2f8e1c43ed9473d4eb603cc25 100644 (file)
@@ -501,8 +501,6 @@ int line6_init_pcm(struct usb_line6 *line6,
        if (err < 0)
                return err;
 
-       snd_card_set_dev(line6->card, line6->ifcdev);
-
        err = snd_line6_new_pcm(line6pcm);
        if (err < 0)
                return err;
index 16dd64920767de37662a63dfb400ddd2298bd33b..9eb2a20ae40a97916721599bbd80bfc04190e795 100644 (file)
@@ -245,8 +245,8 @@ int go7007_snd_init(struct go7007 *go)
        spin_lock_init(&gosnd->lock);
        gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
        gosnd->capturing = 0;
-       ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0,
-                             &gosnd->card);
+       ret = snd_card_new(go->dev, index[dev], id[dev], THIS_MODULE, 0,
+                          &gosnd->card);
        if (ret < 0) {
                kfree(gosnd);
                return ret;
@@ -257,7 +257,6 @@ int go7007_snd_init(struct go7007 *go)
                kfree(gosnd);
                return ret;
        }
-       snd_card_set_dev(gosnd->card, go->dev);
        ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm);
        if (ret < 0) {
                snd_card_free(gosnd->card);
index 1db18c7972a00cfc6db7c94d824f1e7b03676d4c..74f037b6166c2a3f15510914cfff6b70451ccedf 100644 (file)
@@ -366,8 +366,9 @@ int solo_g723_init(struct solo_dev *solo_dev)
        /* Allows for easier mapping between video and audio */
        sprintf(name, "Softlogic%d", solo_dev->vfd->num);
 
-       ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
-                             &solo_dev->snd_card);
+       ret = snd_card_new(&solo_dev->pdev->dev,
+                          SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
+                          &solo_dev->snd_card);
        if (ret < 0)
                return ret;
 
@@ -377,7 +378,6 @@ int solo_g723_init(struct solo_dev *solo_dev)
        strcpy(card->shortname, "SOLO-6x10 Audio");
        sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
                pci_name(solo_dev->pdev), solo_dev->pdev->irq);
-       snd_card_set_dev(card, &solo_dev->pdev->dev);
 
        ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
        if (ret < 0)
index 7f1a7ce4b771a791cdf636906fd5fcdcc16c9ba6..b83ec378d04f8f1ed5fbc820429c6f1657b4d7a0 100644 (file)
@@ -785,7 +785,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
        spin_unlock_bh(&conn->cmd_lock);
 
        list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                iscsit_free_cmd(cmd, false);
        }
 }
@@ -3708,7 +3708,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state
                break;
        case ISTATE_REMOVE:
                spin_lock_bh(&conn->cmd_lock);
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_free_cmd(cmd, false);
@@ -4151,7 +4151,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
        spin_lock_bh(&conn->cmd_lock);
        list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_increment_maxcmdsn(cmd, sess);
@@ -4196,6 +4196,10 @@ int iscsit_close_connection(
        iscsit_stop_timers_for_cmds(conn);
        iscsit_stop_nopin_response_timer(conn);
        iscsit_stop_nopin_timer(conn);
+
+       if (conn->conn_transport->iscsit_wait_conn)
+               conn->conn_transport->iscsit_wait_conn(conn);
+
        iscsit_free_queue_reqs_for_conn(conn);
 
        /*
index 33be1fb1df32f2850b6ceb1d54b3b5340a2b6bb1..4ca8fd2a70db4c05597f6b4bfbac171ce58ea8c7 100644 (file)
@@ -138,7 +138,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
                list_for_each_entry_safe(cmd, cmd_tmp,
                                &cr->conn_recovery_cmd_list, i_conn_node) {
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        cmd->conn = NULL;
                        spin_unlock(&cr->conn_recovery_cmd_lock);
                        iscsit_free_cmd(cmd, true);
@@ -160,7 +160,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
                list_for_each_entry_safe(cmd, cmd_tmp,
                                &cr->conn_recovery_cmd_list, i_conn_node) {
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        cmd->conn = NULL;
                        spin_unlock(&cr->conn_recovery_cmd_lock);
                        iscsit_free_cmd(cmd, true);
@@ -216,7 +216,7 @@ int iscsit_remove_cmd_from_connection_recovery(
        }
        cr = cmd->cr;
 
-       list_del(&cmd->i_conn_node);
+       list_del_init(&cmd->i_conn_node);
        return --cr->cmd_count;
 }
 
@@ -297,7 +297,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
                        continue;
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
 
                spin_unlock_bh(&conn->cmd_lock);
                iscsit_free_cmd(cmd, true);
@@ -335,7 +335,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
        /*
         * Only perform connection recovery on ISCSI_OP_SCSI_CMD or
         * ISCSI_OP_NOOP_OUT opcodes.  For all other opcodes call
-        * list_del(&cmd->i_conn_node); to release the command to the
+        * list_del_init(&cmd->i_conn_node); to release the command to the
         * session pool and remove it from the connection's list.
         *
         * Also stop the DataOUT timer, which will be restarted after
@@ -351,7 +351,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                                " CID: %hu\n", cmd->iscsi_opcode,
                                cmd->init_task_tag, cmd->cmd_sn, conn->cid);
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd, true);
                        spin_lock_bh(&conn->cmd_lock);
@@ -371,7 +371,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                 */
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
                     iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd, true);
                        spin_lock_bh(&conn->cmd_lock);
@@ -393,7 +393,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
 
                cmd->sess = conn->sess;
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_free_all_datain_reqs(cmd);
index 39761837608d3a2ff059356e1049779580182952..44a5471de00ffe95c5fccdf5462931efa0acc361 100644 (file)
@@ -137,7 +137,7 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np(
        list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
 
                spin_lock(&tpg->tpg_state_lock);
-               if (tpg->tpg_state == TPG_STATE_FREE) {
+               if (tpg->tpg_state != TPG_STATE_ACTIVE) {
                        spin_unlock(&tpg->tpg_state_lock);
                        continue;
                }
index 42f18fc1067b63cd8c539959ae43e2548c53c34b..77e6531fb0a1c0a25ed16b71d1936ec37c2ed50a 100644 (file)
@@ -1079,25 +1079,31 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
        left = sectors * dev->prot_length;
 
        for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
-
-               len = min(psg->length, left);
-               if (offset >= sg->length) {
-                       sg = sg_next(sg);
-                       offset = 0;
-               }
+               unsigned int psg_len, copied = 0;
 
                paddr = kmap_atomic(sg_page(psg)) + psg->offset;
-               addr = kmap_atomic(sg_page(sg)) + sg->offset + offset;
-
-               if (read)
-                       memcpy(paddr, addr, len);
-               else
-                       memcpy(addr, paddr, len);
-
-               left -= len;
-               offset += len;
+               psg_len = min(left, psg->length);
+               while (psg_len) {
+                       len = min(psg_len, sg->length - offset);
+                       addr = kmap_atomic(sg_page(sg)) + sg->offset + offset;
+
+                       if (read)
+                               memcpy(paddr + copied, addr, len);
+                       else
+                               memcpy(addr, paddr + copied, len);
+
+                       left -= len;
+                       offset += len;
+                       copied += len;
+                       psg_len -= len;
+
+                       if (offset >= sg->length) {
+                               sg = sg_next(sg);
+                               offset = 0;
+                       }
+                       kunmap_atomic(addr);
+               }
                kunmap_atomic(paddr);
-               kunmap_atomic(addr);
        }
 }
 
index 35c066489a19ecd1def35f044e45dc52d55688a1..5f88d767671e956fa400b039f2cc21de9bc58621 100644 (file)
@@ -136,6 +136,7 @@ config SPEAR_THERMAL
 config RCAR_THERMAL
        tristate "Renesas R-Car thermal driver"
        depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enable this to plug the R-Car thermal sensor driver into the Linux
          thermal framework.
@@ -210,8 +211,16 @@ config ACPI_INT3403_THERMAL
        tristate "ACPI INT3403 thermal driver"
        depends on X86 && ACPI
        help
-         This driver uses ACPI INT3403 device objects. If present, it will
-         register each INT3403 thermal sensor as a thermal zone.
+         Newer laptops and tablets that use ACPI may have thermal sensors
+         outside the core CPU/SOC for thermal safety reasons. These
+         temperature sensors are also exposed for the OS to use via the so
+         called INT3403 ACPI object. This driver will, on devices that have
+         such sensors, expose the temperature information from these sensors
+         to userspace via the normal thermal framework. This means that a wide
+         range of applications and GUI widgets can show this information to
+         the user or use this information for making decisions. For example,
+         the Intel Thermal Daemon can use this information to allow the user
+         to select his laptop to run without turning on the fans.
 
 menu "Texas Instruments thermal drivers"
 source "drivers/thermal/ti-soc-thermal/Kconfig"
index 338a88bf6662d1fd0b963f0f8bc7c02dce55e73b..71b0ec0c370d73aad18d685118c197735c5b2833 100644 (file)
@@ -56,10 +56,15 @@ static LIST_HEAD(thermal_governor_list);
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
+static struct thermal_governor *def_governor;
+
 static struct thermal_governor *__find_governor(const char *name)
 {
        struct thermal_governor *pos;
 
+       if (!name || !name[0])
+               return def_governor;
+
        list_for_each_entry(pos, &thermal_governor_list, governor_list)
                if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
                        return pos;
@@ -82,17 +87,23 @@ int thermal_register_governor(struct thermal_governor *governor)
        if (__find_governor(governor->name) == NULL) {
                err = 0;
                list_add(&governor->governor_list, &thermal_governor_list);
+               if (!def_governor && !strncmp(governor->name,
+                       DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
+                       def_governor = governor;
        }
 
        mutex_lock(&thermal_list_lock);
 
        list_for_each_entry(pos, &thermal_tz_list, node) {
+               /*
+                * only thermal zones with specified tz->tzp->governor_name
+                * may run with tz->govenor unset
+                */
                if (pos->governor)
                        continue;
-               if (pos->tzp)
-                       name = pos->tzp->governor_name;
-               else
-                       name = DEFAULT_THERMAL_GOVERNOR;
+
+               name = pos->tzp->governor_name;
+
                if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
                        pos->governor = governor;
        }
@@ -342,8 +353,8 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
 static void handle_non_critical_trips(struct thermal_zone_device *tz,
                        int trip, enum thermal_trip_type trip_type)
 {
-       if (tz->governor)
-               tz->governor->throttle(tz, trip);
+       tz->governor ? tz->governor->throttle(tz, trip) :
+                      def_governor->throttle(tz, trip);
 }
 
 static void handle_critical_trips(struct thermal_zone_device *tz,
@@ -1107,7 +1118,7 @@ __thermal_cooling_device_register(struct device_node *np,
        INIT_LIST_HEAD(&cdev->thermal_instances);
        cdev->np = np;
        cdev->ops = ops;
-       cdev->updated = true;
+       cdev->updated = false;
        cdev->device.class = &thermal_class;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@ -1533,7 +1544,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        if (tz->tzp)
                tz->governor = __find_governor(tz->tzp->governor_name);
        else
-               tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
+               tz->governor = def_governor;
 
        mutex_unlock(&thermal_governor_lock);
 
index 972e1c73722a4c4ec90cd75af32ce99da6438745..081fd7e6a9f070c683deaea799437a2e459b94f4 100644 (file)
@@ -68,6 +68,10 @@ struct phy_dev_entry {
        struct thermal_zone_device *tzone;
 };
 
+static const struct thermal_zone_params pkg_temp_tz_params = {
+       .no_hwmon       = true,
+};
+
 /* List maintaining number of package instances */
 static LIST_HEAD(phy_dev_list);
 static DEFINE_MUTEX(phy_dev_list_mutex);
@@ -394,7 +398,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        int err;
        u32 tj_max;
        struct phy_dev_entry *phy_dev_entry;
-       char buffer[30];
        int thres_count;
        u32 eax, ebx, ecx, edx;
        u8 *temp;
@@ -440,13 +443,11 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        phy_dev_entry->first_cpu = cpu;
        phy_dev_entry->tj_max = tj_max;
        phy_dev_entry->ref_cnt = 1;
-       snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
-                                       phy_dev_entry->phys_proc_id);
-       phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+       phy_dev_entry->tzone = thermal_zone_device_register("x86_pkg_temp",
                        thres_count,
                        (thres_count == MAX_NUMBER_OF_TRIPS) ?
                                0x03 : 0x01,
-                       phy_dev_entry, &tzone_ops, NULL, 0, 0);
+                       phy_dev_entry, &tzone_ops, &pkg_temp_tz_params, 0, 0);
        if (IS_ERR(phy_dev_entry->tzone)) {
                err = PTR_ERR(phy_dev_entry->tzone);
                goto err_ret_free;
index be33d2b0613bb95a51092b1173c9d1291082a211..7e0b626026322c9319d6588de604231d496e76fc 100644 (file)
@@ -1041,8 +1041,7 @@ static int sci_notifier(struct notifier_block *self,
 
        sci_port = container_of(self, struct sci_port, freq_transition);
 
-       if ((phase == CPUFREQ_POSTCHANGE) ||
-           (phase == CPUFREQ_RESUMECHANGE)) {
+       if (phase == CPUFREQ_POSTCHANGE) {
                struct uart_port *port = &sci_port->port;
 
                spin_lock_irqsave(&port->lock, flags);
index cf86e729532b9fc11b768863c94bfb9fe1da7109..dc697cee248ad3dcfa84e2f1d66f8c439b37dd81 100644 (file)
@@ -433,13 +433,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else
-               spin_lock(&port->lock);
+       if (port->sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       else
+               spin_lock_irqsave(&port->lock, flags);
 
        while (n > 0) {
                unsigned long ra = __pa(con_write_page);
@@ -470,8 +467,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
        }
 
        if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static inline void sunhv_console_putchar(struct uart_port *port, char c)
@@ -492,7 +488,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
        unsigned long flags;
        int i, locked = 1;
 
-       local_irq_save(flags);
+       if (port->sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       else
+               spin_lock_irqsave(&port->lock, flags);
        if (port->sysrq) {
                locked = 0;
        } else if (oops_in_progress) {
@@ -507,8 +506,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
        }
 
        if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static struct console sunhv_console = {
index 380fb5355cb26ae68a472a4e6097c57556d0b8e1..5faa8e905e9896e52489a84dd3f6e7925e147dfc 100644 (file)
@@ -844,20 +844,16 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n)
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
+       if (up->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        uart_console_write(&up->port, s, n, sunsab_console_putchar);
        sunsab_tec_wait(up);
 
        if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 static int sunsab_console_setup(struct console *con, char *options)
index db79b76f5c8e978e09824b719d585cf470d75d68..9a0f24f837209f2b15f9e11901f350dcb0230a19 100644 (file)
@@ -1295,13 +1295,10 @@ static void sunsu_console_write(struct console *co, const char *s,
        unsigned int ier;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
+       if (up->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        /*
         *      First save the UER then disable the interrupts
@@ -1319,8 +1316,7 @@ static void sunsu_console_write(struct console *co, const char *s,
        serial_out(up, UART_IER, ier);
 
        if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 /*
index 45a8c6aa583797ba717ec3da79a24929a6eb425f..a2c40ed287d21b7a7ff545626bba5b0711211149 100644 (file)
@@ -1195,20 +1195,16 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
+       if (up->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        uart_console_write(&up->port, s, count, sunzilog_putchar);
        udelay(2);
 
        if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 static int __init sunzilog_console_setup(struct console *con, char *options)
index d8a55e87877f06f3141602e4f08cdcb668c465b0..0ffb0cbe28237239ffd093877a363c7957c8e328 100644 (file)
                                lock_acquire(&(l)->dep_map, s, t, r, c, n, i)
 # define __rel(l, n, i)                                \
                                lock_release(&(l)->dep_map, n, i)
-# ifdef CONFIG_PROVE_LOCKING
-#  define lockdep_acquire(l, s, t, i)          __acq(l, s, t, 0, 2, NULL, i)
-#  define lockdep_acquire_nest(l, s, t, n, i)  __acq(l, s, t, 0, 2, n, i)
-#  define lockdep_acquire_read(l, s, t, i)     __acq(l, s, t, 1, 2, NULL, i)
-#  define lockdep_release(l, n, i)             __rel(l, n, i)
-# else
-#  define lockdep_acquire(l, s, t, i)          __acq(l, s, t, 0, 1, NULL, i)
-#  define lockdep_acquire_nest(l, s, t, n, i)  __acq(l, s, t, 0, 1, n, i)
-#  define lockdep_acquire_read(l, s, t, i)     __acq(l, s, t, 1, 1, NULL, i)
-#  define lockdep_release(l, n, i)             __rel(l, n, i)
-# endif
+#define lockdep_acquire(l, s, t, i)            __acq(l, s, t, 0, 1, NULL, i)
+#define lockdep_acquire_nest(l, s, t, n, i)    __acq(l, s, t, 0, 1, n, i)
+#define lockdep_acquire_read(l, s, t, i)       __acq(l, s, t, 1, 1, NULL, i)
+#define lockdep_release(l, n, i)               __rel(l, n, i)
 #else
 # define lockdep_acquire(l, s, t, i)           do { } while (0)
 # define lockdep_acquire_nest(l, s, t, n, i)   do { } while (0)
index 8d72f0c659377371cc6c481e33458c7d555f3493..062967c90b2a06e66a081f81ab53aabe1a9e37e4 100644 (file)
@@ -717,6 +717,10 @@ int usb_get_configuration(struct usb_device *dev)
                        result = -ENOMEM;
                        goto err;
                }
+
+               if (dev->quirks & USB_QUIRK_DELAY_INIT)
+                       msleep(100);
+
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    bigbuffer, length);
                if (result < 0) {
index 64ea21971be23f770986b25cf05890553cf8d195..5cbf78d0be2539c868dab16a815b15e4bfe28b99 100644 (file)
@@ -1040,7 +1040,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                 */
                if (type == HUB_INIT) {
                        delay = hub_power_on(hub, false);
-                       PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2);
+                       INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
                        schedule_delayed_work(&hub->init_work,
                                        msecs_to_jiffies(delay));
 
@@ -1194,7 +1194,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 
                /* Don't do a long sleep inside a workqueue routine */
                if (type == HUB_INIT2) {
-                       PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3);
+                       INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);
                        schedule_delayed_work(&hub->init_work,
                                        msecs_to_jiffies(delay));
                        return;         /* Continues at init3: below */
index 8f37063c0a49eeff7ba2d0902621aaa91800c058..739ee8e8bdfdaf7bc6be98d716255e4f561cc17a 100644 (file)
@@ -47,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Microsoft LifeCam-VX700 v2.0 */
        { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Logitech HD Pro Webcams C920 and C930e */
+       { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+       { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
+
        /* Logitech Quickcam Fusion */
        { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
index b269dbd47fc41edef682380bcd3637a20371b9ee..b1d7ee6e40b7a6e3ac69f60a89dff571012bfe1c 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/extcon.h>
-#include <linux/extcon/of_extcon.h>
 #include <linux/regulator/consumer.h>
 
 #include <linux/usb/otg.h>
@@ -522,7 +521,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
        dwc3_omap_enable_irqs(omap);
 
        if (of_property_read_bool(node, "extcon")) {
-               edev = of_extcon_get_extcon_dev(dev, 0);
+               edev = extcon_get_edev_by_phandle(dev, 0);
                if (IS_ERR(edev)) {
                        dev_vdbg(dev, "couldn't get extcon device\n");
                        ret = -EPROBE_DEFER;
index 36d4bb23087f4743a9309783ab80b7d3c4d31d18..807b31c0edc31b547b079637cac1bf26a06fe6c8 100644 (file)
@@ -664,9 +664,10 @@ static int f_midi_register_card(struct f_midi *midi)
                .dev_free = f_midi_snd_free,
        };
 
-       err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&midi->gadget->dev, midi->index, midi->id,
+                          THIS_MODULE, 0, &card);
        if (err < 0) {
-               ERROR(midi, "snd_card_create() failed\n");
+               ERROR(midi, "snd_card_new() failed\n");
                goto fail;
        }
        midi->card = card;
@@ -703,8 +704,6 @@ static int f_midi_register_card(struct f_midi *midi)
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
 
-       snd_card_set_dev(card, &midi->gadget->dev);
-
        /* register it - we're ready to go */
        err = snd_card_register(card);
        if (err < 0) {
index 2f23566e53d88bf7fd618efcc100b49447c0cf27..bc23040c7790387b4a206b2814de5860f61a3b1c 100644 (file)
@@ -394,7 +394,7 @@ static int snd_uac2_probe(struct platform_device *pdev)
        int err;
 
        /* Choose any slot, with no id */
-       err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -421,8 +421,6 @@ static int snd_uac2_probe(struct platform_device *pdev)
        strcpy(card->shortname, "UAC2_Gadget");
        sprintf(card->longname, "UAC2_Gadget %i", pdev->id);
 
-       snd_card_set_dev(card, &pdev->dev);
-
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
                snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
 
index 6fe577d46fa2d392e586d608efc3805666ac452c..924a6ccdb622777a6fc71b21dfb6a0ee0792f536 100644 (file)
@@ -4733,6 +4733,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        /* Accept arbitrarily long scatter-gather lists */
        hcd->self.sg_tablesize = ~0;
 
+       /* support to build packet from discontinuous buffers */
+       hcd->self.no_sg_constraint = 1;
+
        /* XHCI controllers don't stop the ep queue on short packets :| */
        hcd->self.no_stop_on_short = 1;
 
@@ -4757,14 +4760,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                /* xHCI private pointer was set in xhci_pci_probe for the second
                 * registered roothub.
                 */
-               xhci = hcd_to_xhci(hcd);
-               /*
-                * Support arbitrarily aligned sg-list entries on hosts without
-                * TD fragment rules (which are currently unsupported).
-                */
-               if (xhci->hci_version < 0x100)
-                       hcd->self.no_sg_constraint = 1;
-
                return 0;
        }
 
@@ -4793,9 +4788,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        if (xhci->hci_version > 0x96)
                xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
 
-       if (xhci->hci_version < 0x100)
-               hcd->self.no_sg_constraint = 1;
-
        /* Make sure the HC is halted. */
        retval = xhci_halt(xhci);
        if (retval)
index 210357691dc0a06e65b522e5847321e62c43541c..9dd49c9839ac6de24496d37e0f4020e424415a1d 100644 (file)
@@ -482,15 +482,19 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
                for (i = 0; i < nvec; i++)
                        vdev->msix[i].entry = i;
 
-               ret = pci_enable_msix(pdev, vdev->msix, nvec);
-               if (ret) {
+               ret = pci_enable_msix_range(pdev, vdev->msix, 1, nvec);
+               if (ret < nvec) {
+                       if (ret > 0)
+                               pci_disable_msix(pdev);
                        kfree(vdev->msix);
                        kfree(vdev->ctx);
                        return ret;
                }
        } else {
-               ret = pci_enable_msi_block(pdev, nvec);
-               if (ret) {
+               ret = pci_enable_msi_range(pdev, 1, nvec);
+               if (ret < nvec) {
+                       if (ret > 0)
+                               pci_disable_msi(pdev);
                        kfree(vdev->ctx);
                        return ret;
                }
index 4fb7a8f83c8a99ff8d3412a5328b2407c98409a8..54af4e93369583e5629a4bac6d1ecdbd74f885cf 100644 (file)
@@ -186,12 +186,12 @@ static bool is_invalid_reserved_pfn(unsigned long pfn)
        if (pfn_valid(pfn)) {
                bool reserved;
                struct page *tail = pfn_to_page(pfn);
-               struct page *head = compound_trans_head(tail);
+               struct page *head = compound_head(tail);
                reserved = !!(PageReserved(head));
                if (head != tail) {
                        /*
                         * "head" is not a dangling pointer
-                        * (compound_trans_head takes care of that)
+                        * (compound_head takes care of that)
                         * but the hugepage may have been split
                         * from under us (and we may not hold a
                         * reference count on the head page so it can
index a0fa5de210cf57ac6842625ceb21499ac07a7969..e1e22e0f01e881fe2961dbf1c43cb56f4e22cade 100644 (file)
@@ -505,9 +505,13 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
                        r = -ENOBUFS;
                        goto err;
                }
-               d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+               r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
                                      ARRAY_SIZE(vq->iov) - seg, &out,
                                      &in, log, log_num);
+               if (unlikely(r < 0))
+                       goto err;
+
+               d = r;
                if (d == vq->num) {
                        r = 0;
                        goto err;
@@ -532,6 +536,12 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
        *iovcount = seg;
        if (unlikely(log))
                *log_num = nlogs;
+
+       /* Detect overrun */
+       if (unlikely(datalen > 0)) {
+               r = UIO_MAXIOV + 1;
+               goto err;
+       }
        return headcount;
 err:
        vhost_discard_vq_desc(vq, headcount);
@@ -587,6 +597,14 @@ static void handle_rx(struct vhost_net *net)
                /* On error, stop handling until the next kick. */
                if (unlikely(headcount < 0))
                        break;
+               /* On overrun, truncate and discard */
+               if (unlikely(headcount > UIO_MAXIOV)) {
+                       msg.msg_iovlen = 1;
+                       err = sock->ops->recvmsg(NULL, sock, &msg,
+                                                1, MSG_DONTWAIT | MSG_TRUNC);
+                       pr_debug("Discarded rx packet: len %zd\n", sock_len);
+                       continue;
+               }
                /* OK, now we need to know about added descriptors. */
                if (!headcount) {
                        if (unlikely(vhost_enable_notify(&net->dev, vq))) {
index dade5b7699bc240e81225e8d489136af9e0d71e0..97a8f3a12a7b2bafb7ee704fcba1ee13e40f37ab 100644 (file)
@@ -27,12 +27,6 @@ config VGASTATE
        tristate
        default n
 
-config VIDEO_OUTPUT_CONTROL
-       tristate "Lowlevel video output switch controls"
-       help
-         This framework adds support for low-level control of the video 
-         output switch.
-
 config VIDEOMODE_HELPERS
        bool
 
index ae17ddf49a00d39c04a31570cd1f4955c9630af5..08d6a4ab3ace29a6ac2c96cd4526ffda9d27be12 100644 (file)
@@ -172,8 +172,6 @@ obj-$(CONFIG_FB_SIMPLE)           += simplefb.o
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
 
-#video output switch sysfs driver
-obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
 obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
 ifeq ($(CONFIG_OF),y)
 obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
index 130708f96430e2806fa0c4eed32264cd61309995..e23392ec5af359ed1f4c8eb0c228325ff6d4c396 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/completion.h>
 #include <linux/fb.h>
 #include <linux/pci.h>
+#include <linux/efi.h>
 
 #include <linux/hyperv.h>
 
@@ -212,6 +213,7 @@ struct synthvid_msg {
 
 struct hvfb_par {
        struct fb_info *info;
+       struct resource mem;
        bool fb_ready; /* fb device is ready */
        struct completion wait;
        u32 synthvid_version;
@@ -460,13 +462,13 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
                goto error;
        }
 
-       if (par->synthvid_version == SYNTHVID_VERSION_WIN7) {
+       if (par->synthvid_version == SYNTHVID_VERSION_WIN7)
                screen_depth = SYNTHVID_DEPTH_WIN7;
-               screen_fb_size = SYNTHVID_FB_SIZE_WIN7;
-       } else {
+       else
                screen_depth = SYNTHVID_DEPTH_WIN8;
-               screen_fb_size = SYNTHVID_FB_SIZE_WIN8;
-       }
+
+       screen_fb_size = hdev->channel->offermsg.offer.
+                               mmio_megabytes * 1024 * 1024;
 
        return 0;
 
@@ -627,26 +629,46 @@ static void hvfb_get_option(struct fb_info *info)
 /* Get framebuffer memory from Hyper-V video pci space */
 static int hvfb_getmem(struct fb_info *info)
 {
-       struct pci_dev *pdev;
-       ulong fb_phys;
+       struct hvfb_par *par = info->par;
+       struct pci_dev *pdev  = NULL;
        void __iomem *fb_virt;
+       int gen2vm = efi_enabled(EFI_BOOT);
+       int ret;
 
-       pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
+       par->mem.name = KBUILD_MODNAME;
+       par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       if (gen2vm) {
+               ret = allocate_resource(&hyperv_mmio, &par->mem,
+                                       screen_fb_size,
+                                       0, -1,
+                                       screen_fb_size,
+                                       NULL, NULL);
+               if (ret != 0) {
+                       pr_err("Unable to allocate framebuffer memory\n");
+                       return -ENODEV;
+               }
+       } else {
+               pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
                              PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
-       if (!pdev) {
-               pr_err("Unable to find PCI Hyper-V video\n");
-               return -ENODEV;
-       }
+               if (!pdev) {
+                       pr_err("Unable to find PCI Hyper-V video\n");
+                       return -ENODEV;
+               }
 
-       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
-           pci_resource_len(pdev, 0) < screen_fb_size)
-               goto err1;
+               if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+                   pci_resource_len(pdev, 0) < screen_fb_size)
+                       goto err1;
 
-       fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1;
-       if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME))
-               goto err1;
+               par->mem.end = pci_resource_end(pdev, 0);
+               par->mem.start = par->mem.end - screen_fb_size + 1;
+               ret = request_resource(&pdev->resource[0], &par->mem);
+               if (ret != 0) {
+                       pr_err("Unable to request framebuffer memory\n");
+                       goto err1;
+               }
+       }
 
-       fb_virt = ioremap(fb_phys, screen_fb_size);
+       fb_virt = ioremap(par->mem.start, screen_fb_size);
        if (!fb_virt)
                goto err2;
 
@@ -654,30 +676,44 @@ static int hvfb_getmem(struct fb_info *info)
        if (!info->apertures)
                goto err3;
 
-       info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
-       info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
-       info->fix.smem_start = fb_phys;
+       if (gen2vm) {
+               info->apertures->ranges[0].base = screen_info.lfb_base;
+               info->apertures->ranges[0].size = screen_info.lfb_size;
+               remove_conflicting_framebuffers(info->apertures,
+                                               KBUILD_MODNAME, false);
+       } else {
+               info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
+               info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
+       }
+
+       info->fix.smem_start = par->mem.start;
        info->fix.smem_len = screen_fb_size;
        info->screen_base = fb_virt;
        info->screen_size = screen_fb_size;
 
-       pci_dev_put(pdev);
+       if (!gen2vm)
+               pci_dev_put(pdev);
+
        return 0;
 
 err3:
        iounmap(fb_virt);
 err2:
-       release_mem_region(fb_phys, screen_fb_size);
+       release_resource(&par->mem);
 err1:
-       pci_dev_put(pdev);
+       if (!gen2vm)
+               pci_dev_put(pdev);
+
        return -ENOMEM;
 }
 
 /* Release the framebuffer */
 static void hvfb_putmem(struct fb_info *info)
 {
+       struct hvfb_par *par = info->par;
+
        iounmap(info->screen_base);
-       release_mem_region(info->fix.smem_start, screen_fb_size);
+       release_resource(&par->mem);
 }
 
 
diff --git a/drivers/video/output.c b/drivers/video/output.c
deleted file mode 100644 (file)
index 1446c49..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *  output.c - Display Output Switch driver
- *
- *  Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or (at
- *  your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/module.h>
-#include <linux/video_output.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/ctype.h>
-
-
-MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       ssize_t ret_size = 0;
-       struct output_device *od = to_output_device(dev);
-       if (od->props)
-               ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
-       return ret_size;
-}
-
-static ssize_t state_store(struct device *dev, struct device_attribute *attr,
-                          const char *buf,size_t count)
-{
-       char *endp;
-       struct output_device *od = to_output_device(dev);
-       int request_state = simple_strtoul(buf,&endp,0);
-       size_t size = endp - buf;
-
-       if (isspace(*endp))
-               size++;
-       if (size != count)
-               return -EINVAL;
-
-       if (od->props) {
-               od->request_state = request_state;
-               od->props->set_state(od);
-       }
-       return count;
-}
-static DEVICE_ATTR_RW(state);
-
-static void video_output_release(struct device *dev)
-{
-       struct output_device *od = to_output_device(dev);
-       kfree(od);
-}
-
-static struct attribute *video_output_attrs[] = {
-       &dev_attr_state.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(video_output);
-
-static struct class video_output_class = {
-       .name = "video_output",
-       .dev_release = video_output_release,
-       .dev_groups = video_output_groups,
-};
-
-struct output_device *video_output_register(const char *name,
-       struct device *dev,
-       void *devdata,
-       struct output_properties *op)
-{
-       struct output_device *new_dev;
-       int ret_code = 0;
-
-       new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
-       if (!new_dev) {
-               ret_code = -ENOMEM;
-               goto error_return;
-       }
-       new_dev->props = op;
-       new_dev->dev.class = &video_output_class;
-       new_dev->dev.parent = dev;
-       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) {
-               kfree(new_dev);
-               goto error_return;
-       }
-       return new_dev;
-
-error_return:
-       return ERR_PTR(ret_code);
-}
-EXPORT_SYMBOL(video_output_register);
-
-void video_output_unregister(struct output_device *dev)
-{
-       if (!dev)
-               return;
-       device_unregister(&dev->dev);
-}
-EXPORT_SYMBOL(video_output_unregister);
-
-static void __exit video_output_class_exit(void)
-{
-       class_unregister(&video_output_class);
-}
-
-static int __init video_output_class_init(void)
-{
-       return class_register(&video_output_class);
-}
-
-postcore_initcall(video_output_class_init);
-module_exit(video_output_class_exit);
index 256fba7f46416fb0d5b293e2e0829872d6d344a4..1f38445014c17c85860d88bb0dac0d9086c08102 100644 (file)
@@ -190,7 +190,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
        uvfb_tasks[seq] = task;
        mutex_unlock(&uvfb_lock);
 
-       err = cn_netlink_send(m, 0, GFP_KERNEL);
+       err = cn_netlink_send(m, 0, 0, GFP_KERNEL);
        if (err == -ESRCH) {
                /*
                 * Try to start the userspace helper if sending
@@ -204,7 +204,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
                                        "helper is installed and executable\n");
                } else {
                        v86d_started = 1;
-                       err = cn_netlink_send(m, 0, gfp_any());
+                       err = cn_netlink_send(m, 0, 0, gfp_any());
                        if (err == -ENOBUFS)
                                err = 0;
                }
index 1b5d48c578e19208fbb2ef06f9e4788f93a0f5f5..bfb2d3f06738481d302e7edb3550addbbb6a4691 100644 (file)
@@ -869,14 +869,13 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
 
        spin_lock(&image->lock);
 
-       /* The following code handles VME address alignment problem
-        * in order to assure the maximal data width cycle.
-        * We cannot use memcpy_xxx directly here because it
-        * may cut data transfer in 8-bits cycles, thus making
-        * D16 cycle impossible.
-        * From the other hand, the bridge itself assures that
-        * maximal configured data cycle is used and splits it
-        * automatically for non-aligned addresses.
+       /* The following code handles VME address alignment. We cannot use
+        * memcpy_xxx here because it may cut data transfers in to 8-bit
+        * cycles when D16 or D32 cycles are required on the VME bus.
+        * On the other hand, the bridge itself assures that the maximum data
+        * cycle configured for the transfer is used and splits it
+        * automatically for non-aligned addresses, so we don't want the
+        * overhead of needlessly forcing small transfers for the entire cycle.
         */
        if ((uintptr_t)addr & 0x1) {
                *(u8 *)buf = ioread8(addr);
@@ -896,9 +895,9 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
        }
 
        count32 = (count - done) & ~0x3;
-       if (count32 > 0) {
-               memcpy_fromio(buf + done, addr + done, (unsigned int)count);
-               done += count32;
+       while (done < count32) {
+               *(u32 *)(buf + done) = ioread32(addr + done);
+               done += 4;
        }
 
        if ((count - done) & 0x2) {
@@ -930,7 +929,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
        spin_lock(&image->lock);
 
        /* Here we apply for the same strategy we do in master_read
-        * function in order to assure D16 cycle when required.
+        * function in order to assure the correct cycles.
         */
        if ((uintptr_t)addr & 0x1) {
                iowrite8(*(u8 *)buf, addr);
@@ -950,9 +949,9 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
        }
 
        count32 = (count - done) & ~0x3;
-       if (count32 > 0) {
-               memcpy_toio(addr + done, buf + done, count32);
-               done += count32;
+       while (done < count32) {
+               iowrite32(*(u32 *)(buf + done), addr + done);
+               done += 4;
        }
 
        if ((count - done) & 0x2) {
index 9911cd5fddb58415b56ad23efadef06504b822f3..06990c6a1a698c4d89c391848b185885b80767bb 100644 (file)
@@ -1276,8 +1276,8 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
        spin_lock(&image->lock);
 
        /* The following code handles VME address alignment. We cannot use
-        * memcpy_xxx directly here because it may cut small data transfers in
-        * to 8-bit cycles, thus making D16 cycle impossible.
+        * memcpy_xxx here because it may cut data transfers in to 8-bit
+        * cycles when D16 or D32 cycles are required on the VME bus.
         * On the other hand, the bridge itself assures that the maximum data
         * cycle configured for the transfer is used and splits it
         * automatically for non-aligned addresses, so we don't want the
@@ -1301,9 +1301,9 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
        }
 
        count32 = (count - done) & ~0x3;
-       if (count32 > 0) {
-               memcpy_fromio(buf + done, addr + done, count32);
-               done += count32;
+       while (done < count32) {
+               *(u32 *)(buf + done) = ioread32(addr + done);
+               done += 4;
        }
 
        if ((count - done) & 0x2) {
@@ -1363,7 +1363,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
        spin_lock(&image->lock);
 
        /* Here we apply for the same strategy we do in master_read
-        * function in order to assure D16 cycle when required.
+        * function in order to assure the correct cycles.
         */
        if ((uintptr_t)addr & 0x1) {
                iowrite8(*(u8 *)buf, addr);
@@ -1383,9 +1383,9 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
        }
 
        count32 = (count - done) & ~0x3;
-       if (count32 > 0) {
-               memcpy_toio(addr + done, buf + done, count32);
-               done += count32;
+       while (done < count32) {
+               iowrite32(*(u32 *)(buf + done), addr + done);
+               done += 4;
        }
 
        if ((count - done) & 0x2) {
index efc7f075fcbe2de8f09cbebbf4d0209b765379ed..1708b2300c7a9ca2ecbbbd3be21342b0cefeee79 100644 (file)
@@ -36,13 +36,12 @@ config W1_MASTER_DS2482
 
 config W1_MASTER_MXC
        tristate "Freescale MXC 1-wire busmaster"
-       depends on W1 && ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Say Y here to enable MXC 1-wire host
 
 config W1_MASTER_DS1WM
        tristate "Maxim DS1WM 1-wire busmaster"
-       depends on W1
        help
          Say Y here to enable the DS1WM 1-wire driver, such as that
          in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
index 4f7e1d770f81fcb6af19f665fff2ecebacca9baf..7404ad3062b7680e91a6b23f51fab7fcdbdf881d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     dscore.c
+ *     ds2490.c  USB to one wire bridge
  *
  * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
  *
 #include "../w1_int.h"
 #include "../w1.h"
 
+/* USB Standard */
+/* USB Control request vendor type */
+#define VENDOR                         0x40
+
 /* COMMAND TYPE CODES */
 #define CONTROL_CMD                    0x00
 #define COMM_CMD                       0x01
 #define ST_HALT                                0x10  /* DS2490 is currently halted */
 #define ST_IDLE                                0x20  /* DS2490 is currently idle */
 #define ST_EPOF                                0x80
+/* Status transfer size, 16 bytes status, 16 byte result flags */
+#define ST_SIZE                                0x20
 
 /* Result Register flags */
 #define RR_DETECT                      0xA5 /* New device detected */
@@ -198,7 +204,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
        int err;
 
        err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
-                       CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
+                       CONTROL_CMD, VENDOR, value, index, NULL, 0, 1000);
        if (err < 0) {
                printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
                                value, index, err);
@@ -213,7 +219,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
        int err;
 
        err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
-                       MODE_CMD, 0x40, value, index, NULL, 0, 1000);
+                       MODE_CMD, VENDOR, value, index, NULL, 0, 1000);
        if (err < 0) {
                printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
                                value, index, err);
@@ -228,7 +234,7 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
        int err;
 
        err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
-                       COMM_CMD, 0x40, value, index, NULL, 0, 1000);
+                       COMM_CMD, VENDOR, value, index, NULL, 0, 1000);
        if (err < 0) {
                printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
                                value, index, err);
@@ -246,7 +252,8 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
        memset(st, 0, sizeof(*st));
 
        count = 0;
-       err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
+       err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev,
+               dev->ep[EP_STATUS]), buf, size, &count, 100);
        if (err < 0) {
                printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
                return err;
@@ -353,7 +360,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
        err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
                                buf, size, &count, 1000);
        if (err < 0) {
-               u8 buf[0x20];
+               u8 buf[ST_SIZE];
                int count;
 
                printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
@@ -398,7 +405,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
 {
        struct ds_status st;
        int count = 0, err = 0;
-       u8 buf[0x20];
+       u8 buf[ST_SIZE];
 
        do {
                err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
@@ -450,10 +457,11 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
 
 static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
 {
-       u8 buf[0x20];
+       u8 buf[ST_SIZE];
        int err, count = 0;
 
        do {
+               st->status = 0;
                err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
 #if 0
                if (err >= 0) {
@@ -464,7 +472,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
                        printk("\n");
                }
 #endif
-       } while (!(buf[0x08] & ST_IDLE) && !(err < 0) && ++count < 100);
+       } while (!(st->status & ST_IDLE) && !(err < 0) && ++count < 100);
 
        if (err >= 16 && st->status & ST_EPOF) {
                printk(KERN_INFO "Resetting device after ST_EPOF.\n");
@@ -690,37 +698,106 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
        return !(err == len);
 }
 
-#if 0
-
-static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
+static void ds9490r_search(void *data, struct w1_master *master,
+       u8 search_type, w1_slave_found_callback callback)
 {
+       /* When starting with an existing id, the first id returned will
+        * be that device (if it is still on the bus most likely).
+        *
+        * If the number of devices found is less than or equal to the
+        * search_limit, that number of IDs will be returned.  If there are
+        * more, search_limit IDs will be returned followed by a non-zero
+        * discrepency value.
+        */
+       struct ds_device *dev = data;
        int err;
        u16 value, index;
        struct ds_status st;
+       u8 st_buf[ST_SIZE];
+       int search_limit;
+       int found = 0;
+       int i;
 
-       memset(buf, 0, sizeof(buf));
+       /* DS18b20 spec, 13.16 ms per device, 75 per second, sleep for
+        * discovering 8 devices (1 bulk transfer and 1/2 FIFO size) at a time.
+        */
+       const unsigned long jtime = msecs_to_jiffies(1000*8/75);
+       /* FIFO 128 bytes, bulk packet size 64, read a multiple of the
+        * packet size.
+        */
+       u64 buf[2*64/8];
 
-       err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
-       if (err)
-               return err;
+       mutex_lock(&master->bus_mutex);
 
-       ds_wait_status(ds_dev, &st);
+       /* address to start searching at */
+       if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0)
+               goto search_out;
+       master->search_id = 0;
 
-       value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
-       index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
-       err = ds_send_control(ds_dev, value, index);
-       if (err)
-               return err;
+       value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F |
+               COMM_RTS;
+       search_limit = master->max_slave_count;
+       if (search_limit > 255)
+               search_limit = 0;
+       index = search_type | (search_limit << 8);
+       if (ds_send_control(dev, value, index) < 0)
+               goto search_out;
 
-       ds_wait_status(ds_dev, &st);
+       do {
+               schedule_timeout(jtime);
 
-       err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
-       if (err < 0)
-               return err;
+               if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) <
+                       sizeof(st)) {
+                       break;
+               }
 
-       return err/8;
+               if (st.data_in_buffer_status) {
+                       /* Bulk in can receive partial ids, but when it does
+                        * they fail crc and will be discarded anyway.
+                        * That has only been seen when status in buffer
+                        * is 0 and bulk is read anyway, so don't read
+                        * bulk without first checking if status says there
+                        * is data to read.
+                        */
+                       err = ds_recv_data(dev, (u8 *)buf, sizeof(buf));
+                       if (err < 0)
+                               break;
+                       for (i = 0; i < err/8; ++i) {
+                               ++found;
+                               if (found <= search_limit)
+                                       callback(master, buf[i]);
+                               /* can't know if there will be a discrepancy
+                                * value after until the next id */
+                               if (found == search_limit)
+                                       master->search_id = buf[i];
+                       }
+               }
+
+               if (test_bit(W1_ABORT_SEARCH, &master->flags))
+                       break;
+       } while (!(st.status & (ST_IDLE | ST_HALT)));
+
+       /* only continue the search if some weren't found */
+       if (found <= search_limit) {
+               master->search_id = 0;
+       } else if (!test_bit(W1_WARN_MAX_COUNT, &master->flags)) {
+               /* Only max_slave_count will be scanned in a search,
+                * but it will start where it left off next search
+                * until all ids are identified and then it will start
+                * over.  A continued search will report the previous
+                * last id as the first id (provided it is still on the
+                * bus).
+                */
+               dev_info(&dev->udev->dev, "%s: max_slave_count %d reached, "
+                       "will continue next search.\n", __func__,
+                       master->max_slave_count);
+               set_bit(W1_WARN_MAX_COUNT, &master->flags);
+       }
+search_out:
+       mutex_unlock(&master->bus_mutex);
 }
 
+#if 0
 static int ds_match_access(struct ds_device *dev, u64 init)
 {
        int err;
@@ -894,6 +971,7 @@ static int ds_w1_init(struct ds_device *dev)
        dev->master.write_block = &ds9490r_write_block;
        dev->master.reset_bus   = &ds9490r_reset;
        dev->master.set_pullup  = &ds9490r_set_pullup;
+       dev->master.search      = &ds9490r_search;
 
        return w1_add_master_device(&dev->master);
 }
@@ -910,15 +988,13 @@ static int ds_probe(struct usb_interface *intf,
        struct usb_endpoint_descriptor *endpoint;
        struct usb_host_interface *iface_desc;
        struct ds_device *dev;
-       int i, err;
+       int i, err, alt;
 
-       dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
+       dev = kzalloc(sizeof(struct ds_device), GFP_KERNEL);
        if (!dev) {
                printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
                return -ENOMEM;
        }
-       dev->spu_sleep = 0;
-       dev->spu_bit = 0;
        dev->udev = usb_get_dev(udev);
        if (!dev->udev) {
                err = -ENOMEM;
@@ -928,20 +1004,25 @@ static int ds_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, dev);
 
-       err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
+       err = usb_reset_configuration(dev->udev);
        if (err) {
-               printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
-                               intf->altsetting[0].desc.bInterfaceNumber, err);
+               dev_err(&dev->udev->dev,
+                       "Failed to reset configuration: err=%d.\n", err);
                goto err_out_clear;
        }
 
-       err = usb_reset_configuration(dev->udev);
+       /* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */
+       alt = 3;
+       err = usb_set_interface(dev->udev,
+               intf->altsetting[alt].desc.bInterfaceNumber, alt);
        if (err) {
-               printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
+               dev_err(&dev->udev->dev, "Failed to set alternative setting %d "
+                       "for %d interface: err=%d.\n", alt,
+                       intf->altsetting[alt].desc.bInterfaceNumber, err);
                goto err_out_clear;
        }
 
-       iface_desc = &intf->altsetting[0];
+       iface_desc = &intf->altsetting[alt];
        if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
                printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
                err = -EINVAL;
index 1e5d94c5afc9668af993bacbdcc2ea8a6e1de497..67b067a3e2abbcddadd60a4b9051fb23e5392f45 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
  */
 
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
 #include <linux/clk.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
-#include "../w1_log.h"
 
 /* According to the mx27 Datasheet the reset procedure should take up to about
  * 1350us. We set the timeout to 500*100us = 50ms for sure */
 /*
  * MXC W1 Register offsets
  */
-#define MXC_W1_CONTROL          0x00
-#define MXC_W1_TIME_DIVIDER     0x02
-#define MXC_W1_RESET            0x04
-#define MXC_W1_COMMAND          0x06
-#define MXC_W1_TXRX             0x08
-#define MXC_W1_INTERRUPT        0x0A
-#define MXC_W1_INTERRUPT_EN     0x0C
+#define MXC_W1_CONTROL         0x00
+# define MXC_W1_CONTROL_RDST   BIT(3)
+# define MXC_W1_CONTROL_WR(x)  BIT(5 - (x))
+# define MXC_W1_CONTROL_PST    BIT(6)
+# define MXC_W1_CONTROL_RPP    BIT(7)
+#define MXC_W1_TIME_DIVIDER    0x02
+#define MXC_W1_RESET           0x04
 
 struct mxc_w1_device {
        void __iomem *regs;
@@ -61,12 +53,12 @@ static u8 mxc_w1_ds2_reset_bus(void *data)
        unsigned int timeout_cnt = 0;
        struct mxc_w1_device *dev = data;
 
-       __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL));
+       writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL));
 
        while (1) {
-               reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL);
+               reg_val = readb(dev->regs + MXC_W1_CONTROL);
 
-               if (((reg_val >> 7) & 0x1) == 0 ||
+               if (!(reg_val & MXC_W1_CONTROL_RPP) ||
                    timeout_cnt > MXC_W1_RESET_TIMEOUT)
                        break;
                else
@@ -74,7 +66,7 @@ static u8 mxc_w1_ds2_reset_bus(void *data)
 
                udelay(100);
        }
-       return (reg_val >> 7) & 0x1;
+       return !!(reg_val & MXC_W1_CONTROL_PST);
 }
 
 /*
@@ -90,16 +82,16 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
                                         * datasheet.
                                         */
 
-       __raw_writeb((1 << (5 - bit)), ctrl_addr);
+       writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr);
 
        while (timeout_cnt--) {
-               if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1))
+               if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit)))
                        break;
 
                udelay(1);
        }
 
-       return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
+       return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST);
 }
 
 static int mxc_w1_probe(struct platform_device *pdev)
@@ -139,7 +131,7 @@ static int mxc_w1_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       __raw_writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
+       writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
 
        mdev->bus_master.data = mdev;
        mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
@@ -177,6 +169,7 @@ MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
 static struct platform_driver mxc_w1_driver = {
        .driver = {
                .name = "mxc_w1",
+               .owner = THIS_MODULE,
                .of_match_table = mxc_w1_dt_ids,
        },
        .probe = mxc_w1_probe,
index 9709b8b484bacc8fcd9ddb4c1a88e137e2afa961..1d111e56c8c8c6c4a49badcd5f92febcf5e666d3 100644 (file)
@@ -89,11 +89,22 @@ static int w1_gpio_probe_dt(struct platform_device *pdev)
                pdata->is_open_drain = 1;
 
        gpio = of_get_gpio(np, 0);
-       if (gpio < 0)
+       if (gpio < 0) {
+               if (gpio != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                                       "Failed to parse gpio property for data pin (%d)\n",
+                                       gpio);
+
                return gpio;
+       }
        pdata->pin = gpio;
 
-       pdata->ext_pullup_enable_pin = of_get_gpio(np, 1);
+       gpio = of_get_gpio(np, 1);
+       if (gpio == -EPROBE_DEFER)
+               return gpio;
+       /* ignore other errors as the pullup gpio is optional */
+       pdata->ext_pullup_enable_pin = gpio;
+
        pdev->dev.platform_data = pdata;
 
        return 0;
@@ -107,10 +118,8 @@ static int w1_gpio_probe(struct platform_device *pdev)
 
        if (of_have_populated_dt()) {
                err = w1_gpio_probe_dt(pdev);
-               if (err < 0) {
-                       dev_err(&pdev->dev, "Failed to parse DT\n");
+               if (err < 0)
                        return err;
-               }
        }
 
        pdata = dev_get_platdata(&pdev->dev);
index 5e6a3c9e510b43f54c4467faa4219c077a1f7bb7..1cdce80b6abfca9961cb7cb4623f9ea2ec14741f 100644 (file)
@@ -72,7 +72,6 @@ config W1_SLAVE_DS2433_CRC
 
 config W1_SLAVE_DS2760
        tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)"
-       depends on W1
        help
          If you enable this you will have the DS2760 battery monitor
          chip support.
@@ -85,7 +84,6 @@ config W1_SLAVE_DS2760
 
 config W1_SLAVE_DS2780
        tristate "Dallas 2780 battery monitor chip"
-       depends on W1
        help
          If you enable this you will have the DS2780 battery monitor
          chip support.
@@ -98,7 +96,6 @@ config W1_SLAVE_DS2780
 
 config W1_SLAVE_DS2781
        tristate "Dallas 2781 battery monitor chip"
-       depends on W1
        help
          If you enable this you will have the DS2781 battery monitor
          chip support.
@@ -111,7 +108,6 @@ config W1_SLAVE_DS2781
 
 config W1_SLAVE_DS28E04
        tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
-       depends on W1
        select CRC16
        help
          If you enable this you will have the DS28E04-100
@@ -124,7 +120,6 @@ config W1_SLAVE_DS28E04
 
 config W1_SLAVE_BQ27000
        tristate "BQ27000 slave support"
-       depends on W1
        help
          Say Y here if you want to use a hdq
          bq27000 slave support.
index 8b5ff33f72cf461ce3e2f774883f87d0a1762731..1f11a20a8ab9dac08fd498da405f3068c48415ab 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/types.h>
+#include <linux/slab.h>
 #include <linux/delay.h>
 
 #include "../w1.h"
@@ -58,6 +59,19 @@ MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));
 static int w1_strong_pullup = 1;
 module_param_named(strong_pullup, w1_strong_pullup, int, 0);
 
+static int w1_therm_add_slave(struct w1_slave *sl)
+{
+       sl->family_data = kzalloc(9, GFP_KERNEL);
+       if (!sl->family_data)
+               return -ENOMEM;
+       return 0;
+}
+
+static void w1_therm_remove_slave(struct w1_slave *sl)
+{
+       kfree(sl->family_data);
+       sl->family_data = NULL;
+}
 
 static ssize_t w1_slave_show(struct device *device,
        struct device_attribute *attr, char *buf);
@@ -71,6 +85,8 @@ static struct attribute *w1_therm_attrs[] = {
 ATTRIBUTE_GROUPS(w1_therm);
 
 static struct w1_family_ops w1_therm_fops = {
+       .add_slave      = w1_therm_add_slave,
+       .remove_slave   = w1_therm_remove_slave,
        .groups         = w1_therm_groups,
 };
 
@@ -253,12 +269,13 @@ static ssize_t w1_slave_show(struct device *device,
        c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
                           crc, (verdict) ? "YES" : "NO");
        if (verdict)
-               memcpy(sl->rom, rom, sizeof(sl->rom));
+               memcpy(sl->family_data, rom, sizeof(rom));
        else
                dev_warn(device, "Read failed CRC check\n");
 
        for (i = 0; i < 9; ++i)
-               c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", sl->rom[i]);
+               c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ",
+                             ((u8 *)sl->family_data)[i]);
 
        c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
                w1_convert_temp(rom, sl->family->fid));
index 66efa96c460354b6fb8087634be49e3a25643fd0..b96f61b15dc65e866564a075686072eddc49f905 100644 (file)
@@ -46,18 +46,29 @@ MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
 
 static int w1_timeout = 10;
-int w1_max_slave_count = 10;
+int w1_max_slave_count = 64;
 int w1_max_slave_ttl = 10;
 
 module_param_named(timeout, w1_timeout, int, 0);
+MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
+/* A search stops when w1_max_slave_count devices have been found in that
+ * search.  The next search will start over and detect the same set of devices
+ * on a static 1-wire bus.  Memory is not allocated based on this number, just
+ * on the number of devices known to the kernel.  Having a high number does not
+ * consume additional resources.  As a special case, if there is only one
+ * device on the network and w1_max_slave_count is set to 1, the device id can
+ * be read directly skipping the normal slower search process.
+ */
 module_param_named(max_slave_count, w1_max_slave_count, int, 0);
+MODULE_PARM_DESC(max_slave_count,
+       "maximum number of slaves detected in a search");
 module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
+MODULE_PARM_DESC(slave_ttl,
+       "Number of searches not seeing a slave before it will be removed");
 
 DEFINE_MUTEX(w1_mlock);
 LIST_HEAD(w1_masters);
 
-static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
-
 static int w1_master_match(struct device *dev, struct device_driver *drv)
 {
        return 1;
@@ -81,19 +92,10 @@ static void w1_slave_release(struct device *dev)
 {
        struct w1_slave *sl = dev_to_w1_slave(dev);
 
-       dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
-
-       while (atomic_read(&sl->refcnt)) {
-               dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
-                               sl->name, atomic_read(&sl->refcnt));
-               if (msleep_interruptible(1000))
-                       flush_signals(current);
-       }
+       dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);
 
        w1_family_put(sl->family);
        sl->master->slave_count--;
-
-       complete(&sl->released);
 }
 
 static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -243,7 +245,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
        mutex_lock(&md->mutex);
        md->search_count = tmp;
        mutex_unlock(&md->mutex);
-       wake_up_process(md->thread);
+       /* Only wake if it is going to be searching. */
+       if (tmp)
+               wake_up_process(md->thread);
 
        return count;
 }
@@ -277,7 +281,6 @@ static ssize_t w1_master_attribute_store_pullup(struct device *dev,
        mutex_lock(&md->mutex);
        md->enable_pullup = tmp;
        mutex_unlock(&md->mutex);
-       wake_up_process(md->thread);
 
        return count;
 }
@@ -314,6 +317,24 @@ static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct devic
        return count;
 }
 
+static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       int tmp;
+       struct w1_master *md = dev_to_w1_master(dev);
+
+       if (kstrtoint(buf, 0, &tmp) == -EINVAL || tmp < 1)
+               return -EINVAL;
+
+       mutex_lock(&md->mutex);
+       md->max_slave_count = tmp;
+       /* allow each time the max_slave_count is updated */
+       clear_bit(W1_WARN_MAX_COUNT, &md->flags);
+       mutex_unlock(&md->mutex);
+
+       return count;
+}
+
 static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct w1_master *md = dev_to_w1_master(dev);
@@ -352,23 +373,20 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev,
 {
        struct w1_master *md = dev_to_w1_master(dev);
        int c = PAGE_SIZE;
+       struct list_head *ent, *n;
+       struct w1_slave *sl = NULL;
 
-       mutex_lock(&md->mutex);
-
-       if (md->slave_count == 0)
-               c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
-       else {
-               struct list_head *ent, *n;
-               struct w1_slave *sl;
+       mutex_lock(&md->list_mutex);
 
-               list_for_each_safe(ent, n, &md->slist) {
-                       sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+       list_for_each_safe(ent, n, &md->slist) {
+               sl = list_entry(ent, struct w1_slave, w1_slave_entry);
 
-                       c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
-               }
+               c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
        }
+       if (!sl)
+               c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
 
-       mutex_unlock(&md->mutex);
+       mutex_unlock(&md->list_mutex);
 
        return PAGE_SIZE - c;
 }
@@ -422,19 +440,22 @@ static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
 }
 
 /* Searches the slaves in the w1_master and returns a pointer or NULL.
- * Note: must hold the mutex
+ * Note: must not hold list_mutex
  */
-static struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+struct w1_slave *w1_slave_search_device(struct w1_master *dev,
        struct w1_reg_num *rn)
 {
        struct w1_slave *sl;
+       mutex_lock(&dev->list_mutex);
        list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
                if (sl->reg_num.family == rn->family &&
                                sl->reg_num.id == rn->id &&
                                sl->reg_num.crc == rn->crc) {
+                       mutex_unlock(&dev->list_mutex);
                        return sl;
                }
        }
+       mutex_unlock(&dev->list_mutex);
        return NULL;
 }
 
@@ -491,7 +512,10 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,
        mutex_lock(&md->mutex);
        sl = w1_slave_search_device(md, &rn);
        if (sl) {
-               w1_slave_detach(sl);
+               result = w1_slave_detach(sl);
+               /* refcnt 0 means it was detached in the call */
+               if (result == 0)
+                       result = count;
        } else {
                dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
                        (unsigned long long)rn.id);
@@ -516,7 +540,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,
 static W1_MASTER_ATTR_RO(name, S_IRUGO);
 static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
 static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
-static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
 static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
 static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
 static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
@@ -686,12 +710,14 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
        dev_set_uevent_suppress(&sl->dev, false);
        kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
 
+       mutex_lock(&sl->master->list_mutex);
        list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
+       mutex_unlock(&sl->master->list_mutex);
 
        return 0;
 }
 
-static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
+int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 {
        struct w1_slave *sl;
        struct w1_family *f;
@@ -713,8 +739,8 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 
        memset(&msg, 0, sizeof(msg));
        memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
-       atomic_set(&sl->refcnt, 0);
-       init_completion(&sl->released);
+       atomic_set(&sl->refcnt, 1);
+       atomic_inc(&sl->master->refcnt);
 
        /* slave modules need to be loaded in a context with unlocked mutex */
        mutex_unlock(&dev->mutex);
@@ -754,23 +780,48 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
        return 0;
 }
 
-void w1_slave_detach(struct w1_slave *sl)
+int w1_unref_slave(struct w1_slave *sl)
 {
-       struct w1_netlink_msg msg;
-
-       dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__, sl->name, sl);
-
-       list_del(&sl->w1_slave_entry);
-
-       memset(&msg, 0, sizeof(msg));
-       memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
-       msg.type = W1_SLAVE_REMOVE;
-       w1_netlink_send(sl->master, &msg);
-
-       device_unregister(&sl->dev);
+       struct w1_master *dev = sl->master;
+       int refcnt;
+       mutex_lock(&dev->list_mutex);
+       refcnt = atomic_sub_return(1, &sl->refcnt);
+       if (refcnt == 0) {
+               struct w1_netlink_msg msg;
+
+               dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__,
+                       sl->name, sl);
+
+               list_del(&sl->w1_slave_entry);
+
+               memset(&msg, 0, sizeof(msg));
+               memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
+               msg.type = W1_SLAVE_REMOVE;
+               w1_netlink_send(sl->master, &msg);
+
+               device_unregister(&sl->dev);
+               #ifdef DEBUG
+               memset(sl, 0, sizeof(*sl));
+               #endif
+               kfree(sl);
+       }
+       atomic_dec(&dev->refcnt);
+       mutex_unlock(&dev->list_mutex);
+       return refcnt;
+}
 
-       wait_for_completion(&sl->released);
-       kfree(sl);
+int w1_slave_detach(struct w1_slave *sl)
+{
+       /* Only detach a slave once as it decreases the refcnt each time. */
+       int destroy_now;
+       mutex_lock(&sl->master->list_mutex);
+       destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags);
+       set_bit(W1_SLAVE_DETACH, &sl->flags);
+       mutex_unlock(&sl->master->list_mutex);
+
+       if (destroy_now)
+               destroy_now = !w1_unref_slave(sl);
+       return destroy_now ? 0 : -EBUSY;
 }
 
 struct w1_master *w1_search_master_id(u32 id)
@@ -799,7 +850,7 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
 
        mutex_lock(&w1_mlock);
        list_for_each_entry(dev, &w1_masters, w1_master_entry) {
-               mutex_lock(&dev->mutex);
+               mutex_lock(&dev->list_mutex);
                list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
                        if (sl->reg_num.family == id->family &&
                                        sl->reg_num.id == id->id &&
@@ -810,7 +861,7 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
                                break;
                        }
                }
-               mutex_unlock(&dev->mutex);
+               mutex_unlock(&dev->list_mutex);
 
                if (found)
                        break;
@@ -830,6 +881,7 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)
                dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
                        "for family %02x.\n", dev->name, f->fid);
                mutex_lock(&dev->mutex);
+               mutex_lock(&dev->list_mutex);
                list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
                        /* If it is a new family, slaves with the default
                         * family driver and are that family will be
@@ -841,14 +893,19 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)
                                (!attach && sl->family->fid == f->fid)) {
                                struct w1_reg_num rn;
 
+                               mutex_unlock(&dev->list_mutex);
                                memcpy(&rn, &sl->reg_num, sizeof(rn));
-                               w1_slave_detach(sl);
-
-                               w1_attach_slave_device(dev, &rn);
+                               /* If it was already in use let the automatic
+                                * scan pick it up again later.
+                                */
+                               if (!w1_slave_detach(sl))
+                                       w1_attach_slave_device(dev, &rn);
+                               mutex_lock(&dev->list_mutex);
                        }
                }
                dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
                        "has been finished.\n", dev->name);
+               mutex_unlock(&dev->list_mutex);
                mutex_unlock(&dev->mutex);
        }
        mutex_unlock(&w1_mlock);
@@ -876,7 +933,12 @@ void w1_slave_found(struct w1_master *dev, u64 rn)
 }
 
 /**
- * Performs a ROM Search & registers any devices found.
+ * w1_search() - Performs a ROM Search & registers any devices found.
+ * @dev: The master device to search
+ * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH
+ * to return only devices in the alarmed state
+ * @cb: Function to call when a device is found
+ *
  * The 1-wire search is a simple binary tree search.
  * For each bit of the address, we read two bits and write one bit.
  * The bit written will put to sleep all devies that don't match that bit.
@@ -886,8 +948,6 @@ void w1_slave_found(struct w1_master *dev, u64 rn)
  *
  * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
  *
- * @dev        The master device to search
- * @cb         Function to call when a device is found
  */
 void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
 {
@@ -898,7 +958,8 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
        u8  triplet_ret = 0;
 
        search_bit = 0;
-       rn = last_rn = 0;
+       rn = dev->search_id;
+       last_rn = 0;
        last_device = 0;
        last_zero = -1;
 
@@ -945,7 +1006,7 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
                        else
                                search_bit = ((last_rn >> i) & 0x1);
 
-                       /** Read two bits and write one bit */
+                       /* Read two bits and write one bit */
                        triplet_ret = w1_triplet(dev, search_bit);
 
                        /* quit if no device responded */
@@ -960,8 +1021,7 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
                        tmp64 = (triplet_ret >> 2);
                        rn |= (tmp64 << i);
 
-                       /* ensure we're called from kthread and not by netlink callback */
-                       if (!dev->priv && kthread_should_stop()) {
+                       if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
                                mutex_unlock(&dev->bus_mutex);
                                dev_dbg(&dev->dev, "Abort w1_search\n");
                                return;
@@ -970,11 +1030,30 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
                mutex_unlock(&dev->bus_mutex);
 
                if ( (triplet_ret & 0x03) != 0x03 ) {
-                       if ( (desc_bit == last_zero) || (last_zero < 0))
+                       if ((desc_bit == last_zero) || (last_zero < 0)) {
                                last_device = 1;
+                               dev->search_id = 0;
+                       } else {
+                               dev->search_id = rn;
+                       }
                        desc_bit = last_zero;
                        cb(dev, rn);
                }
+
+               if (!last_device && slave_count == dev->max_slave_count &&
+                       !test_bit(W1_WARN_MAX_COUNT, &dev->flags)) {
+                       /* Only max_slave_count will be scanned in a search,
+                        * but it will start where it left off next search
+                        * until all ids are identified and then it will start
+                        * over.  A continued search will report the previous
+                        * last id as the first id (provided it is still on the
+                        * bus).
+                        */
+                       dev_info(&dev->dev, "%s: max_slave_count %d reached, "
+                               "will continue next search.\n", __func__,
+                               dev->max_slave_count);
+                       set_bit(W1_WARN_MAX_COUNT, &dev->flags);
+               }
        }
 }
 
@@ -983,17 +1062,24 @@ void w1_search_process_cb(struct w1_master *dev, u8 search_type,
 {
        struct w1_slave *sl, *sln;
 
+       mutex_lock(&dev->list_mutex);
        list_for_each_entry(sl, &dev->slist, w1_slave_entry)
                clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
+       mutex_unlock(&dev->list_mutex);
 
        w1_search_devices(dev, search_type, cb);
 
+       mutex_lock(&dev->list_mutex);
        list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
-               if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl)
+               if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
+                       mutex_unlock(&dev->list_mutex);
                        w1_slave_detach(sl);
+                       mutex_lock(&dev->list_mutex);
+               }
                else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
                        sl->ttl = dev->slave_ttl;
        }
+       mutex_unlock(&dev->list_mutex);
 
        if (dev->search_count > 0)
                dev->search_count--;
@@ -1004,6 +1090,32 @@ static void w1_search_process(struct w1_master *dev, u8 search_type)
        w1_search_process_cb(dev, search_type, w1_slave_found);
 }
 
+/**
+ * w1_process_callbacks() - execute each dev->async_list callback entry
+ * @dev: w1_master device
+ *
+ * Return: 1 if there were commands to executed 0 otherwise
+ */
+int w1_process_callbacks(struct w1_master *dev)
+{
+       int ret = 0;
+       struct w1_async_cmd *async_cmd, *async_n;
+
+       /* The list can be added to in another thread, loop until it is empty */
+       while (!list_empty(&dev->async_list)) {
+               list_for_each_entry_safe(async_cmd, async_n, &dev->async_list,
+                       async_entry) {
+                       /* drop the lock, if it is a search it can take a long
+                        * time */
+                       mutex_unlock(&dev->list_mutex);
+                       async_cmd->cb(dev, async_cmd);
+                       ret = 1;
+                       mutex_lock(&dev->list_mutex);
+               }
+       }
+       return ret;
+}
+
 int w1_process(void *data)
 {
        struct w1_master *dev = (struct w1_master *) data;
@@ -1011,23 +1123,46 @@ int w1_process(void *data)
         * time can be calculated in jiffies once.
         */
        const unsigned long jtime = msecs_to_jiffies(w1_timeout * 1000);
+       /* remainder if it woke up early */
+       unsigned long jremain = 0;
 
-       while (!kthread_should_stop()) {
-               if (dev->search_count) {
+       for (;;) {
+
+               if (!jremain && dev->search_count) {
                        mutex_lock(&dev->mutex);
                        w1_search_process(dev, W1_SEARCH);
                        mutex_unlock(&dev->mutex);
                }
 
+               mutex_lock(&dev->list_mutex);
+               /* Note, w1_process_callback drops the lock while processing,
+                * but locks it again before returning.
+                */
+               if (!w1_process_callbacks(dev) && jremain) {
+                       /* a wake up is either to stop the thread, process
+                        * callbacks, or search, it isn't process callbacks, so
+                        * schedule a search.
+                        */
+                       jremain = 1;
+               }
+
                try_to_freeze();
                __set_current_state(TASK_INTERRUPTIBLE);
 
+               /* hold list_mutex until after interruptible to prevent loosing
+                * the wakeup signal when async_cmd is added.
+                */
+               mutex_unlock(&dev->list_mutex);
+
                if (kthread_should_stop())
                        break;
 
                /* Only sleep when the search is active. */
-               if (dev->search_count)
-                       schedule_timeout(jtime);
+               if (dev->search_count) {
+                       if (!jremain)
+                               jremain = jtime;
+                       jremain = schedule_timeout(jremain);
+               }
                else
                        schedule();
        }
index ca8081a101d64ac34fadbc872aeaf3e0898c4fc8..734dab7fc687a743e43e8f391b0922f55139b78e 100644 (file)
 #ifndef __W1_H
 #define __W1_H
 
+/**
+ * struct w1_reg_num - broken out slave device id
+ *
+ * @family: identifies the type of device
+ * @id: along with family is the unique device id
+ * @crc: checksum of the other bytes
+ */
 struct w1_reg_num
 {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
@@ -58,7 +65,24 @@ struct w1_reg_num
 #define W1_RESUME_CMD          0xA5
 
 #define W1_SLAVE_ACTIVE                0
+#define W1_SLAVE_DETACH                1
 
+/**
+ * struct w1_slave - holds a single slave device on the bus
+ *
+ * @owner: Points to the one wire "wire" kernel module.
+ * @name: Device id is ascii.
+ * @w1_slave_entry: data for the linked list
+ * @reg_num: the slave id in binary
+ * @refcnt: reference count, delete when 0
+ * @flags: bit flags for W1_SLAVE_ACTIVE W1_SLAVE_DETACH
+ * @ttl: decrement per search this slave isn't found, deatch at 0
+ * @master: bus which this slave is on
+ * @family: module for device family type
+ * @family_data: pointer for use by the family module
+ * @dev: kernel device identifier
+ *
+ */
 struct w1_slave
 {
        struct module           *owner;
@@ -66,7 +90,6 @@ struct w1_slave
        struct list_head        w1_slave_entry;
        struct w1_reg_num       reg_num;
        atomic_t                refcnt;
-       u8                      rom[9];
        int                     ttl;
        unsigned long           flags;
 
@@ -74,99 +97,146 @@ struct w1_slave
        struct w1_family        *family;
        void                    *family_data;
        struct device           dev;
-       struct completion       released;
 };
 
 typedef void (*w1_slave_found_callback)(struct w1_master *, u64);
 
 
 /**
+ * struct w1_bus_master - operations available on a bus master
+ *
+ * @data: the first parameter in all the functions below
+ *
+ * @read_bit: Sample the line level @return the level read (0 or 1)
+ *
+ * @write_bit: Sets the line level
+ *
+ * @touch_bit: the lowest-level function for devices that really support the
+ * 1-wire protocol.
+ * touch_bit(0) = write-0 cycle
+ * touch_bit(1) = write-1 / read cycle
+ * @return the bit read (0 or 1)
+ *
+ * @read_byte: Reads a bytes. Same as 8 touch_bit(1) calls.
+ * @return the byte read
+ *
+ * @write_byte: Writes a byte. Same as 8 touch_bit(x) calls.
+ *
+ * @read_block: Same as a series of read_byte() calls
+ * @return the number of bytes read
+ *
+ * @write_block: Same as a series of write_byte() calls
+ *
+ * @triplet: Combines two reads and a smart write for ROM searches
+ * @return bit0=Id bit1=comp_id bit2=dir_taken
+ *
+ * @reset_bus: long write-0 with a read for the presence pulse detection
+ * @return -1=Error, 0=Device present, 1=No device present
+ *
+ * @set_pullup: Put out a strong pull-up pulse of the specified duration.
+ * @return -1=Error, 0=completed
+ *
+ * @search: Really nice hardware can handles the different types of ROM search
+ * w1_master* is passed to the slave found callback.
+ * u8 is search_type, W1_SEARCH or W1_ALARM_SEARCH
+ *
  * Note: read_bit and write_bit are very low level functions and should only
  * be used with hardware that doesn't really support 1-wire operations,
  * like a parallel/serial port.
  * Either define read_bit and write_bit OR define, at minimum, touch_bit and
  * reset_bus.
+ *
  */
 struct w1_bus_master
 {
-       /** the first parameter in all the functions below */
        void            *data;
 
-       /**
-        * Sample the line level
-        * @return the level read (0 or 1)
-        */
        u8              (*read_bit)(void *);
 
-       /** Sets the line level */
        void            (*write_bit)(void *, u8);
 
-       /**
-        * touch_bit is the lowest-level function for devices that really
-        * support the 1-wire protocol.
-        * touch_bit(0) = write-0 cycle
-        * touch_bit(1) = write-1 / read cycle
-        * @return the bit read (0 or 1)
-        */
        u8              (*touch_bit)(void *, u8);
 
-       /**
-        * Reads a bytes. Same as 8 touch_bit(1) calls.
-        * @return the byte read
-        */
        u8              (*read_byte)(void *);
 
-       /**
-        * Writes a byte. Same as 8 touch_bit(x) calls.
-        */
        void            (*write_byte)(void *, u8);
 
-       /**
-        * Same as a series of read_byte() calls
-        * @return the number of bytes read
-        */
        u8              (*read_block)(void *, u8 *, int);
 
-       /** Same as a series of write_byte() calls */
        void            (*write_block)(void *, const u8 *, int);
 
-       /**
-        * Combines two reads and a smart write for ROM searches
-        * @return bit0=Id bit1=comp_id bit2=dir_taken
-        */
        u8              (*triplet)(void *, u8);
 
-       /**
-        * long write-0 with a read for the presence pulse detection
-        * @return -1=Error, 0=Device present, 1=No device present
-        */
        u8              (*reset_bus)(void *);
 
-       /**
-        * Put out a strong pull-up pulse of the specified duration.
-        * @return -1=Error, 0=completed
-        */
        u8              (*set_pullup)(void *, int);
 
-       /** Really nice hardware can handles the different types of ROM search
-        *  w1_master* is passed to the slave found callback.
-        */
        void            (*search)(void *, struct w1_master *,
                u8, w1_slave_found_callback);
 };
 
+/**
+ * enum w1_master_flags - bitfields used in w1_master.flags
+ * @W1_ABORT_SEARCH: abort searching early on shutdown
+ * @W1_WARN_MAX_COUNT: limit warning when the maximum count is reached
+ */
+enum w1_master_flags {
+       W1_ABORT_SEARCH = 0,
+       W1_WARN_MAX_COUNT = 1,
+};
+
+/**
+ * struct w1_master - one per bus master
+ * @w1_master_entry:   master linked list
+ * @owner:             module owner
+ * @name:              dynamically allocate bus name
+ * @list_mutex:                protect slist and async_list
+ * @slist:             linked list of slaves
+ * @async_list:                linked list of netlink commands to execute
+ * @max_slave_count:   maximum number of slaves to search for at a time
+ * @slave_count:       current number of slaves known
+ * @attempts:          number of searches ran
+ * @slave_ttl:         number of searches before a slave is timed out
+ * @initialized:       prevent init/removal race conditions
+ * @id:                        w1 bus number
+ * @search_count:      number of automatic searches to run, -1 unlimited
+ * @search_id:         allows continuing a search
+ * @refcnt:            reference count
+ * @priv:              private data storage
+ * @priv_size:         size allocated
+ * @enable_pullup:     allows a strong pullup
+ * @pullup_duration:   time for the next strong pullup
+ * @flags:             one of w1_master_flags
+ * @thread:            thread for bus search and netlink commands
+ * @mutex:             protect most of w1_master
+ * @bus_mutex:         pretect concurrent bus access
+ * @driver:            sysfs driver
+ * @dev:               sysfs device
+ * @bus_master:                io operations available
+ * @seq:               sequence number used for netlink broadcasts
+ * @portid:            destination for the current netlink command
+ */
 struct w1_master
 {
        struct list_head        w1_master_entry;
        struct module           *owner;
        unsigned char           name[W1_MAXNAMELEN];
+       /* list_mutex protects just slist and async_list so slaves can be
+        * searched for and async commands added while the master has
+        * w1_master.mutex locked and is operating on the bus.
+        * lock order w1_mlock, w1_master.mutex, w1_master.list_mutex
+        */
+       struct mutex            list_mutex;
        struct list_head        slist;
+       struct list_head        async_list;
        int                     max_slave_count, slave_count;
        unsigned long           attempts;
        int                     slave_ttl;
        int                     initialized;
        u32                     id;
        int                     search_count;
+       /* id to start searching on, to continue a search or 0 to restart */
+       u64                     search_id;
 
        atomic_t                refcnt;
 
@@ -178,6 +248,8 @@ struct w1_master
        /** 5V strong pullup duration in milliseconds, zero disabled. */
        int                     pullup_duration;
 
+       long                    flags;
+
        struct task_struct      *thread;
        struct mutex            mutex;
        struct mutex            bus_mutex;
@@ -188,16 +260,41 @@ struct w1_master
        struct w1_bus_master    *bus_master;
 
        u32                     seq;
+       /* port id to send netlink responses to.  The value is temporarily
+        * stored here while processing a message, set after locking the
+        * mutex, zero before unlocking the mutex.
+        */
+       u32                     portid;
+};
+
+/**
+ * struct w1_async_cmd - execute callback from the w1_process kthread
+ * @async_entry: link entry
+ * @cb: callback function, must list_del and destroy this list before
+ * returning
+ *
+ * When inserted into the w1_master async_list, w1_process will execute
+ * the callback.  Embed this into the structure with the command details.
+ */
+struct w1_async_cmd {
+       struct list_head        async_entry;
+       void (*cb)(struct w1_master *dev, struct w1_async_cmd *async_cmd);
 };
 
 int w1_create_master_attributes(struct w1_master *);
 void w1_destroy_master_attributes(struct w1_master *master);
 void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
 void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
+/* call w1_unref_slave to release the reference counts w1_search_slave added */
 struct w1_slave *w1_search_slave(struct w1_reg_num *id);
+/* decrements the reference on sl->master and sl, and cleans up if zero
+ * returns the reference count after it has been decremented */
+int w1_unref_slave(struct w1_slave *sl);
 void w1_slave_found(struct w1_master *dev, u64 rn);
 void w1_search_process_cb(struct w1_master *dev, u8 search_type,
        w1_slave_found_callback cb);
+struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+       struct w1_reg_num *rn);
 struct w1_master *w1_search_master_id(u32 id);
 
 /* Disconnect and reconnect devices in the given family.  Used for finding
@@ -206,7 +303,9 @@ struct w1_master *w1_search_master_id(u32 id);
  * has just been registered, to 0 when it has been unregistered.
  */
 void w1_reconnect_slaves(struct w1_family *f, int attach);
-void w1_slave_detach(struct w1_slave *sl);
+int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
+/* 0 success, otherwise EBUSY */
+int w1_slave_detach(struct w1_slave *sl);
 
 u8 w1_triplet(struct w1_master *dev, int bdir);
 void w1_write_8(struct w1_master *, u8);
@@ -242,6 +341,7 @@ extern int w1_max_slave_ttl;
 extern struct list_head w1_masters;
 extern struct mutex w1_mlock;
 
+extern int w1_process_callbacks(struct w1_master *dev);
 extern int w1_process(void *);
 
 #endif /* __KERNEL__ */
index e9309778ee72c84e72581b5e3ae54c88816cbb64..3bff6b37b4727f5ad692d31e6fcbdf62ab07b34a 100644 (file)
 DEFINE_SPINLOCK(w1_flock);
 static LIST_HEAD(w1_families);
 
+/**
+ * w1_register_family() - register a device family driver
+ * @newf:      family to register
+ */
 int w1_register_family(struct w1_family *newf)
 {
        struct list_head *ent, *n;
@@ -59,6 +63,10 @@ int w1_register_family(struct w1_family *newf)
        return ret;
 }
 
+/**
+ * w1_unregister_family() - unregister a device family driver
+ * @fent:      family to unregister
+ */
 void w1_unregister_family(struct w1_family *fent)
 {
        struct list_head *ent, *n;
index 4ad0e81b640460a14e25841a82b6b3eb2f9588bd..26ca1343055bc91a7068c54e01f347d42990ae92 100644 (file)
 
 struct w1_slave;
 
+/**
+ * struct w1_family_ops - operations for a family type
+ * @add_slave: add_slave
+ * @remove_slave: remove_slave
+ * @groups: sysfs group
+ */
 struct w1_family_ops
 {
        int  (* add_slave)(struct w1_slave *);
@@ -55,6 +61,13 @@ struct w1_family_ops
        const struct attribute_group **groups;
 };
 
+/**
+ * struct w1_family - reference counted family structure.
+ * @family_entry:      family linked list
+ * @fid:               8 bit family identifier
+ * @fops:              operations for this family
+ * @refcnt:            reference counter
+ */
 struct w1_family
 {
        struct list_head        family_entry;
index 590bd8a7cd1bf3f071b145a7a48c47c30cabe510..9b084db739c745b9940cd68ee268542f76820695 100644 (file)
@@ -75,8 +75,10 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
        atomic_set(&dev->refcnt, 2);
 
        INIT_LIST_HEAD(&dev->slist);
+       INIT_LIST_HEAD(&dev->async_list);
        mutex_init(&dev->mutex);
        mutex_init(&dev->bus_mutex);
+       mutex_init(&dev->list_mutex);
 
        memcpy(&dev->dev, device, sizeof(struct device));
        dev_set_name(&dev->dev, "w1_bus_master%u", dev->id);
@@ -103,6 +105,10 @@ static void w1_free_dev(struct w1_master *dev)
        device_unregister(&dev->dev);
 }
 
+/**
+ * w1_add_master_device() - registers a new master device
+ * @master:    master bus device to register
+ */
 int w1_add_master_device(struct w1_bus_master *master)
 {
        struct w1_master *dev, *entry;
@@ -172,6 +178,7 @@ int w1_add_master_device(struct w1_bus_master *master)
 
 #if 0 /* Thread cleanup code, not required currently. */
 err_out_kill_thread:
+       set_bit(W1_ABORT_SEARCH, &dev->flags);
        kthread_stop(dev->thread);
 #endif
 err_out_rm_attr:
@@ -187,16 +194,22 @@ void __w1_remove_master_device(struct w1_master *dev)
        struct w1_netlink_msg msg;
        struct w1_slave *sl, *sln;
 
-       kthread_stop(dev->thread);
-
        mutex_lock(&w1_mlock);
        list_del(&dev->w1_master_entry);
        mutex_unlock(&w1_mlock);
 
+       set_bit(W1_ABORT_SEARCH, &dev->flags);
+       kthread_stop(dev->thread);
+
        mutex_lock(&dev->mutex);
-       list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry)
+       mutex_lock(&dev->list_mutex);
+       list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+               mutex_unlock(&dev->list_mutex);
                w1_slave_detach(sl);
+               mutex_lock(&dev->list_mutex);
+       }
        w1_destroy_master_attributes(dev);
+       mutex_unlock(&dev->list_mutex);
        mutex_unlock(&dev->mutex);
        atomic_dec(&dev->refcnt);
 
@@ -206,7 +219,9 @@ void __w1_remove_master_device(struct w1_master *dev)
 
                if (msleep_interruptible(1000))
                        flush_signals(current);
+               w1_process_callbacks(dev);
        }
+       w1_process_callbacks(dev);
 
        memset(&msg, 0, sizeof(msg));
        msg.id.mst.id = dev->id;
@@ -216,6 +231,10 @@ void __w1_remove_master_device(struct w1_master *dev)
        w1_free_dev(dev);
 }
 
+/**
+ * w1_remove_master_device() - unregister a master device
+ * @bm:        master bus device to remove
+ */
 void w1_remove_master_device(struct w1_bus_master *bm)
 {
        struct w1_master *dev, *found = NULL;
index e10acc23773395699d2bc8f19b37cb32f781fcc3..282092421cc9ee29d541e8722139387d0060c7db 100644 (file)
@@ -62,7 +62,9 @@ static void w1_write_bit(struct w1_master *dev, int bit);
 static u8 w1_read_bit(struct w1_master *dev);
 
 /**
- * Generates a write-0 or write-1 cycle and samples the level.
+ * w1_touch_bit() - Generates a write-0 or write-1 cycle and samples the level.
+ * @dev:       the master device
+ * @bit:       0 - write a 0, 1 - write a 0 read the level
  */
 static u8 w1_touch_bit(struct w1_master *dev, int bit)
 {
@@ -77,7 +79,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
 }
 
 /**
- * Generates a write-0 or write-1 cycle.
+ * w1_write_bit() - Generates a write-0 or write-1 cycle.
+ * @dev:       the master device
+ * @bit:       bit to write
+ *
  * Only call if dev->bus_master->touch_bit is NULL
  */
 static void w1_write_bit(struct w1_master *dev, int bit)
@@ -102,11 +107,12 @@ static void w1_write_bit(struct w1_master *dev, int bit)
 }
 
 /**
+ * w1_pre_write() - pre-write operations
+ * @dev:       the master device
+ *
  * Pre-write operation, currently only supporting strong pullups.
  * Program the hardware for a strong pullup, if one has been requested and
  * the hardware supports it.
- *
- * @param dev     the master device
  */
 static void w1_pre_write(struct w1_master *dev)
 {
@@ -118,11 +124,12 @@ static void w1_pre_write(struct w1_master *dev)
 }
 
 /**
+ * w1_post_write() - post-write options
+ * @dev:       the master device
+ *
  * Post-write operation, currently only supporting strong pullups.
  * If a strong pullup was requested, clear it if the hardware supports
  * them, or execute the delay otherwise, in either case clear the request.
- *
- * @param dev     the master device
  */
 static void w1_post_write(struct w1_master *dev)
 {
@@ -136,10 +143,9 @@ static void w1_post_write(struct w1_master *dev)
 }
 
 /**
- * Writes 8 bits.
- *
- * @param dev     the master device
- * @param byte    the byte to write
+ * w1_write_8() - Writes 8 bits.
+ * @dev:       the master device
+ * @byte:      the byte to write
  */
 void w1_write_8(struct w1_master *dev, u8 byte)
 {
@@ -161,7 +167,9 @@ EXPORT_SYMBOL_GPL(w1_write_8);
 
 
 /**
- * Generates a write-1 cycle and samples the level.
+ * w1_read_bit() - Generates a write-1 cycle and samples the level.
+ * @dev:       the master device
+ *
  * Only call if dev->bus_master->touch_bit is NULL
  */
 static u8 w1_read_bit(struct w1_master *dev)
@@ -185,16 +193,17 @@ static u8 w1_read_bit(struct w1_master *dev)
 }
 
 /**
- * Does a triplet - used for searching ROM addresses.
+ * w1_triplet() - * Does a triplet - used for searching ROM addresses.
+ * @dev:       the master device
+ * @bdir:      the bit to write if both id_bit and comp_bit are 0
+ *
  * Return bits:
  *  bit 0 = id_bit
  *  bit 1 = comp_bit
  *  bit 2 = dir_taken
  * If both bits 0 & 1 are set, the search should be restarted.
  *
- * @param dev     the master device
- * @param bdir    the bit to write if both id_bit and comp_bit are 0
- * @return        bit fields - see above
+ * Return:        bit fields - see above
  */
 u8 w1_triplet(struct w1_master *dev, int bdir)
 {
@@ -226,10 +235,10 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
 }
 
 /**
- * Reads 8 bits.
+ * w1_read_8() - Reads 8 bits.
+ * @dev:       the master device
  *
- * @param dev     the master device
- * @return        the byte read
+ * Return:        the byte read
  */
 u8 w1_read_8(struct w1_master *dev)
 {
@@ -247,11 +256,10 @@ u8 w1_read_8(struct w1_master *dev)
 EXPORT_SYMBOL_GPL(w1_read_8);
 
 /**
- * Writes a series of bytes.
- *
- * @param dev     the master device
- * @param buf     pointer to the data to write
- * @param len     the number of bytes to write
+ * w1_write_block() - Writes a series of bytes.
+ * @dev:       the master device
+ * @buf:       pointer to the data to write
+ * @len:       the number of bytes to write
  */
 void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
 {
@@ -269,11 +277,10 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
 EXPORT_SYMBOL_GPL(w1_write_block);
 
 /**
- * Touches a series of bytes.
- *
- * @param dev     the master device
- * @param buf     pointer to the data to write
- * @param len     the number of bytes to write
+ * w1_touch_block() - Touches a series of bytes.
+ * @dev:       the master device
+ * @buf:       pointer to the data to write
+ * @len:       the number of bytes to write
  */
 void w1_touch_block(struct w1_master *dev, u8 *buf, int len)
 {
@@ -294,12 +301,11 @@ void w1_touch_block(struct w1_master *dev, u8 *buf, int len)
 EXPORT_SYMBOL_GPL(w1_touch_block);
 
 /**
- * Reads a series of bytes.
- *
- * @param dev     the master device
- * @param buf     pointer to the buffer to fill
- * @param len     the number of bytes to read
- * @return        the number of bytes read
+ * w1_read_block() - Reads a series of bytes.
+ * @dev:       the master device
+ * @buf:       pointer to the buffer to fill
+ * @len:       the number of bytes to read
+ * Return:     the number of bytes read
  */
 u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
 {
@@ -319,10 +325,9 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
 EXPORT_SYMBOL_GPL(w1_read_block);
 
 /**
- * Issues a reset bus sequence.
- *
- * @param  dev The bus master pointer
- * @return     0=Device present, 1=No device present or error
+ * w1_reset_bus() - Issues a reset bus sequence.
+ * @dev:       the master device
+ * Return:     0=Device present, 1=No device present or error
  */
 int w1_reset_bus(struct w1_master *dev)
 {
@@ -383,12 +388,15 @@ void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_cal
 }
 
 /**
+ * w1_reset_select_slave() - reset and select a slave
+ * @sl:                the slave to select
+ *
  * Resets the bus and then selects the slave by sending either a skip rom
- * or a rom match.
+ * or a rom match.  A skip rom is issued if there is only one device
+ * registered on the bus.
  * The w1 master lock must be held.
  *
- * @param sl   the slave to select
- * @return     0=success, anything else=error
+ * Return:     0=success, anything else=error
  */
 int w1_reset_select_slave(struct w1_slave *sl)
 {
@@ -409,6 +417,9 @@ int w1_reset_select_slave(struct w1_slave *sl)
 EXPORT_SYMBOL_GPL(w1_reset_select_slave);
 
 /**
+ * w1_reset_resume_command() - resume instead of another match ROM
+ * @dev:       the master device
+ *
  * When the workflow with a slave amongst many requires several
  * successive commands a reset between each, this function is similar
  * to doing a reset then a match ROM for the last matched ROM. The
@@ -420,8 +431,6 @@ EXPORT_SYMBOL_GPL(w1_reset_select_slave);
  * doesn't work of course, but the resume command is the next best thing.
  *
  * The w1 master lock must be held.
- *
- * @param dev     the master device
  */
 int w1_reset_resume_command(struct w1_master *dev)
 {
@@ -435,6 +444,10 @@ int w1_reset_resume_command(struct w1_master *dev)
 EXPORT_SYMBOL_GPL(w1_reset_resume_command);
 
 /**
+ * w1_next_pullup() - register for a strong pullup
+ * @dev:       the master device
+ * @delay:     time in milliseconds
+ *
  * Put out a strong pull-up of the specified duration after the next write
  * operation.  Not all hardware supports strong pullups.  Hardware that
  * doesn't support strong pullups will sleep for the given time after the
@@ -442,8 +455,7 @@ EXPORT_SYMBOL_GPL(w1_reset_resume_command);
  * the next write, specifying zero will clear a previous request.
  * The w1 master lock must be held.
  *
- * @param delay        time in milliseconds
- * @return     0=success, anything else=error
+ * Return:     0=success, anything else=error
  */
 void w1_next_pullup(struct w1_master *dev, int delay)
 {
index 40788c925d1c9b4d847e6572f5a8510ac402ac71..5234964fe001e95935b8170d56d6eae7a8181a3b 100644 (file)
@@ -45,7 +45,7 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
 
        memcpy(w, msg, sizeof(struct w1_netlink_msg));
 
-       cn_netlink_send(m, 0, GFP_KERNEL);
+       cn_netlink_send(m, dev->portid, 0, GFP_KERNEL);
 }
 
 static void w1_send_slave(struct w1_master *dev, u64 rn)
@@ -54,53 +54,95 @@ static void w1_send_slave(struct w1_master *dev, u64 rn)
        struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
        struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
        int avail;
-
-       /* update kernel slave list */
-       w1_slave_found(dev, rn);
+       u64 *data;
 
        avail = dev->priv_size - cmd->len;
 
-       if (avail > 8) {
-               u64 *data = (void *)(cmd + 1) + cmd->len;
+       if (avail < 8) {
+               msg->ack++;
+               cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL);
 
-               *data = rn;
-               cmd->len += 8;
-               hdr->len += 8;
-               msg->len += 8;
-               return;
+               msg->len = sizeof(struct w1_netlink_msg) +
+                       sizeof(struct w1_netlink_cmd);
+               hdr->len = sizeof(struct w1_netlink_cmd);
+               cmd->len = 0;
        }
 
-       msg->ack++;
-       cn_netlink_send(msg, 0, GFP_KERNEL);
+       data = (void *)(cmd + 1) + cmd->len;
 
-       msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
-       hdr->len = sizeof(struct w1_netlink_cmd);
-       cmd->len = 0;
+       *data = rn;
+       cmd->len += 8;
+       hdr->len += 8;
+       msg->len += 8;
 }
 
-static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,
-               unsigned int avail)
+static void w1_found_send_slave(struct w1_master *dev, u64 rn)
 {
-       struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
-       struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
-       int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH;
+       /* update kernel slave list */
+       w1_slave_found(dev, rn);
 
-       dev->priv = msg;
-       dev->priv_size = avail;
+       w1_send_slave(dev, rn);
+}
+
+/* Get the current slave list, or search (with or without alarm) */
+static int w1_get_slaves(struct w1_master *dev,
+               struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr,
+               struct w1_netlink_cmd *req_cmd)
+{
+       struct cn_msg *msg;
+       struct w1_netlink_msg *hdr;
+       struct w1_netlink_cmd *cmd;
+       struct w1_slave *sl;
+
+       msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->id = req_msg->id;
+       msg->seq = req_msg->seq;
+       msg->ack = 0;
+       msg->len = sizeof(struct w1_netlink_msg) +
+               sizeof(struct w1_netlink_cmd);
+
+       hdr = (struct w1_netlink_msg *)(msg + 1);
+       cmd = (struct w1_netlink_cmd *)(hdr + 1);
+
+       hdr->type = W1_MASTER_CMD;
+       hdr->id = req_hdr->id;
+       hdr->len = sizeof(struct w1_netlink_cmd);
+
+       cmd->cmd = req_cmd->cmd;
+       cmd->len = 0;
 
-       w1_search_process_cb(dev, search_type, w1_send_slave);
+       dev->priv = msg;
+       dev->priv_size = PAGE_SIZE - msg->len - sizeof(struct cn_msg);
+
+       if (req_cmd->cmd == W1_CMD_LIST_SLAVES) {
+               __u64 rn;
+               mutex_lock(&dev->list_mutex);
+               list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+                       memcpy(&rn, &sl->reg_num, sizeof(rn));
+                       w1_send_slave(dev, rn);
+               }
+               mutex_unlock(&dev->list_mutex);
+       } else {
+               w1_search_process_cb(dev, cmd->cmd == W1_CMD_ALARM_SEARCH ?
+                       W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave);
+       }
 
        msg->ack = 0;
-       cn_netlink_send(msg, 0, GFP_KERNEL);
+       cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL);
 
        dev->priv = NULL;
        dev->priv_size = 0;
 
+       kfree(msg);
+
        return 0;
 }
 
 static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr,
-               struct w1_netlink_cmd *cmd)
+               struct w1_netlink_cmd *cmd, u32 portid)
 {
        void *data;
        struct w1_netlink_msg *h;
@@ -131,7 +173,7 @@ static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr,
 
        memcpy(c->data, cmd->data, c->len);
 
-       err = cn_netlink_send(cm, 0, GFP_KERNEL);
+       err = cn_netlink_send(cm, portid, 0, GFP_KERNEL);
 
        kfree(data);
 
@@ -146,11 +188,11 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg,
        switch (cmd->cmd) {
        case W1_CMD_TOUCH:
                w1_touch_block(dev, cmd->data, cmd->len);
-               w1_send_read_reply(msg, hdr, cmd);
+               w1_send_read_reply(msg, hdr, cmd, dev->portid);
                break;
        case W1_CMD_READ:
                w1_read_block(dev, cmd->data, cmd->len);
-               w1_send_read_reply(msg, hdr, cmd);
+               w1_send_read_reply(msg, hdr, cmd, dev->portid);
                break;
        case W1_CMD_WRITE:
                w1_write_block(dev, cmd->data, cmd->len);
@@ -163,38 +205,57 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg,
        return err;
 }
 
-static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg,
-               struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd)
+static int w1_process_command_addremove(struct w1_master *dev,
+       struct cn_msg *msg, struct w1_netlink_msg *hdr,
+       struct w1_netlink_cmd *cmd)
 {
-       int err = -EINVAL;
-       struct cn_msg *msg;
-       struct w1_netlink_msg *hdr;
-       struct w1_netlink_cmd *cmd;
+       struct w1_slave *sl;
+       int err = 0;
+       struct w1_reg_num *id;
 
-       msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
+       if (cmd->len != 8)
+               return -EINVAL;
 
-       msg->id = req_msg->id;
-       msg->seq = req_msg->seq;
-       msg->ack = 0;
-       msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
+       id = (struct w1_reg_num *)cmd->data;
 
-       hdr = (struct w1_netlink_msg *)(msg + 1);
-       cmd = (struct w1_netlink_cmd *)(hdr + 1);
+       sl = w1_slave_search_device(dev, id);
+       switch (cmd->cmd) {
+       case W1_CMD_SLAVE_ADD:
+               if (sl)
+                       err = -EINVAL;
+               else
+                       err = w1_attach_slave_device(dev, id);
+               break;
+       case W1_CMD_SLAVE_REMOVE:
+               if (sl)
+                       w1_slave_detach(sl);
+               else
+                       err = -EINVAL;
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
 
-       hdr->type = W1_MASTER_CMD;
-       hdr->id = req_hdr->id;
-       hdr->len = sizeof(struct w1_netlink_cmd);
+       return err;
+}
 
-       cmd->cmd = req_cmd->cmd;
-       cmd->len = 0;
+static int w1_process_command_master(struct w1_master *dev,
+       struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr,
+       struct w1_netlink_cmd *req_cmd)
+{
+       int err = -EINVAL;
 
-       switch (cmd->cmd) {
+       /* drop bus_mutex for search (does it's own locking), and add/remove
+        * which doesn't use the bus
+        */
+       switch (req_cmd->cmd) {
        case W1_CMD_SEARCH:
        case W1_CMD_ALARM_SEARCH:
-               err = w1_process_search_command(dev, msg,
-                               PAGE_SIZE - msg->len - sizeof(struct cn_msg));
+       case W1_CMD_LIST_SLAVES:
+               mutex_unlock(&dev->bus_mutex);
+               err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd);
+               mutex_lock(&dev->bus_mutex);
                break;
        case W1_CMD_READ:
        case W1_CMD_WRITE:
@@ -204,12 +265,20 @@ static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_m
        case W1_CMD_RESET:
                err = w1_reset_bus(dev);
                break;
+       case W1_CMD_SLAVE_ADD:
+       case W1_CMD_SLAVE_REMOVE:
+               mutex_unlock(&dev->bus_mutex);
+               mutex_lock(&dev->mutex);
+               err = w1_process_command_addremove(dev, req_msg, req_hdr,
+                       req_cmd);
+               mutex_unlock(&dev->mutex);
+               mutex_lock(&dev->bus_mutex);
+               break;
        default:
                err = -EINVAL;
                break;
        }
 
-       kfree(msg);
        return err;
 }
 
@@ -223,7 +292,8 @@ static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg,
        return w1_process_command_io(sl->master, msg, hdr, cmd);
 }
 
-static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd)
+static int w1_process_command_root(struct cn_msg *msg,
+       struct w1_netlink_msg *mcmd, u32 portid)
 {
        struct w1_master *m;
        struct cn_msg *cn;
@@ -256,7 +326,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc
        mutex_lock(&w1_mlock);
        list_for_each_entry(m, &w1_masters, w1_master_entry) {
                if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
-                       cn_netlink_send(cn, 0, GFP_KERNEL);
+                       cn_netlink_send(cn, portid, 0, GFP_KERNEL);
                        cn->ack++;
                        cn->len = sizeof(struct w1_netlink_msg);
                        w->len = 0;
@@ -269,7 +339,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc
                id++;
        }
        cn->ack = 0;
-       cn_netlink_send(cn, 0, GFP_KERNEL);
+       cn_netlink_send(cn, portid, 0, GFP_KERNEL);
        mutex_unlock(&w1_mlock);
 
        kfree(cn);
@@ -277,7 +347,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc
 }
 
 static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg,
-               struct w1_netlink_cmd *rcmd, int error)
+               struct w1_netlink_cmd *rcmd, int portid, int error)
 {
        struct cn_msg *cmsg;
        struct w1_netlink_msg *msg;
@@ -304,35 +374,147 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm
                cmsg->len += sizeof(*cmd);
        }
 
-       error = cn_netlink_send(cmsg, 0, GFP_KERNEL);
+       error = cn_netlink_send(cmsg, portid, 0, GFP_KERNEL);
        kfree(cmsg);
 
        return error;
 }
 
+/* Bundle together a reference count, the full message, and broken out
+ * commands to be executed on each w1 master kthread in one memory allocation.
+ */
+struct w1_cb_block {
+       atomic_t refcnt;
+       u32 portid; /* Sending process port ID */
+       struct cn_msg msg;
+       /* cn_msg data */
+       /* one or more variable length struct w1_cb_node */
+};
+struct w1_cb_node {
+       struct w1_async_cmd async;
+       /* pointers within w1_cb_block and msg data */
+       struct w1_cb_block *block;
+       struct w1_netlink_msg *m;
+       struct w1_slave *sl;
+       struct w1_master *dev;
+};
+
+static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
+{
+       struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node,
+               async);
+       u16 mlen = node->m->len;
+       u8 *cmd_data = node->m->data;
+       int err = 0;
+       struct w1_slave *sl = node->sl;
+       struct w1_netlink_cmd *cmd = NULL;
+
+       mutex_lock(&dev->bus_mutex);
+       dev->portid = node->block->portid;
+       if (sl && w1_reset_select_slave(sl))
+               err = -ENODEV;
+
+       while (mlen && !err) {
+               cmd = (struct w1_netlink_cmd *)cmd_data;
+
+               if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
+                       err = -E2BIG;
+                       break;
+               }
+
+               if (sl)
+                       err = w1_process_command_slave(sl, &node->block->msg,
+                               node->m, cmd);
+               else
+                       err = w1_process_command_master(dev, &node->block->msg,
+                               node->m, cmd);
+
+               w1_netlink_send_error(&node->block->msg, node->m, cmd,
+                       node->block->portid, err);
+               err = 0;
+
+               cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
+               mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
+       }
+
+       if (!cmd || err)
+               w1_netlink_send_error(&node->block->msg, node->m, cmd,
+                       node->block->portid, err);
+
+       if (sl)
+               w1_unref_slave(sl);
+       else
+               atomic_dec(&dev->refcnt);
+       dev->portid = 0;
+       mutex_unlock(&dev->bus_mutex);
+
+       mutex_lock(&dev->list_mutex);
+       list_del(&async_cmd->async_entry);
+       mutex_unlock(&dev->list_mutex);
+
+       if (atomic_sub_return(1, &node->block->refcnt) == 0)
+               kfree(node->block);
+}
+
 static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 {
        struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
-       struct w1_netlink_cmd *cmd;
        struct w1_slave *sl;
        struct w1_master *dev;
+       u16 msg_len;
        int err = 0;
+       struct w1_cb_block *block = NULL;
+       struct w1_cb_node *node = NULL;
+       int node_count = 0;
+
+       /* Count the number of master or slave commands there are to allocate
+        * space for one cb_node each.
+        */
+       msg_len = msg->len;
+       while (msg_len && !err) {
+               if (m->len + sizeof(struct w1_netlink_msg) > msg_len) {
+                       err = -E2BIG;
+                       break;
+               }
+
+               if (m->type == W1_MASTER_CMD || m->type == W1_SLAVE_CMD)
+                       ++node_count;
 
-       while (msg->len && !err) {
+               msg_len -= sizeof(struct w1_netlink_msg) + m->len;
+               m = (struct w1_netlink_msg *)(((u8 *)m) +
+                       sizeof(struct w1_netlink_msg) + m->len);
+       }
+       m = (struct w1_netlink_msg *)(msg + 1);
+       if (node_count) {
+               /* msg->len doesn't include itself */
+               long size = sizeof(struct w1_cb_block) + msg->len +
+                       node_count*sizeof(struct w1_cb_node);
+               block = kmalloc(size, GFP_KERNEL);
+               if (!block) {
+                       w1_netlink_send_error(msg, m, NULL, nsp->portid,
+                               -ENOMEM);
+                       return;
+               }
+               atomic_set(&block->refcnt, 1);
+               block->portid = nsp->portid;
+               memcpy(&block->msg, msg, sizeof(*msg) + msg->len);
+               node = (struct w1_cb_node *)((u8 *)block->msg.data + msg->len);
+       }
+
+       msg_len = msg->len;
+       while (msg_len && !err) {
                struct w1_reg_num id;
                u16 mlen = m->len;
-               u8 *cmd_data = m->data;
 
                dev = NULL;
                sl = NULL;
-               cmd = NULL;
 
                memcpy(&id, m->id.id, sizeof(id));
 #if 0
                printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n",
                                __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len);
 #endif
-               if (m->len + sizeof(struct w1_netlink_msg) > msg->len) {
+               if (m->len + sizeof(struct w1_netlink_msg) > msg_len) {
                        err = -E2BIG;
                        break;
                }
@@ -344,7 +526,7 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
                        if (sl)
                                dev = sl->master;
                } else {
-                       err = w1_process_command_root(msg, m);
+                       err = w1_process_command_root(msg, m, nsp->portid);
                        goto out_cont;
                }
 
@@ -357,41 +539,24 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
                if (!mlen)
                        goto out_cont;
 
-               mutex_lock(&dev->mutex);
-
-               if (sl && w1_reset_select_slave(sl)) {
-                       err = -ENODEV;
-                       goto out_up;
-               }
+               atomic_inc(&block->refcnt);
+               node->async.cb = w1_process_cb;
+               node->block = block;
+               node->m = (struct w1_netlink_msg *)((u8 *)&block->msg +
+                       (size_t)((u8 *)m - (u8 *)msg));
+               node->sl = sl;
+               node->dev = dev;
 
-               while (mlen) {
-                       cmd = (struct w1_netlink_cmd *)cmd_data;
+               mutex_lock(&dev->list_mutex);
+               list_add_tail(&node->async.async_entry, &dev->async_list);
+               wake_up_process(dev->thread);
+               mutex_unlock(&dev->list_mutex);
+               ++node;
 
-                       if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
-                               err = -E2BIG;
-                               break;
-                       }
-
-                       if (sl)
-                               err = w1_process_command_slave(sl, msg, m, cmd);
-                       else
-                               err = w1_process_command_master(dev, msg, m, cmd);
-
-                       w1_netlink_send_error(msg, m, cmd, err);
-                       err = 0;
-
-                       cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
-                       mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
-               }
-out_up:
-               atomic_dec(&dev->refcnt);
-               if (sl)
-                       atomic_dec(&sl->refcnt);
-               mutex_unlock(&dev->mutex);
 out_cont:
-               if (!cmd || err)
-                       w1_netlink_send_error(msg, m, cmd, err);
-               msg->len -= sizeof(struct w1_netlink_msg) + m->len;
+               if (err)
+                       w1_netlink_send_error(msg, m, NULL, nsp->portid, err);
+               msg_len -= sizeof(struct w1_netlink_msg) + m->len;
                m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len);
 
                /*
@@ -400,6 +565,8 @@ out_cont:
                if (err == -ENODEV)
                        err = 0;
        }
+       if (block && atomic_sub_return(1, &block->refcnt) == 0)
+               kfree(block);
 }
 
 int w1_init_netlink(void)
index b0922dc29658a3fe1d19e8b17942e2521009beb0..1e9504e67650aca2966a4647ba54aea15850eeb6 100644 (file)
 
 #include "w1.h"
 
+/**
+ * enum w1_netlink_message_types - message type
+ *
+ * @W1_SLAVE_ADD: notification that a slave device was added
+ * @W1_SLAVE_REMOVE: notification that a slave device was removed
+ * @W1_MASTER_ADD: notification that a new bus master was added
+ * @W1_MASTER_REMOVE: notification that a bus masterwas removed
+ * @W1_MASTER_CMD: initiate operations on a specific master
+ * @W1_SLAVE_CMD: sends reset, selects the slave, then does a read/write/touch
+ * operation
+ * @W1_LIST_MASTERS: used to determine the bus master identifiers
+ */
 enum w1_netlink_message_types {
        W1_SLAVE_ADD = 0,
        W1_SLAVE_REMOVE,
@@ -52,6 +64,22 @@ struct w1_netlink_msg
        __u8                            data[0];
 };
 
+/**
+ * enum w1_commands - commands available for master or slave operations
+ * @W1_CMD_READ: read len bytes
+ * @W1_CMD_WRITE: write len bytes
+ * @W1_CMD_SEARCH: initiate a standard search, returns only the slave
+ * devices found during that search
+ * @W1_CMD_ALARM_SEARCH: search for devices that are currently alarming
+ * @W1_CMD_TOUCH: Touches a series of bytes.
+ * @W1_CMD_RESET: sends a bus reset on the given master
+ * @W1_CMD_SLAVE_ADD: adds a slave to the given master,
+ * 8 byte slave id at data[0]
+ * @W1_CMD_SLAVE_REMOVE: removes a slave to the given master,
+ * 8 byte slave id at data[0]
+ * @W1_CMD_LIST_SLAVES: list of slaves registered on this master
+ * @W1_CMD_MAX: number of available commands
+ */
 enum w1_commands {
        W1_CMD_READ = 0,
        W1_CMD_WRITE,
@@ -59,7 +87,10 @@ enum w1_commands {
        W1_CMD_ALARM_SEARCH,
        W1_CMD_TOUCH,
        W1_CMD_RESET,
-       W1_CMD_MAX,
+       W1_CMD_SLAVE_ADD,
+       W1_CMD_SLAVE_REMOVE,
+       W1_CMD_LIST_SLAVES,
+       W1_CMD_MAX
 };
 
 struct w1_netlink_cmd
index 79d25894343a0f7d52e8702d05ec4020927d1040..0c6048d5c9a363a5ebd18256eaec3c149fff4d5b 100644 (file)
@@ -111,6 +111,15 @@ config WM8350_WATCHDOG
          Support for the watchdog in the WM8350 AudioPlus PMIC.  When
          the watchdog triggers the system will be reset.
 
+config XILINX_WATCHDOG
+       tristate "Xilinx Watchdog timer"
+       select WATCHDOG_CORE
+       help
+         Watchdog driver for the xps_timebase_wdt ip core.
+
+         To compile this driver as a module, choose M here: the
+         module will be called of_xilinx_wdt.
+
 # ALPHA Architecture
 
 # ARM Architecture
@@ -292,7 +301,7 @@ config DAVINCI_WATCHDOG
 
 config ORION_WATCHDOG
        tristate "Orion watchdog"
-       depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
+       depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE
        select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
@@ -421,6 +430,17 @@ config SIRFSOC_WATCHDOG
          Support for CSR SiRFprimaII and SiRFatlasVI watchdog. When
          the watchdog triggers the system will be reset.
 
+config TEGRA_WATCHDOG
+       tristate "Tegra watchdog"
+       depends on ARCH_TEGRA || COMPILE_TEST
+       select WATCHDOG_CORE
+       help
+         Say Y here to include support for the watchdog timer
+         embedded in NVIDIA Tegra SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tegra_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
@@ -533,7 +553,7 @@ config GEODE_WDT
 
 config SC520_WDT
        tristate "AMD Elan SC520 processor Watchdog"
-       depends on X86
+       depends on MELAN
        help
          This is the driver for the hardware watchdog built in to the
          AMD "Elan" SC520 microcomputer commonly used in embedded systems.
@@ -1023,18 +1043,6 @@ config M54xx_WATCHDOG
 
 # MicroBlaze Architecture
 
-config XILINX_WATCHDOG
-       tristate "Xilinx Watchdog timer"
-       depends on MICROBLAZE
-       ---help---
-         Watchdog driver for the xps_timebase_wdt ip core.
-
-         IMPORTANT: The xps_timebase_wdt parent must have the property
-         "clock-frequency" at device tree.
-
-         To compile this driver as a module, choose M here: the
-         module will be called of_xilinx_wdt.
-
 # MIPS Architecture
 
 config ATH79_WDT
@@ -1160,7 +1168,7 @@ config BCM2835_WDT
 
 config BCM_KONA_WDT
        tristate "BCM Kona Watchdog"
-       depends on ARCH_BCM
+       depends on ARCH_BCM_MOBILE
        select WATCHDOG_CORE
        help
          Support for the watchdog timer on the following Broadcom BCM281xx
index 985a66cda76f23ac89932672f1f813c9cab2dade..1b5f3d5efad5bb20e8f64c9b24b24e61a8d0bd23 100644 (file)
@@ -58,6 +58,7 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
 obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
 obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o
 obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
+obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
index 5cf1621def9c690a2e5947e1e712c1d846769379..5614416f1032a08e53ab02de2dc259e864efde30 100644 (file)
@@ -239,7 +239,7 @@ static struct miscdevice acq_miscdev = {
  *     Init & exit routines
  */
 
-static int acq_probe(struct platform_device *dev)
+static int __init acq_probe(struct platform_device *dev)
 {
        int ret;
 
@@ -291,7 +291,6 @@ static void acq_shutdown(struct platform_device *dev)
 }
 
 static struct platform_driver acquirewdt_driver = {
-       .probe          = acq_probe,
        .remove         = acq_remove,
        .shutdown       = acq_shutdown,
        .driver         = {
@@ -306,20 +305,18 @@ static int __init acq_init(void)
 
        pr_info("WDT driver for Acquire single board computer initialising\n");
 
-       err = platform_driver_register(&acquirewdt_driver);
-       if (err)
-               return err;
-
        acq_platform_device = platform_device_register_simple(DRV_NAME,
                                                                -1, NULL, 0);
-       if (IS_ERR(acq_platform_device)) {
-               err = PTR_ERR(acq_platform_device);
-               goto unreg_platform_driver;
-       }
+       if (IS_ERR(acq_platform_device))
+               return PTR_ERR(acq_platform_device);
+
+       err = platform_driver_probe(&acquirewdt_driver, acq_probe);
+       if (err)
+               goto unreg_platform_device;
        return 0;
 
-unreg_platform_driver:
-       platform_driver_unregister(&acquirewdt_driver);
+unreg_platform_device:
+       platform_device_unregister(acq_platform_device);
        return err;
 }
 
index a8961addc59cf110df2a0ff3d5cbdff67b4fbd4a..7796db7fa6e1db1899ab86ebdf5e3ac02c81ba05 100644 (file)
@@ -238,7 +238,7 @@ static struct miscdevice advwdt_miscdev = {
  *     Init & exit routines
  */
 
-static int advwdt_probe(struct platform_device *dev)
+static int __init advwdt_probe(struct platform_device *dev)
 {
        int ret;
 
@@ -299,7 +299,6 @@ static void advwdt_shutdown(struct platform_device *dev)
 }
 
 static struct platform_driver advwdt_driver = {
-       .probe          = advwdt_probe,
        .remove         = advwdt_remove,
        .shutdown       = advwdt_shutdown,
        .driver         = {
@@ -314,21 +313,19 @@ static int __init advwdt_init(void)
 
        pr_info("WDT driver for Advantech single board computer initialising\n");
 
-       err = platform_driver_register(&advwdt_driver);
-       if (err)
-               return err;
-
        advwdt_platform_device = platform_device_register_simple(DRV_NAME,
                                                                -1, NULL, 0);
-       if (IS_ERR(advwdt_platform_device)) {
-               err = PTR_ERR(advwdt_platform_device);
-               goto unreg_platform_driver;
-       }
+       if (IS_ERR(advwdt_platform_device))
+               return PTR_ERR(advwdt_platform_device);
+
+       err = platform_driver_probe(&advwdt_driver, advwdt_probe);
+       if (err)
+               goto unreg_platform_device;
 
        return 0;
 
-unreg_platform_driver:
-       platform_driver_unregister(&advwdt_driver);
+unreg_platform_device:
+       platform_device_unregister(advwdt_platform_device);
        return err;
 }
 
index 3a996576343a3b8abb20b8cab7bf65c7b503a803..ae6c287a49cb72c094167b18f534d34c2d85a54a 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
index afe7d17e677634f1fd447a147deeb133ac366f36..25b5c67d3af99cfb6608a5dd1a8c556e73ca7e31 100644 (file)
@@ -323,10 +323,8 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
 
        wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_at32ap700x),
                        GFP_KERNEL);
-       if (!wdt) {
-               dev_dbg(&pdev->dev, "no memory for wdt structure\n");
+       if (!wdt)
                return -ENOMEM;
-       }
 
        wdt->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
        if (!wdt->regs) {
index 9fa1f69dac1328d73c45fccd9034032fcb4412d8..399c3fddecf6471ac12296ba028f296e54327e43 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
index cafa973c43be7af984fb9d39456b1d36b8913ea8..8df450c090a913d0394ca16c5ae241fd7d233db6 100644 (file)
@@ -114,10 +114,8 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
        int err;
 
        wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL);
-       if (!wdt) {
-               dev_err(dev, "Failed to allocate memory for watchdog device");
+       if (!wdt)
                return -ENOMEM;
-       }
        platform_set_drvdata(pdev, wdt);
 
        spin_lock_init(&wdt->lock);
index b4021a2b459b6c0889173a30f89d4d365eb8e9f2..b61fcc53597920eadbf046af3054c95a332b4a9a 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/bcm47xx_wdt.h>
 #include <linux/bitops.h>
 #include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index 4eb188b87f8eb881784488e78d3447400499388e..5a8e879a430a0e9c9d4e4dcc674a796787a05679 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
@@ -45,7 +44,6 @@
 static struct {
        void __iomem *regs;
        struct timer_list timer;
-       int default_ticks;
        unsigned long inuse;
        atomic_t ticks;
 } bcm63xx_wdt_device;
index f7ae49edb5186d13080fe369aa5cc50f38ef791f..6d03e8e30f8bf4369cfaa6cecde6cb2a6dccb03c 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/completion.h>
index 213225edd0599a6aa7aa933ead68570fa8dddda9..e55ed702209ff8450c3c4bb2bc9d62b5685aa1c6 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/major.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
index f09c54e9686fad94104a7679aa7a7675d32d3ebd..2e9589652e1eee2a88f6fd137bde5366b6af77c3 100644 (file)
@@ -185,7 +185,6 @@ static int da9052_wdt_probe(struct platform_device *pdev)
        driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
                                   GFP_KERNEL);
        if (!driver_data) {
-               dev_err(da9052->dev, "Unable to alloacate watchdog device\n");
                ret = -ENOMEM;
                goto err;
        }
index 575f37a965a471ba93a77a4bdda5840f0dc7b8e0..495089d8dbfeb7965142c48f2579672ed8882d6c 100644 (file)
@@ -151,10 +151,8 @@ static int da9055_wdt_probe(struct platform_device *pdev)
 
        driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
                                   GFP_KERNEL);
-       if (!driver_data) {
-               dev_err(da9055->dev, "Failed to allocate watchdog device\n");
+       if (!driver_data)
                return -ENOMEM;
-       }
 
        driver_data->da9055 = da9055;
 
index b1bae03742a9a6cf5a2c32e5746ecc520c45add9..d09ad2254b577f19089608d308a3e1bb3ab94d8d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/device.h>
index d1d07f2f69df7cf61cd838feaa89650c22908098..5f54e1e5819af5ddbcb301a143ef88a07db62cfa 100644 (file)
@@ -118,16 +118,9 @@ static int ep93xx_wdt_probe(struct platform_device *pdev)
        int err;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), pdev->name))
-               return -EBUSY;
-
-       mmio_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!mmio_base)
-               return -ENXIO;
+       mmio_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mmio_base))
+               return PTR_ERR(mmio_base);
 
        if (timeout < 1 || timeout > 3600) {
                timeout = WDT_TIMEOUT;
@@ -172,9 +165,9 @@ static struct platform_driver ep93xx_wdt_driver = {
 
 module_platform_driver(ep93xx_wdt_driver);
 
-MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
-               "Alessandro Zummo <a.zummo@towertech.it>,"
-               "H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>");
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
 MODULE_DESCRIPTION("EP93xx Watchdog");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(WDT_VERSION);
index 4a6ae84b42bcc5b2e829a8bec9a51b017d2a63d5..4c43e3fa8bd2e30d4989dc99c76e3250cafcf25d 100644 (file)
@@ -215,7 +215,7 @@ static struct miscdevice geodewdt_miscdev = {
        .fops = &geodewdt_fops,
 };
 
-static int geodewdt_probe(struct platform_device *dev)
+static int __init geodewdt_probe(struct platform_device *dev)
 {
        int ret;
 
@@ -255,7 +255,6 @@ static void geodewdt_shutdown(struct platform_device *dev)
 }
 
 static struct platform_driver geodewdt_driver = {
-       .probe          = geodewdt_probe,
        .remove         = geodewdt_remove,
        .shutdown       = geodewdt_shutdown,
        .driver         = {
@@ -268,20 +267,18 @@ static int __init geodewdt_init(void)
 {
        int ret;
 
-       ret = platform_driver_register(&geodewdt_driver);
-       if (ret)
-               return ret;
-
        geodewdt_platform_device = platform_device_register_simple(DRV_NAME,
                                                                -1, NULL, 0);
-       if (IS_ERR(geodewdt_platform_device)) {
-               ret = PTR_ERR(geodewdt_platform_device);
+       if (IS_ERR(geodewdt_platform_device))
+               return PTR_ERR(geodewdt_platform_device);
+
+       ret = platform_driver_probe(&geodewdt_driver, geodewdt_probe);
+       if (ret)
                goto err;
-       }
 
        return 0;
 err:
-       platform_driver_unregister(&geodewdt_driver);
+       platform_device_unregister(geodewdt_platform_device);
        return ret;
 }
 
index 2b75e8b472796e987c3651599b7583442d5b1089..75d2243b94f51ccc2c8b250b46b30d0866c6b3b6 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/device.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/bitops.h>
 #include <linux/kernel.h>
index 25a2bfdb4e9d2e41812b676e4b93b0c4219c47a9..d7befd58b391a98cf074be706f3230b9e7c26d01 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/uaccess.h>
index 04f8af65acfd568b486c68460ff5227a841cf9a2..0e6c0333f775775aa776902cff248abddd9e3a5e 100644 (file)
@@ -347,15 +347,15 @@ static const struct watchdog_info ident = {
 static const struct watchdog_ops iTCO_wdt_ops = {
        .owner =                THIS_MODULE,
        .start =                iTCO_wdt_start,
-       .stop =                 iTCO_wdt_stop,
-       .ping =                 iTCO_wdt_ping,
+       .stop =                 iTCO_wdt_stop,
+       .ping =                 iTCO_wdt_ping,
        .set_timeout =          iTCO_wdt_set_timeout,
        .get_timeleft =         iTCO_wdt_get_timeleft,
 };
 
 static struct watchdog_device iTCO_wdt_watchdog_dev = {
        .info =         &ident,
-       .ops =          &iTCO_wdt_ops,
+       .ops =          &iTCO_wdt_ops,
 };
 
 /*
@@ -485,7 +485,7 @@ static int iTCO_wdt_probe(struct platform_device *dev)
        iTCO_wdt_watchdog_dev.bootstatus = 0;
        iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
        watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
-       iTCO_wdt_watchdog_dev.parent = dev->dev.parent;
+       iTCO_wdt_watchdog_dev.parent = &dev->dev;
 
        /* Make sure the watchdog is not running */
        iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
index 7ae36690c44916305508408d61fdb117af3d7945..4247c498ee78b22d2d91dc0ccad0b7407a0a9f24 100644 (file)
@@ -277,7 +277,7 @@ static struct miscdevice ibwdt_miscdev = {
  *     Init & exit routines
  */
 
-static int ibwdt_probe(struct platform_device *dev)
+static int __init ibwdt_probe(struct platform_device *dev)
 {
        int res;
 
@@ -336,7 +336,6 @@ static void ibwdt_shutdown(struct platform_device *dev)
 }
 
 static struct platform_driver ibwdt_driver = {
-       .probe          = ibwdt_probe,
        .remove         = ibwdt_remove,
        .shutdown       = ibwdt_shutdown,
        .driver         = {
@@ -351,21 +350,19 @@ static int __init ibwdt_init(void)
 
        pr_info("WDT driver for IB700 single board computer initialising\n");
 
-       err = platform_driver_register(&ibwdt_driver);
-       if (err)
-               return err;
-
        ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
                                                                -1, NULL, 0);
-       if (IS_ERR(ibwdt_platform_device)) {
-               err = PTR_ERR(ibwdt_platform_device);
-               goto unreg_platform_driver;
-       }
+       if (IS_ERR(ibwdt_platform_device))
+               return PTR_ERR(ibwdt_platform_device);
+
+       err = platform_driver_probe(&ibwdt_driver, ibwdt_probe);
+       if (err)
+               goto unreg_platform_device;
 
        return 0;
 
-unreg_platform_driver:
-       platform_driver_unregister(&ibwdt_driver);
+unreg_platform_device:
+       platform_device_unregister(ibwdt_platform_device);
        return err;
 }
 
index db0a34460e57a796a3891cb407d52d2985d20102..366b0474f27851406cf103a0e4420d560759d47a 100644 (file)
@@ -360,7 +360,7 @@ struct ibmasr_id {
        int type;
 };
 
-static struct ibmasr_id __initdata ibmasr_id_table[] = {
+static struct ibmasr_id ibmasr_id_table[] __initdata = {
        { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
        { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
        { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
index 1b5c25a47b876194561490aba581d84ac5cd27cc..5d20cdd30efe6679fa56fc7b34cce151d54da679 100644 (file)
@@ -41,24 +41,15 @@ MODULE_PARM_DESC(nowayout,
 
 static void indydog_start(void)
 {
-       u32 mc_ctrl0;
-
        spin_lock(&indydog_lock);
-       mc_ctrl0 = sgimc->cpuctrl0;
-       mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
-       sgimc->cpuctrl0 = mc_ctrl0;
+       sgimc->cpuctrl0 |= SGIMC_CCTRL0_WDOG;
        spin_unlock(&indydog_lock);
 }
 
 static void indydog_stop(void)
 {
-       u32 mc_ctrl0;
-
        spin_lock(&indydog_lock);
-
-       mc_ctrl0 = sgimc->cpuctrl0;
-       mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
-       sgimc->cpuctrl0 = mc_ctrl0;
+       sgimc->cpuctrl0 &= ~SGIMC_CCTRL0_WDOG;
        spin_unlock(&indydog_lock);
 
        pr_info("Stopped watchdog timer\n");
index e13e65e996aa7b996f18232243642f7298f8532b..0caab6241eb77a84bd2911dbaa011be68498fd85 100644 (file)
@@ -211,7 +211,6 @@ static int intel_scu_set_heartbeat(u32 t)
        int                      ipc_ret;
        int                      retry_count;
        u32                      soft_value;
-       u32                      hw_pre_value;
        u32                      hw_value;
 
        watchdog_device.timer_set = t;
@@ -273,8 +272,7 @@ static int intel_scu_set_heartbeat(u32 t)
                        watchdog_device.timer_load_count_addr);
 
                /* read count value before starting timer */
-               hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
-               hw_pre_value = hw_pre_value & 0xFFFF0000;
+               ioread32(watchdog_device.timer_load_count_addr);
 
                /* Start the timer */
                iowrite32(0x00000003, watchdog_device.timer_control_addr);
index e2bba68ae71e0108707a24dfa9d14feb6c3c974d..0b93739c0106b17c885a4ef8292681d449851491 100644 (file)
@@ -54,6 +54,7 @@
 
 /* Defaults for Module Parameter */
 #define DEFAULT_NOGAMEPORT     0
+#define DEFAULT_NOCIR          0
 #define DEFAULT_EXCLUSIVE      1
 #define DEFAULT_TIMEOUT                60
 #define DEFAULT_TESTMODE       0
 #define WDTS_LOCKED    3
 #define WDTS_USE_GP    4
 #define WDTS_EXPECTED  5
+#define WDTS_USE_CIR   6
 
 static unsigned int base, gpact, ciract, max_units, chip_type;
 static unsigned long wdt_status;
 
 static int nogameport = DEFAULT_NOGAMEPORT;
+static int nocir      = DEFAULT_NOCIR;
 static int exclusive  = DEFAULT_EXCLUSIVE;
 static int timeout    = DEFAULT_TIMEOUT;
 static int testmode   = DEFAULT_TESTMODE;
@@ -149,6 +152,9 @@ static      bool nowayout   = DEFAULT_NOWAYOUT;
 module_param(nogameport, int, 0);
 MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
                __MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(nocir, int, 0);
+MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default="
+               __MODULE_STRING(DEFAULT_NOCIR));
 module_param(exclusive, int, 0);
 MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
                __MODULE_STRING(DEFAULT_EXCLUSIVE));
@@ -258,9 +264,17 @@ static void wdt_keepalive(void)
 {
        if (test_bit(WDTS_USE_GP, &wdt_status))
                inb(base);
-       else
+       else if (test_bit(WDTS_USE_CIR, &wdt_status))
                /* The timer reloads with around 5 msec delay */
                outb(0x55, CIR_DR(base));
+       else {
+               if (superio_enter())
+                       return;
+
+               superio_select(GPIO);
+               wdt_update_timeout();
+               superio_exit();
+       }
        set_bit(WDTS_KEEPALIVE, &wdt_status);
 }
 
@@ -273,7 +287,7 @@ static int wdt_start(void)
        superio_select(GPIO);
        if (test_bit(WDTS_USE_GP, &wdt_status))
                superio_outb(WDT_GAMEPORT, WDTCTRL);
-       else
+       else if (test_bit(WDTS_USE_CIR, &wdt_status))
                superio_outb(WDT_CIRINT, WDTCTRL);
        wdt_update_timeout();
 
@@ -660,7 +674,7 @@ static int __init it87_wdt_init(void)
        }
 
        /* If we haven't Gameport support, try to get CIR support */
-       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+       if (!nocir && !test_bit(WDTS_USE_GP, &wdt_status)) {
                if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
                        if (gp_rreq_fail)
                                pr_err("I/O Address 0x%04x and 0x%04x already in use\n",
@@ -682,6 +696,7 @@ static int __init it87_wdt_init(void)
                        superio_select(GAMEPORT);
                        superio_outb(gpact, ACTREG);
                }
+               set_bit(WDTS_USE_CIR, &wdt_status);
        }
 
        if (timeout < 1 || timeout > max_units * 60) {
@@ -707,7 +722,7 @@ static int __init it87_wdt_init(void)
        }
 
        /* Initialize CIR to use it as keepalive source */
-       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+       if (test_bit(WDTS_USE_CIR, &wdt_status)) {
                outb(0x00, CIR_RCR(base));
                outb(0xc0, CIR_TCR1(base));
                outb(0x5c, CIR_TCR2(base));
@@ -717,9 +732,9 @@ static int __init it87_wdt_init(void)
                outb(0x09, CIR_IER(base));
        }
 
-       pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
+       pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d nocir=%d)\n",
                chip_type, chip_rev, timeout,
-               nowayout, testmode, exclusive, nogameport);
+               nowayout, testmode, exclusive, nogameport, nocir);
 
        superio_exit();
        return 0;
@@ -727,8 +742,10 @@ static int __init it87_wdt_init(void)
 err_out_reboot:
        unregister_reboot_notifier(&wdt_notifier);
 err_out_region:
-       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
-       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               release_region(base, 1);
+       else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
+               release_region(base, 8);
                superio_select(CIR);
                superio_outb(ciract, ACTREG);
        }
@@ -754,7 +771,7 @@ static void __exit it87_wdt_exit(void)
                if (test_bit(WDTS_USE_GP, &wdt_status)) {
                        superio_select(GAMEPORT);
                        superio_outb(gpact, ACTREG);
-               } else {
+               } else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
                        superio_select(CIR);
                        superio_outb(ciract, ACTREG);
                }
@@ -763,7 +780,11 @@ static void __exit it87_wdt_exit(void)
 
        misc_deregister(&wdt_miscdev);
        unregister_reboot_notifier(&wdt_notifier);
-       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               release_region(base, 1);
+       else if (test_bit(WDTS_USE_CIR, &wdt_status))
+               release_region(base, 8);
 }
 
 module_init(it87_wdt_init);
index 3aa50cfa335fda1576950451a492a92336da41cd..91e45ca589e61f47e07fb43ce533f65fe2c33ee6 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/device.h>
index bdb3f4a5b27c760b5c7509f957213037e234e2be..0e9cc6f5a91995ec2731b5f2a9308e85d980a19a 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
index c1f65b4c0aa4050442bd1742d32a0883e68537dd..7831955cd9e19f1ff3d3adca74512d48880c8be2 100644 (file)
@@ -237,6 +237,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
                .compatible = "fsl,mpc823-wdt",
                .data = &(struct mpc8xxx_wdt_type) {
                        .prescaler = 0x800,
+                       .hw_enabled = true,
                },
        },
        {},
index edb31ffd79270c7e8edf86d255215efa2aeaaf28..ff27c4ac96e442dadec4129ecb98931ddc2ca150 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/completion.h>
index a0d893b0930e3309969963a8c5422d31e57d3032..7135803ca1a3903abbc78656f83b6c7f26f13283 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/kernel.h>
index fb57103c8ebcc2e6dcee213d12527cdc81a83aed..57ccae8327ff96b0072b2013f8ebb9fb2499006d 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
  *
+ * (C) Copyright 2013 - 2014 Xilinx, Inc.
  * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
  *
  * This program is free software; you can redistribute it and/or
  * 2 of the License, or (at your option) any later version.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/watchdog.h>
 #include <linux/io.h>
-#include <linux/uaccess.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #define XWT_TIMER_FAILED            0xFFFFFFFF
 
 #define WATCHDOG_NAME     "Xilinx Watchdog"
-#define PFX WATCHDOG_NAME ": "
 
 struct xwdt_device {
-       struct resource  res;
        void __iomem *base;
-       u32 nowayout;
        u32 wdt_interval;
-       u32 boot_status;
+       spinlock_t spinlock;
+       struct watchdog_device xilinx_wdt_wdd;
 };
 
-static struct xwdt_device xdev;
-
-static  u32 timeout;
-static  u32 control_status_reg;
-static  u8  expect_close;
-static  u8  no_timeout;
-static unsigned long driver_open;
-
-static  DEFINE_SPINLOCK(spinlock);
-
-static void xwdt_start(void)
+static int xilinx_wdt_start(struct watchdog_device *wdd)
 {
-       spin_lock(&spinlock);
+       u32 control_status_reg;
+       struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+
+       spin_lock(&xdev->spinlock);
 
        /* Clean previous status and enable the watchdog timer */
-       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
        control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
 
        iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
-                               xdev.base + XWT_TWCSR0_OFFSET);
+                 xdev->base + XWT_TWCSR0_OFFSET);
+
+       iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET);
 
-       iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
+       spin_unlock(&xdev->spinlock);
 
-       spin_unlock(&spinlock);
+       return 0;
 }
 
-static void xwdt_stop(void)
+static int xilinx_wdt_stop(struct watchdog_device *wdd)
 {
-       spin_lock(&spinlock);
+       u32 control_status_reg;
+       struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+
+       spin_lock(&xdev->spinlock);
 
-       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
 
        iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
-                               xdev.base + XWT_TWCSR0_OFFSET);
+                 xdev->base + XWT_TWCSR0_OFFSET);
 
-       iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
+       iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET);
 
-       spin_unlock(&spinlock);
+       spin_unlock(&xdev->spinlock);
        pr_info("Stopped!\n");
+
+       return 0;
 }
 
-static void xwdt_keepalive(void)
+static int xilinx_wdt_keepalive(struct watchdog_device *wdd)
 {
-       spin_lock(&spinlock);
+       u32 control_status_reg;
+       struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
 
-       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
-       control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
-       iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
+       spin_lock(&xdev->spinlock);
 
-       spin_unlock(&spinlock);
-}
+       control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
+       control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
+       iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET);
 
-static void xwdt_get_status(int *status)
-{
-       int new_status;
+       spin_unlock(&xdev->spinlock);
 
-       spin_lock(&spinlock);
+       return 0;
+}
 
-       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
-       new_status = ((control_status_reg &
-                       (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0);
-       spin_unlock(&spinlock);
+static const struct watchdog_info xilinx_wdt_ident = {
+       .options =  WDIOF_MAGICCLOSE |
+                   WDIOF_KEEPALIVEPING,
+       .firmware_version =     1,
+       .identity =     WATCHDOG_NAME,
+};
 
-       *status = 0;
-       if (new_status & 1)
-               *status |= WDIOF_CARDRESET;
-}
+static const struct watchdog_ops xilinx_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = xilinx_wdt_start,
+       .stop = xilinx_wdt_stop,
+       .ping = xilinx_wdt_keepalive,
+};
 
-static u32 xwdt_selftest(void)
+static u32 xwdt_selftest(struct xwdt_device *xdev)
 {
        int i;
        u32 timer_value1;
        u32 timer_value2;
 
-       spin_lock(&spinlock);
+       spin_lock(&xdev->spinlock);
 
-       timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
-       timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+       timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET);
+       timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
 
        for (i = 0;
                ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
                        (timer_value2 == timer_value1)); i++) {
-               timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+               timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
        }
 
-       spin_unlock(&spinlock);
+       spin_unlock(&xdev->spinlock);
 
        if (timer_value2 != timer_value1)
                return ~XWT_TIMER_FAILED;
@@ -146,238 +143,83 @@ static u32 xwdt_selftest(void)
                return XWT_TIMER_FAILED;
 }
 
-static int xwdt_open(struct inode *inode, struct file *file)
-{
-       /* Only one process can handle the wdt at a time */
-       if (test_and_set_bit(0, &driver_open))
-               return -EBUSY;
-
-       /* Make sure that the module are always loaded...*/
-       if (xdev.nowayout)
-               __module_get(THIS_MODULE);
-
-       xwdt_start();
-       pr_info("Started...\n");
-
-       return nonseekable_open(inode, file);
-}
-
-static int xwdt_release(struct inode *inode, struct file *file)
-{
-       if (expect_close == 42) {
-               xwdt_stop();
-       } else {
-               pr_crit("Unexpected close, not stopping watchdog!\n");
-               xwdt_keepalive();
-       }
-
-       clear_bit(0, &driver_open);
-       expect_close = 0;
-       return 0;
-}
-
-/*
- *      xwdt_write:
- *      @file: file handle to the watchdog
- *      @buf: buffer to write (unused as data does not matter here
- *      @count: count of bytes
- *      @ppos: pointer to the position to write. No seeks allowed
- *
- *      A write to a watchdog device is defined as a keepalive signal. Any
- *      write of data will do, as we don't define content meaning.
- */
-static ssize_t xwdt_write(struct file *file, const char __user *buf,
-                                               size_t len, loff_t *ppos)
-{
-       if (len) {
-               if (!xdev.nowayout) {
-                       size_t i;
-
-                       /* In case it was set long ago */
-                       expect_close = 0;
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, buf + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       expect_close = 42;
-                       }
-               }
-               xwdt_keepalive();
-       }
-       return len;
-}
-
-static const struct watchdog_info ident = {
-       .options =  WDIOF_MAGICCLOSE |
-                   WDIOF_KEEPALIVEPING,
-       .firmware_version =     1,
-       .identity =     WATCHDOG_NAME,
-};
-
-/*
- *      xwdt_ioctl:
- *      @file: file handle to the device
- *      @cmd: watchdog command
- *      @arg: argument pointer
- *
- *      The watchdog API defines a common set of functions for all watchdogs
- *      according to their available features.
- */
-static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       int status;
-
-       union {
-               struct watchdog_info __user *ident;
-               int __user *i;
-       } uarg;
-
-       uarg.i = (int __user *)arg;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(uarg.ident, &ident,
-                                       sizeof(ident)) ? -EFAULT : 0;
-
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(xdev.boot_status, uarg.i);
-
-       case WDIOC_GETSTATUS:
-               xwdt_get_status(&status);
-               return put_user(status, uarg.i);
-
-       case WDIOC_KEEPALIVE:
-               xwdt_keepalive();
-               return 0;
-
-       case WDIOC_GETTIMEOUT:
-               if (no_timeout)
-                       return -ENOTTY;
-               else
-                       return put_user(timeout, uarg.i);
-
-       default:
-               return -ENOTTY;
-       }
-}
-
-static const struct file_operations xwdt_fops = {
-       .owner      = THIS_MODULE,
-       .llseek     = no_llseek,
-       .write      = xwdt_write,
-       .open       = xwdt_open,
-       .release    = xwdt_release,
-       .unlocked_ioctl = xwdt_ioctl,
-};
-
-static struct miscdevice xwdt_miscdev = {
-       .minor      = WATCHDOG_MINOR,
-       .name       = "watchdog",
-       .fops       = &xwdt_fops,
-};
-
 static int xwdt_probe(struct platform_device *pdev)
 {
        int rc;
-       u32 *tmptr;
-       u32 *pfreq;
-
-       no_timeout = 0;
-
-       pfreq = (u32 *)of_get_property(pdev->dev.of_node,
-                                       "clock-frequency", NULL);
-
-       if (pfreq == NULL) {
-               pr_warn("The watchdog clock frequency cannot be obtained!\n");
-               no_timeout = 1;
-       }
-
-       rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
-       if (rc) {
-               pr_warn("invalid address!\n");
-               return rc;
-       }
-
-       tmptr = (u32 *)of_get_property(pdev->dev.of_node,
-                                       "xlnx,wdt-interval", NULL);
-       if (tmptr == NULL) {
-               pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
-               no_timeout = 1;
-       } else {
-               xdev.wdt_interval = *tmptr;
-       }
-
-       tmptr = (u32 *)of_get_property(pdev->dev.of_node,
-                                       "xlnx,wdt-enable-once", NULL);
-       if (tmptr == NULL) {
-               pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
-               xdev.nowayout = WATCHDOG_NOWAYOUT;
-       }
-
-/*
- *  Twice of the 2^wdt_interval / freq  because the first wdt overflow is
- *  ignored (interrupt), reset is only generated at second wdt overflow
- */
-       if (!no_timeout)
-               timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
-
-       if (!request_mem_region(xdev.res.start,
-                       xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
-               rc = -ENXIO;
-               pr_err("memory request failure!\n");
-               goto err_out;
-       }
-
-       xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
-       if (xdev.base == NULL) {
-               rc = -ENOMEM;
-               pr_err("ioremap failure!\n");
-               goto release_mem;
-       }
-
-       rc = xwdt_selftest();
+       u32 pfreq = 0, enable_once = 0;
+       struct resource *res;
+       struct xwdt_device *xdev;
+       struct watchdog_device *xilinx_wdt_wdd;
+
+       xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+       if (!xdev)
+               return -ENOMEM;
+
+       xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
+       xilinx_wdt_wdd->info = &xilinx_wdt_ident;
+       xilinx_wdt_wdd->ops = &xilinx_wdt_ops;
+       xilinx_wdt_wdd->parent = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xdev->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(xdev->base))
+               return PTR_ERR(xdev->base);
+
+       rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq);
+       if (rc)
+               dev_warn(&pdev->dev,
+                        "The watchdog clock frequency cannot be obtained\n");
+
+       rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval",
+                                 &xdev->wdt_interval);
+       if (rc)
+               dev_warn(&pdev->dev,
+                        "Parameter \"xlnx,wdt-interval\" not found\n");
+
+       rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once",
+                                 &enable_once);
+       if (rc)
+               dev_warn(&pdev->dev,
+                        "Parameter \"xlnx,wdt-enable-once\" not found\n");
+
+       watchdog_set_nowayout(xilinx_wdt_wdd, enable_once);
+
+       /*
+        * Twice of the 2^wdt_interval / freq  because the first wdt overflow is
+        * ignored (interrupt), reset is only generated at second wdt overflow
+        */
+       if (pfreq && xdev->wdt_interval)
+               xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) /
+                                         pfreq);
+
+       spin_lock_init(&xdev->spinlock);
+       watchdog_set_drvdata(xilinx_wdt_wdd, xdev);
+
+       rc = xwdt_selftest(xdev);
        if (rc == XWT_TIMER_FAILED) {
-               pr_err("SelfTest routine error!\n");
-               goto unmap_io;
+               dev_err(&pdev->dev, "SelfTest routine error\n");
+               return rc;
        }
 
-       xwdt_get_status(&xdev.boot_status);
-
-       rc = misc_register(&xwdt_miscdev);
+       rc = watchdog_register_device(xilinx_wdt_wdd);
        if (rc) {
-               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                      xwdt_miscdev.minor, rc);
-               goto unmap_io;
+               dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc);
+               return rc;
        }
 
-       if (no_timeout)
-               pr_info("driver loaded (timeout=? sec, nowayout=%d)\n",
-                       xdev.nowayout);
-       else
-               pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n",
-                       timeout, xdev.nowayout);
+       dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
+                xdev->base, xilinx_wdt_wdd->timeout);
 
-       expect_close = 0;
-       clear_bit(0, &driver_open);
+       platform_set_drvdata(pdev, xdev);
 
        return 0;
-
-unmap_io:
-       iounmap(xdev.base);
-release_mem:
-       release_mem_region(xdev.res.start, resource_size(&xdev.res));
-err_out:
-       return rc;
 }
 
-static int xwdt_remove(struct platform_device *dev)
+static int xwdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&xwdt_miscdev);
-       iounmap(xdev.base);
-       release_mem_region(xdev.res.start, resource_size(&xdev.res));
+       struct xwdt_device *xdev = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&xdev->xilinx_wdt_wdd);
 
        return 0;
 }
index 09cf0135e8acd3078d2480870109984ece309301..3691b157516a5589a6c6e96113889d7283fdc640 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/mm.h>
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
-#include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
@@ -58,7 +57,6 @@ struct omap_wdt_dev {
        void __iomem    *base;          /* physical */
        struct device   *dev;
        bool            omap_wdt_users;
-       struct resource *mem;
        int             wdt_trgr_pattern;
        struct mutex    lock;           /* to avoid races with PM */
 };
@@ -207,7 +205,7 @@ static int omap_wdt_probe(struct platform_device *pdev)
 {
        struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct watchdog_device *omap_wdt;
-       struct resource *res, *mem;
+       struct resource *res;
        struct omap_wdt_dev *wdev;
        u32 rs;
        int ret;
@@ -216,29 +214,20 @@ static int omap_wdt_probe(struct platform_device *pdev)
        if (!omap_wdt)
                return -ENOMEM;
 
-       /* reserve static register mappings */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
-       mem = devm_request_mem_region(&pdev->dev, res->start,
-                                     resource_size(res), pdev->name);
-       if (!mem)
-               return -EBUSY;
-
        wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
        if (!wdev)
                return -ENOMEM;
 
        wdev->omap_wdt_users    = false;
-       wdev->mem               = mem;
        wdev->dev               = &pdev->dev;
        wdev->wdt_trgr_pattern  = 0x1234;
        mutex_init(&wdev->lock);
 
-       wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!wdev->base)
-               return -ENOMEM;
+       /* reserve static register mappings */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdev->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(wdev->base))
+               return PTR_ERR(wdev->base);
 
        omap_wdt->info        = &omap_wdt_info;
        omap_wdt->ops         = &omap_wdt_ops;
index f7722a42467632030b4d36dc608e1af7cf497002..498163497c1cc039db45a4f2fdd373b6dbf49d42 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
 #include <linux/clk.h>
index 5211d56b368183ca1b1dc7de2bfe97adcde90efd..9f15dd9435d1a4efe5dd69fbab25363be026fe46 100644 (file)
@@ -512,9 +512,8 @@ static int __init pc87413_init(void)
                return -EBUSY;
 
        ret = register_reboot_notifier(&pc87413_notifier);
-       if (ret != 0) {
+       if (ret != 0)
                pr_err("cannot register reboot notifier (err=%d)\n", ret);
-       }
 
        ret = misc_register(&pc87413_miscdev);
        if (ret != 0) {
@@ -575,8 +574,8 @@ static void __exit pc87413_exit(void)
 module_init(pc87413_init);
 module_exit(pc87413_exit);
 
-MODULE_AUTHOR("Sven Anders <anders@anduras.de>, "
-               "Marcus Junker <junker@anduras.de>,");
+MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
+MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
 MODULE_DESCRIPTION("PC87413 WDT driver");
 MODULE_LICENSE("GPL");
 
index e562e04760161003f75e2cbd19a443d9dbd251f5..1a11aedc4fe850738bfe17d469232da64959b84d 100644 (file)
@@ -645,10 +645,8 @@ static int usb_pcwd_probe(struct usb_interface *interface,
 
        /* allocate memory for our device and initialize it */
        usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
-       if (usb_pcwd == NULL) {
-               pr_err("Out of memory\n");
+       if (usb_pcwd == NULL)
                goto error;
-       }
 
        usb_pcwd_device = usb_pcwd;
 
index 5bec20f5dc2db29ec5294bbdf03ee7b8106cb21a..15fb316e94374950e5e6c5baaaad5313bd807b9d 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/spinlock.h>
index 082d062629592970f741967fe4a458ce7bd1df2f..29cf4dcbc59c6c5dbe9af8aefc852989c7c3691f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/completion.h>
index f53615dc633d650f4cf176f9939a746b55a7dbac..a7a0695971e468e19142645b7bdca8be38671bb4 100644 (file)
@@ -16,7 +16,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/device.h>
index 3dd8ed28adc8e92dad4c58c4a4663887a3492f8b..cfed0fe264dce0b6edfe2477a7f1b159a3a87ea7 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/of.h>
index aec946df6ed976d2479762dc51d69060a5504382..7c6ccd071baf502711cf0491daa3fa215cb4b9cb 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/watchdog.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
@@ -526,7 +525,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                goto err;
        }
 
-       clk_prepare_enable(wdt->clock);
+       ret = clk_prepare_enable(wdt->clock);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable clock\n");
+               return ret;
+       }
 
        ret = s3c2410wdt_cpufreq_register(wdt);
        if (ret < 0) {
@@ -608,7 +611,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
  err_clk:
        clk_disable_unprepare(wdt->clock);
-       wdt->clock = NULL;
 
  err:
        return ret;
@@ -628,7 +630,6 @@ static int s3c2410wdt_remove(struct platform_device *dev)
        s3c2410wdt_cpufreq_deregister(wdt);
 
        clk_disable_unprepare(wdt->clock);
-       wdt->clock = NULL;
 
        return 0;
 }
index f353e18b1a82fc65221a0dcf9efa7bf696eedbe3..1cfd3f6a13d5f428adebe5a7b3e030b155f06a44 100644 (file)
@@ -158,12 +158,11 @@ static void wdt_timer_ping(unsigned long data)
 
 static void wdt_config(int writeval)
 {
-       __u16 dummy;
        unsigned long flags;
 
        /* buy some time (ping) */
        spin_lock_irqsave(&wdt_spinlock, flags);
-       dummy = readw(wdtmrctl);        /* ensure write synchronization */
+       readw(wdtmrctl);        /* ensure write synchronization */
        writew(0xAAAA, wdtmrctl);
        writew(0x5555, wdtmrctl);
        /* unlock WDT = make WDT configuration register writable one time */
index af3528f84d65469196d2a409dbcfc531a09e57c6..d04d02b41c329d9de7467d110ad2f595125bdc79 100644 (file)
@@ -293,8 +293,6 @@ static int sh_wdt_probe(struct platform_device *pdev)
 
 static int sh_wdt_remove(struct platform_device *pdev)
 {
-       struct sh_wdt *wdt = platform_get_drvdata(pdev);
-
        watchdog_unregister_device(&sh_wdt_dev);
 
        pm_runtime_disable(&pdev->dev);
index c04a1aa158e25762fcbe2b161052beaf56897d7f..0dc5e323d59dec2f72da587e32a70a03e1606dd3 100644 (file)
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static int soft_noboot = 0;
+static int soft_noboot;
 module_param(soft_noboot, int, 0);
 MODULE_PARM_DESC(soft_noboot,
        "Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
index 3f786ce0a6f2ae93fbb788f7b5dbfc1a06efeac5..47629d268e0a674a74899a8c620dc128476508ea 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/amba/bus.h>
 #include <linux/bitops.h>
 #include <linux/clk.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
@@ -209,27 +208,15 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
        struct sp805_wdt *wdt;
        int ret = 0;
 
-       if (!devm_request_mem_region(&adev->dev, adev->res.start,
-                               resource_size(&adev->res), "sp805_wdt")) {
-               dev_warn(&adev->dev, "Failed to get memory region resource\n");
-               ret = -ENOENT;
-               goto err;
-       }
-
        wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt) {
-               dev_warn(&adev->dev, "Kzalloc failed\n");
                ret = -ENOMEM;
                goto err;
        }
 
-       wdt->base = devm_ioremap(&adev->dev, adev->res.start,
-                       resource_size(&adev->res));
-       if (!wdt->base) {
-               ret = -ENOMEM;
-               dev_warn(&adev->dev, "ioremap fail\n");
-               goto err;
-       }
+       wdt->base = devm_ioremap_resource(&adev->dev, &adev->res);
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
 
        wdt->clk = devm_clk_get(&adev->dev, NULL);
        if (IS_ERR(wdt->clk)) {
index bb64ae3f47da58079ac816bde0d5c9abac5f0bff..3804d5e9baea694f8e0c10c3240f7610a5d55db5 100644 (file)
@@ -9,7 +9,6 @@
  * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/watchdog.h>
index 76332d893e122a3293ec3d2b6e7230ad354b04a2..cd00a7836cdc1450ad78a6ecacf35be1048bb4c4 100644 (file)
@@ -205,7 +205,7 @@ static void sunxi_wdt_shutdown(struct platform_device *pdev)
 }
 
 static const struct of_device_id sunxi_wdt_dt_ids[] = {
-       { .compatible = "allwinner,sun4i-wdt" },
+       { .compatible = "allwinner,sun4i-a10-wdt" },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
new file mode 100644 (file)
index 0000000..750e2a2
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+/* minimum and maximum watchdog trigger timeout, in seconds */
+#define MIN_WDT_TIMEOUT                        1
+#define MAX_WDT_TIMEOUT                        255
+
+/*
+ * Base of the WDT registers, from the timer base address.  There are
+ * actually 5 watchdogs that can be configured (by pairing with an available
+ * timer), at bases 0x100 + (WDT ID) * 0x20, where WDT ID is 0 through 4.
+ * This driver only configures the first watchdog (WDT ID 0).
+ */
+#define WDT_BASE                       0x100
+#define WDT_ID                         0
+
+/*
+ * Register base of the timer that's selected for pairing with the watchdog.
+ * This driver arbitrarily uses timer 5, which is currently unused by
+ * other drivers (in particular, the Tegra clocksource driver).  If this
+ * needs to change, take care that the new timer is not used by the
+ * clocksource driver.
+ */
+#define WDT_TIMER_BASE                 0x60
+#define WDT_TIMER_ID                   5
+
+/* WDT registers */
+#define WDT_CFG                                0x0
+#define WDT_CFG_PERIOD_SHIFT           4
+#define WDT_CFG_PERIOD_MASK            0xff
+#define WDT_CFG_INT_EN                 (1 << 12)
+#define WDT_CFG_PMC2CAR_RST_EN         (1 << 15)
+#define WDT_STS                                0x4
+#define WDT_STS_COUNT_SHIFT            4
+#define WDT_STS_COUNT_MASK             0xff
+#define WDT_STS_EXP_SHIFT              12
+#define WDT_STS_EXP_MASK               0x3
+#define WDT_CMD                                0x8
+#define WDT_CMD_START_COUNTER          (1 << 0)
+#define WDT_CMD_DISABLE_COUNTER                (1 << 1)
+#define WDT_UNLOCK                     (0xc)
+#define WDT_UNLOCK_PATTERN             (0xc45a << 0)
+
+/* Timer registers */
+#define TIMER_PTV                      0x0
+#define TIMER_EN                       (1 << 31)
+#define TIMER_PERIODIC                 (1 << 30)
+
+struct tegra_wdt {
+       struct watchdog_device  wdd;
+       void __iomem            *wdt_regs;
+       void __iomem            *tmr_regs;
+};
+
+#define WDT_HEARTBEAT 120
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+       "Watchdog heartbeats in seconds. (default = "
+       __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int tegra_wdt_start(struct watchdog_device *wdd)
+{
+       struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+       u32 val;
+
+       /*
+        * This thing has a fixed 1MHz clock.  Normally, we would set the
+        * period to 1 second by writing 1000000ul, but the watchdog system
+        * reset actually occurs on the 4th expiration of this counter,
+        * so we set the period to 1/4 of this amount.
+        */
+       val = 1000000ul / 4;
+       val |= (TIMER_EN | TIMER_PERIODIC);
+       writel(val, wdt->tmr_regs + TIMER_PTV);
+
+       /*
+        * Set number of periods and start counter.
+        *
+        * Interrupt handler is not required for user space
+        * WDT accesses, since the caller is responsible to ping the
+        * WDT to reset the counter before expiration, through ioctls.
+        */
+       val = WDT_TIMER_ID |
+             (wdd->timeout << WDT_CFG_PERIOD_SHIFT) |
+             WDT_CFG_PMC2CAR_RST_EN;
+       writel(val, wdt->wdt_regs + WDT_CFG);
+
+       writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
+
+       return 0;
+}
+
+static int tegra_wdt_stop(struct watchdog_device *wdd)
+{
+       struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       writel(WDT_UNLOCK_PATTERN, wdt->wdt_regs + WDT_UNLOCK);
+       writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_regs + WDT_CMD);
+       writel(0, wdt->tmr_regs + TIMER_PTV);
+
+       return 0;
+}
+
+static int tegra_wdt_ping(struct watchdog_device *wdd)
+{
+       struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
+
+       return 0;
+}
+
+static int tegra_wdt_set_timeout(struct watchdog_device *wdd,
+                                unsigned int timeout)
+{
+       wdd->timeout = timeout;
+
+       if (watchdog_active(wdd))
+               return tegra_wdt_start(wdd);
+
+       return 0;
+}
+
+static unsigned int tegra_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+       struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+       u32 val;
+       int count;
+       int exp;
+
+       val = readl(wdt->wdt_regs + WDT_STS);
+
+       /* Current countdown (from timeout) */
+       count = (val >> WDT_STS_COUNT_SHIFT) & WDT_STS_COUNT_MASK;
+
+       /* Number of expirations (we are waiting for the 4th expiration) */
+       exp = (val >> WDT_STS_EXP_SHIFT) & WDT_STS_EXP_MASK;
+
+       /*
+        * The entire thing is divided by 4 because we are ticking down 4 times
+        * faster due to needing to wait for the 4th expiration.
+        */
+       return (((3 - exp) * wdd->timeout) + count) / 4;
+}
+
+static const struct watchdog_info tegra_wdt_info = {
+       .options        = WDIOF_SETTIMEOUT |
+                         WDIOF_MAGICCLOSE |
+                         WDIOF_KEEPALIVEPING,
+       .firmware_version = 0,
+       .identity       = "Tegra Watchdog",
+};
+
+static struct watchdog_ops tegra_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = tegra_wdt_start,
+       .stop = tegra_wdt_stop,
+       .ping = tegra_wdt_ping,
+       .set_timeout = tegra_wdt_set_timeout,
+       .get_timeleft = tegra_wdt_get_timeleft,
+};
+
+static int tegra_wdt_probe(struct platform_device *pdev)
+{
+       struct watchdog_device *wdd;
+       struct tegra_wdt *wdt;
+       struct resource *res;
+       void __iomem *regs;
+       int ret;
+
+       /* This is the timer base. */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       /*
+        * Allocate our watchdog driver data, which has the
+        * struct watchdog_device nested within it.
+        */
+       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       /* Initialize struct tegra_wdt. */
+       wdt->wdt_regs = regs + WDT_BASE;
+       wdt->tmr_regs = regs + WDT_TIMER_BASE;
+
+       /* Initialize struct watchdog_device. */
+       wdd = &wdt->wdd;
+       wdd->timeout = heartbeat;
+       wdd->info = &tegra_wdt_info;
+       wdd->ops = &tegra_wdt_ops;
+       wdd->min_timeout = MIN_WDT_TIMEOUT;
+       wdd->max_timeout = MAX_WDT_TIMEOUT;
+
+       watchdog_set_drvdata(wdd, wdt);
+
+       watchdog_set_nowayout(wdd, nowayout);
+
+       ret = watchdog_register_device(wdd);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "failed to register watchdog device\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, wdt);
+
+       dev_info(&pdev->dev,
+                "initialized (heartbeat = %d sec, nowayout = %d)\n",
+                heartbeat, nowayout);
+
+       return 0;
+}
+
+static int tegra_wdt_remove(struct platform_device *pdev)
+{
+       struct tegra_wdt *wdt = platform_get_drvdata(pdev);
+
+       tegra_wdt_stop(&wdt->wdd);
+
+       watchdog_unregister_device(&wdt->wdd);
+
+       dev_info(&pdev->dev, "removed wdt\n");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_wdt_runtime_suspend(struct device *dev)
+{
+       struct tegra_wdt *wdt = dev_get_drvdata(dev);
+
+       if (watchdog_active(&wdt->wdd))
+               tegra_wdt_stop(&wdt->wdd);
+
+       return 0;
+}
+
+static int tegra_wdt_runtime_resume(struct device *dev)
+{
+       struct tegra_wdt *wdt = dev_get_drvdata(dev);
+
+       if (watchdog_active(&wdt->wdd))
+               tegra_wdt_start(&wdt->wdd);
+
+       return 0;
+}
+#endif
+
+static const struct of_device_id tegra_wdt_of_match[] = {
+       { .compatible = "nvidia,tegra30-timer", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, tegra_wdt_of_match);
+
+static const struct dev_pm_ops tegra_wdt_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend,
+                               tegra_wdt_runtime_resume)
+};
+
+static struct platform_driver tegra_wdt_driver = {
+       .probe          = tegra_wdt_probe,
+       .remove         = tegra_wdt_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "tegra-wdt",
+               .pm     = &tegra_wdt_pm_ops,
+               .of_match_table = tegra_wdt_of_match,
+       },
+};
+module_platform_driver(tegra_wdt_driver);
+
+MODULE_AUTHOR("NVIDIA Corporation");
+MODULE_DESCRIPTION("Tegra Watchdog Driver");
+MODULE_LICENSE("GPL v2");
index 09d4831aa61f8328b6291f97849c9adf06b62b0a..afa9d6ef353ab3ab8e13f44acfa5a448953961a8 100644 (file)
@@ -61,7 +61,7 @@ struct ts72xx_wdt {
        struct platform_device *pdev;
 };
 
-struct platform_device *ts72xx_wdt_pdev;
+static struct platform_device *ts72xx_wdt_pdev;
 
 /*
  * TS-72xx Watchdog supports following timeouts (value written
@@ -394,10 +394,8 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
        int error = 0;
 
        wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL);
-       if (!wdt) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       if (!wdt)
                return -ENOMEM;
-       }
 
        r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
index 68b45fc9ba6a5de684f18128ca337c09e7b3657e..e9ea856b8ff297fba50a668dd5ca8d147684437c 100644 (file)
@@ -455,6 +455,6 @@ module_init(wdt_init);
 module_exit(wdt_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, "
-               "Samuel Tardieu <sam@rfc1149.net>");
+MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
+MODULE_AUTHOR("Samuel Tardieu <sam@rfc1149.net>");
 MODULE_DESCRIPTION("w83697hf/hg WDT driver");
index 7355ddd0b2073be68c78e3ced5932942c690876c..ebbb183be6182f3083a5da4ce2e75731ea1bc2ec 100644 (file)
@@ -139,9 +139,8 @@ static const struct watchdog_info ident = {
 static long watchdog_ioctl(struct file *file, unsigned int cmd,
                           unsigned long arg)
 {
-       unsigned int new_margin;
        int __user *int_arg = (int __user *)arg;
-       int ret = -ENOTTY;
+       int new_margin, ret = -ENOTTY;
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
index 3dc578e7121110bea28748b16c7a44b6817a566f..48b2c058b00910ffee5a313812b5cb4d0ee135c5 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/delay.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
-#include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/pci.h>
 #include <linux/io.h>
index e243bd01c774274813e48c7dbfdcb56e53af3197..2fa17e746ff6f43dfff2042d5306934c4eab4cf8 100644 (file)
@@ -204,7 +204,6 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
        driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
                                   GFP_KERNEL);
        if (!driver_data) {
-               dev_err(wm831x->dev, "Unable to alloacate watchdog device\n");
                ret = -ENOMEM;
                goto err;
        }
index 37d06ea624aa953d40448bcd2a2d4943baf79fa9..61a6ac8fa8fc7ab00dcc7c33cea47981f2509d4b 100644 (file)
@@ -399,11 +399,25 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                        state = BP_EAGAIN;
                        break;
                }
+               scrub_page(page);
 
-               pfn = page_to_pfn(page);
-               frame_list[i] = pfn_to_mfn(pfn);
+               frame_list[i] = page_to_pfn(page);
+       }
 
-               scrub_page(page);
+       /*
+        * Ensure that ballooned highmem pages don't have kmaps.
+        *
+        * Do this before changing the p2m as kmap_flush_unused()
+        * reads PTEs to obtain pages (and hence needs the original
+        * p2m entry).
+        */
+       kmap_flush_unused();
+
+       /* Update direct mapping, invalidate P2M, and add to balloon. */
+       for (i = 0; i < nr_pages; i++) {
+               pfn = frame_list[i];
+               frame_list[i] = pfn_to_mfn(pfn);
+               page = pfn_to_page(pfn);
 
 #ifdef CONFIG_XEN_HAVE_PVMMU
                /*
@@ -429,11 +443,9 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                }
 #endif
 
-               balloon_append(pfn_to_page(pfn));
+               balloon_append(page);
        }
 
-       /* Ensure that ballooned highmem pages don't have kmaps. */
-       kmap_flush_unused();
        flush_tlb_all();
 
        set_xen_guest_handle(reservation.extent_start, frame_list);
index d7ff9175730747488aac13569ed6125c3ae1a6ca..5db43fc100a413bf0ee55676d2b359e4db94e7ec 100644 (file)
@@ -166,7 +166,6 @@ static void evtchn_2l_handle_events(unsigned cpu)
        int start_word_idx, start_bit_idx;
        int word_idx, bit_idx;
        int i;
-       struct irq_desc *desc;
        struct shared_info *s = HYPERVISOR_shared_info;
        struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
 
@@ -176,11 +175,8 @@ static void evtchn_2l_handle_events(unsigned cpu)
                unsigned int evtchn = evtchn_from_irq(irq);
                word_idx = evtchn / BITS_PER_LONG;
                bit_idx = evtchn % BITS_PER_LONG;
-               if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx)) {
-                       desc = irq_to_desc(irq);
-                       if (desc)
-                               generic_handle_irq_desc(irq, desc);
-               }
+               if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx))
+                       generic_handle_irq(irq);
        }
 
        /*
@@ -245,11 +241,8 @@ static void evtchn_2l_handle_events(unsigned cpu)
                        port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
                        irq = get_evtchn_to_irq(port);
 
-                       if (irq != -1) {
-                               desc = irq_to_desc(irq);
-                               if (desc)
-                                       generic_handle_irq_desc(irq, desc);
-                       }
+                       if (irq != -1)
+                               generic_handle_irq(irq);
 
                        bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD;
 
index f4a9e3311297b7b562f9235dae03e92b9266a9cc..c3458f58de905efb9eb8ae6a611532abda763f9e 100644 (file)
@@ -336,9 +336,8 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
 
        BUG_ON(irq == -1);
 #ifdef CONFIG_SMP
-       cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
+       cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(cpu));
 #endif
-
        xen_evtchn_port_bind_to_cpu(info, cpu);
 
        info->cpu = cpu;
@@ -373,10 +372,8 @@ static void xen_irq_init(unsigned irq)
 {
        struct irq_info *info;
 #ifdef CONFIG_SMP
-       struct irq_desc *desc = irq_to_desc(irq);
-
        /* By default all event channels notify CPU#0. */
-       cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
+       cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(0));
 #endif
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -490,13 +487,6 @@ static void pirq_query_unmask(int irq)
                info->u.pirq.flags |= PIRQ_NEEDS_EOI;
 }
 
-static bool probing_irq(int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       return desc && desc->action == NULL;
-}
-
 static void eoi_pirq(struct irq_data *data)
 {
        int evtchn = evtchn_from_irq(data->irq);
@@ -538,8 +528,7 @@ static unsigned int __startup_pirq(unsigned int irq)
                                        BIND_PIRQ__WILL_SHARE : 0;
        rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq);
        if (rc != 0) {
-               if (!probing_irq(irq))
-                       pr_info("Failed to obtain physical IRQ %d\n", irq);
+               pr_warn("Failed to obtain physical IRQ %d\n", irq);
                return 0;
        }
        evtchn = bind_pirq.port;
@@ -772,17 +761,12 @@ error_irq:
 
 int xen_destroy_irq(int irq)
 {
-       struct irq_desc *desc;
        struct physdev_unmap_pirq unmap_irq;
        struct irq_info *info = info_for_irq(irq);
        int rc = -ENOENT;
 
        mutex_lock(&irq_mapping_update_lock);
 
-       desc = irq_to_desc(irq);
-       if (!desc)
-               goto out;
-
        if (xen_initial_domain()) {
                unmap_irq.pirq = info->u.pirq.pirq;
                unmap_irq.domid = info->u.pirq.domid;
@@ -1251,6 +1235,7 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
 #ifdef CONFIG_X86
        exit_idle();
 #endif
+       inc_irq_stat(irq_hv_callback_count);
 
        __xen_evtchn_do_upcall();
 
@@ -1339,7 +1324,7 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
 static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
                            bool force)
 {
-       unsigned tcpu = cpumask_first(dest);
+       unsigned tcpu = cpumask_first_and(dest, cpu_online_mask);
 
        return rebind_irq_to_cpu(data->irq, tcpu);
 }
index 1de2a191b395b342491ce10398f70d5bc7d395d3..96109a9972b6113cdb88d1861bf00353a00a0a93 100644 (file)
@@ -235,14 +235,10 @@ static uint32_t clear_linked(volatile event_word_t *word)
 static void handle_irq_for_port(unsigned port)
 {
        int irq;
-       struct irq_desc *desc;
 
        irq = get_evtchn_to_irq(port);
-       if (irq != -1) {
-               desc = irq_to_desc(irq);
-               if (desc)
-                       generic_handle_irq_desc(irq, desc);
-       }
+       if (irq != -1)
+               generic_handle_irq(irq);
 }
 
 static void consume_one_event(unsigned cpu,
index 80875fb770ed931681c75db5aa4209c15acfc7a7..3e62ee4b3b6641208e6833b639e25e5203f75ec9 100644 (file)
@@ -313,7 +313,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
                goto out;
        }
 
-       (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
+       (void) acpi_evaluate_ost(handle, event, ost_code, NULL);
 
 out:
        acpi_scan_lock_release();
index f8d18626969a48819ae5810f1d424dc4eacf3f31..34e40b733f9a8f27cdfb142f8ce67f081188d63b 100644 (file)
@@ -285,7 +285,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
                return;
        }
 
-       (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
+       (void) acpi_evaluate_ost(handle, event, ost_code, NULL);
        return;
 }
 
index 40c4bc06b5fa0929af0b9b8ffddd9d59e6bcbc36..f83b754505f83e1f0906f7d0e4d628bf2ad16e83 100644 (file)
@@ -77,27 +77,14 @@ static int acpi_pad_pur(acpi_handle handle)
        return num;
 }
 
-/* Notify firmware how many CPUs are idle */
-static void acpi_pad_ost(acpi_handle handle, int stat,
-       uint32_t idle_nums)
-{
-       union acpi_object params[3] = {
-               {.type = ACPI_TYPE_INTEGER,},
-               {.type = ACPI_TYPE_INTEGER,},
-               {.type = ACPI_TYPE_BUFFER,},
-       };
-       struct acpi_object_list arg_list = {3, params};
-
-       params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
-       params[1].integer.value =  stat;
-       params[2].buffer.length = 4;
-       params[2].buffer.pointer = (void *)&idle_nums;
-       acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-}
-
 static void acpi_pad_handle_notify(acpi_handle handle)
 {
        int idle_nums;
+       struct acpi_buffer param = {
+               .length = 4,
+               .pointer = (void *)&idle_nums,
+       };
+
 
        mutex_lock(&xen_cpu_lock);
        idle_nums = acpi_pad_pur(handle);
@@ -109,7 +96,8 @@ static void acpi_pad_handle_notify(acpi_handle handle)
        idle_nums = xen_acpi_pad_idle_cpus(idle_nums)
                    ?: xen_acpi_pad_idle_cpus_num();
        if (idle_nums >= 0)
-               acpi_pad_ost(handle, 0, idle_nums);
+               acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY,
+                                 0, &param);
        mutex_unlock(&xen_cpu_lock);
 }
 
index 6621f800812287f6f0fc27cdc7f71a2a32287af2..be75b500005d0d4f68b2d6e3855e71660016353d 100644 (file)
@@ -75,6 +75,7 @@ struct afs_call {
        const struct afs_call_type *type;       /* type of call */
        const struct afs_wait_mode *wait_mode;  /* completion wait mode */
        wait_queue_head_t       waitq;          /* processes awaiting completion */
+       work_func_t             async_workfn;
        struct work_struct      async_work;     /* asynchronous work processor */
        struct work_struct      work;           /* actual work processor */
        struct sk_buff_head     rx_queue;       /* received packets */
index 8ad8c2a0703a120c2dde7f425225f1d515b13f0c..ef943df73b8cdee2c6964439b81417a9c1110b12 100644 (file)
@@ -644,7 +644,7 @@ static void afs_process_async_call(struct work_struct *work)
 
                /* we can't just delete the call because the work item may be
                 * queued */
-               PREPARE_WORK(&call->async_work, afs_delete_async_call);
+               call->async_workfn = afs_delete_async_call;
                queue_work(afs_async_calls, &call->async_work);
        }
 
@@ -663,6 +663,13 @@ void afs_transfer_reply(struct afs_call *call, struct sk_buff *skb)
        call->reply_size += len;
 }
 
+static void afs_async_workfn(struct work_struct *work)
+{
+       struct afs_call *call = container_of(work, struct afs_call, async_work);
+
+       call->async_workfn(work);
+}
+
 /*
  * accept the backlog of incoming calls
  */
@@ -685,7 +692,8 @@ static void afs_collect_incoming_call(struct work_struct *work)
                                return;
                        }
 
-                       INIT_WORK(&call->async_work, afs_process_async_call);
+                       call->async_workfn = afs_process_async_call;
+                       INIT_WORK(&call->async_work, afs_async_workfn);
                        call->wait_mode = &afs_async_incoming_call;
                        call->type = &afs_RXCMxxxx;
                        init_waitqueue_head(&call->waitq);
index 24084732b1d0b264b5c3262796f1ec3dd5fc505f..80ef38c73e5a16af0f9443d94bec3aae700370df 100644 (file)
@@ -41,19 +41,8 @@ static const struct dentry_operations anon_inodefs_dentry_operations = {
 static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
                                int flags, const char *dev_name, void *data)
 {
-       struct dentry *root;
-       root = mount_pseudo(fs_type, "anon_inode:", NULL,
+       return mount_pseudo(fs_type, "anon_inode:", NULL,
                        &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
-       if (!IS_ERR(root)) {
-               struct super_block *s = root->d_sb;
-               anon_inode_inode = alloc_anon_inode(s);
-               if (IS_ERR(anon_inode_inode)) {
-                       dput(root);
-                       deactivate_locked_super(s);
-                       root = ERR_CAST(anon_inode_inode);
-               }
-       }
-       return root;
 }
 
 static struct file_system_type anon_inode_fs_type = {
@@ -175,22 +164,15 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd);
 
 static int __init anon_inode_init(void)
 {
-       int error;
-
-       error = register_filesystem(&anon_inode_fs_type);
-       if (error)
-               goto err_exit;
        anon_inode_mnt = kern_mount(&anon_inode_fs_type);
-       if (IS_ERR(anon_inode_mnt)) {
-               error = PTR_ERR(anon_inode_mnt);
-               goto err_unregister_filesystem;
-       }
-       return 0;
+       if (IS_ERR(anon_inode_mnt))
+               panic("anon_inode_init() kernel mount failed (%ld)\n", PTR_ERR(anon_inode_mnt));
 
-err_unregister_filesystem:
-       unregister_filesystem(&anon_inode_fs_type);
-err_exit:
-       panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
+       anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
+       if (IS_ERR(anon_inode_inode))
+               panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode));
+
+       return 0;
 }
 
 fs_initcall(anon_inode_init);
index 0129b78a69086b3ba2d53f24ab6d54b23faf6862..4f70f383132cc9dfe143c570fbb9759967fefc6f 100644 (file)
@@ -458,11 +458,10 @@ static int bio_integrity_verify(struct bio *bio)
        struct blk_integrity_exchg bix;
        struct bio_vec *bv;
        sector_t sector = bio->bi_integrity->bip_iter.bi_sector;
-       unsigned int sectors, total, ret;
+       unsigned int sectors, ret = 0;
        void *prot_buf = bio->bi_integrity->bip_buf;
        int i;
 
-       ret = total = 0;
        bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
        bix.sector_size = bi->sector_size;
 
@@ -484,8 +483,6 @@ static int bio_integrity_verify(struct bio *bio)
                sectors = bv->bv_len / bi->sector_size;
                sector += sectors;
                prot_buf += sectors * bi->tuple_size;
-               total += sectors * bi->tuple_size;
-               BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
 
                kunmap_atomic(kaddr);
        }
index cf32f03933694cb56fd518a5e25388f35d834162..c0f3718b77a83e7e0e010b089e436356e83a1eb7 100644 (file)
@@ -513,7 +513,7 @@ struct cifs_mnt_data {
 static inline unsigned int
 get_rfc1002_length(void *buf)
 {
-       return be32_to_cpu(*((__be32 *)buf));
+       return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
 }
 
 static inline void
index 53c15074bb3622b9a251bef0eafeed866a24ce0b..834fce759d8075313261dfa0a01c76ba9c2cb5b3 100644 (file)
@@ -2579,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
        struct cifsInodeInfo *cinode = CIFS_I(inode);
        struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
        ssize_t rc = -EACCES;
+       loff_t lock_pos = pos;
 
-       BUG_ON(iocb->ki_pos != pos);
-
+       if (file->f_flags & O_APPEND)
+               lock_pos = i_size_read(inode);
        /*
         * We need to hold the sem to be sure nobody modifies lock list
         * with a brlock that prevents writing.
         */
        down_read(&cinode->lock_sem);
-       if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+       if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
                                     server->vals->exclusive_lock_type, NULL,
-                                    CIFS_WRITE_OP)) {
-               mutex_lock(&inode->i_mutex);
-               rc = __generic_file_aio_write(iocb, iov, nr_segs,
-                                              &iocb->ki_pos);
-               mutex_unlock(&inode->i_mutex);
-       }
-
-       if (rc > 0) {
-               ssize_t err;
-
-               err = generic_write_sync(file, iocb->ki_pos - rc, rc);
-               if (err < 0)
-                       rc = err;
-       }
-
+                                    CIFS_WRITE_OP))
+               rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
        up_read(&cinode->lock_sem);
        return rc;
 }
index b375709528467b5a1a74e078fae2aeb7813e1a1e..18cd5650a5fc6106394691f6ee5baf37f5d8d49b 100644 (file)
@@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
                iov->iov_len = rqst->rq_pagesz;
 }
 
+static unsigned long
+rqst_len(struct smb_rqst *rqst)
+{
+       unsigned int i;
+       struct kvec *iov = rqst->rq_iov;
+       unsigned long buflen = 0;
+
+       /* total up iov array first */
+       for (i = 0; i < rqst->rq_nvec; i++)
+               buflen += iov[i].iov_len;
+
+       /* add in the page array if there is one */
+       if (rqst->rq_npages) {
+               buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
+               buflen += rqst->rq_tailsz;
+       }
+
+       return buflen;
+}
+
 static int
 smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
@@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
        unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
+       unsigned long send_length;
        unsigned int i;
        size_t total_len = 0, sent;
        struct socket *ssocket = server->ssocket;
@@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        if (ssocket == NULL)
                return -ENOTSOCK;
 
+       /* sanity check send length */
+       send_length = rqst_len(rqst);
+       if (send_length != smb_buf_length + 4) {
+               WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
+                       send_length, smb_buf_length);
+               return -EIO;
+       }
+
        cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
        dump_smb(iov[0].iov_base, iov[0].iov_len);
 
index 6af20de2c1a3c29d5cc7c251d8fb3fa2182de445..19252b97f0cc9662940c2782c76e6782c7fa787a 100644 (file)
@@ -72,8 +72,8 @@ int compat_printk(const char *fmt, ...)
  * Not all architectures have sys_utime, so implement this in terms
  * of sys_utimes.
  */
-asmlinkage long compat_sys_utime(const char __user *filename,
-                                struct compat_utimbuf __user *t)
+COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename,
+                      struct compat_utimbuf __user *, t)
 {
        struct timespec tv[2];
 
@@ -87,7 +87,7 @@ asmlinkage long compat_sys_utime(const char __user *filename,
        return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
 }
 
-asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename, struct compat_timespec __user *t, int flags)
+COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags)
 {
        struct timespec tv[2];
 
@@ -102,7 +102,7 @@ asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filena
        return do_utimes(dfd, filename, t ? tv : NULL, flags);
 }
 
-asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename, struct compat_timeval __user *t)
+COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, struct compat_timeval __user *, t)
 {
        struct timespec tv[2];
 
@@ -121,7 +121,7 @@ asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filena
        return do_utimes(dfd, filename, t ? tv : NULL, 0);
 }
 
-asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_timeval __user *t)
+COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t)
 {
        return compat_sys_futimesat(AT_FDCWD, filename, t);
 }
@@ -159,8 +159,8 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
        return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
-asmlinkage long compat_sys_newstat(const char __user * filename,
-               struct compat_stat __user *statbuf)
+COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename,
+                      struct compat_stat __user *, statbuf)
 {
        struct kstat stat;
        int error;
@@ -171,8 +171,8 @@ asmlinkage long compat_sys_newstat(const char __user * filename,
        return cp_compat_stat(&stat, statbuf);
 }
 
-asmlinkage long compat_sys_newlstat(const char __user * filename,
-               struct compat_stat __user *statbuf)
+COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename,
+                      struct compat_stat __user *, statbuf)
 {
        struct kstat stat;
        int error;
@@ -184,9 +184,9 @@ asmlinkage long compat_sys_newlstat(const char __user * filename,
 }
 
 #ifndef __ARCH_WANT_STAT64
-asmlinkage long compat_sys_newfstatat(unsigned int dfd,
-               const char __user *filename,
-               struct compat_stat __user *statbuf, int flag)
+COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd,
+                      const char __user *, filename,
+                      struct compat_stat __user *, statbuf, int, flag)
 {
        struct kstat stat;
        int error;
@@ -198,8 +198,8 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd,
 }
 #endif
 
-asmlinkage long compat_sys_newfstat(unsigned int fd,
-               struct compat_stat __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
+                      struct compat_stat __user *, statbuf)
 {
        struct kstat stat;
        int error = vfs_fstat(fd, &stat);
@@ -247,7 +247,7 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
  * The following statfs calls are copies of code from fs/statfs.c and
  * should be checked against those from time to time
  */
-asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
+COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
 {
        struct kstatfs tmp;
        int error = user_statfs(pathname, &tmp);
@@ -256,7 +256,7 @@ asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_sta
        return error;
 }
 
-asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
+COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
 {
        struct kstatfs tmp;
        int error = fd_statfs(fd, &tmp);
@@ -298,7 +298,7 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
        return 0;
 }
 
-asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
+COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
 {
        struct kstatfs tmp;
        int error;
@@ -312,7 +312,7 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t s
        return error;
 }
 
-asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
+COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
 {
        struct kstatfs tmp;
        int error;
@@ -331,7 +331,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
  * Given how simple this syscall is that apporach is more maintainable
  * than the various conversion hacks.
  */
-asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u)
+COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
 {
        struct compat_ustat tmp;
        struct kstatfs sbuf;
@@ -399,8 +399,8 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u
 }
 #endif
 
-asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
-               unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
+                      compat_ulong_t, arg)
 {
        mm_segment_t old_fs;
        struct flock f;
@@ -468,16 +468,15 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
        return ret;
 }
 
-asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
-               unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
+                      compat_ulong_t, arg)
 {
        if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
                return -EINVAL;
        return compat_sys_fcntl64(fd, cmd, arg);
 }
 
-asmlinkage long
-compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
+COMPAT_SYSCALL_DEFINE2(io_setup, unsigned, nr_reqs, u32 __user *, ctx32p)
 {
        long ret;
        aio_context_t ctx64;
@@ -496,32 +495,24 @@ compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
        return ret;
 }
 
-asmlinkage long
-compat_sys_io_getevents(aio_context_t ctx_id,
-                                unsigned long min_nr,
-                                unsigned long nr,
-                                struct io_event __user *events,
-                                struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
+                      compat_long_t, min_nr,
+                      compat_long_t, nr,
+                      struct io_event __user *, events,
+                      struct compat_timespec __user *, timeout)
 {
-       long ret;
        struct timespec t;
        struct timespec __user *ut = NULL;
 
-       ret = -EFAULT;
-       if (unlikely(!access_ok(VERIFY_WRITE, events, 
-                               nr * sizeof(struct io_event))))
-               goto out;
        if (timeout) {
                if (get_compat_timespec(&t, timeout))
-                       goto out;
+                       return -EFAULT;
 
                ut = compat_alloc_user_space(sizeof(*ut));
                if (copy_to_user(ut, &t, sizeof(t)) )
-                       goto out;
+                       return -EFAULT;
        } 
-       ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
-out:
-       return ret;
+       return sys_io_getevents(ctx_id, min_nr, nr, events, ut);
 }
 
 /* A write operation does a read from user space and vice versa */
@@ -617,8 +608,8 @@ copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
 
 #define MAX_AIO_SUBMITS        (PAGE_SIZE/sizeof(struct iocb *))
 
-asmlinkage long
-compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
+COMPAT_SYSCALL_DEFINE3(io_submit, compat_aio_context_t, ctx_id,
+                      int, nr, u32 __user *, iocb)
 {
        struct iocb __user * __user *iocb64; 
        long ret;
@@ -770,10 +761,10 @@ static int do_nfs4_super_data_conv(void *raw_data)
 #define NCPFS_NAME      "ncpfs"
 #define NFS4_NAME      "nfs4"
 
-asmlinkage long compat_sys_mount(const char __user * dev_name,
-                                const char __user * dir_name,
-                                const char __user * type, unsigned long flags,
-                                const void __user * data)
+COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
+                      const char __user *, dir_name,
+                      const char __user *, type, compat_ulong_t, flags,
+                      const void __user *, data)
 {
        char *kernel_type;
        unsigned long data_page;
@@ -869,8 +860,8 @@ efault:
        return -EFAULT;
 }
 
-asmlinkage long compat_sys_old_readdir(unsigned int fd,
-       struct compat_old_linux_dirent __user *dirent, unsigned int count)
+COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
+               struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
 {
        int error;
        struct fd f = fdget(fd);
@@ -948,8 +939,8 @@ efault:
        return -EFAULT;
 }
 
-asmlinkage long compat_sys_getdents(unsigned int fd,
-               struct compat_linux_dirent __user *dirent, unsigned int count)
+COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
+               struct compat_linux_dirent __user *, dirent, unsigned int, count)
 {
        struct fd f;
        struct compat_linux_dirent __user * lastdirent;
@@ -981,7 +972,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
        return error;
 }
 
-#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
+#ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64
 
 struct compat_getdents_callback64 {
        struct dir_context ctx;
@@ -1033,8 +1024,8 @@ efault:
        return -EFAULT;
 }
 
-asmlinkage long compat_sys_getdents64(unsigned int fd,
-               struct linux_dirent64 __user * dirent, unsigned int count)
+COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
+               struct linux_dirent64 __user *, dirent, unsigned int, count)
 {
        struct fd f;
        struct linux_dirent64 __user * lastdirent;
@@ -1066,7 +1057,7 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
        fdput(f);
        return error;
 }
-#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
+#endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */
 
 /*
  * Exactly like fs/open.c:sys_open(), except that it doesn't set the
@@ -1287,9 +1278,9 @@ out_nofds:
        return ret;
 }
 
-asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
-       compat_ulong_t __user *outp, compat_ulong_t __user *exp,
-       struct compat_timeval __user *tvp)
+COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp,
+       compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
+       struct compat_timeval __user *tvp)
 {
        struct timespec end_time, *to = NULL;
        struct compat_timeval tv;
@@ -1320,7 +1311,7 @@ struct compat_sel_arg_struct {
        compat_uptr_t tvp;
 };
 
-asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg)
+COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg)
 {
        struct compat_sel_arg_struct a;
 
@@ -1381,9 +1372,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
        return ret;
 }
 
-asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
-       compat_ulong_t __user *outp, compat_ulong_t __user *exp,
-       struct compat_timespec __user *tsp, void __user *sig)
+COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp,
+       compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
+       struct compat_timespec __user *, tsp, void __user *, sig)
 {
        compat_size_t sigsetsize = 0;
        compat_uptr_t up = 0;
@@ -1400,9 +1391,9 @@ asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
                                 sigsetsize);
 }
 
-asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
-       unsigned int nfds, struct compat_timespec __user *tsp,
-       const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
+COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
+       unsigned int,  nfds, struct compat_timespec __user *, tsp,
+       const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
 {
        compat_sigset_t ss32;
        sigset_t ksigmask, sigsaved;
index a81147e2e4ef2eef2c2fb330a0f9ce464e2c67f6..4d24d17bcfc1dc3ecd917f12f2a889da1a506e24 100644 (file)
@@ -88,6 +88,11 @@ static void cputime_to_compat_timeval(const cputime_t cputime,
 #define        ELF_HWCAP               COMPAT_ELF_HWCAP
 #endif
 
+#ifdef COMPAT_ELF_HWCAP2
+#undef ELF_HWCAP2
+#define        ELF_HWCAP2              COMPAT_ELF_HWCAP2
+#endif
+
 #ifdef COMPAT_ARCH_DLINFO
 #undef ARCH_DLINFO
 #define        ARCH_DLINFO             COMPAT_ARCH_DLINFO
index 3881610b64384cee634367c3c35d237a4fa2f2aa..e82289047272d6e636583e20969f59450987da05 100644 (file)
@@ -1538,9 +1538,10 @@ static int compat_ioctl_check_table(unsigned int xcmd)
        return ioctl_pointer[i] == xcmd;
 }
 
-asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
-                               unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
+                      compat_ulong_t, arg32)
 {
+       unsigned long arg = arg32;
        struct fd f = fdget(fd);
        int error = -EBADF;
        if (!f.file)
index 265e0ce9769c70db65d5f9df11c4365f44c6dd29..ca02c13a84aa24d55b18bbced577ece923605665 100644 (file)
@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
        u32 dlen = ACCESS_ONCE(name->len);
        char *p;
 
-       if (*buflen < dlen + 1)
-               return -ENAMETOOLONG;
        *buflen -= dlen + 1;
+       if (*buflen < 0)
+               return -ENAMETOOLONG;
        p = *buffer -= dlen + 1;
        *p++ = '/';
        while (dlen--) {
index 8dd524f322847b346e119c6d5c5b3693de6fb8bc..cdb2971192a53fbfe2e340feb9819b7454f8ffa2 100644 (file)
@@ -21,7 +21,7 @@ static ssize_t efivarfs_file_write(struct file *file,
        u32 attributes;
        struct inode *inode = file->f_mapping->host;
        unsigned long datasize = count - sizeof(attributes);
-       ssize_t bytes = 0;
+       ssize_t bytes;
        bool set = false;
 
        if (count < sizeof(attributes))
@@ -33,14 +33,9 @@ static ssize_t efivarfs_file_write(struct file *file,
        if (attributes & ~(EFI_VARIABLE_MASK))
                return -EINVAL;
 
-       data = kmalloc(datasize, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
-               bytes = -EFAULT;
-               goto out;
-       }
+       data = memdup_user(userbuf + sizeof(attributes), datasize);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        bytes = efivar_entry_set_get_size(var, attributes, &datasize,
                                          data, &set);
index 3d78fccdd723e21119b6c93c70e2564a11d0e6a3..4f59402fdda541bd22349aad786a95d12cc6d089 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1619,9 +1619,9 @@ SYSCALL_DEFINE3(execve,
        return do_execve(getname(filename), argv, envp);
 }
 #ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_execve(const char __user * filename,
-       const compat_uptr_t __user * argv,
-       const compat_uptr_t __user * envp)
+COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename,
+       const compat_uptr_t __user *, argv,
+       const compat_uptr_t __user *, envp)
 {
        return compat_do_execve(getname(filename), argv, envp);
 }
index 6e39895a91b80aaae3914cc3a51756b3fa48a4c8..24bfd7ff30491457283b22821eb5a9b93b2adec4 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
 #include <linux/aio.h>
+#include <linux/bitops.h>
 
 #include "ext4_jbd2.h"
 #include "xattr.h"
@@ -3921,18 +3922,20 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc)
 void ext4_set_inode_flags(struct inode *inode)
 {
        unsigned int flags = EXT4_I(inode)->i_flags;
+       unsigned int new_fl = 0;
 
-       inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
        if (flags & EXT4_SYNC_FL)
-               inode->i_flags |= S_SYNC;
+               new_fl |= S_SYNC;
        if (flags & EXT4_APPEND_FL)
-               inode->i_flags |= S_APPEND;
+               new_fl |= S_APPEND;
        if (flags & EXT4_IMMUTABLE_FL)
-               inode->i_flags |= S_IMMUTABLE;
+               new_fl |= S_IMMUTABLE;
        if (flags & EXT4_NOATIME_FL)
-               inode->i_flags |= S_NOATIME;
+               new_fl |= S_NOATIME;
        if (flags & EXT4_DIRSYNC_FL)
-               inode->i_flags |= S_DIRSYNC;
+               new_fl |= S_DIRSYNC;
+       set_mask_bits(&inode->i_flags,
+                     S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl);
 }
 
 /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
index db25c2bdfe464035be537cee3fc09acad77e8cdb..b61293badfb1a9c98742a5bcc790751979251741 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -497,7 +497,7 @@ repeat:
        error = fd;
 #if 1
        /* Sanity check */
-       if (rcu_dereference_raw(fdt->fd[fd]) != NULL) {
+       if (rcu_access_pointer(fdt->fd[fd]) != NULL) {
                printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);
                rcu_assign_pointer(fdt->fd[fd], NULL);
        }
@@ -683,35 +683,54 @@ EXPORT_SYMBOL(fget_raw);
  * The fput_needed flag returned by fget_light should be passed to the
  * corresponding fput_light.
  */
-struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
+static unsigned long __fget_light(unsigned int fd, fmode_t mask)
 {
        struct files_struct *files = current->files;
        struct file *file;
 
-       *fput_needed = 0;
        if (atomic_read(&files->count) == 1) {
                file = __fcheck_files(files, fd);
-               if (file && (file->f_mode & mask))
-                       file = NULL;
+               if (!file || unlikely(file->f_mode & mask))
+                       return 0;
+               return (unsigned long)file;
        } else {
                file = __fget(fd, mask);
-               if (file)
-                       *fput_needed = 1;
+               if (!file)
+                       return 0;
+               return FDPUT_FPUT | (unsigned long)file;
        }
-
-       return file;
 }
-struct file *fget_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget(unsigned int fd)
 {
-       return __fget_light(fd, FMODE_PATH, fput_needed);
+       return __fget_light(fd, FMODE_PATH);
 }
-EXPORT_SYMBOL(fget_light);
+EXPORT_SYMBOL(__fdget);
 
-struct file *fget_raw_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget_raw(unsigned int fd)
 {
-       return __fget_light(fd, 0, fput_needed);
+       return __fget_light(fd, 0);
 }
 
+unsigned long __fdget_pos(unsigned int fd)
+{
+       unsigned long v = __fdget(fd);
+       struct file *file = (struct file *)(v & ~3);
+
+       if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
+               if (file_count(file) > 1) {
+                       v |= FDPUT_POS_UNLOCK;
+                       mutex_lock(&file->f_pos_lock);
+               }
+       }
+       return v;
+}
+
+/*
+ * We only lock f_pos if we have threads or if the file might be
+ * shared with another process. In both cases we'll have an elevated
+ * file count (done either by fdget() or by fork()).
+ */
+
 void set_close_on_exec(unsigned int fd, int flag)
 {
        struct files_struct *files = current->files;
index 5fff9030be34df26aff0c0ed56081aee1306bf02..5b24008ea4f678b668ff2a52fa41f1812b579645 100644 (file)
@@ -135,6 +135,7 @@ struct file *get_empty_filp(void)
        atomic_long_set(&f->f_count, 1);
        rwlock_init(&f->f_owner.lock);
        spin_lock_init(&f->f_lock);
+       mutex_init(&f->f_pos_lock);
        eventpoll_init_file(f);
        /* f->f_version: 0 */
        return f;
index 968ce411db53e807b6f3b0fd216cd6730f226b5d..32602c667b4aaf697c97b7f7e709d808328a5468 100644 (file)
@@ -103,6 +103,8 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
                folder = &entry->folder;
                memset(folder, 0, sizeof(*folder));
                folder->type = cpu_to_be16(HFSPLUS_FOLDER);
+               if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags))
+                       folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT);
                folder->id = cpu_to_be32(inode->i_ino);
                HFSPLUS_I(inode)->create_date =
                        folder->create_date =
@@ -203,6 +205,36 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
        return hfs_brec_find(fd, hfs_find_rec_by_key);
 }
 
+static void hfsplus_subfolders_inc(struct inode *dir)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               /*
+                * Increment subfolder count. Note, the value is only meaningful
+                * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+                */
+               HFSPLUS_I(dir)->subfolders++;
+       }
+}
+
+static void hfsplus_subfolders_dec(struct inode *dir)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               /*
+                * Decrement subfolder count. Note, the value is only meaningful
+                * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+                *
+                * Check for zero. Some subfolders may have been created
+                * by an implementation ignorant of this counter.
+                */
+               if (HFSPLUS_I(dir)->subfolders)
+                       HFSPLUS_I(dir)->subfolders--;
+       }
+}
+
 int hfsplus_create_cat(u32 cnid, struct inode *dir,
                struct qstr *str, struct inode *inode)
 {
@@ -247,6 +279,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
                goto err1;
 
        dir->i_size++;
+       if (S_ISDIR(inode->i_mode))
+               hfsplus_subfolders_inc(dir);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 
@@ -336,6 +370,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                goto out;
 
        dir->i_size--;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_dec(dir);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 
@@ -380,6 +416,7 @@ int hfsplus_rename_cat(u32 cnid,
 
        hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
                                src_fd.entrylength);
+       type = be16_to_cpu(entry.type);
 
        /* create new dir entry with the data from the old entry */
        hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
@@ -394,6 +431,8 @@ int hfsplus_rename_cat(u32 cnid,
        if (err)
                goto out;
        dst_dir->i_size++;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_inc(dst_dir);
        dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
 
        /* finally remove the old entry */
@@ -405,6 +444,8 @@ int hfsplus_rename_cat(u32 cnid,
        if (err)
                goto out;
        src_dir->i_size--;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_dec(src_dir);
        src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
 
        /* remove old thread entry */
index 08846425b67ffa112b7978650e1521b74955a1dc..62d571eb69bae9c7d04b5c27238b9fa2a1d4a633 100644 (file)
@@ -242,6 +242,7 @@ struct hfsplus_inode_info {
         */
        sector_t fs_blocks;
        u8 userflags;           /* BSD user file flags */
+       u32 subfolders;         /* Subfolder count (HFSX only) */
        struct list_head open_dir_list;
        loff_t phys_size;
 
index 8ffb3a8ffe75b9d6374cb9198d83d5dce5553457..5a126828d85eb011714b067976f0a14981103c7c 100644 (file)
@@ -261,7 +261,7 @@ struct hfsplus_cat_folder {
        struct DInfo user_info;
        struct DXInfo finder_info;
        __be32 text_encoding;
-       u32 reserved;
+       __be32 subfolders;      /* Subfolder count in HFSX. Reserved in HFS+. */
 } __packed;
 
 /* HFS file info (stolen from hfs.h) */
@@ -301,11 +301,13 @@ struct hfsplus_cat_file {
        struct hfsplus_fork_raw rsrc_fork;
 } __packed;
 
-/* File attribute bits */
+/* File and folder flag bits */
 #define HFSPLUS_FILE_LOCKED            0x0001
 #define HFSPLUS_FILE_THREAD_EXISTS     0x0002
 #define HFSPLUS_XATTR_EXISTS           0x0004
 #define HFSPLUS_ACL_EXISTS             0x0008
+#define HFSPLUS_HAS_FOLDER_COUNT       0x0010  /* Folder has subfolder count
+                                                * (HFSX only) */
 
 /* HFS+ catalog thread (part of a cat_entry) */
 struct hfsplus_cat_thread {
index fa929f325f87502074d66e208c1a57feba089c82..a4f45bd88a631ad5a153a8f45fdd1044a3637c1c 100644 (file)
@@ -375,6 +375,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
        hip->extent_state = 0;
        hip->flags = 0;
        hip->userflags = 0;
+       hip->subfolders = 0;
        memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
        memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
        hip->alloc_blocks = 0;
@@ -494,6 +495,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
                HFSPLUS_I(inode)->create_date = folder->create_date;
                HFSPLUS_I(inode)->fs_blocks = 0;
+               if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+                       HFSPLUS_I(inode)->subfolders =
+                               be32_to_cpu(folder->subfolders);
+               }
                inode->i_op = &hfsplus_dir_inode_operations;
                inode->i_fop = &hfsplus_dir_operations;
        } else if (type == HFSPLUS_FILE) {
@@ -566,6 +571,10 @@ int hfsplus_cat_write_inode(struct inode *inode)
                folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
                folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
                folder->valence = cpu_to_be32(inode->i_size - 2);
+               if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+                       folder->subfolders =
+                               cpu_to_be32(HFSPLUS_I(inode)->subfolders);
+               }
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                         sizeof(struct hfsplus_cat_folder));
        } else if (HFSPLUS_IS_RSRC(inode)) {
index 968eab5bc1f5623f09169c65f178518dbd87ee2b..68537e8b7a0934859048ecd4cfb0e67cdcb6b819 100644 (file)
@@ -75,7 +75,7 @@ int hfsplus_parse_options_remount(char *input, int *force)
        int token;
 
        if (!input)
-               return 0;
+               return 1;
 
        while ((p = strsep(&input, ",")) != NULL) {
                if (!*p)
index a17458ca6f29e4dbf1f1a1b8bb9e97949b279d29..b29e42f05f3442b887e58ca1972a9333ec474bd7 100644 (file)
@@ -19,13 +19,13 @@ struct mnt_pcp {
 };
 
 struct mountpoint {
-       struct list_head m_hash;
+       struct hlist_node m_hash;
        struct dentry *m_dentry;
        int m_count;
 };
 
 struct mount {
-       struct list_head mnt_hash;
+       struct hlist_node mnt_hash;
        struct mount *mnt_parent;
        struct dentry *mnt_mountpoint;
        struct vfsmount mnt;
index 385f7817bfccbd12fbc352c39827586d4cf953d7..4b491b4319905b2dd6698d3f58aae1d0d0141499 100644 (file)
@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                        return false;
 
                if (!d_mountpoint(path->dentry))
-                       break;
+                       return true;
 
                mounted = __lookup_mnt(path->mnt, path->dentry);
                if (!mounted)
@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 */
                *inode = path->dentry->d_inode;
        }
-       return true;
-}
-
-static void follow_mount_rcu(struct nameidata *nd)
-{
-       while (d_mountpoint(nd->path.dentry)) {
-               struct mount *mounted;
-               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
-               if (!mounted)
-                       break;
-               nd->path.mnt = &mounted->mnt;
-               nd->path.dentry = mounted->mnt.mnt_root;
-               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-       }
+       return read_seqretry(&mount_lock, nd->m_seq);
 }
 
 static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                        break;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
        }
-       follow_mount_rcu(nd);
+       while (d_mountpoint(nd->path.dentry)) {
+               struct mount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+               if (!mounted)
+                       break;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               if (!read_seqretry(&mount_lock, nd->m_seq))
+                       goto failed;
+       }
        nd->inode = nd->path.dentry->d_inode;
        return 0;
 
@@ -1884,7 +1881,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 
                nd->path = f.file->f_path;
                if (flags & LOOKUP_RCU) {
-                       if (f.need_put)
+                       if (f.flags & FDPUT_FPUT)
                                *fp = f.file;
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
                        rcu_read_lock();
index 22e536705c45d128ab8651759cea74d83f481ab1..2ffc5a2905d463e828c387fbfb92a31f219f98bc 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/proc_ns.h>
 #include <linux/magic.h>
+#include <linux/bootmem.h>
 #include "pnode.h"
 #include "internal.h"
 
-#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
-#define HASH_SIZE (1UL << HASH_SHIFT)
+static unsigned int m_hash_mask __read_mostly;
+static unsigned int m_hash_shift __read_mostly;
+static unsigned int mp_hash_mask __read_mostly;
+static unsigned int mp_hash_shift __read_mostly;
+
+static __initdata unsigned long mhash_entries;
+static int __init set_mhash_entries(char *str)
+{
+       if (!str)
+               return 0;
+       mhash_entries = simple_strtoul(str, &str, 0);
+       return 1;
+}
+__setup("mhash_entries=", set_mhash_entries);
+
+static __initdata unsigned long mphash_entries;
+static int __init set_mphash_entries(char *str)
+{
+       if (!str)
+               return 0;
+       mphash_entries = simple_strtoul(str, &str, 0);
+       return 1;
+}
+__setup("mphash_entries=", set_mphash_entries);
 
 static int event;
 static DEFINE_IDA(mnt_id_ida);
@@ -36,8 +59,8 @@ static DEFINE_SPINLOCK(mnt_id_lock);
 static int mnt_id_start = 0;
 static int mnt_group_start = 1;
 
-static struct list_head *mount_hashtable __read_mostly;
-static struct list_head *mountpoint_hashtable __read_mostly;
+static struct hlist_head *mount_hashtable __read_mostly;
+static struct hlist_head *mountpoint_hashtable __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
 static DECLARE_RWSEM(namespace_sem);
 
@@ -55,12 +78,19 @@ EXPORT_SYMBOL_GPL(fs_kobj);
  */
 __cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock);
 
-static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
+static inline struct hlist_head *m_hash(struct vfsmount *mnt, struct dentry *dentry)
 {
        unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
        tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
-       tmp = tmp + (tmp >> HASH_SHIFT);
-       return tmp & (HASH_SIZE - 1);
+       tmp = tmp + (tmp >> m_hash_shift);
+       return &mount_hashtable[tmp & m_hash_mask];
+}
+
+static inline struct hlist_head *mp_hash(struct dentry *dentry)
+{
+       unsigned long tmp = ((unsigned long)dentry / L1_CACHE_BYTES);
+       tmp = tmp + (tmp >> mp_hash_shift);
+       return &mountpoint_hashtable[tmp & mp_hash_mask];
 }
 
 /*
@@ -187,7 +217,7 @@ static struct mount *alloc_vfsmnt(const char *name)
                mnt->mnt_writers = 0;
 #endif
 
-               INIT_LIST_HEAD(&mnt->mnt_hash);
+               INIT_HLIST_NODE(&mnt->mnt_hash);
                INIT_LIST_HEAD(&mnt->mnt_child);
                INIT_LIST_HEAD(&mnt->mnt_mounts);
                INIT_LIST_HEAD(&mnt->mnt_list);
@@ -575,10 +605,10 @@ bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
  */
 struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 {
-       struct list_head *head = mount_hashtable + hash(mnt, dentry);
+       struct hlist_head *head = m_hash(mnt, dentry);
        struct mount *p;
 
-       list_for_each_entry_rcu(p, head, mnt_hash)
+       hlist_for_each_entry_rcu(p, head, mnt_hash)
                if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
                        return p;
        return NULL;
@@ -590,13 +620,17 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
  */
 struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
 {
-       struct list_head *head = mount_hashtable + hash(mnt, dentry);
-       struct mount *p;
-
-       list_for_each_entry_reverse(p, head, mnt_hash)
-               if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
-                       return p;
-       return NULL;
+       struct mount *p, *res;
+       res = p = __lookup_mnt(mnt, dentry);
+       if (!p)
+               goto out;
+       hlist_for_each_entry_continue(p, mnt_hash) {
+               if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry)
+                       break;
+               res = p;
+       }
+out:
+       return res;
 }
 
 /*
@@ -633,11 +667,11 @@ struct vfsmount *lookup_mnt(struct path *path)
 
 static struct mountpoint *new_mountpoint(struct dentry *dentry)
 {
-       struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry);
+       struct hlist_head *chain = mp_hash(dentry);
        struct mountpoint *mp;
        int ret;
 
-       list_for_each_entry(mp, chain, m_hash) {
+       hlist_for_each_entry(mp, chain, m_hash) {
                if (mp->m_dentry == dentry) {
                        /* might be worth a WARN_ON() */
                        if (d_unlinked(dentry))
@@ -659,7 +693,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
 
        mp->m_dentry = dentry;
        mp->m_count = 1;
-       list_add(&mp->m_hash, chain);
+       hlist_add_head(&mp->m_hash, chain);
        return mp;
 }
 
@@ -670,7 +704,7 @@ static void put_mountpoint(struct mountpoint *mp)
                spin_lock(&dentry->d_lock);
                dentry->d_flags &= ~DCACHE_MOUNTED;
                spin_unlock(&dentry->d_lock);
-               list_del(&mp->m_hash);
+               hlist_del(&mp->m_hash);
                kfree(mp);
        }
 }
@@ -712,7 +746,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path)
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt.mnt_root;
        list_del_init(&mnt->mnt_child);
-       list_del_init(&mnt->mnt_hash);
+       hlist_del_init_rcu(&mnt->mnt_hash);
        put_mountpoint(mnt->mnt_mp);
        mnt->mnt_mp = NULL;
 }
@@ -739,15 +773,14 @@ static void attach_mnt(struct mount *mnt,
                        struct mountpoint *mp)
 {
        mnt_set_mountpoint(parent, mp, mnt);
-       list_add_tail(&mnt->mnt_hash, mount_hashtable +
-                       hash(&parent->mnt, mp->m_dentry));
+       hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry));
        list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
 }
 
 /*
  * vfsmount lock must be held for write
  */
-static void commit_tree(struct mount *mnt)
+static void commit_tree(struct mount *mnt, struct mount *shadows)
 {
        struct mount *parent = mnt->mnt_parent;
        struct mount *m;
@@ -762,8 +795,11 @@ static void commit_tree(struct mount *mnt)
 
        list_splice(&head, n->list.prev);
 
-       list_add_tail(&mnt->mnt_hash, mount_hashtable +
-                               hash(&parent->mnt, mnt->mnt_mountpoint));
+       if (shadows)
+               hlist_add_after_rcu(&shadows->mnt_hash, &mnt->mnt_hash);
+       else
+               hlist_add_head_rcu(&mnt->mnt_hash,
+                               m_hash(&parent->mnt, mnt->mnt_mountpoint));
        list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
        touch_mnt_namespace(n);
 }
@@ -1153,26 +1189,28 @@ int may_umount(struct vfsmount *mnt)
 
 EXPORT_SYMBOL(may_umount);
 
-static LIST_HEAD(unmounted);   /* protected by namespace_sem */
+static HLIST_HEAD(unmounted);  /* protected by namespace_sem */
 
 static void namespace_unlock(void)
 {
        struct mount *mnt;
-       LIST_HEAD(head);
+       struct hlist_head head = unmounted;
 
-       if (likely(list_empty(&unmounted))) {
+       if (likely(hlist_empty(&head))) {
                up_write(&namespace_sem);
                return;
        }
 
-       list_splice_init(&unmounted, &head);
+       head.first->pprev = &head.first;
+       INIT_HLIST_HEAD(&unmounted);
+
        up_write(&namespace_sem);
 
        synchronize_rcu();
 
-       while (!list_empty(&head)) {
-               mnt = list_first_entry(&head, struct mount, mnt_hash);
-               list_del_init(&mnt->mnt_hash);
+       while (!hlist_empty(&head)) {
+               mnt = hlist_entry(head.first, struct mount, mnt_hash);
+               hlist_del_init(&mnt->mnt_hash);
                if (mnt->mnt_ex_mountpoint.mnt)
                        path_put(&mnt->mnt_ex_mountpoint);
                mntput(&mnt->mnt);
@@ -1193,16 +1231,19 @@ static inline void namespace_lock(void)
  */
 void umount_tree(struct mount *mnt, int how)
 {
-       LIST_HEAD(tmp_list);
+       HLIST_HEAD(tmp_list);
        struct mount *p;
+       struct mount *last = NULL;
 
-       for (p = mnt; p; p = next_mnt(p, mnt))
-               list_move(&p->mnt_hash, &tmp_list);
+       for (p = mnt; p; p = next_mnt(p, mnt)) {
+               hlist_del_init_rcu(&p->mnt_hash);
+               hlist_add_head(&p->mnt_hash, &tmp_list);
+       }
 
        if (how)
                propagate_umount(&tmp_list);
 
-       list_for_each_entry(p, &tmp_list, mnt_hash) {
+       hlist_for_each_entry(p, &tmp_list, mnt_hash) {
                list_del_init(&p->mnt_expire);
                list_del_init(&p->mnt_list);
                __touch_mnt_namespace(p->mnt_ns);
@@ -1220,8 +1261,13 @@ void umount_tree(struct mount *mnt, int how)
                        p->mnt_mp = NULL;
                }
                change_mnt_propagation(p, MS_PRIVATE);
+               last = p;
+       }
+       if (last) {
+               last->mnt_hash.next = unmounted.first;
+               unmounted.first = tmp_list.first;
+               unmounted.first->pprev = &unmounted.first;
        }
-       list_splice(&tmp_list, &unmounted);
 }
 
 static void shrink_submounts(struct mount *mnt);
@@ -1605,24 +1651,23 @@ static int attach_recursive_mnt(struct mount *source_mnt,
                        struct mountpoint *dest_mp,
                        struct path *parent_path)
 {
-       LIST_HEAD(tree_list);
+       HLIST_HEAD(tree_list);
        struct mount *child, *p;
+       struct hlist_node *n;
        int err;
 
        if (IS_MNT_SHARED(dest_mnt)) {
                err = invent_group_ids(source_mnt, true);
                if (err)
                        goto out;
-       }
-       err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list);
-       if (err)
-               goto out_cleanup_ids;
-
-       lock_mount_hash();
-
-       if (IS_MNT_SHARED(dest_mnt)) {
+               err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list);
+               if (err)
+                       goto out_cleanup_ids;
+               lock_mount_hash();
                for (p = source_mnt; p; p = next_mnt(p, source_mnt))
                        set_mnt_shared(p);
+       } else {
+               lock_mount_hash();
        }
        if (parent_path) {
                detach_mnt(source_mnt, parent_path);
@@ -1630,20 +1675,22 @@ static int attach_recursive_mnt(struct mount *source_mnt,
                touch_mnt_namespace(source_mnt->mnt_ns);
        } else {
                mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);
-               commit_tree(source_mnt);
+               commit_tree(source_mnt, NULL);
        }
 
-       list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
-               list_del_init(&child->mnt_hash);
-               commit_tree(child);
+       hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) {
+               struct mount *q;
+               hlist_del_init(&child->mnt_hash);
+               q = __lookup_mnt_last(&child->mnt_parent->mnt,
+                                     child->mnt_mountpoint);
+               commit_tree(child, q);
        }
        unlock_mount_hash();
 
        return 0;
 
  out_cleanup_ids:
-       if (IS_MNT_SHARED(dest_mnt))
-               cleanup_group_ids(source_mnt, NULL);
+       cleanup_group_ids(source_mnt, NULL);
  out:
        return err;
 }
@@ -2777,18 +2824,24 @@ void __init mnt_init(void)
        mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
                        0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
 
-       mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
-       mountpoint_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
+       mount_hashtable = alloc_large_system_hash("Mount-cache",
+                               sizeof(struct hlist_head),
+                               mhash_entries, 19,
+                               0,
+                               &m_hash_shift, &m_hash_mask, 0, 0);
+       mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache",
+                               sizeof(struct hlist_head),
+                               mphash_entries, 19,
+                               0,
+                               &mp_hash_shift, &mp_hash_mask, 0, 0);
 
        if (!mount_hashtable || !mountpoint_hashtable)
                panic("Failed to allocate mount hash table\n");
 
-       printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE);
-
-       for (u = 0; u < HASH_SIZE; u++)
-               INIT_LIST_HEAD(&mount_hashtable[u]);
-       for (u = 0; u < HASH_SIZE; u++)
-               INIT_LIST_HEAD(&mountpoint_hashtable[u]);
+       for (u = 0; u <= m_hash_mask; u++)
+               INIT_HLIST_HEAD(&mount_hashtable[u]);
+       for (u = 0; u <= mp_hash_mask; u++)
+               INIT_HLIST_HEAD(&mountpoint_hashtable[u]);
 
        kernfs_init();
 
index ef792f29f831c4c72e3e4edd7db9257165aca2fe..5d8ccecf5f5caada2de94bf30689ecd9e725a15a 100644 (file)
@@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode,
 
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
+       if (delegation == NULL)
+               goto out_enoent;
 
-       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
-               rcu_read_unlock();
-               return -ENOENT;
-       }
+       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
+               goto out_enoent;
        nfs_mark_return_delegation(server, delegation);
        rcu_read_unlock();
 
        nfs_delegation_run_state_manager(clp);
        return 0;
+out_enoent:
+       rcu_read_unlock();
+       return -ENOENT;
 }
 
 static struct inode *
index 12c8132ad4081a3937c12ceebc991d1f61048093..b9a35c05b60f7f418ce91443d46dab88c690ca69 100644 (file)
@@ -324,8 +324,9 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
                        &rdata->res.seq_res,
                        task))
                return;
-       nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
-                       rdata->args.lock_context, FMODE_READ);
+       if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
+                       rdata->args.lock_context, FMODE_READ) == -EIO)
+               rpc_exit(task, -EIO); /* lost lock, terminate I/O */
 }
 
 static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -435,8 +436,9 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
                        &wdata->res.seq_res,
                        task))
                return;
-       nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
-                       wdata->args.lock_context, FMODE_WRITE);
+       if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
+                       wdata->args.lock_context, FMODE_WRITE) == -EIO)
+               rpc_exit(task, -EIO); /* lost lock, terminate I/O */
 }
 
 static void filelayout_write_call_done(struct rpc_task *task, void *data)
index 2da6a698b8f7719c14eefec65e6148a48d030bb3..450bfedbe2f4c0f88cacc44ec504872487279faa 100644 (file)
@@ -2398,13 +2398,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
        if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
                /* Use that stateid */
-       } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
+       } else if (truncate && state != NULL) {
                struct nfs_lockowner lockowner = {
                        .l_owner = current->files,
                        .l_pid = current->tgid,
                };
-               nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
-                               &lockowner);
+               if (!nfs4_valid_open_stateid(state))
+                       return -EBADF;
+               if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+                               &lockowner) == -EIO)
+                       return -EBADF;
        } else
                nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
@@ -4011,8 +4014,9 @@ static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
 {
        nfs4_stateid current_stateid;
 
-       if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode))
-               return false;
+       /* If the current stateid represents a lost lock, then exit */
+       if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode) == -EIO)
+               return true;
        return nfs4_stateid_match(stateid, &current_stateid);
 }
 
@@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server;
        struct nfs_release_lockowner_args args;
-       struct nfs4_sequence_args seq_args;
-       struct nfs4_sequence_res seq_res;
+       struct nfs_release_lockowner_res res;
        unsigned long timestamp;
 };
 
@@ -5837,7 +5840,7 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
 {
        struct nfs_release_lockowner_data *data = calldata;
        nfs40_setup_sequence(data->server,
-                               &data->seq_args, &data->seq_res, task);
+                               &data->args.seq_args, &data->res.seq_res, task);
        data->timestamp = jiffies;
 }
 
@@ -5846,7 +5849,7 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
        struct nfs_release_lockowner_data *data = calldata;
        struct nfs_server *server = data->server;
 
-       nfs40_sequence_done(task, &data->seq_res);
+       nfs40_sequence_done(task, &data->res.seq_res);
 
        switch (task->tk_status) {
        case 0:
@@ -5887,7 +5890,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
-       nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
@@ -5895,6 +5897,8 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
        data->args.lock_owner.s_dev = server->s_dev;
 
        msg.rpc_argp = &data->args;
+       msg.rpc_resp = &data->res;
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
 }
index e1a47217c05e14b7195fae25d5fc725f6983cd03..0deb32105ccf3cb8b40fe95365f91f8b4b9c4da4 100644 (file)
@@ -974,9 +974,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
        else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
                nfs4_stateid_copy(dst, &lsp->ls_stateid);
                ret = 0;
-               smp_rmb();
-               if (!list_empty(&lsp->ls_seqid.list))
-                       ret = -EWOULDBLOCK;
        }
        spin_unlock(&state->state_lock);
        nfs4_put_lock_state(lsp);
@@ -984,10 +981,9 @@ out:
        return ret;
 }
 
-static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 {
        const nfs4_stateid *src;
-       int ret;
        int seq;
 
        do {
@@ -996,12 +992,7 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
                if (test_bit(NFS_OPEN_STATE, &state->flags))
                        src = &state->open_stateid;
                nfs4_stateid_copy(dst, src);
-               ret = 0;
-               smp_rmb();
-               if (!list_empty(&state->owner->so_seqid.list))
-                       ret = -EWOULDBLOCK;
        } while (read_seqretry(&state->seqlock, seq));
-       return ret;
 }
 
 /*
@@ -1026,7 +1017,8 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
                 * choose to use.
                 */
                goto out;
-       ret = nfs4_copy_open_stateid(dst, state);
+       nfs4_copy_open_stateid(dst, state);
+       ret = 0;
 out:
        if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
                dst->seqid = 0;
index 017d3cb5e99b4391027fe37b7c56c23966754e2d..6d7be3f8035631cb207a5733c71dbfc2f800fa4c 100644 (file)
@@ -449,6 +449,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        fh_lock(fhp);
        host_err = notify_change(dentry, iap, NULL);
        fh_unlock(fhp);
+       err = nfserrno(host_err);
 
 out_put_write_access:
        if (size_change)
index 8450262bcf2a782777bafd01fdd3b9b58f0bd318..51632c40e896fd0b7c4e4c87b2afc5dc4f418aca 100644 (file)
@@ -2393,8 +2393,8 @@ out_dio:
 
        if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
            ((file->f_flags & O_DIRECT) && !direct_io)) {
-               ret = filemap_fdatawrite_range(file->f_mapping, pos,
-                                              pos + count - 1);
+               ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
+                                              *ppos + count - 1);
                if (ret < 0)
                        written = ret;
 
@@ -2407,8 +2407,8 @@ out_dio:
                }
 
                if (!ret)
-                       ret = filemap_fdatawait_range(file->f_mapping, pos,
-                                                     pos + count - 1);
+                       ret = filemap_fdatawait_range(file->f_mapping, *ppos,
+                                                     *ppos + count - 1);
        }
 
        /*
index aaa50611ec66c27f2b6cd9a67a039a05e0253787..d7b5108789e2e7d8a26049b7dc6a01f8a0ff2d6f 100644 (file)
@@ -717,6 +717,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
         */
        if (status < 0)
                mlog_errno(status);
+       /*
+        * Clear dq_off so that we search for the structure in quota file next
+        * time we acquire it. The structure might be deleted and reallocated
+        * elsewhere by another node while our dquot structure is on freelist.
+        */
+       dquot->dq_off = 0;
        clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
 out_trans:
        ocfs2_commit_trans(osb, handle);
@@ -756,16 +762,17 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
        status = ocfs2_lock_global_qf(info, 1);
        if (status < 0)
                goto out;
-       if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
-               status = ocfs2_qinfo_lock(info, 0);
-               if (status < 0)
-                       goto out_dq;
-               status = qtree_read_dquot(&info->dqi_gi, dquot);
-               ocfs2_qinfo_unlock(info, 0);
-               if (status < 0)
-                       goto out_dq;
-       }
-       set_bit(DQ_READ_B, &dquot->dq_flags);
+       status = ocfs2_qinfo_lock(info, 0);
+       if (status < 0)
+               goto out_dq;
+       /*
+        * We always want to read dquot structure from disk because we don't
+        * know what happened with it while it was on freelist.
+        */
+       status = qtree_read_dquot(&info->dqi_gi, dquot);
+       ocfs2_qinfo_unlock(info, 0);
+       if (status < 0)
+               goto out_dq;
 
        OCFS2_DQUOT(dquot)->dq_use_count++;
        OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
index 2e4344be3b962b40a6cd4e5743a87f088b7abe63..2001862bf2b1cfbb20ed78bd9febeacbc96b42a4 100644 (file)
@@ -1303,10 +1303,6 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
        ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
 
 out:
-       /* Clear the read bit so that next time someone uses this
-        * dquot he reads fresh info from disk and allocates local
-        * dquot structure */
-       clear_bit(DQ_READ_B, &dquot->dq_flags);
        return status;
 }
 
index 1324e6600e57378b8e4d1624dc1366af57fde7b2..ca5ce14cbddcef81498305f8ccbccc978750faed 100644 (file)
@@ -346,7 +346,9 @@ int ocfs2_cluster_connect(const char *stack_name,
 
        strlcpy(new_conn->cc_name, group, GROUP_NAME_MAX + 1);
        new_conn->cc_namelen = grouplen;
-       strlcpy(new_conn->cc_cluster_name, cluster_name, CLUSTER_NAME_MAX + 1);
+       if (cluster_name_len)
+               strlcpy(new_conn->cc_cluster_name, cluster_name,
+                       CLUSTER_NAME_MAX + 1);
        new_conn->cc_cluster_name_len = cluster_name_len;
        new_conn->cc_recovery_handler = recovery_handler;
        new_conn->cc_recovery_data = recovery_data;
index 4b3e1edf2fe4d917e69e56b3e268e32f2ae7301a..b9ed8b25c108c69d68889b5b6eadac9878eb7bd9 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -705,6 +705,10 @@ static int do_dentry_open(struct file *f,
                return 0;
        }
 
+       /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
+       if (S_ISREG(inode->i_mode))
+               f->f_mode |= FMODE_ATOMIC_POS;
+
        f->f_op = fops_get(inode->i_fop);
        if (unlikely(WARN_ON(!f->f_op))) {
                error = -ENODEV;
index c7221bb19801e6b6251ad1ed3cea6f4f79dcf876..88396df725b4bbe84dc7d57eaf7a259877e5d87c 100644 (file)
@@ -220,14 +220,14 @@ static struct mount *get_source(struct mount *dest,
  * @tree_list : list of heads of trees to be attached.
  */
 int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
-                   struct mount *source_mnt, struct list_head *tree_list)
+                   struct mount *source_mnt, struct hlist_head *tree_list)
 {
        struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
        struct mount *m, *child;
        int ret = 0;
        struct mount *prev_dest_mnt = dest_mnt;
        struct mount *prev_src_mnt  = source_mnt;
-       LIST_HEAD(tmp_list);
+       HLIST_HEAD(tmp_list);
 
        for (m = propagation_next(dest_mnt, dest_mnt); m;
                        m = propagation_next(m, dest_mnt)) {
@@ -246,27 +246,29 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
                child = copy_tree(source, source->mnt.mnt_root, type);
                if (IS_ERR(child)) {
                        ret = PTR_ERR(child);
-                       list_splice(tree_list, tmp_list.prev);
+                       tmp_list = *tree_list;
+                       tmp_list.first->pprev = &tmp_list.first;
+                       INIT_HLIST_HEAD(tree_list);
                        goto out;
                }
 
                if (is_subdir(dest_mp->m_dentry, m->mnt.mnt_root)) {
                        mnt_set_mountpoint(m, dest_mp, child);
-                       list_add_tail(&child->mnt_hash, tree_list);
+                       hlist_add_head(&child->mnt_hash, tree_list);
                } else {
                        /*
                         * This can happen if the parent mount was bind mounted
                         * on some subdirectory of a shared/slave mount.
                         */
-                       list_add_tail(&child->mnt_hash, &tmp_list);
+                       hlist_add_head(&child->mnt_hash, &tmp_list);
                }
                prev_dest_mnt = m;
                prev_src_mnt  = child;
        }
 out:
        lock_mount_hash();
-       while (!list_empty(&tmp_list)) {
-               child = list_first_entry(&tmp_list, struct mount, mnt_hash);
+       while (!hlist_empty(&tmp_list)) {
+               child = hlist_entry(tmp_list.first, struct mount, mnt_hash);
                umount_tree(child, 0);
        }
        unlock_mount_hash();
@@ -338,8 +340,10 @@ static void __propagate_umount(struct mount *mnt)
                 * umount the child only if the child has no
                 * other children
                 */
-               if (child && list_empty(&child->mnt_mounts))
-                       list_move_tail(&child->mnt_hash, &mnt->mnt_hash);
+               if (child && list_empty(&child->mnt_mounts)) {
+                       hlist_del_init_rcu(&child->mnt_hash);
+                       hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash);
+               }
        }
 }
 
@@ -350,11 +354,11 @@ static void __propagate_umount(struct mount *mnt)
  *
  * vfsmount lock must be held for write
  */
-int propagate_umount(struct list_head *list)
+int propagate_umount(struct hlist_head *list)
 {
        struct mount *mnt;
 
-       list_for_each_entry(mnt, list, mnt_hash)
+       hlist_for_each_entry(mnt, list, mnt_hash)
                __propagate_umount(mnt);
        return 0;
 }
index 59e7eda1851ec447d705a02866c19a07d91d2c99..fc28a27fa89233d24b90bdd748477994b8713ecd 100644 (file)
@@ -36,8 +36,8 @@ static inline void set_mnt_shared(struct mount *mnt)
 
 void change_mnt_propagation(struct mount *, int);
 int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
-               struct list_head *);
-int propagate_umount(struct list_head *);
+               struct hlist_head *);
+int propagate_umount(struct hlist_head *);
 int propagate_mount_busy(struct mount *, int);
 void mnt_release_group_id(struct mount *);
 int get_dominating_id(struct mount *mnt, const struct path *root);
index 51507065263b29e3b915a6aa2238630fe3f7ac67..b9760628e1fde7b9a5c681798a65185144abeb92 100644 (file)
@@ -1824,6 +1824,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
        if (rc)
                goto out_mmput;
 
+       rc = -ENOENT;
        down_read(&mm->mmap_sem);
        vma = find_exact_vma(mm, vm_start, vm_end);
        if (vma && vma->vm_file) {
index 02174a610315ebb218880a8744e05b2244b6d26f..e647c55275d9ff9f96b92ac859e65c10fc03d318 100644 (file)
@@ -121,9 +121,8 @@ u64 stable_page_flags(struct page *page)
         * just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon
         * to make sure a given page is a thp, not a non-huge compound page.
         */
-       else if (PageTransCompound(page) &&
-                (PageLRU(compound_trans_head(page)) ||
-                 PageAnon(compound_trans_head(page))))
+       else if (PageTransCompound(page) && (PageLRU(compound_head(page)) ||
+                                            PageAnon(compound_head(page))))
                u |= 1 << KPF_THP;
 
        /*
index 6f599c62f0cc939ce2b68a75dbcd38d366ee7fa9..9d231e9e5f0ef48cd7ef372437d85fbf9b8cbc2e 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/irqnr.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
 #include <linux/tick.h>
 
 #ifndef arch_irq_stat_cpu
index 7141b8d0ca9ed9800afb1ae87def5f8aa06b8f46..33de567c25af4b04a6ba283caaf5e4f6d9b4ecdb 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/seq_file.h>
 #include <linux/time.h>
 #include <linux/kernel_stat.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
 
 static int uptime_proc_show(struct seq_file *m, void *v)
 {
index edc5746a902a090ce4dbda6b8b1205e729dff5b3..31c6efa431839e41f4b39b314cb640dd89b68ecc 100644 (file)
@@ -264,10 +264,22 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(vfs_llseek);
 
+static inline struct fd fdget_pos(int fd)
+{
+       return __to_fd(__fdget_pos(fd));
+}
+
+static inline void fdput_pos(struct fd f)
+{
+       if (f.flags & FDPUT_POS_UNLOCK)
+               mutex_unlock(&f.file->f_pos_lock);
+       fdput(f);
+}
+
 SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
 {
        off_t retval;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -278,7 +290,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
                if (res != (loff_t)retval)
                        retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
        }
-       fdput(f);
+       fdput_pos(f);
        return retval;
 }
 
@@ -295,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                unsigned int, whence)
 {
        int retval;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        loff_t offset;
 
        if (!f.file)
@@ -315,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                        retval = 0;
        }
 out_putf:
-       fdput(f);
+       fdput_pos(f);
        return retval;
 }
 #endif
@@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos)
 
 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -506,7 +518,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
                ret = vfs_read(f.file, buf, count, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
        return ret;
 }
@@ -514,7 +526,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
                size_t, count)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -522,7 +534,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
                ret = vfs_write(f.file, buf, count, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        return ret;
@@ -797,7 +809,7 @@ EXPORT_SYMBOL(vfs_writev);
 SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -805,7 +817,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                ret = vfs_readv(f.file, vec, vlen, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        if (ret > 0)
@@ -817,7 +829,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
 SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -825,7 +837,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                ret = vfs_writev(f.file, vec, vlen, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        if (ret > 0)
@@ -968,7 +980,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
                compat_ulong_t, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret;
        loff_t pos;
 
@@ -978,13 +990,13 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
        ret = compat_readv(f.file, vec, vlen, &pos);
        if (ret >= 0)
                f.file->f_pos = pos;
-       fdput(f);
+       fdput_pos(f);
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
-               const struct compat_iovec __user *,vec,
-               unsigned long, vlen, loff_t, pos)
+static long __compat_sys_preadv64(unsigned long fd,
+                                 const struct compat_iovec __user *vec,
+                                 unsigned long vlen, loff_t pos)
 {
        struct fd f;
        ssize_t ret;
@@ -1001,12 +1013,22 @@ COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
        return ret;
 }
 
+#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
+COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
+               const struct compat_iovec __user *,vec,
+               unsigned long, vlen, loff_t, pos)
+{
+       return __compat_sys_preadv64(fd, vec, vlen, pos);
+}
+#endif
+
 COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
                compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
-       return compat_sys_preadv64(fd, vec, vlen, pos);
+
+       return __compat_sys_preadv64(fd, vec, vlen, pos);
 }
 
 static size_t compat_writev(struct file *file,
@@ -1035,7 +1057,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
                const struct compat_iovec __user *, vec,
                compat_ulong_t, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret;
        loff_t pos;
 
@@ -1045,13 +1067,13 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
        ret = compat_writev(f.file, vec, vlen, &pos);
        if (ret >= 0)
                f.file->f_pos = pos;
-       fdput(f);
+       fdput_pos(f);
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
-               const struct compat_iovec __user *,vec,
-               unsigned long, vlen, loff_t, pos)
+static long __compat_sys_pwritev64(unsigned long fd,
+                                  const struct compat_iovec __user *vec,
+                                  unsigned long vlen, loff_t pos)
 {
        struct fd f;
        ssize_t ret;
@@ -1068,12 +1090,22 @@ COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
        return ret;
 }
 
+#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
+COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
+               const struct compat_iovec __user *,vec,
+               unsigned long, vlen, loff_t, pos)
+{
+       return __compat_sys_pwritev64(fd, vec, vlen, pos);
+}
+#endif
+
 COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
                compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
-       return compat_sys_pwritev64(fd, vec, vlen, pos);
+
+       return __compat_sys_pwritev64(fd, vec, vlen, pos);
 }
 #endif
 
index 929312180dd00c39e48de0a4df37a796b326be35..0013142c04759b527485f2abde83c084e17a7f8f 100644 (file)
@@ -317,6 +317,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
            (clockid != CLOCK_MONOTONIC &&
             clockid != CLOCK_REALTIME &&
             clockid != CLOCK_REALTIME_ALARM &&
+            clockid != CLOCK_BOOTTIME &&
             clockid != CLOCK_BOOTTIME_ALARM))
                return -EINVAL;
 
index c927a0b1de78569aa0e49ab8ad13b7b284f2b997..88cb477524a60913201cae59c42935e789906065 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3ea214cff349c87482d4d3a29b0370bb6c90cd42..932a60d6ed8283de2e5c893d9aad53626dabbbbe 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4e280bd226ddaa107a3d19f08b07389279b53922..8b06e4c1dd5d1873b08c3490b8d80a40283b4e87 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1f36777e26febf8fcbbd38650950d6a91ba9b1bd..3dd6e838dc300b22f111449d7314441a4adbf38f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4607b027a6577111d3179d07cc292e25ba8de493..1baae6edda8925d5205f3151c72c19cb31391e43 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 618787715d560c4162ec15f4351c80391436f203..ca0cb603b171cb63bfd957903bb01fa8545e4674 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -62,5 +62,8 @@
 #include <acpi/acrestyp.h>             /* Resource Descriptor structs */
 #include <acpi/acpiosxf.h>             /* OSL interfaces (ACPICA-to-OS) */
 #include <acpi/acpixf.h>               /* ACPI core subsystem external interfaces */
+#ifdef ACPI_NATIVE_INTERFACE_HEADER
+#include ACPI_NATIVE_INTERFACE_HEADER
+#endif
 
 #endif                         /* __ACPI_H__ */
index 8256eb4ad0579be822efd37e22193fa4fdffefdb..84a2e29a231409701de1a9d579a1a139cccbd40c 100644 (file)
@@ -49,8 +49,8 @@ acpi_evaluate_reference(acpi_handle handle,
                        struct acpi_object_list *arguments,
                        struct acpi_handle_list *list);
 acpi_status
-acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
-                       u32 status_code, struct acpi_buffer *status_buf);
+acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
+                 struct acpi_buffer *status_buf);
 
 acpi_status
 acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
@@ -133,9 +133,23 @@ struct acpi_scan_handler {
        struct list_head list_node;
        int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
        void (*detach)(struct acpi_device *dev);
+       void (*bind)(struct device *phys_dev);
+       void (*unbind)(struct device *phys_dev);
        struct acpi_hotplug_profile hotplug;
 };
 
+/*
+ * ACPI Hotplug Context
+ * --------------------
+ */
+
+struct acpi_hotplug_context {
+       struct acpi_device *self;
+       int (*notify)(struct acpi_device *, u32);
+       void (*uevent)(struct acpi_device *, u32);
+       void (*fixup)(struct acpi_device *);
+};
+
 /*
  * ACPI Driver
  * -----------
@@ -190,7 +204,9 @@ struct acpi_device_flags {
        u32 initialized:1;
        u32 visited:1;
        u32 no_hotplug:1;
-       u32 reserved:24;
+       u32 hotplug_notify:1;
+       u32 is_dock_station:1;
+       u32 reserved:22;
 };
 
 /* File System */
@@ -329,6 +345,7 @@ struct acpi_device {
        struct acpi_device_perf performance;
        struct acpi_device_dir dir;
        struct acpi_scan_handler *handler;
+       struct acpi_hotplug_context *hp;
        struct acpi_driver *driver;
        void *driver_data;
        struct device dev;
@@ -351,6 +368,24 @@ static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta)
        *((u32 *)&adev->status) = sta;
 }
 
+static inline void acpi_set_hp_context(struct acpi_device *adev,
+                                      struct acpi_hotplug_context *hp,
+                                      int (*notify)(struct acpi_device *, u32),
+                                      void (*uevent)(struct acpi_device *, u32),
+                                      void (*fixup)(struct acpi_device *))
+{
+       hp->self = adev;
+       hp->notify = notify;
+       hp->uevent = uevent;
+       hp->fixup = fixup;
+       adev->hp = hp;
+}
+
+void acpi_initialize_hp_context(struct acpi_device *adev,
+                               struct acpi_hotplug_context *hp,
+                               int (*notify)(struct acpi_device *, u32),
+                               void (*uevent)(struct acpi_device *, u32));
+
 /* acpi_device.dev.bus == &acpi_bus_type */
 extern struct bus_type acpi_bus_type;
 
@@ -381,6 +416,8 @@ extern int unregister_acpi_notifier(struct notifier_block *);
  */
 
 int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
+struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle);
+void acpi_bus_put_acpi_device(struct acpi_device *adev);
 acpi_status acpi_bus_get_status_handle(acpi_handle handle,
                                       unsigned long long *sta);
 int acpi_bus_get_status(struct acpi_device *device);
@@ -402,6 +439,8 @@ static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
 
 void acpi_scan_lock_acquire(void);
 void acpi_scan_lock_release(void);
+void acpi_lock_hp_context(void);
+void acpi_unlock_hp_context(void);
 int acpi_scan_add_handler(struct acpi_scan_handler *handler);
 int acpi_bus_register_driver(struct acpi_driver *driver);
 void acpi_bus_unregister_driver(struct acpi_driver *driver);
@@ -418,10 +457,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
        return adev && adev->flags.initialized && adev->flags.visited;
 }
 
-typedef void (*acpi_hp_callback)(void *data, u32 src);
-
-acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src);
-
 /**
  * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
  * @__acpi_driver: acpi_driver struct
index b124fdb260469bfa07dbc14fa511cb7dbd0240e2..d504613bbf8081c68c8faa603e9ac9b952d0e23b 100644 (file)
@@ -109,36 +109,14 @@ void pci_acpi_crs_quirks(void);
 /*--------------------------------------------------------------------------
                                   Dock Station
   -------------------------------------------------------------------------- */
-struct acpi_dock_ops {
-       acpi_notify_handler fixup;
-       acpi_notify_handler handler;
-       acpi_notify_handler uevent;
-};
 
 #ifdef CONFIG_ACPI_DOCK
-extern int is_dock_device(acpi_handle handle);
-extern int register_hotplug_dock_device(acpi_handle handle,
-                                       const struct acpi_dock_ops *ops,
-                                       void *context,
-                                       void (*init)(void *),
-                                       void (*release)(void *));
-extern void unregister_hotplug_dock_device(acpi_handle handle);
+extern int is_dock_device(struct acpi_device *adev);
 #else
-static inline int is_dock_device(acpi_handle handle)
+static inline int is_dock_device(struct acpi_device *adev)
 {
        return 0;
 }
-static inline int register_hotplug_dock_device(acpi_handle handle,
-                                              const struct acpi_dock_ops *ops,
-                                              void *context,
-                                              void (*init)(void *),
-                                              void (*release)(void *))
-{
-       return -ENODEV;
-}
-static inline void unregister_hotplug_dock_device(acpi_handle handle)
-{
-}
 #endif /* CONFIG_ACPI_DOCK */
 
 #endif /*__ACPI_DRIVERS_H__*/
index 451823cb88372b2130793abbbb4e17869af34faf..94a37cd7fbda47ce85c6ff1a2e82772c4582045b 100644 (file)
@@ -13,7 +13,6 @@
 
 extern int pxm_to_node(int);
 extern int node_to_pxm(int);
-extern void __acpi_map_pxm_to_node(int, int);
 extern int acpi_map_pxm_to_node(int);
 extern unsigned char acpi_srat_revision;
 
index 01e6c6d8b7e142d58b6e45bc921bace23e2b00f1..f6f5f8af211245571f2c2bd38415afe7e988eb94 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fea6773f87fc7f5fe8e3141579ebd63b4b8efcc8..b0b01b13ea990655c490d7e2c81db4336e486bce 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20131218
+#define ACPI_CA_VERSION                 0x20140214
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -229,6 +229,10 @@ acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data);
 
 acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler);
 
+acpi_status
+acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data,
+                  void (*callback)(void *));
+
 acpi_status
 acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data);
 
index cbf4bf977f75c0483ac9a8fb9211e7d59ff88a6b..eb760ca0b2e05884745e02e09aec222744829c25 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 325aeae1fa9964a8a6512e72082637eca2f75898..3b30e36b53b509d92fc5c00f88bb7c07c5a4f3cc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ec8c194bfe55334fa5076401da04db5a0fa259b..212c65de75df9899a19e05c6c609be3d7d10a309 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 094a906a0e98320747042890dcc98eb4dbf470d0..f3372441e3a5269d8f9d593a5917df9e5ce04368 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 01c2a9013e402bbc8af785372b90165284d7f065..c2295cc4a5c07596fe14558647b3398e2346aca5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 68a3ada689c900b90b26af4ec61377cd8405472f..e76356574374d449fb4ea86305d3d030b2eb2484 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #error ACPI_MACHINE_WIDTH not defined
 #endif
 
-/*! [Begin] no source code translation */
-
 /*
  * Data type ranges
  * Note: These macros are designed to be compiler independent as well as
  * working around problems that some 32-bit compilers have with 64-bit
  * constants.
  */
-#define ACPI_UINT8_MAX                  (UINT8) (~((UINT8)  0))        /* 0xFF               */
-#define ACPI_UINT16_MAX                 (UINT16)(~((UINT16) 0))        /* 0xFFFF             */
-#define ACPI_UINT32_MAX                 (UINT32)(~((UINT32) 0))        /* 0xFFFFFFFF         */
-#define ACPI_UINT64_MAX                 (UINT64)(~((UINT64) 0))        /* 0xFFFFFFFFFFFFFFFF */
+#define ACPI_UINT8_MAX                  (u8) (~((u8)  0))      /* 0xFF               */
+#define ACPI_UINT16_MAX                 (u16)(~((u16) 0))      /* 0xFFFF             */
+#define ACPI_UINT32_MAX                 (u32)(~((u32) 0))      /* 0xFFFFFFFF         */
+#define ACPI_UINT64_MAX                 (u64)(~((u64) 0))      /* 0xFFFFFFFFFFFFFFFF */
 #define ACPI_ASCII_MAX                  0x7F
 
 /*
  *
  * 1) The following types are of fixed size for all targets (16/32/64):
  *
- * BOOLEAN      Logical boolean
+ * u8           Logical boolean
  *
- * UINT8        8-bit  (1 byte) unsigned value
- * UINT16       16-bit (2 byte) unsigned value
- * UINT32       32-bit (4 byte) unsigned value
- * UINT64       64-bit (8 byte) unsigned value
+ * u8           8-bit  (1 byte) unsigned value
+ * u16          16-bit (2 byte) unsigned value
+ * u32          32-bit (4 byte) unsigned value
+ * u64          64-bit (8 byte) unsigned value
  *
- * INT16        16-bit (2 byte) signed value
- * INT32        32-bit (4 byte) signed value
- * INT64        64-bit (8 byte) signed value
+ * s16          16-bit (2 byte) signed value
+ * s32          32-bit (4 byte) signed value
+ * s64          64-bit (8 byte) signed value
  *
- * COMPILER_DEPENDENT_UINT64/INT64 - These types are defined in the
+ * COMPILER_DEPENDENT_UINT64/s64 - These types are defined in the
  * compiler-dependent header(s) and were introduced because there is no common
  * 64-bit integer type across the various compilation models, as shown in
  * the table below.
  * usually used for memory allocation, efficient loop counters, and array
  * indexes. The types are similar to the size_t type in the C library and are
  * required because there is no C type that consistently represents the native
- * data width. ACPI_SIZE is needed because there is no guarantee that a
+ * data width. acpi_size is needed because there is no guarantee that a
  * kernel-level C library is present.
  *
- * ACPI_SIZE        16/32/64-bit unsigned value
- * ACPI_NATIVE_INT  16/32/64-bit signed value
+ * acpi_size        16/32/64-bit unsigned value
+ * acpi_native_int  16/32/64-bit signed value
  */
 
 /*******************************************************************************
  *
  ******************************************************************************/
 
-typedef unsigned char BOOLEAN;
-typedef unsigned char UINT8;
-typedef unsigned short UINT16;
-typedef COMPILER_DEPENDENT_UINT64 UINT64;
-typedef COMPILER_DEPENDENT_INT64 INT64;
+#ifndef ACPI_USE_SYSTEM_INTTYPES
+
+typedef unsigned char u8;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef COMPILER_DEPENDENT_UINT64 u64;
+typedef COMPILER_DEPENDENT_INT64 s64;
 
-/*! [End] no source code translation !*/
+#endif                         /* ACPI_USE_SYSTEM_INTTYPES */
 
 /*
  * Value returned by acpi_os_get_thread_id. There is no standard "thread_id"
@@ -149,12 +149,12 @@ typedef COMPILER_DEPENDENT_INT64 INT64;
 
 #if ACPI_MACHINE_WIDTH == 64
 
-/*! [Begin] no source code translation (keep the typedefs as-is) */
+#ifndef ACPI_USE_SYSTEM_INTTYPES
 
-typedef unsigned int UINT32;
-typedef int INT32;
+typedef unsigned int u32;
+typedef int s32;
 
-/*! [End] no source code translation !*/
+#endif                         /* ACPI_USE_SYSTEM_INTTYPES */
 
 typedef s64 acpi_native_int;
 
@@ -188,12 +188,12 @@ typedef u64 acpi_physical_address;
 
 #elif ACPI_MACHINE_WIDTH == 32
 
-/*! [Begin] no source code translation (keep the typedefs as-is) */
+#ifndef ACPI_USE_SYSTEM_INTTYPES
 
-typedef unsigned int UINT32;
-typedef int INT32;
+typedef unsigned int u32;
+typedef int s32;
 
-/*! [End] no source code translation !*/
+#endif                         /* ACPI_USE_SYSTEM_INTTYPES */
 
 typedef s32 acpi_native_int;
 
index b402eb67af83fd5496669eec6e8ed6fe2d168f58..e863dd5c4e0417411754910c334ee870d8bd8ad7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e077ce6c38ca658756be11c13589d6a2c76f240c..a476b9118b49bbe064def5eb5897ffb1e1b5c3d1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 008aa287c7a9f3184bcd554058471aaf07e882a2..93c55ed7c53d88ec500123d361987478d975d11e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #ifdef __KERNEL__
 
+#define ACPI_USE_SYSTEM_INTTYPES
+
+/* Compile for reduced hardware mode only with this kernel config */
+
+#ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY
+#define ACPI_REDUCED_HARDWARE 1
+#endif
+
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <ctype.h>
 #include <unistd.h>
 
+/* Disable kernel specific declarators */
+
+#ifndef __init
+#define __init
+#endif
+
+#ifndef __iomem
+#define __iomem
+#endif
+
 /* Host-dependent types and defines for user-space ACPICA */
 
 #define ACPI_FLUSH_CPU_CACHE()
index fa2a50b7ee660c774313e20f0027302bfb0b495c..0a7e06623470586b0509ef99410dbc54aa572f9e 100644 (file)
@@ -5,14 +5,15 @@
  * Compile time versions of __arch_hweightN()
  */
 #define __const_hweight8(w)            \
-      (        (!!((w) & (1ULL << 0))) +       \
-       (!!((w) & (1ULL << 1))) +       \
-       (!!((w) & (1ULL << 2))) +       \
-       (!!((w) & (1ULL << 3))) +       \
-       (!!((w) & (1ULL << 4))) +       \
-       (!!((w) & (1ULL << 5))) +       \
-       (!!((w) & (1ULL << 6))) +       \
-       (!!((w) & (1ULL << 7))) )
+       ((unsigned int)                 \
+        ((!!((w) & (1ULL << 0))) +     \
+         (!!((w) & (1ULL << 1))) +     \
+         (!!((w) & (1ULL << 2))) +     \
+         (!!((w) & (1ULL << 3))) +     \
+         (!!((w) & (1ULL << 4))) +     \
+         (!!((w) & (1ULL << 5))) +     \
+         (!!((w) & (1ULL << 6))) +     \
+         (!!((w) & (1ULL << 7)))))
 
 #define __const_hweight16(w) (__const_hweight8(w)  + __const_hweight8((w)  >> 8 ))
 #define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16))
index 272ecba9f5889672b4b4e555c3208946a8c5e002..d5cb78f539861afdc82eae345ee4c8148fb2448e 100644 (file)
@@ -15,8 +15,10 @@ typedef u64 __nocast cputime64_t;
 
 
 /*
- * Convert nanoseconds to cputime
+ * Convert nanoseconds <-> cputime
  */
+#define cputime_to_nsecs(__ct)         \
+       jiffies_to_nsecs(cputime_to_jiffies(__ct))
 #define nsecs_to_cputime64(__nsec)     \
        jiffies64_to_cputime64(nsecs_to_jiffies64(__nsec))
 #define nsecs_to_cputime(__nsec)       \
index 2c9e62c2bfd03cce685243832d5db4c8e71ec04c..4e817606c5494126a31ae50e58a6e76242d89f07 100644 (file)
@@ -44,7 +44,10 @@ typedef u64 __nocast cputime64_t;
 /*
  * Convert cputime <-> nanoseconds
  */
-#define nsecs_to_cputime(__nsecs)      ((__force u64)(__nsecs))
+#define cputime_to_nsecs(__ct)         \
+       (__force u64)(__ct)
+#define nsecs_to_cputime(__nsecs)      \
+       (__force cputime_t)(__nsecs)
 
 
 /*
diff --git a/include/asm-generic/mcs_spinlock.h b/include/asm-generic/mcs_spinlock.h
new file mode 100644 (file)
index 0000000..10cd4ff
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __ASM_MCS_SPINLOCK_H
+#define __ASM_MCS_SPINLOCK_H
+
+/*
+ * Architectures can define their own:
+ *
+ *   arch_mcs_spin_lock_contended(l)
+ *   arch_mcs_spin_unlock_contended(l)
+ *
+ * See kernel/locking/mcs_spinlock.c.
+ */
+
+#endif /* __ASM_MCS_SPINLOCK_H */
index 34c7bdc06014c0b5c787ec2faa85ab4d2b388096..1ec08c198b66a8ed7203b63d4cec3af7dc6424df 100644 (file)
@@ -193,6 +193,19 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)
 }
 #endif
 
+#ifndef __HAVE_ARCH_PTE_UNUSED
+/*
+ * Some architectures provide facilities to virtualization guests
+ * so that they can flag allocated pages as unused. This allows the
+ * host to transparently reclaim unused pages. This function returns
+ * whether the pte's page is unused.
+ */
+static inline int pte_unused(pte_t pte)
+{
+       return 0;
+}
+#endif
+
 #ifndef __HAVE_ARCH_PMD_SAME
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
index bb1e2cdeb9bff0ec6322680196c11e5e676b2ca6..d48bf5a95cc1bd6e2a3f93ebbe6f3022202c1b98 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_RWSEM_H
-#define _ASM_POWERPC_RWSEM_H
+#ifndef _ASM_GENERIC_RWSEM_H
+#define _ASM_GENERIC_RWSEM_H
 
 #ifndef _LINUX_RWSEM_H
 #error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
@@ -8,7 +8,7 @@
 #ifdef __KERNEL__
 
 /*
- * R/W semaphores for PPC using the stuff in lib/rwsem.c.
+ * R/W semaphores originally for PPC using the stuff in lib/rwsem.c.
  * Adapted largely from include/asm-i386/rwsem.h
  * by Paul Mackerras <paulus@samba.org>.
  */
@@ -16,7 +16,7 @@
 /*
  * the semaphore definition
  */
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_64BIT
 # define RWSEM_ACTIVE_MASK             0xffffffffL
 #else
 # define RWSEM_ACTIVE_MASK             0x0000ffffL
@@ -129,4 +129,4 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
 }
 
 #endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_RWSEM_H */
+#endif /* _ASM_GENERIC_RWSEM_H */
index a1116a3b54ef106b610e74cc54ac0326b76805f6..8c1603b10665d141a2b0cb67e2643c0db7452146 100644 (file)
 #define TEGRA124_CLK_PWM 17
 #define TEGRA124_CLK_I2S2 18
 /* 20 (register bit affects vi and vi_sensor) */
-#define TEGRA124_CLK_GR_2D 21
+/* 21 */
 #define TEGRA124_CLK_USBD 22
 #define TEGRA124_CLK_ISP 23
-#define TEGRA124_CLK_GR_3D 24
+/* 26 */
 /* 25 */
 #define TEGRA124_CLK_DISP2 26
 #define TEGRA124_CLK_DISP1 27
diff --git a/include/dt-bindings/sound/tlv320aic31xx-micbias.h b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
new file mode 100644 (file)
index 0000000..f5cb772
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DT_TLV320AIC31XX_MICBIAS_H
+#define __DT_TLV320AIC31XX_MICBIAS_H
+
+#define MICBIAS_2_0V           1
+#define MICBIAS_2_5V           2
+#define MICBIAS_AVDDV          3
+
+#endif /* __DT_TLV320AIC31XX_MICBIAS_H */
diff --git a/include/dt-bindings/spmi/spmi.h b/include/dt-bindings/spmi/spmi.h
new file mode 100644 (file)
index 0000000..d11e1e5
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DT_BINDINGS_SPMI_H
+#define __DT_BINDINGS_SPMI_H
+
+#define SPMI_USID      0
+#define SPMI_GSID      1
+
+#endif
index be85127bfed3a2da2a58a3284a48b7e72094ca91..f27000f55a83d6a27921372f9890520e492a747b 100644 (file)
@@ -171,6 +171,11 @@ static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 add
        return 0;
 }
 
+static inline int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+       return -ENXIO;
+}
+
 static inline int kvm_vgic_init(struct kvm *kvm)
 {
        return 0;
index 1151a1dcfe41d950339bef27d8f9b12fa40d5c68..7a8f2cd66c8bb9ff5dc866f1f6f28da10b69ccbe 100644 (file)
@@ -108,6 +108,10 @@ static inline void acpi_initrd_override(void *data, size_t size)
 }
 #endif
 
+#define BAD_MADT_ENTRY(entry, end) (                                       \
+               (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
+               ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
+
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 void __acpi_unmap_table(char *map, unsigned long size);
 int early_acpi_boot_init(void);
@@ -259,14 +263,9 @@ extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
 extern void acpi_osi_setup(char *str);
 
 #ifdef CONFIG_ACPI_NUMA
-int acpi_get_pxm(acpi_handle handle);
-int acpi_get_node(acpi_handle *handle);
+int acpi_get_node(acpi_handle handle);
 #else
-static inline int acpi_get_pxm(acpi_handle handle)
-{
-       return 0;
-}
-static inline int acpi_get_node(acpi_handle *handle)
+static inline int acpi_get_node(acpi_handle handle)
 {
        return 0;
 }
index 73a25005d88aa7cc76f7e8049b9697be18955c39..1f16d502600c5d887dbb54fea12440bd7bf9692a 100644 (file)
 
 struct device;
 struct ata_port_info;
+struct ahci_host_priv;
+struct platform_device;
 
+/*
+ * Note ahci_platform_data is deprecated, it is only kept around for use
+ * by the old da850 and spear13xx ahci code.
+ * New drivers should instead declare their own platform_driver struct, and
+ * use ahci_platform* functions in their own probe, suspend and resume methods.
+ */
 struct ahci_platform_data {
        int (*init)(struct device *dev, void __iomem *addr);
        void (*exit)(struct device *dev);
        int (*suspend)(struct device *dev);
        int (*resume)(struct device *dev);
-       const struct ata_port_info *ata_port_info;
-       unsigned int force_port_map;
-       unsigned int mask_port_map;
 };
 
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
+struct ahci_host_priv *ahci_platform_get_resources(
+       struct platform_device *pdev);
+int ahci_platform_init_host(struct platform_device *pdev,
+                           struct ahci_host_priv *hpriv,
+                           const struct ata_port_info *pi_template,
+                           unsigned int force_port_map,
+                           unsigned int mask_port_map);
+
+int ahci_platform_suspend_host(struct device *dev);
+int ahci_platform_resume_host(struct device *dev);
+int ahci_platform_suspend(struct device *dev);
+int ahci_platform_resume(struct device *dev);
+
 #endif /* _AHCI_PLATFORM_H */
index 66a0e5384edd6090ae3793082c8a4f56fb6ea74d..571a12ebb018da65d40068e72232031865b67145 100644 (file)
@@ -18,6 +18,7 @@ struct ssc_device {
        struct clk              *clk;
        int                     user;
        int                     irq;
+       bool                    clk_from_rk_pin;
 };
 
 struct ssc_device * __must_check ssc_request(unsigned int ssc_num);
index aa865a9a4c4f862b4aa693ed9918399b338e7696..ec1464df4c60930a7fde38f1bc6f35a35b7f79d3 100644 (file)
@@ -43,6 +43,7 @@ struct mq_attr;
 struct mqstat;
 struct audit_watch;
 struct audit_tree;
+struct sk_buff;
 
 struct audit_krule {
        int                     vers_ops;
@@ -463,7 +464,7 @@ extern int audit_filter_user(int type);
 extern int audit_filter_type(int type);
 extern int audit_rule_change(int type, __u32 portid, int seq,
                                void *data, size_t datasz);
-extern int audit_list_rules_send(__u32 portid, int seq);
+extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
 
 extern u32 audit_enabled;
 #else /* CONFIG_AUDIT */
index abc9ca7784568ba5737add4fce84577348428eac..be5fd38bd5a05d83eaac250055defcccacafe054 100644 (file)
@@ -196,6 +196,21 @@ static inline unsigned long __ffs64(u64 word)
 
 #ifdef __KERNEL__
 
+#ifndef set_mask_bits
+#define set_mask_bits(ptr, _mask, _bits)       \
+({                                                             \
+       const typeof(*ptr) mask = (_mask), bits = (_bits);      \
+       typeof(*ptr) old, new;                                  \
+                                                               \
+       do {                                                    \
+               old = ACCESS_ONCE(*ptr);                        \
+               new = (old & ~mask) | bits;                     \
+       } while (cmpxchg(ptr, old, new) != old);                \
+                                                               \
+       new;                                                    \
+})
+#endif
+
 #ifndef find_last_bit
 /**
  * find_last_bit - find the last set bit in a memory region
index 18ba8a627f46e0fd77a97aa0257940d845f7f8a4..2ff2e8d982bea9b689050a2802fba5ec29e44b81 100644 (file)
@@ -121,8 +121,7 @@ void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struc
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
 
-void blk_mq_insert_request(struct request_queue *, struct request *,
-               bool, bool);
+void blk_mq_insert_request(struct request *, bool, bool, bool);
 void blk_mq_run_queues(struct request_queue *q, bool async);
 void blk_mq_free_request(struct request *rq);
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
@@ -134,7 +133,13 @@ struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_ind
 struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *, unsigned int);
 void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int);
 
-void blk_mq_end_io(struct request *rq, int error);
+bool blk_mq_end_io_partial(struct request *rq, int error,
+               unsigned int nr_bytes);
+static inline void blk_mq_end_io(struct request *rq, int error)
+{
+       bool done = !blk_mq_end_io_partial(rq, error, blk_rq_bytes(rq));
+       BUG_ON(!done);
+}
 
 void blk_mq_complete_request(struct request *rq);
 
index 092b64168d7fa6935dfe476f1657af9dda620a7a..4a21a872dbbd6423025f1a9253832f228cfe1c48 100644 (file)
@@ -245,6 +245,10 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 void omap2_init_clk_clkdm(struct clk_hw *clk);
 unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
                                    unsigned long parent_rate);
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate);
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate);
 int omap2_clkops_enable_clkdm(struct clk_hw *hw);
 void omap2_clkops_disable_clkdm(struct clk_hw *hw);
 int omap2_clk_disable_autoidle_all(void);
index 493aa021c7a9429a892c8ccb6f19110d1b4c9065..2e4cb67f6e560094aa719fe75f595dfbb562cf8e 100644 (file)
@@ -62,6 +62,11 @@ enum clock_event_mode {
 #define CLOCK_EVT_FEAT_DYNIRQ          0x000020
 #define CLOCK_EVT_FEAT_PERCPU          0x000040
 
+/*
+ * Clockevent device is based on a hrtimer for broadcast
+ */
+#define CLOCK_EVT_FEAT_HRTIMER         0x000080
+
 /**
  * struct clock_event_device - clock event device descriptor
  * @event_handler:     Assigned by the framework to be called by the low
@@ -83,6 +88,7 @@ enum clock_event_mode {
  * @name:              ptr to clock event name
  * @rating:            variable to rate clock event devices
  * @irq:               IRQ number (only for non CPU local devices)
+ * @bound_on:          Bound on CPU
  * @cpumask:           cpumask to indicate for which CPUs this device works
  * @list:              list head for the management code
  * @owner:             module reference
@@ -113,6 +119,7 @@ struct clock_event_device {
        const char              *name;
        int                     rating;
        int                     irq;
+       int                     bound_on;
        const struct cpumask    *cpumask;
        struct list_head        list;
        struct module           *owner;
@@ -180,15 +187,17 @@ extern int tick_receive_broadcast(void);
 #endif
 
 #if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
+extern void tick_setup_hrtimer_broadcast(void);
 extern int tick_check_broadcast_expired(void);
 #else
 static inline int tick_check_broadcast_expired(void) { return 0; }
+static inline void tick_setup_hrtimer_broadcast(void) {};
 #endif
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
-extern void clockevents_notify(unsigned long reason, void *arg);
+extern int clockevents_notify(unsigned long reason, void *arg);
 #else
-static inline void clockevents_notify(unsigned long reason, void *arg) {}
+static inline int clockevents_notify(unsigned long reason, void *arg) { return 0; }
 #endif
 
 #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
@@ -196,8 +205,9 @@ static inline void clockevents_notify(unsigned long reason, void *arg) {}
 static inline void clockevents_suspend(void) {}
 static inline void clockevents_resume(void) {}
 
-static inline void clockevents_notify(unsigned long reason, void *arg) {}
+static inline int clockevents_notify(unsigned long reason, void *arg) { return 0; }
 static inline int tick_check_broadcast_expired(void) { return 0; }
+static inline void tick_setup_hrtimer_broadcast(void) {};
 
 #endif
 
index 3f448c65511b525ae9d92c38d7201f087b568334..01c0aa57ccecf39420b3fd30f830614e613fbe58 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/if.h>
 #include <linux/fs.h>
 #include <linux/aio_abi.h>     /* for aio_context_t */
+#include <linux/unistd.h>
 
 #include <asm/compat.h>
 #include <asm/siginfo.h>
@@ -27,6 +28,9 @@
 #define __SC_DELOUSE(t,v) ((t)(unsigned long)(v))
 #endif
 
+#define COMPAT_SYSCALL_DEFINE0(name) \
+       asmlinkage long compat_sys_##name(void)
+
 #define COMPAT_SYSCALL_DEFINE1(name, ...) \
         COMPAT_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
 #define COMPAT_SYSCALL_DEFINE2(name, ...) \
@@ -68,6 +72,8 @@ typedef struct compat_sigaltstack {
 typedef __compat_uid32_t       compat_uid_t;
 typedef __compat_gid32_t       compat_gid_t;
 
+typedef        compat_ulong_t          compat_aio_context_t;
+
 struct compat_sel_arg_struct;
 struct rusage;
 
@@ -318,7 +324,7 @@ asmlinkage long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
 asmlinkage long compat_sys_msgsnd(int msqid, compat_uptr_t msgp,
                compat_ssize_t msgsz, int msgflg);
 asmlinkage long compat_sys_msgrcv(int msqid, compat_uptr_t msgp,
-               compat_ssize_t msgsz, long msgtyp, int msgflg);
+               compat_ssize_t msgsz, compat_long_t msgtyp, int msgflg);
 long compat_sys_msgctl(int first, int second, void __user *uptr);
 long compat_sys_shmctl(int first, int second, void __user *uptr);
 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
@@ -337,6 +343,19 @@ asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd,
 asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd,
                const struct compat_iovec __user *vec,
                compat_ulong_t vlen, u32 pos_low, u32 pos_high);
+
+#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
+asmlinkage long compat_sys_preadv64(unsigned long fd,
+               const struct compat_iovec __user *vec,
+               unsigned long vlen, loff_t pos);
+#endif
+
+#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
+asmlinkage long compat_sys_pwritev64(unsigned long fd,
+               const struct compat_iovec __user *vec,
+               unsigned long vlen, loff_t pos);
+#endif
+
 asmlinkage long compat_sys_lseek(unsigned int, compat_off_t, unsigned int);
 
 asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv,
@@ -451,7 +470,7 @@ asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
 asmlinkage long compat_sys_timerfd_gettime(int ufd,
                                   struct compat_itimerspec __user *otmr);
 
-asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page,
+asmlinkage long compat_sys_move_pages(pid_t pid, compat_ulong_t nr_pages,
                                      __u32 __user *pages,
                                      const int __user *nodes,
                                      int __user *status,
@@ -481,20 +500,20 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname,
 asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz,
                                     struct compat_statfs64 __user *buf);
 asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
-                                  unsigned long arg);
+                                  compat_ulong_t arg);
 asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
-                                unsigned long arg);
+                                compat_ulong_t arg);
 asmlinkage long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p);
-asmlinkage long compat_sys_io_getevents(aio_context_t ctx_id,
-                                       unsigned long min_nr,
-                                       unsigned long nr,
+asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id,
+                                       compat_long_t min_nr,
+                                       compat_long_t nr,
                                        struct io_event __user *events,
                                        struct compat_timespec __user *timeout);
-asmlinkage long compat_sys_io_submit(aio_context_t ctx_id, int nr,
+asmlinkage long compat_sys_io_submit(compat_aio_context_t ctx_id, int nr,
                                     u32 __user *iocb);
 asmlinkage long compat_sys_mount(const char __user *dev_name,
                                 const char __user *dir_name,
-                                const char __user *type, unsigned long flags,
+                                const char __user *type, compat_ulong_t flags,
                                 const void __user *data);
 asmlinkage long compat_sys_old_readdir(unsigned int fd,
                                       struct compat_old_linux_dirent __user *,
@@ -502,9 +521,11 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
 asmlinkage long compat_sys_getdents(unsigned int fd,
                                    struct compat_linux_dirent __user *dirent,
                                    unsigned int count);
+#ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64
 asmlinkage long compat_sys_getdents64(unsigned int fd,
                                      struct linux_dirent64 __user *dirent,
                                      unsigned int count);
+#endif
 asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *,
                                    unsigned int nr_segs, unsigned int flags);
 asmlinkage long compat_sys_open(const char __user *filename, int flags,
@@ -549,9 +570,9 @@ asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
                                    unsigned vlen, unsigned int flags);
 asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg,
                                   unsigned int flags);
-asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len,
+asmlinkage long compat_sys_recv(int fd, void __user *buf, compat_size_t len,
                                unsigned flags);
-asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
+asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, compat_size_t len,
                            unsigned flags, struct sockaddr __user *addr,
                            int __user *addrlen);
 asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
@@ -615,16 +636,16 @@ asmlinkage long compat_sys_rt_sigqueueinfo(compat_pid_t pid, int sig,
                                struct compat_siginfo __user *uinfo);
 asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info);
 asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
-                                unsigned long arg);
+                                compat_ulong_t arg);
 asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
                struct compat_timespec __user *utime, u32 __user *uaddr2,
                u32 val3);
 asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
                                      char __user *optval, int __user *optlen);
-asmlinkage long compat_sys_kexec_load(unsigned long entry,
-                                     unsigned long nr_segments,
+asmlinkage long compat_sys_kexec_load(compat_ulong_t entry,
+                                     compat_ulong_t nr_segments,
                                      struct compat_kexec_segment __user *,
-                                     unsigned long flags);
+                                     compat_ulong_t flags);
 asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
                        const struct compat_mq_attr __user *u_mqstat,
                        struct compat_mq_attr __user *u_omqstat);
@@ -635,11 +656,11 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
                        struct compat_mq_attr __user *u_attr);
 asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
                        const char __user *u_msg_ptr,
-                       size_t msg_len, unsigned int msg_prio,
+                       compat_size_t msg_len, unsigned int msg_prio,
                        const struct compat_timespec __user *u_abs_timeout);
 asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
                        char __user *u_msg_ptr,
-                       size_t msg_len, unsigned int __user *u_msg_prio,
+                       compat_size_t msg_len, unsigned int __user *u_msg_prio,
                        const struct compat_timespec __user *u_abs_timeout);
 asmlinkage long compat_sys_socketcall(int call, u32 __user *args);
 asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args);
@@ -654,12 +675,12 @@ extern void __user *compat_alloc_user_space(unsigned long len);
 
 asmlinkage ssize_t compat_sys_process_vm_readv(compat_pid_t pid,
                const struct compat_iovec __user *lvec,
-               unsigned long liovcnt, const struct compat_iovec __user *rvec,
-               unsigned long riovcnt, unsigned long flags);
+               compat_ulong_t liovcnt, const struct compat_iovec __user *rvec,
+               compat_ulong_t riovcnt, compat_ulong_t flags);
 asmlinkage ssize_t compat_sys_process_vm_writev(compat_pid_t pid,
                const struct compat_iovec __user *lvec,
-               unsigned long liovcnt, const struct compat_iovec __user *rvec,
-               unsigned long riovcnt, unsigned long flags);
+               compat_ulong_t liovcnt, const struct compat_iovec __user *rvec,
+               compat_ulong_t riovcnt, compat_ulong_t flags);
 
 asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
                                    compat_off_t __user *offset, compat_size_t count);
index b2b5a41b6a2400342ff5aec1abb4f2834caaf869..be9c4747d51190bcc92a1ae3c6992ae7c6d45018 100644 (file)
@@ -71,7 +71,7 @@ struct cn_dev {
 int cn_add_callback(struct cb_id *id, const char *name,
                    void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
 void cn_del_callback(struct cb_id *);
-int cn_netlink_send(struct cn_msg *, u32, gfp_t);
+int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 group, gfp_t gfp_mask);
 
 int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
                          struct cb_id *id,
index 4d89e0e6f9ccaa641dd2a6b2c35c8c7b7bbf2916..2d2e62c8666ad71962315ac4f7041029474a5fec 100644 (file)
@@ -74,6 +74,8 @@ struct cpufreq_policy {
        unsigned int            max;    /* in kHz */
        unsigned int            cur;    /* in kHz, only needed if cpufreq
                                         * governors are used */
+       unsigned int            suspend_freq; /* freq to set during suspend */
+
        unsigned int            policy; /* see above */
        struct cpufreq_governor *governor; /* see below */
        void                    *governor_data;
@@ -83,6 +85,7 @@ struct cpufreq_policy {
                                         * called, but you're in IRQ context */
 
        struct cpufreq_real_policy      user_policy;
+       struct cpufreq_frequency_table  *freq_table;
 
        struct list_head        policy_list;
        struct kobject          kobj;
@@ -224,6 +227,7 @@ struct cpufreq_driver {
        int     (*bios_limit)   (int cpu, unsigned int *limit);
 
        int     (*exit)         (struct cpufreq_policy *policy);
+       void    (*stop_cpu)     (struct cpufreq_policy *policy);
        int     (*suspend)      (struct cpufreq_policy *policy);
        int     (*resume)       (struct cpufreq_policy *policy);
        struct freq_attr        **attr;
@@ -296,6 +300,15 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
                        policy->cpuinfo.max_freq);
 }
 
+#ifdef CONFIG_CPU_FREQ
+void cpufreq_suspend(void);
+void cpufreq_resume(void);
+int cpufreq_generic_suspend(struct cpufreq_policy *policy);
+#else
+static inline void cpufreq_suspend(void) {}
+static inline void cpufreq_resume(void) {}
+#endif
+
 /*********************************************************************
  *                     CPUFREQ NOTIFIER INTERFACE                    *
  *********************************************************************/
@@ -306,8 +319,6 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
 /* Transition notifiers */
 #define CPUFREQ_PRECHANGE              (0)
 #define CPUFREQ_POSTCHANGE             (1)
-#define CPUFREQ_RESUMECHANGE           (8)
-#define CPUFREQ_SUSPENDCHANGE          (9)
 
 /* Policy Notifiers  */
 #define CPUFREQ_ADJUST                 (0)
@@ -463,7 +474,6 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
                unsigned int freq);
 
-void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
 ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
 
 #ifdef CONFIG_CPU_FREQ
@@ -490,9 +500,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
 /* the following are really really optional */
 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
 extern struct freq_attr *cpufreq_generic_attr[];
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
-                                     unsigned int cpu);
-void cpufreq_frequency_table_put_attr(unsigned int cpu);
 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
                                      struct cpufreq_frequency_table *table);
 
@@ -500,10 +507,4 @@ unsigned int cpufreq_generic_get(unsigned int cpu);
 int cpufreq_generic_init(struct cpufreq_policy *policy,
                struct cpufreq_frequency_table *table,
                unsigned int transition_latency);
-static inline int cpufreq_generic_exit(struct cpufreq_policy *policy)
-{
-       cpufreq_frequency_table_put_attr(policy->cpu);
-       return 0;
-}
-
 #endif /* _LINUX_CPUFREQ_H */
diff --git a/include/linux/cputime.h b/include/linux/cputime.h
new file mode 100644 (file)
index 0000000..f2eb2ee
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __LINUX_CPUTIME_H
+#define __LINUX_CPUTIME_H
+
+#include <asm/cputime.h>
+
+#ifndef cputime_to_nsecs
+# define cputime_to_nsecs(__ct)        \
+       (cputime_to_usecs(__ct) * NSEC_PER_USEC)
+#endif
+
+#ifndef nsecs_to_cputime
+# define nsecs_to_cputime(__nsecs)     \
+       usecs_to_cputime((__nsecs) / NSEC_PER_USEC)
+#endif
+
+#endif /* __LINUX_CPUTIME_H */
index 1ff3f16975131e702a4445e6cfc817803b074d3d..233bbbeb768d6f8c5a6aa32411675a14b3401272 100644 (file)
@@ -628,6 +628,7 @@ static inline void *devm_kcalloc(struct device *dev,
        return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
 }
 extern void devm_kfree(struct device *dev, void *p);
+extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp);
 
 void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
 void __iomem *devm_request_and_ioremap(struct device *dev,
index 0a819e7a60c961246c529570fedf7717dd6c3c7c..6c100ff0cae4b6eb886e48530c9f48c858b0f257 100644 (file)
@@ -153,6 +153,102 @@ typedef struct {
        u8 sets_to_zero;
 } efi_time_cap_t;
 
+typedef struct {
+       efi_table_hdr_t hdr;
+       u32 raise_tpl;
+       u32 restore_tpl;
+       u32 allocate_pages;
+       u32 free_pages;
+       u32 get_memory_map;
+       u32 allocate_pool;
+       u32 free_pool;
+       u32 create_event;
+       u32 set_timer;
+       u32 wait_for_event;
+       u32 signal_event;
+       u32 close_event;
+       u32 check_event;
+       u32 install_protocol_interface;
+       u32 reinstall_protocol_interface;
+       u32 uninstall_protocol_interface;
+       u32 handle_protocol;
+       u32 __reserved;
+       u32 register_protocol_notify;
+       u32 locate_handle;
+       u32 locate_device_path;
+       u32 install_configuration_table;
+       u32 load_image;
+       u32 start_image;
+       u32 exit;
+       u32 unload_image;
+       u32 exit_boot_services;
+       u32 get_next_monotonic_count;
+       u32 stall;
+       u32 set_watchdog_timer;
+       u32 connect_controller;
+       u32 disconnect_controller;
+       u32 open_protocol;
+       u32 close_protocol;
+       u32 open_protocol_information;
+       u32 protocols_per_handle;
+       u32 locate_handle_buffer;
+       u32 locate_protocol;
+       u32 install_multiple_protocol_interfaces;
+       u32 uninstall_multiple_protocol_interfaces;
+       u32 calculate_crc32;
+       u32 copy_mem;
+       u32 set_mem;
+       u32 create_event_ex;
+} __packed efi_boot_services_32_t;
+
+typedef struct {
+       efi_table_hdr_t hdr;
+       u64 raise_tpl;
+       u64 restore_tpl;
+       u64 allocate_pages;
+       u64 free_pages;
+       u64 get_memory_map;
+       u64 allocate_pool;
+       u64 free_pool;
+       u64 create_event;
+       u64 set_timer;
+       u64 wait_for_event;
+       u64 signal_event;
+       u64 close_event;
+       u64 check_event;
+       u64 install_protocol_interface;
+       u64 reinstall_protocol_interface;
+       u64 uninstall_protocol_interface;
+       u64 handle_protocol;
+       u64 __reserved;
+       u64 register_protocol_notify;
+       u64 locate_handle;
+       u64 locate_device_path;
+       u64 install_configuration_table;
+       u64 load_image;
+       u64 start_image;
+       u64 exit;
+       u64 unload_image;
+       u64 exit_boot_services;
+       u64 get_next_monotonic_count;
+       u64 stall;
+       u64 set_watchdog_timer;
+       u64 connect_controller;
+       u64 disconnect_controller;
+       u64 open_protocol;
+       u64 close_protocol;
+       u64 open_protocol_information;
+       u64 protocols_per_handle;
+       u64 locate_handle_buffer;
+       u64 locate_protocol;
+       u64 install_multiple_protocol_interfaces;
+       u64 uninstall_multiple_protocol_interfaces;
+       u64 calculate_crc32;
+       u64 copy_mem;
+       u64 set_mem;
+       u64 create_event_ex;
+} __packed efi_boot_services_64_t;
+
 /*
  * EFI Boot Services table
  */
@@ -231,12 +327,61 @@ typedef enum {
     EfiPciIoAttributeOperationMaximum
 } EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
 
+typedef struct {
+       u32 read;
+       u32 write;
+} efi_pci_io_protocol_access_32_t;
+
+typedef struct {
+       u64 read;
+       u64 write;
+} efi_pci_io_protocol_access_64_t;
 
 typedef struct {
        void *read;
        void *write;
 } efi_pci_io_protocol_access_t;
 
+typedef struct {
+       u32 poll_mem;
+       u32 poll_io;
+       efi_pci_io_protocol_access_32_t mem;
+       efi_pci_io_protocol_access_32_t io;
+       efi_pci_io_protocol_access_32_t pci;
+       u32 copy_mem;
+       u32 map;
+       u32 unmap;
+       u32 allocate_buffer;
+       u32 free_buffer;
+       u32 flush;
+       u32 get_location;
+       u32 attributes;
+       u32 get_bar_attributes;
+       u32 set_bar_attributes;
+       uint64_t romsize;
+       void *romimage;
+} efi_pci_io_protocol_32;
+
+typedef struct {
+       u64 poll_mem;
+       u64 poll_io;
+       efi_pci_io_protocol_access_64_t mem;
+       efi_pci_io_protocol_access_64_t io;
+       efi_pci_io_protocol_access_64_t pci;
+       u64 copy_mem;
+       u64 map;
+       u64 unmap;
+       u64 allocate_buffer;
+       u64 free_buffer;
+       u64 flush;
+       u64 get_location;
+       u64 attributes;
+       u64 get_bar_attributes;
+       u64 set_bar_attributes;
+       uint64_t romsize;
+       void *romimage;
+} efi_pci_io_protocol_64;
+
 typedef struct {
        void *poll_mem;
        void *poll_io;
@@ -290,6 +435,42 @@ typedef struct {
 #define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL)
 #define EFI_RUNTIME_SERVICES_REVISION  0x00010000
 
+typedef struct {
+       efi_table_hdr_t hdr;
+       u32 get_time;
+       u32 set_time;
+       u32 get_wakeup_time;
+       u32 set_wakeup_time;
+       u32 set_virtual_address_map;
+       u32 convert_pointer;
+       u32 get_variable;
+       u32 get_next_variable;
+       u32 set_variable;
+       u32 get_next_high_mono_count;
+       u32 reset_system;
+       u32 update_capsule;
+       u32 query_capsule_caps;
+       u32 query_variable_info;
+} efi_runtime_services_32_t;
+
+typedef struct {
+       efi_table_hdr_t hdr;
+       u64 get_time;
+       u64 set_time;
+       u64 get_wakeup_time;
+       u64 set_wakeup_time;
+       u64 set_virtual_address_map;
+       u64 convert_pointer;
+       u64 get_variable;
+       u64 get_next_variable;
+       u64 set_variable;
+       u64 get_next_high_mono_count;
+       u64 reset_system;
+       u64 update_capsule;
+       u64 query_capsule_caps;
+       u64 query_variable_info;
+} efi_runtime_services_64_t;
+
 typedef struct {
        efi_table_hdr_t hdr;
        void *get_time;
@@ -483,6 +664,38 @@ struct efi_memory_map {
        unsigned long desc_size;
 };
 
+typedef struct {
+       u32 revision;
+       u32 parent_handle;
+       u32 system_table;
+       u32 device_handle;
+       u32 file_path;
+       u32 reserved;
+       u32 load_options_size;
+       u32 load_options;
+       u32 image_base;
+       __aligned_u64 image_size;
+       unsigned int image_code_type;
+       unsigned int image_data_type;
+       unsigned long unload;
+} efi_loaded_image_32_t;
+
+typedef struct {
+       u32 revision;
+       u64 parent_handle;
+       u64 system_table;
+       u64 device_handle;
+       u64 file_path;
+       u64 reserved;
+       u32 load_options_size;
+       u64 load_options;
+       u64 image_base;
+       __aligned_u64 image_size;
+       unsigned int image_code_type;
+       unsigned int image_data_type;
+       unsigned long unload;
+} efi_loaded_image_64_t;
+
 typedef struct {
        u32 revision;
        void *parent_handle;
@@ -511,6 +724,34 @@ typedef struct {
        efi_char16_t filename[1];
 } efi_file_info_t;
 
+typedef struct {
+       u64 revision;
+       u32 open;
+       u32 close;
+       u32 delete;
+       u32 read;
+       u32 write;
+       u32 get_position;
+       u32 set_position;
+       u32 get_info;
+       u32 set_info;
+       u32 flush;
+} efi_file_handle_32_t;
+
+typedef struct {
+       u64 revision;
+       u64 open;
+       u64 close;
+       u64 delete;
+       u64 read;
+       u64 write;
+       u64 get_position;
+       u64 set_position;
+       u64 get_info;
+       u64 set_info;
+       u64 flush;
+} efi_file_handle_64_t;
+
 typedef struct _efi_file_handle {
        u64 revision;
        efi_status_t (*open)(struct _efi_file_handle *,
@@ -573,6 +814,7 @@ extern struct efi {
        efi_reset_system_t *reset_system;
        efi_set_virtual_address_map_t *set_virtual_address_map;
        struct efi_memory_map *memmap;
+       unsigned long flags;
 } efi;
 
 static inline int
@@ -659,18 +901,17 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_ARCH_1             6       /* First arch-specific bit */
 
 #ifdef CONFIG_EFI
-# ifdef CONFIG_X86
-extern int efi_enabled(int facility);
-# else
-static inline int efi_enabled(int facility)
+/*
+ * Test whether the above EFI_* bits are enabled.
+ */
+static inline bool efi_enabled(int feature)
 {
-       return 1;
+       return test_bit(feature, &efi.flags) != 0;
 }
-# endif
 #else
-static inline int efi_enabled(int facility)
+static inline bool efi_enabled(int feature)
 {
-       return 0;
+       return false;
 }
 #endif
 
@@ -809,6 +1050,17 @@ struct efivar_entry {
        bool deleting;
 };
 
+struct efi_simple_text_output_protocol_32 {
+       u32 reset;
+       u32 output_string;
+       u32 test_string;
+};
+
+struct efi_simple_text_output_protocol_64 {
+       u64 reset;
+       u64 output_string;
+       u64 test_string;
+};
 
 struct efi_simple_text_output_protocol {
        void *reset;
index 21c59af1150b57588fbe697c9ef9fe38aacff06f..f488145bb2d40460ac58add4624e8648af685e3f 100644 (file)
@@ -240,6 +240,12 @@ extern int extcon_register_notifier(struct extcon_dev *edev,
                                    struct notifier_block *nb);
 extern int extcon_unregister_notifier(struct extcon_dev *edev,
                                      struct notifier_block *nb);
+
+/*
+ * Following API get the extcon device from devicetree.
+ * This function use phandle of devicetree to get extcon device directly.
+ */
+extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index);
 #else /* CONFIG_EXTCON */
 static inline int extcon_dev_register(struct extcon_dev *edev)
 {
@@ -324,5 +330,11 @@ static inline int extcon_unregister_interest(struct extcon_specific_cable_nb
 {
        return 0;
 }
+
+static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
+                                                           int index)
+{
+       return ERR_PTR(-ENODEV);
+}
 #endif /* CONFIG_EXTCON */
 #endif /* __LINUX_EXTCON_H__ */
diff --git a/include/linux/extcon/of_extcon.h b/include/linux/extcon/of_extcon.h
deleted file mode 100644 (file)
index 0ebfeff..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * OF helpers for External connector (extcon) framework
- *
- * Copyright (C) 2013 Texas Instruments, Inc.
- * Kishon Vijay Abraham I <kishon@ti.com>
- *
- * Copyright (C) 2013 Samsung Electronics
- * Chanwoo Choi <cw00.choi@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __LINUX_OF_EXTCON_H
-#define __LINUX_OF_EXTCON_H
-
-#include <linux/err.h>
-
-#if IS_ENABLED(CONFIG_OF_EXTCON)
-extern struct extcon_dev
-       *of_extcon_get_extcon_dev(struct device *dev, int index);
-#else
-static inline struct extcon_dev
-       *of_extcon_get_extcon_dev(struct device *dev, int index)
-{
-       return ERR_PTR(-ENOSYS);
-}
-#endif /* CONFIG_OF_EXTCON */
-#endif /* __LINUX_OF_EXTCON_H */
index cbacf4faf447a9dd2b3fd50d3dc2e4f86a120e67..4d69123377a2b4e0a7869ba38cc91ceb4fd1c7b7 100644 (file)
@@ -28,33 +28,36 @@ static inline void fput_light(struct file *file, int fput_needed)
 
 struct fd {
        struct file *file;
-       int need_put;
+       unsigned int flags;
 };
+#define FDPUT_FPUT       1
+#define FDPUT_POS_UNLOCK 2
 
 static inline void fdput(struct fd fd)
 {
-       if (fd.need_put)
+       if (fd.flags & FDPUT_FPUT)
                fput(fd.file);
 }
 
 extern struct file *fget(unsigned int fd);
-extern struct file *fget_light(unsigned int fd, int *fput_needed);
+extern struct file *fget_raw(unsigned int fd);
+extern unsigned long __fdget(unsigned int fd);
+extern unsigned long __fdget_raw(unsigned int fd);
+extern unsigned long __fdget_pos(unsigned int fd);
 
-static inline struct fd fdget(unsigned int fd)
+static inline struct fd __to_fd(unsigned long v)
 {
-       int b;
-       struct file *f = fget_light(fd, &b);
-       return (struct fd){f,b};
+       return (struct fd){(struct file *)(v & ~3),v & 3};
 }
 
-extern struct file *fget_raw(unsigned int fd);
-extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
+static inline struct fd fdget(unsigned int fd)
+{
+       return __to_fd(__fdget(fd));
+}
 
 static inline struct fd fdget_raw(unsigned int fd)
 {
-       int b;
-       struct file *f = fget_raw_light(fd, &b);
-       return (struct fd){f,b};
+       return __to_fd(__fdget_raw(fd));
 }
 
 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
index 5d7782e42b8f22f81df12652348ff9a21aebc7e4..c3683bdf28fe4e677959f33d524bd724a9a1d59d 100644 (file)
@@ -200,6 +200,7 @@ struct fw_device {
        unsigned irmc:1;
        unsigned bc_implemented:2;
 
+       work_func_t workfn;
        struct delayed_work work;
        struct fw_attribute_group attribute_group;
 };
index 1974317a9b3d14b7379ad8318cf07d833c1cbc90..599bd6bab56dad4f058facc7413ebde4f1c2d6e1 100644 (file)
@@ -14,6 +14,8 @@ union sdb_record {
        struct sdb_bridge bridge;
        struct sdb_integration integr;
        struct sdb_empty empty;
+       struct sdb_synthesis synthesis;
+       struct sdb_repo_url repo_url;
 };
 
 struct fmc_device;
index 60829565e5522a2c68f489665909d39f65230a25..23b2a35d712efbec3e31df0cae70b69a17b81616 100644 (file)
@@ -123,6 +123,9 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 /* File is opened with O_PATH; almost nothing can be done with it */
 #define FMODE_PATH             ((__force fmode_t)0x4000)
 
+/* File needs atomic accesses to f_pos */
+#define FMODE_ATOMIC_POS       ((__force fmode_t)0x8000)
+
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
 
@@ -780,13 +783,14 @@ struct file {
        const struct file_operations    *f_op;
 
        /*
-        * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
+        * Protects f_ep_links, f_flags.
         * Must not be taken from IRQ context.
         */
        spinlock_t              f_lock;
        atomic_long_t           f_count;
        unsigned int            f_flags;
        fmode_t                 f_mode;
+       struct mutex            f_pos_lock;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        const struct cred       *f_cred;
@@ -808,7 +812,7 @@ struct file {
 #ifdef CONFIG_DEBUG_WRITECOUNT
        unsigned long f_mnt_write_state;
 #endif
-};
+} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
 
 struct file_handle {
        __u32 handle_bytes;
diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h
new file mode 100644 (file)
index 0000000..f49ddb1
--- /dev/null
@@ -0,0 +1,838 @@
+/* Freescale Integrated Flash Controller
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <dipen.dudhat@freescale.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
+ */
+
+#ifndef __ASM_FSL_IFC_H
+#define __ASM_FSL_IFC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+
+#define FSL_IFC_BANK_COUNT 4
+
+/*
+ * CSPR - Chip Select Property Register
+ */
+#define CSPR_BA                                0xFFFF0000
+#define CSPR_BA_SHIFT                  16
+#define CSPR_PORT_SIZE                 0x00000180
+#define CSPR_PORT_SIZE_SHIFT           7
+/* Port Size 8 bit */
+#define CSPR_PORT_SIZE_8               0x00000080
+/* Port Size 16 bit */
+#define CSPR_PORT_SIZE_16              0x00000100
+/* Port Size 32 bit */
+#define CSPR_PORT_SIZE_32              0x00000180
+/* Write Protect */
+#define CSPR_WP                                0x00000040
+#define CSPR_WP_SHIFT                  6
+/* Machine Select */
+#define CSPR_MSEL                      0x00000006
+#define CSPR_MSEL_SHIFT                        1
+/* NOR */
+#define CSPR_MSEL_NOR                  0x00000000
+/* NAND */
+#define CSPR_MSEL_NAND                 0x00000002
+/* GPCM */
+#define CSPR_MSEL_GPCM                 0x00000004
+/* Bank Valid */
+#define CSPR_V                         0x00000001
+#define CSPR_V_SHIFT                   0
+
+/*
+ * Address Mask Register
+ */
+#define IFC_AMASK_MASK                 0xFFFF0000
+#define IFC_AMASK_SHIFT                        16
+#define IFC_AMASK(n)                   (IFC_AMASK_MASK << \
+                                       (__ilog2(n) - IFC_AMASK_SHIFT))
+
+/*
+ * Chip Select Option Register IFC_NAND Machine
+ */
+/* Enable ECC Encoder */
+#define CSOR_NAND_ECC_ENC_EN           0x80000000
+#define CSOR_NAND_ECC_MODE_MASK                0x30000000
+/* 4 bit correction per 520 Byte sector */
+#define CSOR_NAND_ECC_MODE_4           0x00000000
+/* 8 bit correction per 528 Byte sector */
+#define CSOR_NAND_ECC_MODE_8           0x10000000
+/* Enable ECC Decoder */
+#define CSOR_NAND_ECC_DEC_EN           0x04000000
+/* Row Address Length */
+#define CSOR_NAND_RAL_MASK             0x01800000
+#define CSOR_NAND_RAL_SHIFT            20
+#define CSOR_NAND_RAL_1                        0x00000000
+#define CSOR_NAND_RAL_2                        0x00800000
+#define CSOR_NAND_RAL_3                        0x01000000
+#define CSOR_NAND_RAL_4                        0x01800000
+/* Page Size 512b, 2k, 4k */
+#define CSOR_NAND_PGS_MASK             0x00180000
+#define CSOR_NAND_PGS_SHIFT            16
+#define CSOR_NAND_PGS_512              0x00000000
+#define CSOR_NAND_PGS_2K               0x00080000
+#define CSOR_NAND_PGS_4K               0x00100000
+#define CSOR_NAND_PGS_8K               0x00180000
+/* Spare region Size */
+#define CSOR_NAND_SPRZ_MASK            0x0000E000
+#define CSOR_NAND_SPRZ_SHIFT           13
+#define CSOR_NAND_SPRZ_16              0x00000000
+#define CSOR_NAND_SPRZ_64              0x00002000
+#define CSOR_NAND_SPRZ_128             0x00004000
+#define CSOR_NAND_SPRZ_210             0x00006000
+#define CSOR_NAND_SPRZ_218             0x00008000
+#define CSOR_NAND_SPRZ_224             0x0000A000
+#define CSOR_NAND_SPRZ_CSOR_EXT                0x0000C000
+/* Pages Per Block */
+#define CSOR_NAND_PB_MASK              0x00000700
+#define CSOR_NAND_PB_SHIFT             8
+#define CSOR_NAND_PB(n)                ((__ilog2(n) - 5) << CSOR_NAND_PB_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NAND_TRHZ_MASK            0x0000001C
+#define CSOR_NAND_TRHZ_SHIFT           2
+#define CSOR_NAND_TRHZ_20              0x00000000
+#define CSOR_NAND_TRHZ_40              0x00000004
+#define CSOR_NAND_TRHZ_60              0x00000008
+#define CSOR_NAND_TRHZ_80              0x0000000C
+#define CSOR_NAND_TRHZ_100             0x00000010
+/* Buffer control disable */
+#define CSOR_NAND_BCTLD                        0x00000001
+
+/*
+ * Chip Select Option Register - NOR Flash Mode
+ */
+/* Enable Address shift Mode */
+#define CSOR_NOR_ADM_SHFT_MODE_EN      0x80000000
+/* Page Read Enable from NOR device */
+#define CSOR_NOR_PGRD_EN               0x10000000
+/* AVD Toggle Enable during Burst Program */
+#define CSOR_NOR_AVD_TGL_PGM_EN                0x01000000
+/* Address Data Multiplexing Shift */
+#define CSOR_NOR_ADM_MASK              0x0003E000
+#define CSOR_NOR_ADM_SHIFT_SHIFT       13
+#define CSOR_NOR_ADM_SHIFT(n)  ((n) << CSOR_NOR_ADM_SHIFT_SHIFT)
+/* Type of the NOR device hooked */
+#define CSOR_NOR_NOR_MODE_AYSNC_NOR    0x00000000
+#define CSOR_NOR_NOR_MODE_AVD_NOR      0x00000020
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NOR_TRHZ_MASK             0x0000001C
+#define CSOR_NOR_TRHZ_SHIFT            2
+#define CSOR_NOR_TRHZ_20               0x00000000
+#define CSOR_NOR_TRHZ_40               0x00000004
+#define CSOR_NOR_TRHZ_60               0x00000008
+#define CSOR_NOR_TRHZ_80               0x0000000C
+#define CSOR_NOR_TRHZ_100              0x00000010
+/* Buffer control disable */
+#define CSOR_NOR_BCTLD                 0x00000001
+
+/*
+ * Chip Select Option Register - GPCM Mode
+ */
+/* GPCM Mode - Normal */
+#define CSOR_GPCM_GPMODE_NORMAL                0x00000000
+/* GPCM Mode - GenericASIC */
+#define CSOR_GPCM_GPMODE_ASIC          0x80000000
+/* Parity Mode odd/even */
+#define CSOR_GPCM_PARITY_EVEN          0x40000000
+/* Parity Checking enable/disable */
+#define CSOR_GPCM_PAR_EN               0x20000000
+/* GPCM Timeout Count */
+#define CSOR_GPCM_GPTO_MASK            0x0F000000
+#define CSOR_GPCM_GPTO_SHIFT           24
+#define CSOR_GPCM_GPTO(n)      ((__ilog2(n) - 8) << CSOR_GPCM_GPTO_SHIFT)
+/* GPCM External Access Termination mode for read access */
+#define CSOR_GPCM_RGETA_EXT            0x00080000
+/* GPCM External Access Termination mode for write access */
+#define CSOR_GPCM_WGETA_EXT            0x00040000
+/* Address Data Multiplexing Shift */
+#define CSOR_GPCM_ADM_MASK             0x0003E000
+#define CSOR_GPCM_ADM_SHIFT_SHIFT      13
+#define CSOR_GPCM_ADM_SHIFT(n) ((n) << CSOR_GPCM_ADM_SHIFT_SHIFT)
+/* Generic ASIC Parity error indication delay */
+#define CSOR_GPCM_GAPERRD_MASK         0x00000180
+#define CSOR_GPCM_GAPERRD_SHIFT                7
+#define CSOR_GPCM_GAPERRD(n)   (((n) - 1) << CSOR_GPCM_GAPERRD_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_GPCM_TRHZ_MASK            0x0000001C
+#define CSOR_GPCM_TRHZ_20              0x00000000
+#define CSOR_GPCM_TRHZ_40              0x00000004
+#define CSOR_GPCM_TRHZ_60              0x00000008
+#define CSOR_GPCM_TRHZ_80              0x0000000C
+#define CSOR_GPCM_TRHZ_100             0x00000010
+/* Buffer control disable */
+#define CSOR_GPCM_BCTLD                        0x00000001
+
+/*
+ * Ready Busy Status Register (RB_STAT)
+ */
+/* CSn is READY */
+#define IFC_RB_STAT_READY_CS0          0x80000000
+#define IFC_RB_STAT_READY_CS1          0x40000000
+#define IFC_RB_STAT_READY_CS2          0x20000000
+#define IFC_RB_STAT_READY_CS3          0x10000000
+
+/*
+ * General Control Register (GCR)
+ */
+#define IFC_GCR_MASK                   0x8000F800
+/* reset all IFC hardware */
+#define IFC_GCR_SOFT_RST_ALL           0x80000000
+/* Turnaroud Time of external buffer */
+#define IFC_GCR_TBCTL_TRN_TIME         0x0000F800
+#define IFC_GCR_TBCTL_TRN_TIME_SHIFT   11
+
+/*
+ * Common Event and Error Status Register (CM_EVTER_STAT)
+ */
+/* Chip select error */
+#define IFC_CM_EVTER_STAT_CSER         0x80000000
+
+/*
+ * Common Event and Error Enable Register (CM_EVTER_EN)
+ */
+/* Chip select error checking enable */
+#define IFC_CM_EVTER_EN_CSEREN         0x80000000
+
+/*
+ * Common Event and Error Interrupt Enable Register (CM_EVTER_INTR_EN)
+ */
+/* Chip select error interrupt enable */
+#define IFC_CM_EVTER_INTR_EN_CSERIREN  0x80000000
+
+/*
+ * Common Transfer Error Attribute Register-0 (CM_ERATTR0)
+ */
+/* transaction type of error Read/Write */
+#define IFC_CM_ERATTR0_ERTYP_READ      0x80000000
+#define IFC_CM_ERATTR0_ERAID           0x0FF00000
+#define IFC_CM_ERATTR0_ERAID_SHIFT     20
+#define IFC_CM_ERATTR0_ESRCID          0x0000FF00
+#define IFC_CM_ERATTR0_ESRCID_SHIFT    8
+
+/*
+ * Clock Control Register (CCR)
+ */
+#define IFC_CCR_MASK                   0x0F0F8800
+/* Clock division ratio */
+#define IFC_CCR_CLK_DIV_MASK           0x0F000000
+#define IFC_CCR_CLK_DIV_SHIFT          24
+#define IFC_CCR_CLK_DIV(n)             ((n-1) << IFC_CCR_CLK_DIV_SHIFT)
+/* IFC Clock Delay */
+#define IFC_CCR_CLK_DLY_MASK           0x000F0000
+#define IFC_CCR_CLK_DLY_SHIFT          16
+#define IFC_CCR_CLK_DLY(n)             ((n) << IFC_CCR_CLK_DLY_SHIFT)
+/* Invert IFC clock before sending out */
+#define IFC_CCR_INV_CLK_EN             0x00008000
+/* Fedback IFC Clock */
+#define IFC_CCR_FB_IFC_CLK_SEL         0x00000800
+
+/*
+ * Clock Status Register (CSR)
+ */
+/* Clk is stable */
+#define IFC_CSR_CLK_STAT_STABLE                0x80000000
+
+/*
+ * IFC_NAND Machine Specific Registers
+ */
+/*
+ * NAND Configuration Register (NCFGR)
+ */
+/* Auto Boot Mode */
+#define IFC_NAND_NCFGR_BOOT            0x80000000
+/* Addressing Mode-ROW0+n/COL0 */
+#define IFC_NAND_NCFGR_ADDR_MODE_RC0   0x00000000
+/* Addressing Mode-ROW0+n/COL0+n */
+#define IFC_NAND_NCFGR_ADDR_MODE_RC1   0x00400000
+/* Number of loop iterations of FIR sequences for multi page operations */
+#define IFC_NAND_NCFGR_NUM_LOOP_MASK   0x0000F000
+#define IFC_NAND_NCFGR_NUM_LOOP_SHIFT  12
+#define IFC_NAND_NCFGR_NUM_LOOP(n)     ((n) << IFC_NAND_NCFGR_NUM_LOOP_SHIFT)
+/* Number of wait cycles */
+#define IFC_NAND_NCFGR_NUM_WAIT_MASK   0x000000FF
+#define IFC_NAND_NCFGR_NUM_WAIT_SHIFT  0
+
+/*
+ * NAND Flash Command Registers (NAND_FCR0/NAND_FCR1)
+ */
+/* General purpose FCM flash command bytes CMD0-CMD7 */
+#define IFC_NAND_FCR0_CMD0             0xFF000000
+#define IFC_NAND_FCR0_CMD0_SHIFT       24
+#define IFC_NAND_FCR0_CMD1             0x00FF0000
+#define IFC_NAND_FCR0_CMD1_SHIFT       16
+#define IFC_NAND_FCR0_CMD2             0x0000FF00
+#define IFC_NAND_FCR0_CMD2_SHIFT       8
+#define IFC_NAND_FCR0_CMD3             0x000000FF
+#define IFC_NAND_FCR0_CMD3_SHIFT       0
+#define IFC_NAND_FCR1_CMD4             0xFF000000
+#define IFC_NAND_FCR1_CMD4_SHIFT       24
+#define IFC_NAND_FCR1_CMD5             0x00FF0000
+#define IFC_NAND_FCR1_CMD5_SHIFT       16
+#define IFC_NAND_FCR1_CMD6             0x0000FF00
+#define IFC_NAND_FCR1_CMD6_SHIFT       8
+#define IFC_NAND_FCR1_CMD7             0x000000FF
+#define IFC_NAND_FCR1_CMD7_SHIFT       0
+
+/*
+ * Flash ROW and COL Address Register (ROWn, COLn)
+ */
+/* Main/spare region locator */
+#define IFC_NAND_COL_MS                        0x80000000
+/* Column Address */
+#define IFC_NAND_COL_CA_MASK           0x00000FFF
+
+/*
+ * NAND Flash Byte Count Register (NAND_BC)
+ */
+/* Byte Count for read/Write */
+#define IFC_NAND_BC                    0x000001FF
+
+/*
+ * NAND Flash Instruction Registers (NAND_FIR0/NAND_FIR1/NAND_FIR2)
+ */
+/* NAND Machine specific opcodes OP0-OP14*/
+#define IFC_NAND_FIR0_OP0              0xFC000000
+#define IFC_NAND_FIR0_OP0_SHIFT                26
+#define IFC_NAND_FIR0_OP1              0x03F00000
+#define IFC_NAND_FIR0_OP1_SHIFT                20
+#define IFC_NAND_FIR0_OP2              0x000FC000
+#define IFC_NAND_FIR0_OP2_SHIFT                14
+#define IFC_NAND_FIR0_OP3              0x00003F00
+#define IFC_NAND_FIR0_OP3_SHIFT                8
+#define IFC_NAND_FIR0_OP4              0x000000FC
+#define IFC_NAND_FIR0_OP4_SHIFT                2
+#define IFC_NAND_FIR1_OP5              0xFC000000
+#define IFC_NAND_FIR1_OP5_SHIFT                26
+#define IFC_NAND_FIR1_OP6              0x03F00000
+#define IFC_NAND_FIR1_OP6_SHIFT                20
+#define IFC_NAND_FIR1_OP7              0x000FC000
+#define IFC_NAND_FIR1_OP7_SHIFT                14
+#define IFC_NAND_FIR1_OP8              0x00003F00
+#define IFC_NAND_FIR1_OP8_SHIFT                8
+#define IFC_NAND_FIR1_OP9              0x000000FC
+#define IFC_NAND_FIR1_OP9_SHIFT                2
+#define IFC_NAND_FIR2_OP10             0xFC000000
+#define IFC_NAND_FIR2_OP10_SHIFT       26
+#define IFC_NAND_FIR2_OP11             0x03F00000
+#define IFC_NAND_FIR2_OP11_SHIFT       20
+#define IFC_NAND_FIR2_OP12             0x000FC000
+#define IFC_NAND_FIR2_OP12_SHIFT       14
+#define IFC_NAND_FIR2_OP13             0x00003F00
+#define IFC_NAND_FIR2_OP13_SHIFT       8
+#define IFC_NAND_FIR2_OP14             0x000000FC
+#define IFC_NAND_FIR2_OP14_SHIFT       2
+
+/*
+ * Instruction opcodes to be programmed
+ * in FIR registers- 6bits
+ */
+enum ifc_nand_fir_opcodes {
+       IFC_FIR_OP_NOP,
+       IFC_FIR_OP_CA0,
+       IFC_FIR_OP_CA1,
+       IFC_FIR_OP_CA2,
+       IFC_FIR_OP_CA3,
+       IFC_FIR_OP_RA0,
+       IFC_FIR_OP_RA1,
+       IFC_FIR_OP_RA2,
+       IFC_FIR_OP_RA3,
+       IFC_FIR_OP_CMD0,
+       IFC_FIR_OP_CMD1,
+       IFC_FIR_OP_CMD2,
+       IFC_FIR_OP_CMD3,
+       IFC_FIR_OP_CMD4,
+       IFC_FIR_OP_CMD5,
+       IFC_FIR_OP_CMD6,
+       IFC_FIR_OP_CMD7,
+       IFC_FIR_OP_CW0,
+       IFC_FIR_OP_CW1,
+       IFC_FIR_OP_CW2,
+       IFC_FIR_OP_CW3,
+       IFC_FIR_OP_CW4,
+       IFC_FIR_OP_CW5,
+       IFC_FIR_OP_CW6,
+       IFC_FIR_OP_CW7,
+       IFC_FIR_OP_WBCD,
+       IFC_FIR_OP_RBCD,
+       IFC_FIR_OP_BTRD,
+       IFC_FIR_OP_RDSTAT,
+       IFC_FIR_OP_NWAIT,
+       IFC_FIR_OP_WFR,
+       IFC_FIR_OP_SBRD,
+       IFC_FIR_OP_UA,
+       IFC_FIR_OP_RB,
+};
+
+/*
+ * NAND Chip Select Register (NAND_CSEL)
+ */
+#define IFC_NAND_CSEL                  0x0C000000
+#define IFC_NAND_CSEL_SHIFT            26
+#define IFC_NAND_CSEL_CS0              0x00000000
+#define IFC_NAND_CSEL_CS1              0x04000000
+#define IFC_NAND_CSEL_CS2              0x08000000
+#define IFC_NAND_CSEL_CS3              0x0C000000
+
+/*
+ * NAND Operation Sequence Start (NANDSEQ_STRT)
+ */
+/* NAND Flash Operation Start */
+#define IFC_NAND_SEQ_STRT_FIR_STRT     0x80000000
+/* Automatic Erase */
+#define IFC_NAND_SEQ_STRT_AUTO_ERS     0x00800000
+/* Automatic Program */
+#define IFC_NAND_SEQ_STRT_AUTO_PGM     0x00100000
+/* Automatic Copyback */
+#define IFC_NAND_SEQ_STRT_AUTO_CPB     0x00020000
+/* Automatic Read Operation */
+#define IFC_NAND_SEQ_STRT_AUTO_RD      0x00004000
+/* Automatic Status Read */
+#define IFC_NAND_SEQ_STRT_AUTO_STAT_RD 0x00000800
+
+/*
+ * NAND Event and Error Status Register (NAND_EVTER_STAT)
+ */
+/* Operation Complete */
+#define IFC_NAND_EVTER_STAT_OPC                0x80000000
+/* Flash Timeout Error */
+#define IFC_NAND_EVTER_STAT_FTOER      0x08000000
+/* Write Protect Error */
+#define IFC_NAND_EVTER_STAT_WPER       0x04000000
+/* ECC Error */
+#define IFC_NAND_EVTER_STAT_ECCER      0x02000000
+/* RCW Load Done */
+#define IFC_NAND_EVTER_STAT_RCW_DN     0x00008000
+/* Boot Loadr Done */
+#define IFC_NAND_EVTER_STAT_BOOT_DN    0x00004000
+/* Bad Block Indicator search select */
+#define IFC_NAND_EVTER_STAT_BBI_SRCH_SE        0x00000800
+
+/*
+ * NAND Flash Page Read Completion Event Status Register
+ * (PGRDCMPL_EVT_STAT)
+ */
+#define PGRDCMPL_EVT_STAT_MASK         0xFFFF0000
+/* Small Page 0-15 Done */
+#define PGRDCMPL_EVT_STAT_SECTION_SP(n)        (1 << (31 - (n)))
+/* Large Page(2K) 0-3 Done */
+#define PGRDCMPL_EVT_STAT_LP_2K(n)     (0xF << (28 - (n)*4))
+/* Large Page(4K) 0-1 Done */
+#define PGRDCMPL_EVT_STAT_LP_4K(n)     (0xFF << (24 - (n)*8))
+
+/*
+ * NAND Event and Error Enable Register (NAND_EVTER_EN)
+ */
+/* Operation complete event enable */
+#define IFC_NAND_EVTER_EN_OPC_EN       0x80000000
+/* Page read complete event enable */
+#define IFC_NAND_EVTER_EN_PGRDCMPL_EN  0x20000000
+/* Flash Timeout error enable */
+#define IFC_NAND_EVTER_EN_FTOER_EN     0x08000000
+/* Write Protect error enable */
+#define IFC_NAND_EVTER_EN_WPER_EN      0x04000000
+/* ECC error logging enable */
+#define IFC_NAND_EVTER_EN_ECCER_EN     0x02000000
+
+/*
+ * NAND Event and Error Interrupt Enable Register (NAND_EVTER_INTR_EN)
+ */
+/* Enable interrupt for operation complete */
+#define IFC_NAND_EVTER_INTR_OPCIR_EN           0x80000000
+/* Enable interrupt for Page read complete */
+#define IFC_NAND_EVTER_INTR_PGRDCMPLIR_EN      0x20000000
+/* Enable interrupt for Flash timeout error */
+#define IFC_NAND_EVTER_INTR_FTOERIR_EN         0x08000000
+/* Enable interrupt for Write protect error */
+#define IFC_NAND_EVTER_INTR_WPERIR_EN          0x04000000
+/* Enable interrupt for ECC error*/
+#define IFC_NAND_EVTER_INTR_ECCERIR_EN         0x02000000
+
+/*
+ * NAND Transfer Error Attribute Register-0 (NAND_ERATTR0)
+ */
+#define IFC_NAND_ERATTR0_MASK          0x0C080000
+/* Error on CS0-3 for NAND */
+#define IFC_NAND_ERATTR0_ERCS_CS0      0x00000000
+#define IFC_NAND_ERATTR0_ERCS_CS1      0x04000000
+#define IFC_NAND_ERATTR0_ERCS_CS2      0x08000000
+#define IFC_NAND_ERATTR0_ERCS_CS3      0x0C000000
+/* Transaction type of error Read/Write */
+#define IFC_NAND_ERATTR0_ERTTYPE_READ  0x00080000
+
+/*
+ * NAND Flash Status Register (NAND_FSR)
+ */
+/* First byte of data read from read status op */
+#define IFC_NAND_NFSR_RS0              0xFF000000
+/* Second byte of data read from read status op */
+#define IFC_NAND_NFSR_RS1              0x00FF0000
+
+/*
+ * ECC Error Status Registers (ECCSTAT0-ECCSTAT3)
+ */
+/* Number of ECC errors on sector n (n = 0-15) */
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_MASK  0x0F000000
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_SHIFT 24
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_MASK  0x000F0000
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_SHIFT 16
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_MASK  0x00000F00
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_SHIFT 8
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_MASK  0x0000000F
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_SHIFT 0
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_MASK  0x0F000000
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_SHIFT 24
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_MASK  0x000F0000
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_SHIFT 16
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_MASK  0x00000F00
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_SHIFT 8
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_MASK  0x0000000F
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_SHIFT 0
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_MASK  0x0F000000
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_SHIFT 24
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_MASK  0x000F0000
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_SHIFT 16
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_MASK 0x00000F00
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_SHIFT        8
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_MASK 0x0000000F
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_SHIFT        0
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_MASK 0x0F000000
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_SHIFT        24
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_MASK 0x000F0000
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_SHIFT        16
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_MASK 0x00000F00
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_SHIFT        8
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_MASK 0x0000000F
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_SHIFT        0
+
+/*
+ * NAND Control Register (NANDCR)
+ */
+#define IFC_NAND_NCR_FTOCNT_MASK       0x1E000000
+#define IFC_NAND_NCR_FTOCNT_SHIFT      25
+#define IFC_NAND_NCR_FTOCNT(n) ((_ilog2(n) - 8)  << IFC_NAND_NCR_FTOCNT_SHIFT)
+
+/*
+ * NAND_AUTOBOOT_TRGR
+ */
+/* Trigger RCW load */
+#define IFC_NAND_AUTOBOOT_TRGR_RCW_LD  0x80000000
+/* Trigget Auto Boot */
+#define IFC_NAND_AUTOBOOT_TRGR_BOOT_LD 0x20000000
+
+/*
+ * NAND_MDR
+ */
+/* 1st read data byte when opcode SBRD */
+#define IFC_NAND_MDR_RDATA0            0xFF000000
+/* 2nd read data byte when opcode SBRD */
+#define IFC_NAND_MDR_RDATA1            0x00FF0000
+
+/*
+ * NOR Machine Specific Registers
+ */
+/*
+ * NOR Event and Error Status Register (NOR_EVTER_STAT)
+ */
+/* NOR Command Sequence Operation Complete */
+#define IFC_NOR_EVTER_STAT_OPC_NOR     0x80000000
+/* Write Protect Error */
+#define IFC_NOR_EVTER_STAT_WPER                0x04000000
+/* Command Sequence Timeout Error */
+#define IFC_NOR_EVTER_STAT_STOER       0x01000000
+
+/*
+ * NOR Event and Error Enable Register (NOR_EVTER_EN)
+ */
+/* NOR Command Seq complete event enable */
+#define IFC_NOR_EVTER_EN_OPCEN_NOR     0x80000000
+/* Write Protect Error Checking Enable */
+#define IFC_NOR_EVTER_EN_WPEREN                0x04000000
+/* Timeout Error Enable */
+#define IFC_NOR_EVTER_EN_STOEREN       0x01000000
+
+/*
+ * NOR Event and Error Interrupt Enable Register (NOR_EVTER_INTR_EN)
+ */
+/* Enable interrupt for OPC complete */
+#define IFC_NOR_EVTER_INTR_OPCEN_NOR   0x80000000
+/* Enable interrupt for write protect error */
+#define IFC_NOR_EVTER_INTR_WPEREN      0x04000000
+/* Enable interrupt for timeout error */
+#define IFC_NOR_EVTER_INTR_STOEREN     0x01000000
+
+/*
+ * NOR Transfer Error Attribute Register-0 (NOR_ERATTR0)
+ */
+/* Source ID for error transaction */
+#define IFC_NOR_ERATTR0_ERSRCID                0xFF000000
+/* AXI ID for error transation */
+#define IFC_NOR_ERATTR0_ERAID          0x000FF000
+/* Chip select corresponds to NOR error */
+#define IFC_NOR_ERATTR0_ERCS_CS0       0x00000000
+#define IFC_NOR_ERATTR0_ERCS_CS1       0x00000010
+#define IFC_NOR_ERATTR0_ERCS_CS2       0x00000020
+#define IFC_NOR_ERATTR0_ERCS_CS3       0x00000030
+/* Type of transaction read/write */
+#define IFC_NOR_ERATTR0_ERTYPE_READ    0x00000001
+
+/*
+ * NOR Transfer Error Attribute Register-2 (NOR_ERATTR2)
+ */
+#define IFC_NOR_ERATTR2_ER_NUM_PHASE_EXP       0x000F0000
+#define IFC_NOR_ERATTR2_ER_NUM_PHASE_PER       0x00000F00
+
+/*
+ * NOR Control Register (NORCR)
+ */
+#define IFC_NORCR_MASK                 0x0F0F0000
+/* No. of Address/Data Phase */
+#define IFC_NORCR_NUM_PHASE_MASK       0x0F000000
+#define IFC_NORCR_NUM_PHASE_SHIFT      24
+#define IFC_NORCR_NUM_PHASE(n) ((n-1) << IFC_NORCR_NUM_PHASE_SHIFT)
+/* Sequence Timeout Count */
+#define IFC_NORCR_STOCNT_MASK          0x000F0000
+#define IFC_NORCR_STOCNT_SHIFT         16
+#define IFC_NORCR_STOCNT(n)    ((__ilog2(n) - 8) << IFC_NORCR_STOCNT_SHIFT)
+
+/*
+ * GPCM Machine specific registers
+ */
+/*
+ * GPCM Event and Error Status Register (GPCM_EVTER_STAT)
+ */
+/* Timeout error */
+#define IFC_GPCM_EVTER_STAT_TOER       0x04000000
+/* Parity error */
+#define IFC_GPCM_EVTER_STAT_PER                0x01000000
+
+/*
+ * GPCM Event and Error Enable Register (GPCM_EVTER_EN)
+ */
+/* Timeout error enable */
+#define IFC_GPCM_EVTER_EN_TOER_EN      0x04000000
+/* Parity error enable */
+#define IFC_GPCM_EVTER_EN_PER_EN       0x01000000
+
+/*
+ * GPCM Event and Error Interrupt Enable Register (GPCM_EVTER_INTR_EN)
+ */
+/* Enable Interrupt for timeout error */
+#define IFC_GPCM_EEIER_TOERIR_EN       0x04000000
+/* Enable Interrupt for Parity error */
+#define IFC_GPCM_EEIER_PERIR_EN                0x01000000
+
+/*
+ * GPCM Transfer Error Attribute Register-0 (GPCM_ERATTR0)
+ */
+/* Source ID for error transaction */
+#define IFC_GPCM_ERATTR0_ERSRCID       0xFF000000
+/* AXI ID for error transaction */
+#define IFC_GPCM_ERATTR0_ERAID         0x000FF000
+/* Chip select corresponds to GPCM error */
+#define IFC_GPCM_ERATTR0_ERCS_CS0      0x00000000
+#define IFC_GPCM_ERATTR0_ERCS_CS1      0x00000040
+#define IFC_GPCM_ERATTR0_ERCS_CS2      0x00000080
+#define IFC_GPCM_ERATTR0_ERCS_CS3      0x000000C0
+/* Type of transaction read/Write */
+#define IFC_GPCM_ERATTR0_ERTYPE_READ   0x00000001
+
+/*
+ * GPCM Transfer Error Attribute Register-2 (GPCM_ERATTR2)
+ */
+/* On which beat of address/data parity error is observed */
+#define IFC_GPCM_ERATTR2_PERR_BEAT             0x00000C00
+/* Parity Error on byte */
+#define IFC_GPCM_ERATTR2_PERR_BYTE             0x000000F0
+/* Parity Error reported in addr or data phase */
+#define IFC_GPCM_ERATTR2_PERR_DATA_PHASE       0x00000001
+
+/*
+ * GPCM Status Register (GPCM_STAT)
+ */
+#define IFC_GPCM_STAT_BSY              0x80000000  /* GPCM is busy */
+
+/*
+ * IFC Controller NAND Machine registers
+ */
+struct fsl_ifc_nand {
+       __be32 ncfgr;
+       u32 res1[0x4];
+       __be32 nand_fcr0;
+       __be32 nand_fcr1;
+       u32 res2[0x8];
+       __be32 row0;
+       u32 res3;
+       __be32 col0;
+       u32 res4;
+       __be32 row1;
+       u32 res5;
+       __be32 col1;
+       u32 res6;
+       __be32 row2;
+       u32 res7;
+       __be32 col2;
+       u32 res8;
+       __be32 row3;
+       u32 res9;
+       __be32 col3;
+       u32 res10[0x24];
+       __be32 nand_fbcr;
+       u32 res11;
+       __be32 nand_fir0;
+       __be32 nand_fir1;
+       __be32 nand_fir2;
+       u32 res12[0x10];
+       __be32 nand_csel;
+       u32 res13;
+       __be32 nandseq_strt;
+       u32 res14;
+       __be32 nand_evter_stat;
+       u32 res15;
+       __be32 pgrdcmpl_evt_stat;
+       u32 res16[0x2];
+       __be32 nand_evter_en;
+       u32 res17[0x2];
+       __be32 nand_evter_intr_en;
+       u32 res18[0x2];
+       __be32 nand_erattr0;
+       __be32 nand_erattr1;
+       u32 res19[0x10];
+       __be32 nand_fsr;
+       u32 res20;
+       __be32 nand_eccstat[4];
+       u32 res21[0x20];
+       __be32 nanndcr;
+       u32 res22[0x2];
+       __be32 nand_autoboot_trgr;
+       u32 res23;
+       __be32 nand_mdr;
+       u32 res24[0x5C];
+};
+
+/*
+ * IFC controller NOR Machine registers
+ */
+struct fsl_ifc_nor {
+       __be32 nor_evter_stat;
+       u32 res1[0x2];
+       __be32 nor_evter_en;
+       u32 res2[0x2];
+       __be32 nor_evter_intr_en;
+       u32 res3[0x2];
+       __be32 nor_erattr0;
+       __be32 nor_erattr1;
+       __be32 nor_erattr2;
+       u32 res4[0x4];
+       __be32 norcr;
+       u32 res5[0xEF];
+};
+
+/*
+ * IFC controller GPCM Machine registers
+ */
+struct fsl_ifc_gpcm {
+       __be32 gpcm_evter_stat;
+       u32 res1[0x2];
+       __be32 gpcm_evter_en;
+       u32 res2[0x2];
+       __be32 gpcm_evter_intr_en;
+       u32 res3[0x2];
+       __be32 gpcm_erattr0;
+       __be32 gpcm_erattr1;
+       __be32 gpcm_erattr2;
+       __be32 gpcm_stat;
+       u32 res4[0x1F3];
+};
+
+/*
+ * IFC Controller Registers
+ */
+struct fsl_ifc_regs {
+       __be32 ifc_rev;
+       u32 res1[0x2];
+       struct {
+               __be32 cspr_ext;
+               __be32 cspr;
+               u32 res2;
+       } cspr_cs[FSL_IFC_BANK_COUNT];
+       u32 res3[0x19];
+       struct {
+               __be32 amask;
+               u32 res4[0x2];
+       } amask_cs[FSL_IFC_BANK_COUNT];
+       u32 res5[0x17];
+       struct {
+               __be32 csor_ext;
+               __be32 csor;
+               u32 res6;
+       } csor_cs[FSL_IFC_BANK_COUNT];
+       u32 res7[0x19];
+       struct {
+               __be32 ftim[4];
+               u32 res8[0x8];
+       } ftim_cs[FSL_IFC_BANK_COUNT];
+       u32 res9[0x60];
+       __be32 rb_stat;
+       u32 res10[0x2];
+       __be32 ifc_gcr;
+       u32 res11[0x2];
+       __be32 cm_evter_stat;
+       u32 res12[0x2];
+       __be32 cm_evter_en;
+       u32 res13[0x2];
+       __be32 cm_evter_intr_en;
+       u32 res14[0x2];
+       __be32 cm_erattr0;
+       __be32 cm_erattr1;
+       u32 res15[0x2];
+       __be32 ifc_ccr;
+       __be32 ifc_csr;
+       u32 res16[0x2EB];
+       struct fsl_ifc_nand ifc_nand;
+       struct fsl_ifc_nor ifc_nor;
+       struct fsl_ifc_gpcm ifc_gpcm;
+};
+
+extern unsigned int convert_ifc_address(phys_addr_t addr_base);
+extern int fsl_ifc_find(phys_addr_t addr_base);
+
+/* overview of the fsl ifc controller */
+
+struct fsl_ifc_ctrl {
+       /* device info */
+       struct device                   *dev;
+       struct fsl_ifc_regs __iomem     *regs;
+       int                             irq;
+       int                             nand_irq;
+       spinlock_t                      lock;
+       void                            *nand;
+
+       u32 nand_stat;
+       wait_queue_head_t nand_wait;
+};
+
+extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
+
+
+#endif /* __ASM_FSL_IFC_H */
index 4e4cc28623adff33d7f33bc2f7ceda7269397c62..4cdb3a17bcb5932113020955cf8aa46b7b592f14 100644 (file)
@@ -495,10 +495,6 @@ enum {
        FILTER_TRACE_FN,
 };
 
-#define EVENT_STORAGE_SIZE 128
-extern struct mutex event_storage_mutex;
-extern char event_storage[EVENT_STORAGE_SIZE];
-
 extern int trace_event_raw_init(struct ftrace_event_call *call);
 extern int trace_define_field(struct ftrace_event_call *call, const char *type,
                              const char *name, int offset, int size,
index b0d95cac826e8f310aee6dfa999c69ee56727bfb..6435f46d6e1319b71f52050144f3e871986196df 100644 (file)
@@ -55,7 +55,11 @@ union futex_key {
 #ifdef CONFIG_FUTEX
 extern void exit_robust_list(struct task_struct *curr);
 extern void exit_pi_state_list(struct task_struct *curr);
+#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
+#define futex_cmpxchg_enabled 1
+#else
 extern int futex_cmpxchg_enabled;
+#endif
 #else
 static inline void exit_robust_list(struct task_struct *curr)
 {
index 0437439bc047bd4a99d7465132b1d9417667934e..39b81dc7d01acdb28e6e888fea3399f7866057f8 100644 (file)
@@ -123,6 +123,10 @@ struct vm_area_struct;
                         __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \
                         __GFP_NO_KSWAPD)
 
+/*
+ * GFP_THISNODE does not perform any reclaim, you most likely want to
+ * use __GFP_THISNODE to allocate from a given node without fallback!
+ */
 #ifdef CONFIG_NUMA
 #define GFP_THISNODE   (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
 #else
index 12d5f972f23f46cf1dbf83c0e7fc93333cf49015..cba442ec3c66583a7aceefbbc9ff9eca5fee1563 100644 (file)
@@ -9,6 +9,7 @@
 
 
 extern void synchronize_irq(unsigned int irq);
+extern void synchronize_hardirq(unsigned int irq);
 
 #if defined(CONFIG_TINY_RCU)
 
index d19a5c2d2270ebb9bbe01a167a97875e255da357..e7a8d3fa91d574e322a01a4cc1fff3a30a513a15 100644 (file)
@@ -96,12 +96,12 @@ enum hrtimer_restart {
  * @function:  timer expiry callback function
  * @base:      pointer to the timer base (per cpu and per clock)
  * @state:     state information (See bit values above)
+ * @start_pid: timer statistics field to store the pid of the task which
+ *             started the timer
  * @start_site:        timer statistics field to store the site where the timer
  *             was started
  * @start_comm: timer statistics field to store the name of the process which
  *             started the timer
- * @start_pid: timer statistics field to store the pid of the task which
- *             started the timer
  *
  * The hrtimer structure must be initialized by hrtimer_init()
  */
index db512014e061b27abae7d689175e82d74348683b..b826239bdce0b26a614ae0802782860348dd6fc6 100644 (file)
@@ -157,46 +157,6 @@ static inline int hpage_nr_pages(struct page *page)
                return HPAGE_PMD_NR;
        return 1;
 }
-/*
- * compound_trans_head() should be used instead of compound_head(),
- * whenever the "page" passed as parameter could be the tail of a
- * transparent hugepage that could be undergoing a
- * __split_huge_page_refcount(). The page structure layout often
- * changes across releases and it makes extensive use of unions. So if
- * the page structure layout will change in a way that
- * page->first_page gets clobbered by __split_huge_page_refcount, the
- * implementation making use of smp_rmb() will be required.
- *
- * Currently we define compound_trans_head as compound_head, because
- * page->private is in the same union with page->first_page, and
- * page->private isn't clobbered. However this also means we're
- * currently leaving dirt into the page->private field of anonymous
- * pages resulting from a THP split, instead of setting page->private
- * to zero like for every other page that has PG_private not set. But
- * anonymous pages don't use page->private so this is not a problem.
- */
-#if 0
-/* This will be needed if page->private will be clobbered in split_huge_page */
-static inline struct page *compound_trans_head(struct page *page)
-{
-       if (PageTail(page)) {
-               struct page *head;
-               head = page->first_page;
-               smp_rmb();
-               /*
-                * head may be a dangling pointer.
-                * __split_huge_page_refcount clears PageTail before
-                * overwriting first_page, so if PageTail is still
-                * there it means the head pointer isn't dangling.
-                */
-               if (PageTail(page))
-                       return head;
-       }
-       return page;
-}
-#else
-#define compound_trans_head(page) compound_head(page)
-#endif
 
 extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                unsigned long addr, pmd_t pmd, pmd_t *pmdp);
@@ -226,7 +186,6 @@ static inline int split_huge_page(struct page *page)
        do { } while (0)
 #define split_huge_page_pmd_mm(__mm, __address, __pmd) \
        do { } while (0)
-#define compound_trans_head(page) compound_head(page)
 static inline int hugepage_madvise(struct vm_area_struct *vma,
                                   unsigned long *vm_flags, int advice)
 {
index 344883dce5849b62e8f6c0e59e1daed09b5a0f80..ab7359fde9879fe5b70b3f4e170d4b5da0f86565 100644 (file)
 #ifndef _HYPERV_H
 #define _HYPERV_H
 
-#include <linux/types.h>
-
-/*
- * Framework version for util services.
- */
-#define UTIL_FW_MINOR  0
-
-#define UTIL_WS2K8_FW_MAJOR  1
-#define UTIL_WS2K8_FW_VERSION     (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
-
-#define UTIL_FW_MAJOR  3
-#define UTIL_FW_VERSION     (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
-
-
-/*
- * Implementation of host controlled snapshot of the guest.
- */
-
-#define VSS_OP_REGISTER 128
-
-enum hv_vss_op {
-       VSS_OP_CREATE = 0,
-       VSS_OP_DELETE,
-       VSS_OP_HOT_BACKUP,
-       VSS_OP_GET_DM_INFO,
-       VSS_OP_BU_COMPLETE,
-       /*
-        * Following operations are only supported with IC version >= 5.0
-        */
-       VSS_OP_FREEZE, /* Freeze the file systems in the VM */
-       VSS_OP_THAW, /* Unfreeze the file systems */
-       VSS_OP_AUTO_RECOVER,
-       VSS_OP_COUNT /* Number of operations, must be last */
-};
-
-
-/*
- * Header for all VSS messages.
- */
-struct hv_vss_hdr {
-       __u8 operation;
-       __u8 reserved[7];
-} __attribute__((packed));
-
-
-/*
- * Flag values for the hv_vss_check_feature. Linux supports only
- * one value.
- */
-#define VSS_HBU_NO_AUTO_RECOVERY       0x00000005
-
-struct hv_vss_check_feature {
-       __u32 flags;
-} __attribute__((packed));
-
-struct hv_vss_check_dm_info {
-       __u32 flags;
-} __attribute__((packed));
-
-struct hv_vss_msg {
-       union {
-               struct hv_vss_hdr vss_hdr;
-               int error;
-       };
-       union {
-               struct hv_vss_check_feature vss_cf;
-               struct hv_vss_check_dm_info dm_info;
-       };
-} __attribute__((packed));
-
-/*
- * An implementation of HyperV key value pair (KVP) functionality for Linux.
- *
- *
- * Copyright (C) 2010, Novell, Inc.
- * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
- *
- */
-
-/*
- * Maximum value size - used for both key names and value data, and includes
- * any applicable NULL terminators.
- *
- * Note:  This limit is somewhat arbitrary, but falls easily within what is
- * supported for all native guests (back to Win 2000) and what is reasonable
- * for the IC KVP exchange functionality.  Note that Windows Me/98/95 are
- * limited to 255 character key names.
- *
- * MSDN recommends not storing data values larger than 2048 bytes in the
- * registry.
- *
- * Note:  This value is used in defining the KVP exchange message - this value
- * cannot be modified without affecting the message size and compatibility.
- */
-
-/*
- * bytes, including any null terminators
- */
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE          (2048)
-
-
-/*
- * Maximum key size - the registry limit for the length of an entry name
- * is 256 characters, including the null terminator
- */
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE            (512)
-
-/*
- * In Linux, we implement the KVP functionality in two components:
- * 1) The kernel component which is packaged as part of the hv_utils driver
- * is responsible for communicating with the host and responsible for
- * implementing the host/guest protocol. 2) A user level daemon that is
- * responsible for data gathering.
- *
- * Host/Guest Protocol: The host iterates over an index and expects the guest
- * to assign a key name to the index and also return the value corresponding to
- * the key. The host will have atmost one KVP transaction outstanding at any
- * given point in time. The host side iteration stops when the guest returns
- * an error. Microsoft has specified the following mapping of key names to
- * host specified index:
- *
- *     Index           Key Name
- *     0               FullyQualifiedDomainName
- *     1               IntegrationServicesVersion
- *     2               NetworkAddressIPv4
- *     3               NetworkAddressIPv6
- *     4               OSBuildNumber
- *     5               OSName
- *     6               OSMajorVersion
- *     7               OSMinorVersion
- *     8               OSVersion
- *     9               ProcessorArchitecture
- *
- * The Windows host expects the Key Name and Key Value to be encoded in utf16.
- *
- * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
- * data gathering functionality in a user mode daemon. The user level daemon
- * is also responsible for binding the key name to the index as well. The
- * kernel and user-level daemon communicate using a connector channel.
- *
- * The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
- * for the specified keys. In response to this message the user mode component
- * fills in the value corresponding to the specified key. We overload the
- * sequence field in the cn_msg header to define our KVP message types.
- *
- *
- * The kernel component simply acts as a conduit for communication between the
- * Windows host and the user-level daemon. The kernel component passes up the
- * index received from the Host to the user-level daemon. If the index is
- * valid (supported), the corresponding key as well as its
- * value (both are strings) is returned. If the index is invalid
- * (not supported), a NULL key string is returned.
- */
-
-
-/*
- * Registry value types.
- */
-
-#define REG_SZ 1
-#define REG_U32 4
-#define REG_U64 8
-
-/*
- * As we look at expanding the KVP functionality to include
- * IP injection functionality, we need to maintain binary
- * compatibility with older daemons.
- *
- * The KVP opcodes are defined by the host and it was unfortunate
- * that I chose to treat the registration operation as part of the
- * KVP operations defined by the host.
- * Here is the level of compatibility
- * (between the user level daemon and the kernel KVP driver) that we
- * will implement:
- *
- * An older daemon will always be supported on a newer driver.
- * A given user level daemon will require a minimal version of the
- * kernel driver.
- * If we cannot handle the version differences, we will fail gracefully
- * (this can happen when we have a user level daemon that is more
- * advanced than the KVP driver.
- *
- * We will use values used in this handshake for determining if we have
- * workable user level daemon and the kernel driver. We begin by taking the
- * registration opcode out of the KVP opcode namespace. We will however,
- * maintain compatibility with the existing user-level daemon code.
- */
-
-/*
- * Daemon code not supporting IP injection (legacy daemon).
- */
-
-#define KVP_OP_REGISTER        4
-
-/*
- * Daemon code supporting IP injection.
- * The KVP opcode field is used to communicate the
- * registration information; so define a namespace that
- * will be distinct from the host defined KVP opcode.
- */
-
-#define KVP_OP_REGISTER1 100
-
-enum hv_kvp_exchg_op {
-       KVP_OP_GET = 0,
-       KVP_OP_SET,
-       KVP_OP_DELETE,
-       KVP_OP_ENUMERATE,
-       KVP_OP_GET_IP_INFO,
-       KVP_OP_SET_IP_INFO,
-       KVP_OP_COUNT /* Number of operations, must be last. */
-};
-
-enum hv_kvp_exchg_pool {
-       KVP_POOL_EXTERNAL = 0,
-       KVP_POOL_GUEST,
-       KVP_POOL_AUTO,
-       KVP_POOL_AUTO_EXTERNAL,
-       KVP_POOL_AUTO_INTERNAL,
-       KVP_POOL_COUNT /* Number of pools, must be last. */
-};
-
-/*
- * Some Hyper-V status codes.
- */
+#include <uapi/linux/hyperv.h>
 
-#define HV_S_OK                                0x00000000
-#define HV_E_FAIL                      0x80004005
-#define HV_S_CONT                      0x80070103
-#define HV_ERROR_NOT_SUPPORTED         0x80070032
-#define HV_ERROR_MACHINE_LOCKED                0x800704F7
-#define HV_ERROR_DEVICE_NOT_CONNECTED  0x8007048F
-#define HV_INVALIDARG                  0x80070057
-#define HV_GUID_NOTFOUND               0x80041002
-
-#define ADDR_FAMILY_NONE       0x00
-#define ADDR_FAMILY_IPV4       0x01
-#define ADDR_FAMILY_IPV6       0x02
-
-#define MAX_ADAPTER_ID_SIZE    128
-#define MAX_IP_ADDR_SIZE       1024
-#define MAX_GATEWAY_SIZE       512
-
-
-struct hv_kvp_ipaddr_value {
-       __u16   adapter_id[MAX_ADAPTER_ID_SIZE];
-       __u8    addr_family;
-       __u8    dhcp_enabled;
-       __u16   ip_addr[MAX_IP_ADDR_SIZE];
-       __u16   sub_net[MAX_IP_ADDR_SIZE];
-       __u16   gate_way[MAX_GATEWAY_SIZE];
-       __u16   dns_addr[MAX_IP_ADDR_SIZE];
-} __attribute__((packed));
-
-
-struct hv_kvp_hdr {
-       __u8 operation;
-       __u8 pool;
-       __u16 pad;
-} __attribute__((packed));
-
-struct hv_kvp_exchg_msg_value {
-       __u32 value_type;
-       __u32 key_size;
-       __u32 value_size;
-       __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-       union {
-               __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-               __u32 value_u32;
-               __u64 value_u64;
-       };
-} __attribute__((packed));
-
-struct hv_kvp_msg_enumerate {
-       __u32 index;
-       struct hv_kvp_exchg_msg_value data;
-} __attribute__((packed));
-
-struct hv_kvp_msg_get {
-       struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg_set {
-       struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg_delete {
-       __u32 key_size;
-       __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-};
-
-struct hv_kvp_register {
-       __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-};
-
-struct hv_kvp_msg {
-       union {
-               struct hv_kvp_hdr       kvp_hdr;
-               int error;
-       };
-       union {
-               struct hv_kvp_msg_get           kvp_get;
-               struct hv_kvp_msg_set           kvp_set;
-               struct hv_kvp_msg_delete        kvp_delete;
-               struct hv_kvp_msg_enumerate     kvp_enum_data;
-               struct hv_kvp_ipaddr_value      kvp_ip_val;
-               struct hv_kvp_register          kvp_register;
-       } body;
-} __attribute__((packed));
-
-struct hv_kvp_ip_msg {
-       __u8 operation;
-       __u8 pool;
-       struct hv_kvp_ipaddr_value      kvp_ip_val;
-} __attribute__((packed));
-
-#ifdef __KERNEL__
+#include <linux/types.h>
 #include <linux/scatterlist.h>
 #include <linux/list.h>
-#include <linux/uuid.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/completion.h>
@@ -354,7 +37,7 @@ struct hv_kvp_ip_msg {
 #include <linux/mod_devicetable.h>
 
 
-#define MAX_PAGE_BUFFER_COUNT                          19
+#define MAX_PAGE_BUFFER_COUNT                          32
 #define MAX_MULTIPAGE_BUFFER_COUNT                     32 /* 128K */
 
 #pragma pack(push, 1)
@@ -1043,6 +726,10 @@ struct vmbus_channel {
         * This will be NULL for the primary channel.
         */
        struct vmbus_channel *primary_channel;
+       /*
+        * Support per-channel state for use by vmbus drivers.
+        */
+       void *per_channel_state;
 };
 
 static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
@@ -1050,6 +737,16 @@ static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
        c->batched_reading = state;
 }
 
+static inline void set_per_channel_state(struct vmbus_channel *c, void *s)
+{
+       c->per_channel_state = s;
+}
+
+static inline void *get_per_channel_state(struct vmbus_channel *c)
+{
+       return c->per_channel_state;
+}
+
 void vmbus_onmessage(void *context);
 
 int vmbus_request_offers(void);
@@ -1118,7 +815,7 @@ extern int vmbus_open(struct vmbus_channel *channel,
 extern void vmbus_close(struct vmbus_channel *channel);
 
 extern int vmbus_sendpacket(struct vmbus_channel *channel,
-                                 const void *buffer,
+                                 void *buffer,
                                  u32 bufferLen,
                                  u64 requestid,
                                  enum vmbus_packet_type type,
@@ -1351,6 +1048,17 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
                        0xB7, 0x6B, 0x6F, 0xD0, 0xBE, 0x52, 0x8C, 0xDA \
                }
 
+/*
+ * Guest File Copy Service
+ * {34D14BE3-DEE4-41c8-9AE7-6B174977C192}
+ */
+
+#define HV_FCOPY_GUID \
+       .guid = { \
+                       0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \
+                       0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \
+               }
+
 /*
  * Common header for Hyper-V ICs
  */
@@ -1459,11 +1167,12 @@ int hv_vss_init(struct hv_util_service *);
 void hv_vss_deinit(void);
 void hv_vss_onchannelcallback(void *);
 
+extern struct resource hyperv_mmio;
+
 /*
  * Negotiated version with the Host.
  */
 
 extern __u32 vmbus_proto_version;
 
-#endif /* __KERNEL__ */
 #endif /* _HYPERV_H */
index e1688802964f3ccb6aebc0738a98f9b838a6d02d..a3ba270763426bd7dfd9f0633e0abb4476d2dc50 100644 (file)
@@ -163,6 +163,23 @@ extern bool initcall_debug;
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_LTO
+/* Work around a LTO gcc problem: when there is no reference to a variable
+ * in a module it will be moved to the end of the program. This causes
+ * reordering of initcalls which the kernel does not like.
+ * Add a dummy reference function to avoid this. The function is
+ * deleted by the linker.
+ */
+#define LTO_REFERENCE_INITCALL(x) \
+       ; /* yes this is needed */                      \
+       static __used __exit void *reference_##x(void)  \
+       {                                               \
+               return &x;                              \
+       }
+#else
+#define LTO_REFERENCE_INITCALL(x)
+#endif
+
 /* initcalls are now grouped by functionality into separate 
  * subsections. Ordering inside the subsections is determined
  * by link order. 
@@ -175,7 +192,8 @@ extern bool initcall_debug;
 
 #define __define_initcall(fn, id) \
        static initcall_t __initcall_##fn##id __used \
-       __attribute__((__section__(".initcall" #id ".init"))) = fn
+       __attribute__((__section__(".initcall" #id ".init"))) = fn; \
+       LTO_REFERENCE_INITCALL(__initcall_##fn##id)
 
 /*
  * Early initcalls run before initializing SMP.
index a2678d35b5a2e8fc8f840d91f1ac5c7ec0c97bec..c7bfac1c4a7b8f6c82742b4d9f97c058131ae4fc 100644 (file)
@@ -188,6 +188,7 @@ extern void disable_irq(unsigned int irq);
 extern void disable_percpu_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
 extern void enable_percpu_irq(unsigned int irq, unsigned int type);
+extern void irq_wake_thread(unsigned int irq, void *dev_id);
 
 /* The following three functions are for the core kernel use only. */
 extern void suspend_device_irqs(void);
index f4f42faec68677a6fb032e7ccdf07b8b0bb130cb..8a18e75600ccb25b47f17decfacdef673de89713 100644 (file)
@@ -24,7 +24,7 @@
 
 struct device;
 
-void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
+__visible void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
 void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
 
 #ifdef CONFIG_MMU
index 89b7c24a36e9fd7a8af6fea77bf7986507e86c65..5e3a906cc089a721eaacdf390e3e30927fd37434 100644 (file)
@@ -51,7 +51,7 @@ struct resource {
 
 #define IORESOURCE_EXCLUSIVE   0x08000000      /* Userland may not map this resource */
 #define IORESOURCE_DISABLED    0x10000000
-#define IORESOURCE_UNSET       0x20000000
+#define IORESOURCE_UNSET       0x20000000      /* No address assigned yet */
 #define IORESOURCE_AUTO                0x40000000
 #define IORESOURCE_BUSY                0x80000000      /* Driver has marked this resource busy */
 
@@ -169,6 +169,16 @@ static inline unsigned long resource_type(const struct resource *res)
 {
        return res->flags & IORESOURCE_TYPE_BITS;
 }
+/* True iff r1 completely contains r2 */
+static inline bool resource_contains(struct resource *r1, struct resource *r2)
+{
+       if (resource_type(r1) != resource_type(r2))
+               return false;
+       if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET)
+               return false;
+       return r1->start <= r2->start && r1->end >= r2->end;
+}
+
 
 /* Convenience shorthand with allocation */
 #define request_region(start,n,name)           __request_region(&ioport_resource, (start), (n), (name), 0)
index 7dc10036eff552229cdd964e88669a7759a8152f..d278838908cbc3f1cdac08ae3f3714934f01f188 100644 (file)
@@ -303,6 +303,10 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
  * @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
+ * @irq_request_resources:     optional to request resources before calling
+ *                             any other callback related to this irq
+ * @irq_release_resources:     optional to release resources acquired with
+ *                             irq_request_resources
  * @flags:             chip specific flags
  */
 struct irq_chip {
@@ -336,6 +340,8 @@ struct irq_chip {
        void            (*irq_calc_mask)(struct irq_data *data);
 
        void            (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
+       int             (*irq_request_resources)(struct irq_data *data);
+       void            (*irq_release_resources)(struct irq_data *data);
 
        unsigned long   flags;
 };
@@ -349,6 +355,8 @@ struct irq_chip {
  * IRQCHIP_ONOFFLINE_ENABLED:  Only call irq_on/off_line callbacks
  *                             when irq enabled
  * IRQCHIP_SKIP_SET_WAKE:      Skip chip.irq_set_wake(), for this irq chip
+ * IRQCHIP_ONESHOT_SAFE:       One shot does not require mask/unmask
+ * IRQCHIP_EOI_THREADED:       Chip requires eoi() on unmask in threaded mode
  */
 enum {
        IRQCHIP_SET_TYPE_MASKED         = (1 <<  0),
@@ -357,6 +365,7 @@ enum {
        IRQCHIP_ONOFFLINE_ENABLED       = (1 <<  3),
        IRQCHIP_SKIP_SET_WAKE           = (1 <<  4),
        IRQCHIP_ONESHOT_SAFE            = (1 <<  5),
+       IRQCHIP_EOI_THREADED            = (1 <<  6),
 };
 
 /* This include will go away once we isolated irq_desc usage to core code */
index 66017028dcb3d0aebf70aa7281e7758a42bcb3bf..19ae05d4b8ec26b6dc6fa5f568d2b25b698e3417 100644 (file)
@@ -30,7 +30,9 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
        work->func = func;
 }
 
-void irq_work_queue(struct irq_work *work);
+#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), }
+
+bool irq_work_queue(struct irq_work *work);
 void irq_work_run(void);
 void irq_work_sync(struct irq_work *work);
 
index 196d1ea86df081a5224928b4d75117aec85cd822..08fb0247764177a8b96f83f5181a17c9d33b099c 100644 (file)
@@ -458,7 +458,7 @@ extern enum system_states {
 
 #define TAINT_PROPRIETARY_MODULE       0
 #define TAINT_FORCED_MODULE            1
-#define TAINT_UNSAFE_SMP               2
+#define TAINT_CPU_OUT_OF_SPEC          2
 #define TAINT_FORCED_RMMOD             3
 #define TAINT_MACHINE_CHECK            4
 #define TAINT_BAD_PAGE                 5
index 51c72be4a7c3f1782a5d5f21801b06bea1720f57..ecbc52f9ff77e7921acb4c069bc88056718f6e6a 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/sched.h>
 #include <linux/vtime.h>
 #include <asm/irq.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
 
 /*
  * 'kernel_stat.h' contains the definitions needed for doing
@@ -51,14 +51,8 @@ DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
 
 extern unsigned long long nr_context_switches(void);
 
-#include <linux/irq.h>
 extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
-
-#define kstat_incr_irqs_this_cpu(irqno, DESC)          \
-do {                                                   \
-       __this_cpu_inc(*(DESC)->kstat_irqs);            \
-       __this_cpu_inc(kstat.irqs_sum);                 \
-} while (0)
+extern void kstat_incr_irq_this_cpu(unsigned int irq);
 
 static inline void kstat_incr_softirqs_this_cpu(unsigned int irq)
 {
index 6d4066cdb5b5b8508be5347e50f1c16c1fddf493..a7564193004959ba12bc28361a4c32d76b8297c2 100644 (file)
@@ -127,12 +127,6 @@ extern asmlinkage long sys_kexec_load(unsigned long entry,
                                        struct kexec_segment __user *segments,
                                        unsigned long flags);
 extern int kernel_kexec(void);
-#ifdef CONFIG_COMPAT
-extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
-                               unsigned long nr_segments,
-                               struct compat_kexec_segment __user *segments,
-                               unsigned long flags);
-#endif
 extern struct page *kimage_alloc_control_pages(struct kimage *image,
                                                unsigned int order);
 extern void crash_kexec(struct pt_regs *);
index bec6dbe939a0267def1f73864d07c5025cb687f1..1de36be64df4d1516a2a451901733d36fd32ec4e 100644 (file)
@@ -848,7 +848,6 @@ struct ata_port {
        struct completion       park_req_pending;
 
        pm_message_t            pm_mesg;
-       int                     *pm_result;
        enum ata_lpm_policy     target_lpm_policy;
 
        struct timer_list       fastdrain_timer;
@@ -1140,16 +1139,14 @@ extern bool ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
-extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
-extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
+extern void ata_sas_port_suspend(struct ata_port *ap);
+extern void ata_sas_port_resume(struct ata_port *ap);
 #else
-static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+static inline void ata_sas_port_suspend(struct ata_port *ap)
 {
-       return 0;
 }
-static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+static inline void ata_sas_port_resume(struct ata_port *ap)
 {
-       return 0;
 }
 #endif
 extern int ata_ratelimit(void);
index a6a42dd024661324dbeed5b9cfaa028744bae154..34a513a2727bbe83adff047613a1ad3458684ac2 100644 (file)
@@ -12,9 +12,9 @@
 #endif
 
 #ifdef __cplusplus
-#define CPP_ASMLINKAGE extern "C"
+#define CPP_ASMLINKAGE extern "C" __visible
 #else
-#define CPP_ASMLINKAGE
+#define CPP_ASMLINKAGE __visible
 #endif
 
 #ifndef asmlinkage
index 92b1bfc5da6087850e43015ebdaf7d3de455f522..008388f920d7e93e32ba388dd4b497f33d7bd49d 100644 (file)
@@ -252,9 +252,9 @@ struct held_lock {
        unsigned int trylock:1;                                         /* 16 bits */
 
        unsigned int read:2;        /* see lock_acquire() comment */
-       unsigned int check:2;       /* see lock_acquire() comment */
+       unsigned int check:1;       /* see lock_acquire() comment */
        unsigned int hardirqs_off:1;
-       unsigned int references:11;                                     /* 32 bits */
+       unsigned int references:12;                                     /* 32 bits */
 };
 
 /*
@@ -265,7 +265,7 @@ extern void lockdep_info(void);
 extern void lockdep_reset(void);
 extern void lockdep_reset_lock(struct lockdep_map *lock);
 extern void lockdep_free_key_range(void *start, unsigned long size);
-extern void lockdep_sys_exit(void);
+extern asmlinkage void lockdep_sys_exit(void);
 
 extern void lockdep_off(void);
 extern void lockdep_on(void);
@@ -303,7 +303,7 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
                                 (lock)->dep_map.key, sub)
 
 #define lockdep_set_novalidate_class(lock) \
-       lockdep_set_class(lock, &__lockdep_no_validate__)
+       lockdep_set_class_and_name(lock, &__lockdep_no_validate__, #lock)
 /*
  * Compare locking classes
  */
@@ -326,9 +326,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock,
  *
  * Values for check:
  *
- *   0: disabled
- *   1: simple checks (freeing, held-at-exit-time, etc.)
- *   2: full validation
+ *   0: simple checks (freeing, held-at-exit-time, etc.)
+ *   1: full validation
  */
 extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
                         int trylock, int read, int check,
@@ -479,15 +478,9 @@ static inline void print_irqtrace_events(struct task_struct *curr)
  * on the per lock-class debug mode:
  */
 
-#ifdef CONFIG_PROVE_LOCKING
- #define lock_acquire_exclusive(l, s, t, n, i)         lock_acquire(l, s, t, 0, 2, n, i)
- #define lock_acquire_shared(l, s, t, n, i)            lock_acquire(l, s, t, 1, 2, n, i)
- #define lock_acquire_shared_recursive(l, s, t, n, i)  lock_acquire(l, s, t, 2, 2, n, i)
-#else
- #define lock_acquire_exclusive(l, s, t, n, i)         lock_acquire(l, s, t, 0, 1, n, i)
- #define lock_acquire_shared(l, s, t, n, i)            lock_acquire(l, s, t, 1, 1, n, i)
- #define lock_acquire_shared_recursive(l, s, t, n, i)  lock_acquire(l, s, t, 2, 1, n, i)
-#endif
+#define lock_acquire_exclusive(l, s, t, n, i)          lock_acquire(l, s, t, 0, 1, n, i)
+#define lock_acquire_shared(l, s, t, n, i)             lock_acquire(l, s, t, 1, 1, n, i)
+#define lock_acquire_shared_recursive(l, s, t, n, i)   lock_acquire(l, s, t, 2, 1, n, i)
 
 #define spin_acquire(l, s, t, i)               lock_acquire_exclusive(l, s, t, NULL, i)
 #define spin_acquire_nest(l, s, t, n, i)       lock_acquire_exclusive(l, s, t, n, i)
@@ -518,13 +511,13 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 # define might_lock(lock)                                              \
 do {                                                                   \
        typecheck(struct lockdep_map *, &(lock)->dep_map);              \
-       lock_acquire(&(lock)->dep_map, 0, 0, 0, 2, NULL, _THIS_IP_);    \
+       lock_acquire(&(lock)->dep_map, 0, 0, 0, 1, NULL, _THIS_IP_);    \
        lock_release(&(lock)->dep_map, 0, _THIS_IP_);                   \
 } while (0)
 # define might_lock_read(lock)                                                 \
 do {                                                                   \
        typecheck(struct lockdep_map *, &(lock)->dep_map);              \
-       lock_acquire(&(lock)->dep_map, 0, 0, 1, 2, NULL, _THIS_IP_);    \
+       lock_acquire(&(lock)->dep_map, 0, 0, 1, 1, NULL, _THIS_IP_);    \
        lock_release(&(lock)->dep_map, 0, _THIS_IP_);                   \
 } while (0)
 #else
diff --git a/include/linux/mcb.h b/include/linux/mcb.h
new file mode 100644 (file)
index 0000000..2db284d
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+#ifndef _LINUX_MCB_H
+#define _LINUX_MCB_H
+
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/irqreturn.h>
+
+struct mcb_driver;
+
+/**
+ * struct mcb_bus - MEN Chameleon Bus
+ *
+ * @dev: pointer to carrier device
+ * @children: the child busses
+ * @bus_nr: mcb bus number
+ */
+struct mcb_bus {
+       struct list_head children;
+       struct device dev;
+       int bus_nr;
+};
+#define to_mcb_bus(b) container_of((b), struct mcb_bus, dev)
+
+/**
+ * struct mcb_device - MEN Chameleon Bus device
+ *
+ * @bus_list: internal list handling for bus code
+ * @dev: device in kernel representation
+ * @bus: mcb bus the device is plugged to
+ * @subordinate: subordinate MCBus in case of bridge
+ * @is_added: flag to check if device is added to bus
+ * @driver: associated mcb_driver
+ * @id: mcb device id
+ * @inst: instance in Chameleon table
+ * @group: group in Chameleon table
+ * @var: variant in Chameleon table
+ * @bar: BAR in Chameleon table
+ * @rev: revision in Chameleon table
+ * @irq: IRQ resource
+ * @memory: memory resource
+ */
+struct mcb_device {
+       struct list_head bus_list;
+       struct device dev;
+       struct mcb_bus *bus;
+       struct mcb_bus *subordinate;
+       bool is_added;
+       struct mcb_driver *driver;
+       u16 id;
+       int inst;
+       int group;
+       int var;
+       int bar;
+       int rev;
+       struct resource irq;
+       struct resource mem;
+};
+#define to_mcb_device(x) container_of((x), struct mcb_device, dev)
+
+/**
+ * struct mcb_driver - MEN Chameleon Bus device driver
+ *
+ * @driver: device_driver
+ * @id_table: mcb id table
+ * @probe: probe callback
+ * @remove: remove callback
+ * @shutdown: shutdown callback
+ */
+struct mcb_driver {
+       struct device_driver driver;
+       const struct mcb_device_id *id_table;
+       int (*probe)(struct mcb_device *mdev, const struct mcb_device_id *id);
+       void (*remove)(struct mcb_device *mdev);
+       void (*shutdown)(struct mcb_device *mdev);
+};
+#define to_mcb_driver(x) container_of((x), struct mcb_driver, driver)
+
+static inline void *mcb_get_drvdata(struct mcb_device *dev)
+{
+       return dev_get_drvdata(&dev->dev);
+}
+
+static inline void mcb_set_drvdata(struct mcb_device *dev, void *data)
+{
+       dev_set_drvdata(&dev->dev, data);
+}
+
+extern int __must_check __mcb_register_driver(struct mcb_driver *drv,
+                                       struct module *owner,
+                                       const char *mod_name);
+#define mcb_register_driver(driver)            \
+       __mcb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
+extern void mcb_unregister_driver(struct mcb_driver *driver);
+#define module_mcb_driver(__mcb_driver)                \
+       module_driver(__mcb_driver, mcb_register_driver, mcb_unregister_driver);
+extern void mcb_bus_add_devices(const struct mcb_bus *bus);
+extern int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev);
+extern struct mcb_bus *mcb_alloc_bus(void);
+extern struct mcb_bus *mcb_bus_get(struct mcb_bus *bus);
+extern void mcb_bus_put(struct mcb_bus *bus);
+extern struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus);
+extern void mcb_free_dev(struct mcb_device *dev);
+extern void mcb_release_bus(struct mcb_bus *bus);
+extern struct resource *mcb_request_mem(struct mcb_device *dev,
+                                       const char *name);
+extern void mcb_release_mem(struct resource *mem);
+extern int mcb_get_irq(struct mcb_device *dev);
+
+#endif /* _LINUX_MCB_H */
index fdf3aa376eb298bcb099f9e514630438b476ccfe..3ddaa634b19d45102de7579169a5c50d05abe74b 100644 (file)
 /*
  * R373 (0x175) - FLL1 Control 5
  */
-#define ARIZONA_FLL1_FRATIO_MASK                 0x0700  /* FLL1_FRATIO - [10:8] */
-#define ARIZONA_FLL1_FRATIO_SHIFT                     8  /* FLL1_FRATIO - [10:8] */
-#define ARIZONA_FLL1_FRATIO_WIDTH                     3  /* FLL1_FRATIO - [10:8] */
+#define ARIZONA_FLL1_FRATIO_MASK                 0x0F00  /* FLL1_FRATIO - [11:8] */
+#define ARIZONA_FLL1_FRATIO_SHIFT                     8  /* FLL1_FRATIO - [11:8] */
+#define ARIZONA_FLL1_FRATIO_WIDTH                     4  /* FLL1_FRATIO - [11:8] */
 #define ARIZONA_FLL1_OUTDIV_MASK                 0x000E  /* FLL1_OUTDIV - [3:1] */
 #define ARIZONA_FLL1_OUTDIV_SHIFT                     1  /* FLL1_OUTDIV - [3:1] */
 #define ARIZONA_FLL1_OUTDIV_WIDTH                     3  /* FLL1_OUTDIV - [3:1] */
index 41c9bde410c5b31f0bcdfb61de557ca0fe5353ce..157e32b6ca28790fccbc2a3d47d30c9b210d6ec4 100644 (file)
@@ -18,7 +18,9 @@ enum sec_device_type {
        S5M8751X,
        S5M8763X,
        S5M8767X,
+       S2MPA01,
        S2MPS11X,
+       S2MPS14X,
 };
 
 /**
@@ -50,7 +52,7 @@ struct sec_pmic_dev {
        struct regmap_irq_chip_data *irq_data;
 
        int ono;
-       int type;
+       unsigned long type;
        bool wakeup;
        bool wtsr_smpl;
 };
@@ -92,7 +94,7 @@ struct sec_platform_data {
        int                             buck3_default_idx;
        int                             buck4_default_idx;
 
-       int                             buck_ramp_delay;
+       int                             buck_ramp_delay;
 
        int                             buck2_ramp_delay;
        int                             buck34_ramp_delay;
@@ -100,10 +102,15 @@ struct sec_platform_data {
        int                             buck16_ramp_delay;
        int                             buck7810_ramp_delay;
        int                             buck9_ramp_delay;
-
-       bool                            buck2_ramp_enable;
-       bool                            buck3_ramp_enable;
-       bool                            buck4_ramp_enable;
+       int                             buck24_ramp_delay;
+       int                             buck3_ramp_delay;
+       int                             buck7_ramp_delay;
+       int                             buck8910_ramp_delay;
+
+       bool                            buck1_ramp_enable;
+       bool                            buck2_ramp_enable;
+       bool                            buck3_ramp_enable;
+       bool                            buck4_ramp_enable;
        bool                            buck6_ramp_enable;
 
        int                             buck2_init;
@@ -119,7 +126,8 @@ struct sec_platform_data {
 struct sec_regulator_data {
        int                             id;
        struct regulator_init_data      *initdata;
-       struct device_node *reg_node;
+       struct device_node              *reg_node;
+       int                             ext_control_gpio;
 };
 
 /*
index d43b4f9e7fb27ab4b5014592fe363d3a97ba153e..1224f447356b90a5601fbc1826eb0a67606aeefe 100644 (file)
 #ifndef __LINUX_MFD_SEC_IRQ_H
 #define __LINUX_MFD_SEC_IRQ_H
 
+enum s2mpa01_irq {
+       S2MPA01_IRQ_PWRONF,
+       S2MPA01_IRQ_PWRONR,
+       S2MPA01_IRQ_JIGONBF,
+       S2MPA01_IRQ_JIGONBR,
+       S2MPA01_IRQ_ACOKBF,
+       S2MPA01_IRQ_ACOKBR,
+       S2MPA01_IRQ_PWRON1S,
+       S2MPA01_IRQ_MRB,
+
+       S2MPA01_IRQ_RTC60S,
+       S2MPA01_IRQ_RTCA1,
+       S2MPA01_IRQ_RTCA0,
+       S2MPA01_IRQ_SMPL,
+       S2MPA01_IRQ_RTC1S,
+       S2MPA01_IRQ_WTSR,
+
+       S2MPA01_IRQ_INT120C,
+       S2MPA01_IRQ_INT140C,
+       S2MPA01_IRQ_LDO3_TSD,
+       S2MPA01_IRQ_B16_TSD,
+       S2MPA01_IRQ_B24_TSD,
+       S2MPA01_IRQ_B35_TSD,
+
+       S2MPA01_IRQ_NR,
+};
+
+#define S2MPA01_IRQ_PWRONF_MASK                (1 << 0)
+#define S2MPA01_IRQ_PWRONR_MASK                (1 << 1)
+#define S2MPA01_IRQ_JIGONBF_MASK       (1 << 2)
+#define S2MPA01_IRQ_JIGONBR_MASK       (1 << 3)
+#define S2MPA01_IRQ_ACOKBF_MASK                (1 << 4)
+#define S2MPA01_IRQ_ACOKBR_MASK                (1 << 5)
+#define S2MPA01_IRQ_PWRON1S_MASK       (1 << 6)
+#define S2MPA01_IRQ_MRB_MASK           (1 << 7)
+
+#define S2MPA01_IRQ_RTC60S_MASK                (1 << 0)
+#define S2MPA01_IRQ_RTCA1_MASK         (1 << 1)
+#define S2MPA01_IRQ_RTCA0_MASK         (1 << 2)
+#define S2MPA01_IRQ_SMPL_MASK          (1 << 3)
+#define S2MPA01_IRQ_RTC1S_MASK         (1 << 4)
+#define S2MPA01_IRQ_WTSR_MASK          (1 << 5)
+
+#define S2MPA01_IRQ_INT120C_MASK       (1 << 0)
+#define S2MPA01_IRQ_INT140C_MASK       (1 << 1)
+#define S2MPA01_IRQ_LDO3_TSD_MASK      (1 << 2)
+#define S2MPA01_IRQ_B16_TSD_MASK       (1 << 3)
+#define S2MPA01_IRQ_B24_TSD_MASK       (1 << 4)
+#define S2MPA01_IRQ_B35_TSD_MASK       (1 << 5)
+
 enum s2mps11_irq {
        S2MPS11_IRQ_PWRONF,
        S2MPS11_IRQ_PWRONR,
@@ -24,8 +74,8 @@ enum s2mps11_irq {
        S2MPS11_IRQ_MRB,
 
        S2MPS11_IRQ_RTC60S,
+       S2MPS11_IRQ_RTCA0,
        S2MPS11_IRQ_RTCA1,
-       S2MPS11_IRQ_RTCA2,
        S2MPS11_IRQ_SMPL,
        S2MPS11_IRQ_RTC1S,
        S2MPS11_IRQ_WTSR,
@@ -47,7 +97,7 @@ enum s2mps11_irq {
 
 #define S2MPS11_IRQ_RTC60S_MASK                (1 << 0)
 #define S2MPS11_IRQ_RTCA1_MASK         (1 << 1)
-#define S2MPS11_IRQ_RTCA2_MASK         (1 << 2)
+#define S2MPS11_IRQ_RTCA0_MASK         (1 << 2)
 #define S2MPS11_IRQ_SMPL_MASK          (1 << 3)
 #define S2MPS11_IRQ_RTC1S_MASK         (1 << 4)
 #define S2MPS11_IRQ_WTSR_MASK          (1 << 5)
@@ -55,6 +105,33 @@ enum s2mps11_irq {
 #define S2MPS11_IRQ_INT120C_MASK       (1 << 0)
 #define S2MPS11_IRQ_INT140C_MASK       (1 << 1)
 
+enum s2mps14_irq {
+       S2MPS14_IRQ_PWRONF,
+       S2MPS14_IRQ_PWRONR,
+       S2MPS14_IRQ_JIGONBF,
+       S2MPS14_IRQ_JIGONBR,
+       S2MPS14_IRQ_ACOKBF,
+       S2MPS14_IRQ_ACOKBR,
+       S2MPS14_IRQ_PWRON1S,
+       S2MPS14_IRQ_MRB,
+
+       S2MPS14_IRQ_RTC60S,
+       S2MPS14_IRQ_RTCA1,
+       S2MPS14_IRQ_RTCA0,
+       S2MPS14_IRQ_SMPL,
+       S2MPS14_IRQ_RTC1S,
+       S2MPS14_IRQ_WTSR,
+
+       S2MPS14_IRQ_INT120C,
+       S2MPS14_IRQ_INT140C,
+       S2MPS14_IRQ_TSD,
+
+       S2MPS14_IRQ_NR,
+};
+
+/* Masks for interrupts are the same as in s2mps11 */
+#define S2MPS14_IRQ_TSD_MASK           (1 << 2)
+
 enum s5m8767_irq {
        S5M8767_IRQ_PWRR,
        S5M8767_IRQ_PWRF,
index 94b7cd6d889185f9df10b611099bf06038365b83..3e02b768d53704968a76e27af9cece0f455de6bc 100644 (file)
@@ -1,12 +1,17 @@
-/*  rtc.h
+/* rtc.h
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
  *              http://www.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 free software; you can redistribute  it and/or modify it
+ * under  the terms of  the 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.
  *
  */
 
@@ -43,6 +48,39 @@ enum sec_rtc_reg {
        SEC_RTC_STATUS,
        SEC_WTSR_SMPL_CNTL,
        SEC_RTC_UDR_CON,
+
+       SEC_RTC_REG_MAX,
+};
+
+enum s2mps_rtc_reg {
+       S2MPS_RTC_CTRL,
+       S2MPS_WTSR_SMPL_CNTL,
+       S2MPS_RTC_UDR_CON,
+       S2MPS_RSVD,
+       S2MPS_RTC_SEC,
+       S2MPS_RTC_MIN,
+       S2MPS_RTC_HOUR,
+       S2MPS_RTC_WEEKDAY,
+       S2MPS_RTC_DATE,
+       S2MPS_RTC_MONTH,
+       S2MPS_RTC_YEAR,
+       S2MPS_ALARM0_SEC,
+       S2MPS_ALARM0_MIN,
+       S2MPS_ALARM0_HOUR,
+       S2MPS_ALARM0_WEEKDAY,
+       S2MPS_ALARM0_DATE,
+       S2MPS_ALARM0_MONTH,
+       S2MPS_ALARM0_YEAR,
+       S2MPS_ALARM1_SEC,
+       S2MPS_ALARM1_MIN,
+       S2MPS_ALARM1_HOUR,
+       S2MPS_ALARM1_WEEKDAY,
+       S2MPS_ALARM1_DATE,
+       S2MPS_ALARM1_MONTH,
+       S2MPS_ALARM1_YEAR,
+       S2MPS_OFFSRC,
+
+       S2MPS_RTC_REG_MAX,
 };
 
 #define RTC_I2C_ADDR           (0x0C >> 1)
@@ -54,6 +92,9 @@ enum sec_rtc_reg {
 #define ALARM1_STATUS          (1 << 2)
 #define UPDATE_AD              (1 << 0)
 
+#define S2MPS_ALARM0_STATUS    (1 << 2)
+#define S2MPS_ALARM1_STATUS    (1 << 1)
+
 /* RTC Control Register */
 #define BCD_EN_SHIFT           0
 #define BCD_EN_MASK            (1 << BCD_EN_SHIFT)
@@ -62,6 +103,10 @@ enum sec_rtc_reg {
 /* RTC Update Register1 */
 #define RTC_UDR_SHIFT          0
 #define RTC_UDR_MASK           (1 << RTC_UDR_SHIFT)
+#define S2MPS_RTC_WUDR_SHIFT   4
+#define S2MPS_RTC_WUDR_MASK    (1 << S2MPS_RTC_WUDR_SHIFT)
+#define S2MPS_RTC_RUDR_SHIFT   0
+#define S2MPS_RTC_RUDR_MASK    (1 << S2MPS_RTC_RUDR_SHIFT)
 #define RTC_TCON_SHIFT         1
 #define RTC_TCON_MASK          (1 << RTC_TCON_SHIFT)
 #define RTC_TIME_EN_SHIFT      3
diff --git a/include/linux/mfd/samsung/s2mpa01.h b/include/linux/mfd/samsung/s2mpa01.h
new file mode 100644 (file)
index 0000000..fbc63bc
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ *             http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPA01_H
+#define __LINUX_MFD_S2MPA01_H
+
+/* S2MPA01 registers */
+enum s2mpa01_reg {
+       S2MPA01_REG_ID,
+       S2MPA01_REG_INT1,
+       S2MPA01_REG_INT2,
+       S2MPA01_REG_INT3,
+       S2MPA01_REG_INT1M,
+       S2MPA01_REG_INT2M,
+       S2MPA01_REG_INT3M,
+       S2MPA01_REG_ST1,
+       S2MPA01_REG_ST2,
+       S2MPA01_REG_PWRONSRC,
+       S2MPA01_REG_OFFSRC,
+       S2MPA01_REG_RTC_BUF,
+       S2MPA01_REG_CTRL1,
+       S2MPA01_REG_ETC_TEST,
+       S2MPA01_REG_RSVD1,
+       S2MPA01_REG_BU_CHG,
+       S2MPA01_REG_RAMP1,
+       S2MPA01_REG_RAMP2,
+       S2MPA01_REG_LDO_DSCH1,
+       S2MPA01_REG_LDO_DSCH2,
+       S2MPA01_REG_LDO_DSCH3,
+       S2MPA01_REG_LDO_DSCH4,
+       S2MPA01_REG_OTP_ADRL,
+       S2MPA01_REG_OTP_ADRH,
+       S2MPA01_REG_OTP_DATA,
+       S2MPA01_REG_MON1SEL,
+       S2MPA01_REG_MON2SEL,
+       S2MPA01_REG_LEE,
+       S2MPA01_REG_RSVD2,
+       S2MPA01_REG_RSVD3,
+       S2MPA01_REG_RSVD4,
+       S2MPA01_REG_RSVD5,
+       S2MPA01_REG_RSVD6,
+       S2MPA01_REG_TOP_RSVD,
+       S2MPA01_REG_DVS_SEL,
+       S2MPA01_REG_DVS_PTR,
+       S2MPA01_REG_DVS_DATA,
+       S2MPA01_REG_RSVD_NO,
+       S2MPA01_REG_UVLO,
+       S2MPA01_REG_LEE_NO,
+       S2MPA01_REG_B1CTRL1,
+       S2MPA01_REG_B1CTRL2,
+       S2MPA01_REG_B2CTRL1,
+       S2MPA01_REG_B2CTRL2,
+       S2MPA01_REG_B3CTRL1,
+       S2MPA01_REG_B3CTRL2,
+       S2MPA01_REG_B4CTRL1,
+       S2MPA01_REG_B4CTRL2,
+       S2MPA01_REG_B5CTRL1,
+       S2MPA01_REG_B5CTRL2,
+       S2MPA01_REG_B5CTRL3,
+       S2MPA01_REG_B5CTRL4,
+       S2MPA01_REG_B5CTRL5,
+       S2MPA01_REG_B5CTRL6,
+       S2MPA01_REG_B6CTRL1,
+       S2MPA01_REG_B6CTRL2,
+       S2MPA01_REG_B7CTRL1,
+       S2MPA01_REG_B7CTRL2,
+       S2MPA01_REG_B8CTRL1,
+       S2MPA01_REG_B8CTRL2,
+       S2MPA01_REG_B9CTRL1,
+       S2MPA01_REG_B9CTRL2,
+       S2MPA01_REG_B10CTRL1,
+       S2MPA01_REG_B10CTRL2,
+       S2MPA01_REG_L1CTRL,
+       S2MPA01_REG_L2CTRL,
+       S2MPA01_REG_L3CTRL,
+       S2MPA01_REG_L4CTRL,
+       S2MPA01_REG_L5CTRL,
+       S2MPA01_REG_L6CTRL,
+       S2MPA01_REG_L7CTRL,
+       S2MPA01_REG_L8CTRL,
+       S2MPA01_REG_L9CTRL,
+       S2MPA01_REG_L10CTRL,
+       S2MPA01_REG_L11CTRL,
+       S2MPA01_REG_L12CTRL,
+       S2MPA01_REG_L13CTRL,
+       S2MPA01_REG_L14CTRL,
+       S2MPA01_REG_L15CTRL,
+       S2MPA01_REG_L16CTRL,
+       S2MPA01_REG_L17CTRL,
+       S2MPA01_REG_L18CTRL,
+       S2MPA01_REG_L19CTRL,
+       S2MPA01_REG_L20CTRL,
+       S2MPA01_REG_L21CTRL,
+       S2MPA01_REG_L22CTRL,
+       S2MPA01_REG_L23CTRL,
+       S2MPA01_REG_L24CTRL,
+       S2MPA01_REG_L25CTRL,
+       S2MPA01_REG_L26CTRL,
+
+       S2MPA01_REG_LDO_OVCB1,
+       S2MPA01_REG_LDO_OVCB2,
+       S2MPA01_REG_LDO_OVCB3,
+       S2MPA01_REG_LDO_OVCB4,
+
+};
+
+/* S2MPA01 regulator ids */
+enum s2mpa01_regulators {
+       S2MPA01_LDO1,
+       S2MPA01_LDO2,
+       S2MPA01_LDO3,
+       S2MPA01_LDO4,
+       S2MPA01_LDO5,
+       S2MPA01_LDO6,
+       S2MPA01_LDO7,
+       S2MPA01_LDO8,
+       S2MPA01_LDO9,
+       S2MPA01_LDO10,
+       S2MPA01_LDO11,
+       S2MPA01_LDO12,
+       S2MPA01_LDO13,
+       S2MPA01_LDO14,
+       S2MPA01_LDO15,
+       S2MPA01_LDO16,
+       S2MPA01_LDO17,
+       S2MPA01_LDO18,
+       S2MPA01_LDO19,
+       S2MPA01_LDO20,
+       S2MPA01_LDO21,
+       S2MPA01_LDO22,
+       S2MPA01_LDO23,
+       S2MPA01_LDO24,
+       S2MPA01_LDO25,
+       S2MPA01_LDO26,
+
+       S2MPA01_BUCK1,
+       S2MPA01_BUCK2,
+       S2MPA01_BUCK3,
+       S2MPA01_BUCK4,
+       S2MPA01_BUCK5,
+       S2MPA01_BUCK6,
+       S2MPA01_BUCK7,
+       S2MPA01_BUCK8,
+       S2MPA01_BUCK9,
+       S2MPA01_BUCK10,
+
+       S2MPA01_REGULATOR_MAX,
+};
+
+#define S2MPA01_BUCK_MIN1      600000
+#define S2MPA01_BUCK_MIN2      800000
+#define S2MPA01_BUCK_MIN3      1000000
+#define S2MPA01_BUCK_MIN4      1500000
+#define S2MPA01_LDO_MIN                800000
+
+#define S2MPA01_BUCK_STEP1     6250
+#define S2MPA01_BUCK_STEP2     12500
+
+#define S2MPA01_LDO_STEP1      50000
+#define S2MPA01_LDO_STEP2      25000
+
+#define S2MPA01_LDO_VSEL_MASK  0x3F
+#define S2MPA01_BUCK_VSEL_MASK 0xFF
+#define S2MPA01_ENABLE_MASK    (0x03 << S2MPA01_ENABLE_SHIFT)
+#define S2MPA01_ENABLE_SHIFT   0x06
+#define S2MPA01_LDO_N_VOLTAGES (S2MPA01_LDO_VSEL_MASK + 1)
+#define S2MPA01_BUCK_N_VOLTAGES (S2MPA01_BUCK_VSEL_MASK + 1)
+
+#define S2MPA01_RAMP_DELAY     12500   /* uV/us */
+
+#define S2MPA01_BUCK16_RAMP_SHIFT      4
+#define S2MPA01_BUCK24_RAMP_SHIFT      6
+#define S2MPA01_BUCK3_RAMP_SHIFT       4
+#define S2MPA01_BUCK5_RAMP_SHIFT       6
+#define S2MPA01_BUCK7_RAMP_SHIFT       2
+#define S2MPA01_BUCK8910_RAMP_SHIFT    0
+
+#define S2MPA01_BUCK1_RAMP_EN_SHIFT    3
+#define S2MPA01_BUCK2_RAMP_EN_SHIFT    2
+#define S2MPA01_BUCK3_RAMP_EN_SHIFT    1
+#define S2MPA01_BUCK4_RAMP_EN_SHIFT    0
+#define S2MPA01_PMIC_EN_SHIFT  6
+
+#endif /*__LINUX_MFD_S2MPA01_H */
diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h
new file mode 100644 (file)
index 0000000..4b449b8
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * s2mps14.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *              http://www.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.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPS14_H
+#define __LINUX_MFD_S2MPS14_H
+
+/* S2MPS14 registers */
+enum s2mps14_reg {
+       S2MPS14_REG_ID,
+       S2MPS14_REG_INT1,
+       S2MPS14_REG_INT2,
+       S2MPS14_REG_INT3,
+       S2MPS14_REG_INT1M,
+       S2MPS14_REG_INT2M,
+       S2MPS14_REG_INT3M,
+       S2MPS14_REG_ST1,
+       S2MPS14_REG_ST2,
+       S2MPS14_REG_PWRONSRC,
+       S2MPS14_REG_OFFSRC,
+       S2MPS14_REG_BU_CHG,
+       S2MPS14_REG_RTCCTRL,
+       S2MPS14_REG_CTRL1,
+       S2MPS14_REG_CTRL2,
+       S2MPS14_REG_RSVD1,
+       S2MPS14_REG_RSVD2,
+       S2MPS14_REG_RSVD3,
+       S2MPS14_REG_RSVD4,
+       S2MPS14_REG_RSVD5,
+       S2MPS14_REG_RSVD6,
+       S2MPS14_REG_CTRL3,
+       S2MPS14_REG_RSVD7,
+       S2MPS14_REG_RSVD8,
+       S2MPS14_REG_WRSTBI,
+       S2MPS14_REG_B1CTRL1,
+       S2MPS14_REG_B1CTRL2,
+       S2MPS14_REG_B2CTRL1,
+       S2MPS14_REG_B2CTRL2,
+       S2MPS14_REG_B3CTRL1,
+       S2MPS14_REG_B3CTRL2,
+       S2MPS14_REG_B4CTRL1,
+       S2MPS14_REG_B4CTRL2,
+       S2MPS14_REG_B5CTRL1,
+       S2MPS14_REG_B5CTRL2,
+       S2MPS14_REG_L1CTRL,
+       S2MPS14_REG_L2CTRL,
+       S2MPS14_REG_L3CTRL,
+       S2MPS14_REG_L4CTRL,
+       S2MPS14_REG_L5CTRL,
+       S2MPS14_REG_L6CTRL,
+       S2MPS14_REG_L7CTRL,
+       S2MPS14_REG_L8CTRL,
+       S2MPS14_REG_L9CTRL,
+       S2MPS14_REG_L10CTRL,
+       S2MPS14_REG_L11CTRL,
+       S2MPS14_REG_L12CTRL,
+       S2MPS14_REG_L13CTRL,
+       S2MPS14_REG_L14CTRL,
+       S2MPS14_REG_L15CTRL,
+       S2MPS14_REG_L16CTRL,
+       S2MPS14_REG_L17CTRL,
+       S2MPS14_REG_L18CTRL,
+       S2MPS14_REG_L19CTRL,
+       S2MPS14_REG_L20CTRL,
+       S2MPS14_REG_L21CTRL,
+       S2MPS14_REG_L22CTRL,
+       S2MPS14_REG_L23CTRL,
+       S2MPS14_REG_L24CTRL,
+       S2MPS14_REG_L25CTRL,
+       S2MPS14_REG_LDODSCH1,
+       S2MPS14_REG_LDODSCH2,
+       S2MPS14_REG_LDODSCH3,
+};
+
+/* S2MPS14 regulator ids */
+enum s2mps14_regulators {
+       S2MPS14_LDO1,
+       S2MPS14_LDO2,
+       S2MPS14_LDO3,
+       S2MPS14_LDO4,
+       S2MPS14_LDO5,
+       S2MPS14_LDO6,
+       S2MPS14_LDO7,
+       S2MPS14_LDO8,
+       S2MPS14_LDO9,
+       S2MPS14_LDO10,
+       S2MPS14_LDO11,
+       S2MPS14_LDO12,
+       S2MPS14_LDO13,
+       S2MPS14_LDO14,
+       S2MPS14_LDO15,
+       S2MPS14_LDO16,
+       S2MPS14_LDO17,
+       S2MPS14_LDO18,
+       S2MPS14_LDO19,
+       S2MPS14_LDO20,
+       S2MPS14_LDO21,
+       S2MPS14_LDO22,
+       S2MPS14_LDO23,
+       S2MPS14_LDO24,
+       S2MPS14_LDO25,
+       S2MPS14_BUCK1,
+       S2MPS14_BUCK2,
+       S2MPS14_BUCK3,
+       S2MPS14_BUCK4,
+       S2MPS14_BUCK5,
+
+       S2MPS14_REGULATOR_MAX,
+};
+
+/* Regulator constraints for BUCKx */
+#define S2MPS14_BUCK1235_MIN_600MV     600000
+#define S2MPS14_BUCK4_MIN_1400MV       1400000
+#define S2MPS14_BUCK1235_STEP_6_25MV   6250
+#define S2MPS14_BUCK4_STEP_12_5MV      12500
+#define S2MPS14_BUCK1235_START_SEL     0x20
+#define S2MPS14_BUCK4_START_SEL                0x40
+/*
+ * Default ramp delay in uv/us. Datasheet says that ramp delay can be
+ * controlled however it does not specify which register is used for that.
+ * Let's assume that default value will be set.
+ */
+#define S2MPS14_BUCK_RAMP_DELAY                12500
+
+/* Regulator constraints for different types of LDOx */
+#define S2MPS14_LDO_MIN_800MV          800000
+#define S2MPS14_LDO_MIN_1800MV         1800000
+#define S2MPS14_LDO_STEP_12_5MV                12500
+#define S2MPS14_LDO_STEP_25MV          25000
+
+#define S2MPS14_LDO_VSEL_MASK          0x3F
+#define S2MPS14_BUCK_VSEL_MASK         0xFF
+#define S2MPS14_ENABLE_MASK            (0x03 << S2MPS14_ENABLE_SHIFT)
+#define S2MPS14_ENABLE_SHIFT           6
+/* On/Off controlled by PWREN */
+#define S2MPS14_ENABLE_SUSPEND         (0x01 << S2MPS14_ENABLE_SHIFT)
+#define S2MPS14_LDO_N_VOLTAGES         (S2MPS14_LDO_VSEL_MASK + 1)
+#define S2MPS14_BUCK_N_VOLTAGES                (S2MPS14_BUCK_VSEL_MASK + 1)
+
+#endif /*  __LINUX_MFD_S2MPS14_H */
index 2ab0b0f03641334077cc16c4bbd8ec8c9159619c..243b58fec33dacd3fa053e10bf7ca2e2a9c027a3 100644 (file)
@@ -183,9 +183,16 @@ enum s5m8767_regulators {
        S5M8767_REG_MAX,
 };
 
+/* LDO_EN/BUCK_EN field in registers */
 #define S5M8767_ENCTRL_SHIFT           6
 #define S5M8767_ENCTRL_MASK            (0x3 << S5M8767_ENCTRL_SHIFT)
 
+/*
+ * LDO_EN/BUCK_EN register value for controlling this Buck or LDO
+ * by GPIO (PWREN, BUCKEN).
+ */
+#define S5M8767_ENCTRL_USE_GPIO                0x1
+
 /*
  * Values for BUCK_RAMP field in DVS_RAMP register, matching raw values
  * in mV/us.
index 3737f7218f51362ea9cf1991a66c0328143741b8..2cf1547096d974b6b8dc83f1e906cef0e300a6da 100644 (file)
  */
 
 #define PSMOUSE_MINOR          1
-#define MS_BUSMOUSE_MINOR      2
-#define ATIXL_BUSMOUSE_MINOR   3
+#define MS_BUSMOUSE_MINOR      2       /* unused */
+#define ATIXL_BUSMOUSE_MINOR   3       /* unused */
 /*#define AMIGAMOUSE_MINOR     4       FIXME OBSOLETE */
-#define ATARIMOUSE_MINOR       5
-#define SUN_MOUSE_MINOR                6
-#define APOLLO_MOUSE_MINOR     7
-#define PC110PAD_MINOR         9
+#define ATARIMOUSE_MINOR       5       /* unused */
+#define SUN_MOUSE_MINOR                6       /* unused */
+#define APOLLO_MOUSE_MINOR     7       /* unused */
+#define PC110PAD_MINOR         9       /* unused */
 /*#define ADB_MOUSE_MINOR      10      FIXME OBSOLETE */
 #define WATCHDOG_MINOR         130     /* Watchdog timer     */
 #define TEMP_MINOR             131     /* Temperature Sensor */
 #define RTC_MINOR              135
 #define EFI_RTC_MINOR          136     /* EFI Time services */
 #define SUN_OPENPROM_MINOR     139
-#define DMAPI_MINOR            140     /* DMAPI */
+#define DMAPI_MINOR            140     /* unused */
 #define NVRAM_MINOR            144
 #define SGI_MMTIMER            153
-#define STORE_QUEUE_MINOR      155
+#define STORE_QUEUE_MINOR      155     /* unused */
 #define I2O_MINOR              166
 #define MICROCODE_MINOR                184
 #define VFIO_MINOR             196
index f28f46eade6a642873246fea247f3f5455a18acb..a0df4295e1717a23463d96d4f973a4330f2349ad 100644 (file)
@@ -175,7 +175,7 @@ extern unsigned int kobjsize(const void *objp);
  * Special vmas that are non-mergable, non-mlock()able.
  * Note: mm/huge_memory.c VM_NO_THP depends on this definition.
  */
-#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP)
+#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
 
 /*
  * mapping from the currently active vm_flags protection bits (the
@@ -399,8 +399,18 @@ static inline void compound_unlock_irqrestore(struct page *page,
 
 static inline struct page *compound_head(struct page *page)
 {
-       if (unlikely(PageTail(page)))
-               return page->first_page;
+       if (unlikely(PageTail(page))) {
+               struct page *head = page->first_page;
+
+               /*
+                * page->first_page may be a dangling pointer to an old
+                * compound page, so recheck that it is still a tail
+                * page before returning.
+                */
+               smp_rmb();
+               if (likely(PageTail(page)))
+                       return head;
+       }
        return page;
 }
 
@@ -757,7 +767,7 @@ static inline bool __cpupid_match_pid(pid_t task_pid, int cpupid)
 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
 static inline int page_cpupid_xchg_last(struct page *page, int cpupid)
 {
-       return xchg(&page->_last_cpupid, cpupid);
+       return xchg(&page->_last_cpupid, cpupid & LAST_CPUPID_MASK);
 }
 
 static inline int page_cpupid_last(struct page *page)
@@ -766,7 +776,7 @@ static inline int page_cpupid_last(struct page *page)
 }
 static inline void page_cpupid_reset_last(struct page *page)
 {
-       page->_last_cpupid = -1;
+       page->_last_cpupid = -1 & LAST_CPUPID_MASK;
 }
 #else
 static inline int page_cpupid_last(struct page *page)
@@ -1477,9 +1487,15 @@ static inline void pgtable_page_dtor(struct page *page)
 
 #if USE_SPLIT_PMD_PTLOCKS
 
+static struct page *pmd_to_page(pmd_t *pmd)
+{
+       unsigned long mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1);
+       return virt_to_page((void *)((unsigned long) pmd & mask));
+}
+
 static inline spinlock_t *pmd_lockptr(struct mm_struct *mm, pmd_t *pmd)
 {
-       return ptlock_ptr(virt_to_page(pmd));
+       return ptlock_ptr(pmd_to_page(pmd));
 }
 
 static inline bool pgtable_pmd_page_ctor(struct page *page)
@@ -1498,7 +1514,7 @@ static inline void pgtable_pmd_page_dtor(struct page *page)
        ptlock_free(page);
 }
 
-#define pmd_huge_pte(mm, pmd) (virt_to_page(pmd)->pmd_huge_pte)
+#define pmd_huge_pte(mm, pmd) (pmd_to_page(pmd)->pmd_huge_pte)
 
 #else
 
index 5f2052c831547a33b66606d78ac5713086d285e3..9b61b9bf81ac86a90c1ce70d12400b745b7582eb 100644 (file)
@@ -590,10 +590,10 @@ static inline bool zone_is_empty(struct zone *zone)
 
 /*
  * The NUMA zonelists are doubled because we need zonelists that restrict the
- * allocations to a single node for GFP_THISNODE.
+ * allocations to a single node for __GFP_THISNODE.
  *
  * [0] : Zonelist with fallback
- * [1] : No fallback (GFP_THISNODE)
+ * [1] : No fallback (__GFP_THISNODE)
  */
 #define MAX_ZONELISTS 2
 
index f2ac87c613a5d8a47a9820920ca88c6abb64cc57..9a165a213d9320fa79d088ebe8aaa80408c7fb71 100644 (file)
@@ -432,6 +432,14 @@ struct spi_device_id {
        kernel_ulong_t driver_data;     /* Data private to the driver */
 };
 
+#define SPMI_NAME_SIZE 32
+#define SPMI_MODULE_PREFIX "spmi:"
+
+struct spmi_device_id {
+       char name[SPMI_NAME_SIZE];
+       kernel_ulong_t driver_data;     /* Data private to the driver */
+};
+
 /* dmi */
 enum dmi_field {
        DMI_NONE,
@@ -608,4 +616,9 @@ struct rio_device_id {
        __u16 asm_did, asm_vid;
 };
 
+struct mcb_device_id {
+       __u16 device;
+       kernel_ulong_t driver_data;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index d3181936c138ba2583960815a722aa8f90938a9d..11692dea18aa25a9410ce842cdd851a4d15560c7 100644 (file)
@@ -46,6 +46,7 @@
  * - detects multi-task circular deadlocks and prints out all affected
  *   locks and tasks (and only those tasks)
  */
+struct optimistic_spin_queue;
 struct mutex {
        /* 1: unlocked, 0: locked, negative: locked, possible waiters */
        atomic_t                count;
@@ -55,7 +56,7 @@ struct mutex {
        struct task_struct      *owner;
 #endif
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
-       void                    *spin_mlock;    /* Spinner MCS lock */
+       struct optimistic_spin_queue    *osq;   /* Spinner MCS lock */
 #endif
 #ifdef CONFIG_DEBUG_MUTEXES
        const char              *name;
@@ -179,4 +180,4 @@ extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
 # define arch_mutex_cpu_relax() cpu_relax()
 #endif
 
-#endif
+#endif /* __LINUX_MUTEX_H */
index 1005ebf175752774ada359369a313379a82dc85a..5a09a48f2658a64f7149ecddd30abd56c65cf69f 100644 (file)
@@ -163,4 +163,11 @@ enum {
 /* changeable features with no special hardware requirements */
 #define NETIF_F_SOFT_FEATURES  (NETIF_F_GSO | NETIF_F_GRO)
 
+#define NETIF_F_VLAN_FEATURES  (NETIF_F_HW_VLAN_CTAG_FILTER | \
+                                NETIF_F_HW_VLAN_CTAG_RX | \
+                                NETIF_F_HW_VLAN_CTAG_TX | \
+                                NETIF_F_HW_VLAN_STAG_FILTER | \
+                                NETIF_F_HW_VLAN_STAG_RX | \
+                                NETIF_F_HW_VLAN_STAG_TX)
+
 #endif /* _LINUX_NETDEV_FEATURES_H */
index e8eeebd49a98279837bb6e30afa82f3645465452..daafd9561cbca2335c1f0a3f20cd593e30fa5206 100644 (file)
@@ -3014,7 +3014,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
 {
        return __skb_gso_segment(skb, features, true);
 }
-__be16 skb_network_protocol(struct sk_buff *skb);
+__be16 skb_network_protocol(struct sk_buff *skb, int *depth);
 
 static inline bool can_checksum_protocol(netdev_features_t features,
                                         __be16 protocol)
index b2fb167b2e6d99ed71a1ab6ddeae6c7c3885600a..5624e4e2763c2eb3d73f4e02d2752661ccd9c6b9 100644 (file)
@@ -467,9 +467,14 @@ struct nfs_lockt_res {
 };
 
 struct nfs_release_lockowner_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_lowner       lock_owner;
 };
 
+struct nfs_release_lockowner_res {
+       struct nfs4_sequence_res        seq_res;
+};
+
 struct nfs4_delegreturnargs {
        struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *fhandle;
index 69ae03f6eb159a39b2bd589add2c56b2c1c8f6cc..6b9aafed225fcd9a48228ac9f6044c7a956cc325 100644 (file)
@@ -87,6 +87,7 @@ struct nvme_dev {
        struct list_head namespaces;
        struct kref kref;
        struct miscdevice miscdev;
+       work_func_t reset_workfn;
        struct work_struct reset_work;
        char name[12];
        char serial[20];
index 435cb995904dedc6329916f29cd2378b5e0e7b2e..83d1ac80c91e3745a96d5fdd4e929d5e1542a525 100644 (file)
@@ -198,6 +198,8 @@ extern struct device_node *of_find_node_with_property(
 extern struct property *of_find_property(const struct device_node *np,
                                         const char *name,
                                         int *lenp);
+extern int of_property_count_elems_of_size(const struct device_node *np,
+                               const char *propname, int elem_size);
 extern int of_property_read_u32_index(const struct device_node *np,
                                       const char *propname,
                                       u32 index, u32 *out_value);
@@ -390,6 +392,12 @@ static inline struct device_node *of_find_compatible_node(
        return NULL;
 }
 
+static inline int of_property_count_elems_of_size(const struct device_node *np,
+                       const char *propname, int elem_size)
+{
+       return -ENOSYS;
+}
+
 static inline int of_property_read_u32_index(const struct device_node *np,
                        const char *propname, u32 index, u32 *out_value)
 {
@@ -535,6 +543,74 @@ static inline struct device_node *of_find_matching_node(
        return of_find_matching_node_and_match(from, matches, NULL);
 }
 
+/**
+ * of_property_count_u8_elems - Count the number of u8 elements in a property
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u8 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u8 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u8_elems(const struct device_node *np,
+                               const char *propname)
+{
+       return of_property_count_elems_of_size(np, propname, sizeof(u8));
+}
+
+/**
+ * of_property_count_u16_elems - Count the number of u16 elements in a property
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u16 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u16 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u16_elems(const struct device_node *np,
+                               const char *propname)
+{
+       return of_property_count_elems_of_size(np, propname, sizeof(u16));
+}
+
+/**
+ * of_property_count_u32_elems - Count the number of u32 elements in a property
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u32 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u32 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u32_elems(const struct device_node *np,
+                               const char *propname)
+{
+       return of_property_count_elems_of_size(np, propname, sizeof(u32));
+}
+
+/**
+ * of_property_count_u64_elems - Count the number of u64 elements in a property
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u64 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u64 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u64_elems(const struct device_node *np,
+                               const char *propname)
+{
+       return of_property_count_elems_of_size(np, propname, sizeof(u64));
+}
+
 /**
  * of_property_read_bool - Findfrom a property
  * @np:                device node from which the property value is to be read.
index 5a462c4e5009d68960525d2167728d59ee75e33b..637a608ded0b0091503db1ac4aaa04cf7155823c 100644 (file)
@@ -59,12 +59,12 @@ static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
 void acpiphp_init(void);
 void acpiphp_enumerate_slots(struct pci_bus *bus);
 void acpiphp_remove_slots(struct pci_bus *bus);
-void acpiphp_check_host_bridge(acpi_handle handle);
+void acpiphp_check_host_bridge(struct acpi_device *adev);
 #else
 static inline void acpiphp_init(void) { }
 static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { }
 static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
-static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
+static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
 #endif
 
 #else  /* CONFIG_ACPI */
index 33aa2caf0f0c9e5bd9e7cf07c8d92b08207be959..aab57b4abe7fce4ef59adc14db6400d3a6af57cc 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/atomic.h>
 #include <linux/device.h>
 #include <linux/io.h>
-#include <linux/irqreturn.h>
 #include <uapi/linux/pci.h>
 
 #include <linux/pci_ids.h>
@@ -170,6 +169,8 @@ enum pci_dev_flags {
        PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
        /* Provide indication device is assigned by a Virtual Machine Manager */
        PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
+       /* Flag for quirk use to store if quirk-specific ACS is enabled */
+       PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) 8,
 };
 
 enum pci_irq_reroute_variant {
@@ -461,7 +462,6 @@ struct pci_bus {
        unsigned int            is_added:1;
 };
 
-#define pci_bus_b(n)   list_entry(n, struct pci_bus, node)
 #define to_pci_bus(n)  container_of(n, struct pci_bus, dev)
 
 /*
@@ -1066,7 +1066,7 @@ void pci_bus_remove_resources(struct pci_bus *bus);
 int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
                        struct resource *res, resource_size_t size,
                        resource_size_t align, resource_size_t min,
-                       unsigned int type_mask,
+                       unsigned long type_mask,
                        resource_size_t (*alignf)(void *,
                                                  const struct resource *,
                                                  resource_size_t,
@@ -1530,6 +1530,7 @@ enum pci_fixup_pass {
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
 struct pci_dev *pci_get_dma_source(struct pci_dev *dev);
 int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
+void pci_dev_specific_enable_acs(struct pci_dev *dev);
 #else
 static inline void pci_fixup_device(enum pci_fixup_pass pass,
                                    struct pci_dev *dev) { }
@@ -1542,6 +1543,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
 {
        return -ENOTTY;
 }
+static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { }
 #endif
 
 void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
@@ -1597,7 +1599,6 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
 #ifdef CONFIG_PCI_IOV
 int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
 void pci_disable_sriov(struct pci_dev *dev);
-irqreturn_t pci_sriov_migration(struct pci_dev *dev);
 int pci_num_vf(struct pci_dev *dev);
 int pci_vfs_assigned(struct pci_dev *dev);
 int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
@@ -1606,8 +1607,6 @@ int pci_sriov_get_totalvfs(struct pci_dev *dev);
 static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
 { return -ENODEV; }
 static inline void pci_disable_sriov(struct pci_dev *dev) { }
-static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
-{ return IRQ_NONE; }
 static inline int pci_num_vf(struct pci_dev *dev) { return 0; }
 static inline int pci_vfs_assigned(struct pci_dev *dev)
 { return 0; }
index 97fbecdd7a401157cd290d6f4e981a8557ee4745..297a8026f454287bb7f6abda6e4d4d7bac93bfa7 100644 (file)
 #define PCI_DEVICE_ID_AMD_15H_NB_F5    0x1605
 #define PCI_DEVICE_ID_AMD_16H_NB_F3    0x1533
 #define PCI_DEVICE_ID_AMD_16H_NB_F4    0x1534
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F3 0x1583
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F4 0x1584
 #define PCI_DEVICE_ID_AMD_CNB17H_F3    0x1703
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
 
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_EESSC      0x0008
+#define PCI_DEVICE_ID_INTEL_SNB_IMC    0x0100
+#define PCI_DEVICE_ID_INTEL_IVB_IMC    0x0154
+#define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
 #define PCI_DEVICE_ID_INTEL_PXHD_0     0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1     0x0321
 #define PCI_DEVICE_ID_INTEL_PXH_0      0x0329
diff --git a/include/linux/platform_data/adau1977.h b/include/linux/platform_data/adau1977.h
new file mode 100644 (file)
index 0000000..bed11d9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__
+#define __LINUX_PLATFORM_DATA_ADAU1977_H__
+
+/**
+ * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting
+ * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V
+ * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V
+ * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V
+ * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V
+ * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V
+ * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V
+ * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V
+ * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V
+ * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V
+ */
+enum adau1977_micbias {
+       ADAU1977_MICBIAS_5V0 = 0x0,
+       ADAU1977_MICBIAS_5V5 = 0x1,
+       ADAU1977_MICBIAS_6V0 = 0x2,
+       ADAU1977_MICBIAS_6V5 = 0x3,
+       ADAU1977_MICBIAS_7V0 = 0x4,
+       ADAU1977_MICBIAS_7V5 = 0x5,
+       ADAU1977_MICBIAS_8V0 = 0x6,
+       ADAU1977_MICBIAS_8V5 = 0x7,
+       ADAU1977_MICBIAS_9V0 = 0x8,
+};
+
+/**
+ * struct adau1977_platform_data - Platform configuration data for the ADAU1977
+ * @micbias: Specifies the voltage for the MICBIAS pin
+ */
+struct adau1977_platform_data {
+       enum adau1977_micbias micbias;
+};
+
+#endif
index 9efc04dd255aa59799c69e4bba791551825023e8..709c6f7e2f8c0b9b0cf586cf3386ff9fb2e50740 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/plat-samsung/include/plat/audio.h
- *
+/*
  * Copyright (c) 2009 Samsung Electronics Co. Ltd
  * Author: Jaswinder Singh <jassi.brar@samsung.com>
  *
index 376af5286a3ef8563fec56c5ac3241ba6200d201..d220e54123aa3ebad540b520f9327f7f11d275cd 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/plat-samsung/include/plat/audio-simtec.h
- *
+/*
  * Copyright 2008 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
index 5245992b036734dd4c96f1c544539e070d058b64..85ad68f9206ae929b4cc3ec571735c651134be09 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <linux/genalloc.h>
 
-struct snd_platform_data {
+struct davinci_mcasp_pdata {
        u32 tx_dma_offset;
        u32 rx_dma_offset;
        int asp_chan_q; /* event queue number for ASP channel */
@@ -87,6 +87,8 @@ struct snd_platform_data {
        int tx_dma_channel;
        int rx_dma_channel;
 };
+/* TODO: Fix arch/arm/mach-davinci/ users and remove this define */
+#define snd_platform_data davinci_mcasp_pdata
 
 enum {
        MCASP_VERSION_1 = 0,    /* DM646x */
index 8447f634c7f5a142982b1c6fd0121b4219d91d72..d3889b98a1a12de82558f85fdced79a2896fac89 100644 (file)
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
- *
+/*
  * Copyright (C) 2009 Samsung Electronics Ltd.
  *     Jaswinder Singh <jassi.brar@samsung.com>
  *
@@ -8,8 +7,8 @@
  * published by the Free Software Foundation.
  */
 
-#ifndef __S3C64XX_PLAT_SPI_H
-#define __S3C64XX_PLAT_SPI_H
+#ifndef __SPI_S3C64XX_H
+#define __SPI_S3C64XX_H
 
 #include <linux/dmaengine.h>
 
@@ -68,4 +67,4 @@ extern int s3c64xx_spi2_cfg_gpio(void);
 extern struct s3c64xx_spi_info s3c64xx_spi0_pdata;
 extern struct s3c64xx_spi_info s3c64xx_spi1_pdata;
 extern struct s3c64xx_spi_info s3c64xx_spi2_pdata;
-#endif /* __S3C64XX_PLAT_SPI_H */
+#endif /*__SPI_S3C64XX_H */
index 8c6583a53a0608a796c543d196d52270cbe8ac4d..d915d0345fa1beb770a742e82247916c440e9543 100644 (file)
@@ -264,9 +264,9 @@ typedef struct pm_message {
  *     registers, so that it is fully operational.
  *
  * @runtime_idle: Device appears to be inactive and it might be put into a
- *     low-power state if all of the necessary conditions are satisfied.  Check
- *     these conditions and handle the device as appropriate, possibly queueing
- *     a suspend request for it.  The return value is ignored by the PM core.
+ *     low-power state if all of the necessary conditions are satisfied.
+ *     Check these conditions, and return 0 if it's appropriate to let the PM
+ *     core queue a suspend request for the device.
  *
  * Refer to Documentation/power/runtime_pm.txt for more information about the
  * role of the above callbacks in device runtime power management.
@@ -352,7 +352,7 @@ const struct dev_pm_ops name = { \
 
 /*
  * Use this for defining a set of PM operations to be used in all situations
- * (sustem suspend, hibernation or runtime PM).
+ * (system suspend, hibernation or runtime PM).
  * NOTE: In general, system suspend callbacks, .suspend() and .resume(), should
  * be different from the corresponding runtime PM callbacks, .runtime_suspend(),
  * and .runtime_resume(), because .runtime_suspend() always works on an already
@@ -379,7 +379,7 @@ const struct dev_pm_ops name = { \
  *
  * ON          No transition.
  *
- * FREEZE      System is going to hibernate, call ->prepare() and ->freeze()
+ * FREEZE      System is going to hibernate, call ->prepare() and ->freeze()
  *             for all devices.
  *
  * SUSPEND     System is going to suspend, call ->prepare() and ->suspend()
@@ -423,7 +423,7 @@ const struct dev_pm_ops name = { \
 
 #define PM_EVENT_INVALID       (-1)
 #define PM_EVENT_ON            0x0000
-#define PM_EVENT_FREEZE        0x0001
+#define PM_EVENT_FREEZE                0x0001
 #define PM_EVENT_SUSPEND       0x0002
 #define PM_EVENT_HIBERNATE     0x0004
 #define PM_EVENT_QUIESCE       0x0008
@@ -542,6 +542,8 @@ struct dev_pm_info {
        unsigned int            async_suspend:1;
        bool                    is_prepared:1;  /* Owned by the PM core */
        bool                    is_suspended:1; /* Ditto */
+       bool                    is_noirq_suspended:1;
+       bool                    is_late_suspended:1;
        bool                    ignore_children:1;
        bool                    early_init:1;   /* Owned by the PM core */
        spinlock_t              lock;
@@ -582,6 +584,7 @@ struct dev_pm_info {
        unsigned long           accounting_timestamp;
 #endif
        struct pm_subsys_data   *subsys_data;  /* Owned by the subsystem. */
+       void (*set_latency_tolerance)(struct device *, s32);
        struct dev_pm_qos       *qos;
 };
 
@@ -612,11 +615,11 @@ struct dev_pm_domain {
  * message is implicit:
  *
  * ON          Driver starts working again, responding to hardware events
- *             and software requests.  The hardware may have gone through
- *             a power-off reset, or it may have maintained state from the
- *             previous suspend() which the driver will rely on while
- *             resuming.  On most platforms, there are no restrictions on
- *             availability of resources like clocks during resume().
+ *             and software requests.  The hardware may have gone through
+ *             a power-off reset, or it may have maintained state from the
+ *             previous suspend() which the driver will rely on while
+ *             resuming.  On most platforms, there are no restrictions on
+ *             availability of resources like clocks during resume().
  *
  * Other transitions are triggered by messages sent using suspend().  All
  * these transitions quiesce the driver, so that I/O queues are inactive.
@@ -626,21 +629,21 @@ struct dev_pm_domain {
  * differ according to the message:
  *
  * SUSPEND     Quiesce, enter a low power device state appropriate for
- *             the upcoming system state (such as PCI_D3hot), and enable
- *             wakeup events as appropriate.
+ *             the upcoming system state (such as PCI_D3hot), and enable
+ *             wakeup events as appropriate.
  *
  * HIBERNATE   Enter a low power device state appropriate for the hibernation
- *             state (eg. ACPI S4) and enable wakeup events as appropriate.
+ *             state (eg. ACPI S4) and enable wakeup events as appropriate.
  *
  * FREEZE      Quiesce operations so that a consistent image can be saved;
- *             but do NOT otherwise enter a low power device state, and do
- *             NOT emit system wakeup events.
+ *             but do NOT otherwise enter a low power device state, and do
+ *             NOT emit system wakeup events.
  *
  * PRETHAW     Quiesce as if for FREEZE; additionally, prepare for restoring
- *             the system from a snapshot taken after an earlier FREEZE.
- *             Some drivers will need to reset their hardware state instead
- *             of preserving it, to ensure that it's never mistaken for the
- *             state which that earlier snapshot had set up.
+ *             the system from a snapshot taken after an earlier FREEZE.
+ *             Some drivers will need to reset their hardware state instead
+ *             of preserving it, to ensure that it's never mistaken for the
+ *             state which that earlier snapshot had set up.
  *
  * A minimally power-aware driver treats all messages as SUSPEND, fully
  * reinitializes its device during resume() -- whether or not it was reset
@@ -717,14 +720,26 @@ static inline void dpm_for_each_dev(void *data, void (*fn)(struct device *, void
 {
 }
 
-#define pm_generic_prepare     NULL
-#define pm_generic_suspend     NULL
-#define pm_generic_resume      NULL
-#define pm_generic_freeze      NULL
-#define pm_generic_thaw                NULL
-#define pm_generic_restore     NULL
-#define pm_generic_poweroff    NULL
-#define pm_generic_complete    NULL
+#define pm_generic_prepare             NULL
+#define pm_generic_suspend_late                NULL
+#define pm_generic_suspend_noirq       NULL
+#define pm_generic_suspend             NULL
+#define pm_generic_resume_early                NULL
+#define pm_generic_resume_noirq                NULL
+#define pm_generic_resume              NULL
+#define pm_generic_freeze_noirq                NULL
+#define pm_generic_freeze_late         NULL
+#define pm_generic_freeze              NULL
+#define pm_generic_thaw_noirq          NULL
+#define pm_generic_thaw_early          NULL
+#define pm_generic_thaw                        NULL
+#define pm_generic_restore_noirq       NULL
+#define pm_generic_restore_early       NULL
+#define pm_generic_restore             NULL
+#define pm_generic_poweroff_noirq      NULL
+#define pm_generic_poweroff_late       NULL
+#define pm_generic_poweroff            NULL
+#define pm_generic_complete            NULL
 #endif /* !CONFIG_PM_SLEEP */
 
 /* How to reorder dpm_list after device_move() */
index 5a95013905c8c9ab96fde04c3dc8a914b78119da..9ab4bf7c464660821b976afad421d4b86d5811ac 100644 (file)
@@ -32,7 +32,10 @@ enum pm_qos_flags_status {
 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
 #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE        0
-#define PM_QOS_DEV_LAT_DEFAULT_VALUE           0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE    0
+#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
+#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
+#define PM_QOS_LATENCY_ANY                     ((s32)(~(__u32)0 >> 1))
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
 #define PM_QOS_FLAG_REMOTE_WAKEUP      (1 << 1)
@@ -49,7 +52,8 @@ struct pm_qos_flags_request {
 };
 
 enum dev_pm_qos_req_type {
-       DEV_PM_QOS_LATENCY = 1,
+       DEV_PM_QOS_RESUME_LATENCY = 1,
+       DEV_PM_QOS_LATENCY_TOLERANCE,
        DEV_PM_QOS_FLAGS,
 };
 
@@ -77,6 +81,7 @@ struct pm_qos_constraints {
        struct plist_head list;
        s32 target_value;       /* Do not change to 64 bit */
        s32 default_value;
+       s32 no_constraint_value;
        enum pm_qos_type type;
        struct blocking_notifier_head *notifiers;
 };
@@ -87,9 +92,11 @@ struct pm_qos_flags {
 };
 
 struct dev_pm_qos {
-       struct pm_qos_constraints latency;
+       struct pm_qos_constraints resume_latency;
+       struct pm_qos_constraints latency_tolerance;
        struct pm_qos_flags flags;
-       struct dev_pm_qos_request *latency_req;
+       struct dev_pm_qos_request *resume_latency_req;
+       struct dev_pm_qos_request *latency_tolerance_req;
        struct dev_pm_qos_request *flags_req;
 };
 
@@ -142,7 +149,8 @@ int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
 void dev_pm_qos_constraints_init(struct device *dev);
 void dev_pm_qos_constraints_destroy(struct device *dev);
 int dev_pm_qos_add_ancestor_request(struct device *dev,
-                                   struct dev_pm_qos_request *req, s32 value);
+                                   struct dev_pm_qos_request *req,
+                                   enum dev_pm_qos_req_type type, s32 value);
 #else
 static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
                                                          s32 mask)
@@ -185,7 +193,9 @@ static inline void dev_pm_qos_constraints_destroy(struct device *dev)
        dev->power.power_state = PMSG_INVALID;
 }
 static inline int dev_pm_qos_add_ancestor_request(struct device *dev,
-                                   struct dev_pm_qos_request *req, s32 value)
+                                                 struct dev_pm_qos_request *req,
+                                                 enum dev_pm_qos_req_type type,
+                                                 s32 value)
                        { return 0; }
 #endif
 
@@ -195,10 +205,12 @@ void dev_pm_qos_hide_latency_limit(struct device *dev);
 int dev_pm_qos_expose_flags(struct device *dev, s32 value);
 void dev_pm_qos_hide_flags(struct device *dev);
 int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set);
+s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev);
+int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val);
 
-static inline s32 dev_pm_qos_requested_latency(struct device *dev)
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
 {
-       return dev->power.qos->latency_req->data.pnode.prio;
+       return dev->power.qos->resume_latency_req->data.pnode.prio;
 }
 
 static inline s32 dev_pm_qos_requested_flags(struct device *dev)
@@ -214,8 +226,12 @@ static inline int dev_pm_qos_expose_flags(struct device *dev, s32 value)
 static inline void dev_pm_qos_hide_flags(struct device *dev) {}
 static inline int dev_pm_qos_update_flags(struct device *dev, s32 m, bool set)
                        { return 0; }
+static inline s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
+                       { return PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; }
+static inline int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
+                       { return 0; }
 
-static inline s32 dev_pm_qos_requested_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
 static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
 #endif
 
index 16c9a62fa1c0f0650edcdc5d258a0cca6a7b8ad9..2a5897a4afbc29e8eb52ce45f808fb4fc3107821 100644 (file)
 #ifdef CONFIG_PM
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
+extern int pm_runtime_force_suspend(struct device *dev);
+extern int pm_runtime_force_resume(struct device *dev);
 #else
 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 int pm_runtime_force_suspend(struct device *dev) { return 0; }
+static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
index dbaf9908411217c57a257309c5949e8d4b76ff5b..8183b46fbaa2d6da9817ead257735396a6ec7b0c 100644 (file)
@@ -247,9 +247,10 @@ static inline void list_splice_init_rcu(struct list_head *list,
  * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
  */
 #define list_entry_rcu(ptr, type, member) \
-       ({typeof (*ptr) __rcu *__ptr = (typeof (*ptr) __rcu __force *)ptr; \
-        container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
-       })
+({ \
+       typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \
+       container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
+})
 
 /**
  * Where are list_empty_rcu() and list_first_entry_rcu()?
@@ -285,11 +286,11 @@ static inline void list_splice_init_rcu(struct list_head *list,
  * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
  */
 #define list_first_or_null_rcu(ptr, type, member) \
-       ({struct list_head *__ptr = (ptr); \
-         struct list_head *__next = ACCESS_ONCE(__ptr->next); \
-         likely(__ptr != __next) ? \
-               list_entry_rcu(__next, type, member) : NULL; \
-       })
+({ \
+       struct list_head *__ptr = (ptr); \
+       struct list_head *__next = ACCESS_ONCE(__ptr->next); \
+       likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
+})
 
 /**
  * list_for_each_entry_rcu     -       iterate over rcu list of given type
index 72bf3a01a4ee67ac8908212c3de3897d383a2161..00a7fd61b3c6540521109c4c79e412a0833bef02 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2001
  *
@@ -44,7 +44,9 @@
 #include <linux/debugobjects.h>
 #include <linux/bug.h>
 #include <linux/compiler.h>
+#include <asm/barrier.h>
 
+extern int rcu_expedited; /* for sysctl */
 #ifdef CONFIG_RCU_TORTURE_TEST
 extern int rcutorture_runnable; /* for sysctl */
 #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
@@ -314,7 +316,7 @@ static inline bool rcu_lockdep_current_cpu_online(void)
 
 static inline void rcu_lock_acquire(struct lockdep_map *map)
 {
-       lock_acquire(map, 0, 0, 2, 1, NULL, _THIS_IP_);
+       lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
 }
 
 static inline void rcu_lock_release(struct lockdep_map *map)
@@ -479,11 +481,9 @@ static inline void rcu_preempt_sleep_check(void)
        do {                                                            \
                rcu_preempt_sleep_check();                              \
                rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map),     \
-                                  "Illegal context switch in RCU-bh"   \
-                                  " read-side critical section");      \
+                                  "Illegal context switch in RCU-bh read-side critical section"); \
                rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map),  \
-                                  "Illegal context switch in RCU-sched"\
-                                  " read-side critical section");      \
+                                  "Illegal context switch in RCU-sched read-side critical section"); \
        } while (0)
 
 #else /* #ifdef CONFIG_PROVE_RCU */
@@ -510,43 +510,40 @@ static inline void rcu_preempt_sleep_check(void)
 #endif /* #else #ifdef __CHECKER__ */
 
 #define __rcu_access_pointer(p, space) \
-       ({ \
-               typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
-               rcu_dereference_sparse(p, space); \
-               ((typeof(*p) __force __kernel *)(_________p1)); \
-       })
+({ \
+       typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \
+       rcu_dereference_sparse(p, space); \
+       ((typeof(*p) __force __kernel *)(_________p1)); \
+})
 #define __rcu_dereference_check(p, c, space) \
-       ({ \
-               typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
-               rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
-                                     " usage"); \
-               rcu_dereference_sparse(p, space); \
-               smp_read_barrier_depends(); \
-               ((typeof(*p) __force __kernel *)(_________p1)); \
-       })
+({ \
+       typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \
+       rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \
+       rcu_dereference_sparse(p, space); \
+       smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
+       ((typeof(*p) __force __kernel *)(_________p1)); \
+})
 #define __rcu_dereference_protected(p, c, space) \
-       ({ \
-               rcu_lockdep_assert(c, "suspicious rcu_dereference_protected()" \
-                                     " usage"); \
-               rcu_dereference_sparse(p, space); \
-               ((typeof(*p) __force __kernel *)(p)); \
-       })
+({ \
+       rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \
+       rcu_dereference_sparse(p, space); \
+       ((typeof(*p) __force __kernel *)(p)); \
+})
 
 #define __rcu_access_index(p, space) \
-       ({ \
-               typeof(p) _________p1 = ACCESS_ONCE(p); \
-               rcu_dereference_sparse(p, space); \
-               (_________p1); \
-       })
+({ \
+       typeof(p) _________p1 = ACCESS_ONCE(p); \
+       rcu_dereference_sparse(p, space); \
+       (_________p1); \
+})
 #define __rcu_dereference_index_check(p, c) \
-       ({ \
-               typeof(p) _________p1 = ACCESS_ONCE(p); \
-               rcu_lockdep_assert(c, \
-                                  "suspicious rcu_dereference_index_check()" \
-                                  " usage"); \
-               smp_read_barrier_depends(); \
-               (_________p1); \
-       })
+({ \
+       typeof(p) _________p1 = ACCESS_ONCE(p); \
+       rcu_lockdep_assert(c, \
+                          "suspicious rcu_dereference_index_check() usage"); \
+       smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
+       (_________p1); \
+})
 
 /**
  * RCU_INITIALIZER() - statically initialize an RCU-protected global variable
@@ -585,12 +582,7 @@ static inline void rcu_preempt_sleep_check(void)
  * please be careful when making changes to rcu_assign_pointer() and the
  * other macros that it invokes.
  */
-#define rcu_assign_pointer(p, v) \
-       do { \
-               smp_wmb(); \
-               ACCESS_ONCE(p) = RCU_INITIALIZER(v); \
-       } while (0)
-
+#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v))
 
 /**
  * rcu_access_pointer() - fetch RCU pointer with no dereferencing
@@ -1015,11 +1007,21 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
 #define kfree_rcu(ptr, rcu_head)                                       \
        __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
 
-#ifdef CONFIG_RCU_NOCB_CPU
+#if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL)
+static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
+{
+       *delta_jiffies = ULONG_MAX;
+       return 0;
+}
+#endif /* #if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) */
+
+#if defined(CONFIG_RCU_NOCB_CPU_ALL)
+static inline bool rcu_is_nocb_cpu(int cpu) { return true; }
+#elif defined(CONFIG_RCU_NOCB_CPU)
 bool rcu_is_nocb_cpu(int cpu);
 #else
 static inline bool rcu_is_nocb_cpu(int cpu) { return false; }
-#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
+#endif
 
 
 /* Only for use by adaptive-ticks code. */
index 6f01771b571c00eede5aaae145fdcf7382e61cd9..425c659d54e576a1991aa9aa2d777ee001d66546 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
  *
 
 #include <linux/cache.h>
 
+static inline unsigned long get_state_synchronize_rcu(void)
+{
+       return 0;
+}
+
+static inline void cond_synchronize_rcu(unsigned long oldstate)
+{
+       might_sleep();
+}
+
 static inline void rcu_barrier_bh(void)
 {
        wait_rcu_gp(call_rcu_bh);
@@ -68,12 +78,6 @@ static inline void kfree_call_rcu(struct rcu_head *head,
        call_rcu(head, func);
 }
 
-static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
-{
-       *delta_jiffies = ULONG_MAX;
-       return 0;
-}
-
 static inline void rcu_note_context_switch(int cpu)
 {
        rcu_sched_qs(cpu);
index 72137ee8c603b2c0c45ea7f729211e12cfad3941..a59ca05fd4e36eca1de98e849f6e8b9855b37c82 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
  *
@@ -31,7 +31,9 @@
 #define __LINUX_RCUTREE_H
 
 void rcu_note_context_switch(int cpu);
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
 int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies);
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
 void rcu_cpu_stall_reset(void);
 
 /*
@@ -74,6 +76,8 @@ static inline void synchronize_rcu_bh_expedited(void)
 void rcu_barrier(void);
 void rcu_barrier_bh(void);
 void rcu_barrier_sched(void);
+unsigned long get_state_synchronize_rcu(void);
+void cond_synchronize_rcu(unsigned long oldstate);
 
 extern unsigned long rcutorture_testseq;
 extern unsigned long rcutorture_vernum;
index 4149f1a9b00320dfeea8768817b2adbd2d1a4da2..85691b9b4fa76a778db7f338874849c27d99d74c 100644 (file)
@@ -164,6 +164,9 @@ typedef void (*regmap_unlock)(void *);
  * @use_single_rw: If set, converts the bulk read and write operations into
  *                 a series of single read and write operations. This is useful
  *                 for device that does not support bulk read and write.
+ * @can_multi_write: If set, the device supports the multi write mode of bulk
+ *                   write operations, if clear multi write requests will be
+ *                   split into individual write operations
  *
  * @cache_type: The actual cache type.
  * @reg_defaults_raw: Power on reset values for registers (for use with
@@ -215,6 +218,7 @@ struct regmap_config {
        u8 write_flag_mask;
 
        bool use_single_rw;
+       bool can_multi_write;
 
        enum regmap_endian reg_format_endian;
        enum regmap_endian val_format_endian;
@@ -317,12 +321,16 @@ struct regmap *regmap_init(struct device *dev,
                           const struct regmap_bus *bus,
                           void *bus_context,
                           const struct regmap_config *config);
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+                                const struct regmap_config *config);
 struct regmap *regmap_init_i2c(struct i2c_client *i2c,
                               const struct regmap_config *config);
 struct regmap *regmap_init_spi(struct spi_device *dev,
                               const struct regmap_config *config);
-struct regmap *regmap_init_spmi(struct spmi_device *dev,
-                              const struct regmap_config *config);
+struct regmap *regmap_init_spmi_base(struct spmi_device *dev,
+                                    const struct regmap_config *config);
+struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
+                                   const struct regmap_config *config);
 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
                                    void __iomem *regs,
                                    const struct regmap_config *config);
@@ -335,8 +343,10 @@ struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
                                    const struct regmap_config *config);
 struct regmap *devm_regmap_init_spi(struct spi_device *dev,
                                    const struct regmap_config *config);
-struct regmap *devm_regmap_init_spmi(struct spmi_device *dev,
-                                    const struct regmap_config *config);
+struct regmap *devm_regmap_init_spmi_base(struct spmi_device *dev,
+                                         const struct regmap_config *config);
+struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
+                                        const struct regmap_config *config);
 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
                                         void __iomem *regs,
                                         const struct regmap_config *config);
@@ -386,8 +396,11 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
                     const void *val, size_t val_len);
 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
                        size_t val_count);
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
                        int num_regs);
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+                                   const struct reg_default *regs,
+                                   int num_regs);
 int regmap_raw_write_async(struct regmap *map, unsigned int reg,
                           const void *val, size_t val_len);
 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
@@ -423,6 +436,8 @@ bool regmap_check_range_table(struct regmap *map, unsigned int reg,
 
 int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                          int num_regs);
+int regmap_parse_val(struct regmap *map, const void *buf,
+                               unsigned int *val);
 
 static inline bool regmap_reg_in_range(unsigned int reg,
                                       const struct regmap_range *range)
@@ -695,6 +710,13 @@ static inline int regmap_register_patch(struct regmap *map,
        return -EINVAL;
 }
 
+static inline int regmap_parse_val(struct regmap *map, const void *buf,
+                               unsigned int *val)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
 static inline struct regmap *dev_get_regmap(struct device *dev,
                                            const char *name)
 {
index 9370e65348a40ba5a92620fbfe4cfed4305a3963..bbe03a1924c04182be79d128854557ebb262b6e3 100644 (file)
@@ -228,10 +228,14 @@ enum regulator_type {
  *                output when using regulator_set_voltage_sel_regmap
  * @enable_reg: Register for control when using regmap enable/disable ops
  * @enable_mask: Mask for control when using regmap enable/disable ops
+ * @enable_val: Enabling value for control when using regmap enable/disable ops
+ * @disable_val: Disabling value for control when using regmap enable/disable ops
  * @enable_is_inverted: A flag to indicate set enable_mask bits to disable
  *                      when using regulator_enable_regmap and friends APIs.
  * @bypass_reg: Register for control when using regmap set_bypass
  * @bypass_mask: Mask for control when using regmap set_bypass
+ * @bypass_val_on: Enabling value for control when using regmap set_bypass
+ * @bypass_val_off: Disabling value for control when using regmap set_bypass
  *
  * @enable_time: Time taken for initial enable of regulator (in uS).
  */
@@ -263,9 +267,13 @@ struct regulator_desc {
        unsigned int apply_bit;
        unsigned int enable_reg;
        unsigned int enable_mask;
+       unsigned int enable_val;
+       unsigned int disable_val;
        bool enable_is_inverted;
        unsigned int bypass_reg;
        unsigned int bypass_mask;
+       unsigned int bypass_val_on;
+       unsigned int bypass_val_off;
 
        unsigned int enable_time;
 };
index 65d550bf395474f8427f8d67a2eaa1bd2db20945..364f7a7c43db3db23e67805983e90b3dd0187837 100644 (file)
 #define PFUZE100_VGEN6         14
 #define PFUZE100_MAX_REGULATOR 15
 
+#define PFUZE200_SW1AB         0
+#define PFUZE200_SW2           1
+#define PFUZE200_SW3A          2
+#define PFUZE200_SW3B          3
+#define PFUZE200_SWBST         4
+#define PFUZE200_VSNVS         5
+#define PFUZE200_VREFDDR       6
+#define PFUZE200_VGEN1         7
+#define PFUZE200_VGEN2         8
+#define PFUZE200_VGEN3         9
+#define PFUZE200_VGEN4         10
+#define PFUZE200_VGEN5         11
+#define PFUZE200_VGEN6         12
+
 struct regulator_init_data;
 
 struct pfuze_regulator_platform_data {
index 1da693d51255d974c60ba4b50527fe3e1808c03d..b66c2110cb1ff045dec9e7b23ba15a142e0f84fb 100644 (file)
@@ -250,8 +250,7 @@ struct rmap_walk_control {
        int (*rmap_one)(struct page *page, struct vm_area_struct *vma,
                                        unsigned long addr, void *arg);
        int (*done)(struct page *page);
-       int (*file_nonlinear)(struct page *, struct address_space *,
-                                       struct vm_area_struct *vma);
+       int (*file_nonlinear)(struct page *, struct address_space *, void *arg);
        struct anon_vma *(*anon_lock)(struct page *page);
        bool (*invalid_vma)(struct vm_area_struct *vma, void *arg);
 };
index a781dec1cd0b58d219427fdc71b37574ac972ec8..7cb07fd266808835ca8d4309891f19567cbe7503 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <uapi/linux/sched.h>
 
+#include <linux/sched/prio.h>
+
 
 struct sched_param {
        int sched_priority;
@@ -27,7 +29,7 @@ struct sched_param {
 
 #include <asm/page.h>
 #include <asm/ptrace.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
 
 #include <linux/smp.h>
 #include <linux/sem.h>
@@ -292,10 +294,14 @@ extern int runqueue_is_locked(int cpu);
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
 extern void nohz_balance_enter_idle(int cpu);
 extern void set_cpu_sd_state_idle(void);
-extern int get_nohz_timer_target(void);
+extern int get_nohz_timer_target(int pinned);
 #else
 static inline void nohz_balance_enter_idle(int cpu) { }
 static inline void set_cpu_sd_state_idle(void) { }
+static inline int get_nohz_timer_target(int pinned)
+{
+       return smp_processor_id();
+}
 #endif
 
 /*
@@ -1077,6 +1083,7 @@ struct sched_entity {
 #endif
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+       int                     depth;
        struct sched_entity     *parent;
        /* rq on which this entity is (to be) queued: */
        struct cfs_rq           *cfs_rq;
@@ -1460,6 +1467,9 @@ struct task_struct {
        struct mutex perf_event_mutex;
        struct list_head perf_event_list;
 #endif
+#ifdef CONFIG_DEBUG_PREEMPT
+       unsigned long preempt_disable_ip;
+#endif
 #ifdef CONFIG_NUMA
        struct mempolicy *mempolicy;    /* Protected by alloc_lock */
        short il_next;
@@ -1470,9 +1480,10 @@ struct task_struct {
        unsigned int numa_scan_period;
        unsigned int numa_scan_period_max;
        int numa_preferred_nid;
-       int numa_migrate_deferred;
        unsigned long numa_migrate_retry;
        u64 node_stamp;                 /* migration stamp  */
+       u64 last_task_numa_placement;
+       u64 last_sum_exec_runtime;
        struct callback_head numa_work;
 
        struct list_head numa_entry;
@@ -1483,15 +1494,22 @@ struct task_struct {
         * Scheduling placement decisions are made based on the these counts.
         * The values remain static for the duration of a PTE scan
         */
-       unsigned long *numa_faults;
+       unsigned long *numa_faults_memory;
        unsigned long total_numa_faults;
 
        /*
         * numa_faults_buffer records faults per node during the current
-        * scan window. When the scan completes, the counts in numa_faults
-        * decay and these values are copied.
+        * scan window. When the scan completes, the counts in
+        * numa_faults_memory decay and these values are copied.
         */
-       unsigned long *numa_faults_buffer;
+       unsigned long *numa_faults_buffer_memory;
+
+       /*
+        * Track the nodes the process was running on when a NUMA hinting
+        * fault was incurred.
+        */
+       unsigned long *numa_faults_cpu;
+       unsigned long *numa_faults_buffer_cpu;
 
        /*
         * numa_faults_locality tracks if faults recorded during the last
@@ -1596,8 +1614,8 @@ extern void task_numa_fault(int last_node, int node, int pages, int flags);
 extern pid_t task_numa_group_id(struct task_struct *p);
 extern void set_numabalancing_state(bool enabled);
 extern void task_numa_free(struct task_struct *p);
-
-extern unsigned int sysctl_numa_balancing_migrate_deferred;
+extern bool should_numa_migrate_memory(struct task_struct *p, struct page *page,
+                                       int src_nid, int dst_cpu);
 #else
 static inline void task_numa_fault(int last_node, int node, int pages,
                                   int flags)
@@ -1613,6 +1631,11 @@ static inline void set_numabalancing_state(bool enabled)
 static inline void task_numa_free(struct task_struct *p)
 {
 }
+static inline bool should_numa_migrate_memory(struct task_struct *p,
+                               struct page *page, int src_nid, int dst_cpu)
+{
+       return true;
+}
 #endif
 
 static inline struct pid *task_pid(struct task_struct *task)
@@ -2080,7 +2103,16 @@ static inline void sched_autogroup_exit(struct signal_struct *sig) { }
 extern bool yield_to(struct task_struct *p, bool preempt);
 extern void set_user_nice(struct task_struct *p, long nice);
 extern int task_prio(const struct task_struct *p);
-extern int task_nice(const struct task_struct *p);
+/**
+ * task_nice - return the nice value of a given task.
+ * @p: the task in question.
+ *
+ * Return: The nice value [ -20 ... 0 ... 19 ].
+ */
+static inline int task_nice(const struct task_struct *p)
+{
+       return PRIO_TO_NICE((p)->static_prio);
+}
 extern int can_nice(const struct task_struct *p, const int nice);
 extern int task_curr(const struct task_struct *p);
 extern int idle_cpu(int cpu);
diff --git a/include/linux/sched/prio.h b/include/linux/sched/prio.h
new file mode 100644 (file)
index 0000000..ac32258
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _SCHED_PRIO_H
+#define _SCHED_PRIO_H
+
+#define MAX_NICE       19
+#define MIN_NICE       -20
+#define NICE_WIDTH     (MAX_NICE - MIN_NICE + 1)
+
+/*
+ * Priority of a process goes from 0..MAX_PRIO-1, valid RT
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
+ * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
+ * values are inverted: lower p->prio value means higher priority.
+ *
+ * The MAX_USER_RT_PRIO value allows the actual maximum
+ * RT priority to be separate from the value exported to
+ * user-space.  This allows kernel threads to set their
+ * priority to a value higher than any user task. Note:
+ * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
+ */
+
+#define MAX_USER_RT_PRIO       100
+#define MAX_RT_PRIO            MAX_USER_RT_PRIO
+
+#define MAX_PRIO               (MAX_RT_PRIO + NICE_WIDTH)
+#define DEFAULT_PRIO           (MAX_RT_PRIO + NICE_WIDTH / 2)
+
+/*
+ * Convert user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
+ * and back.
+ */
+#define NICE_TO_PRIO(nice)     ((nice) + DEFAULT_PRIO)
+#define PRIO_TO_NICE(prio)     ((prio) - DEFAULT_PRIO)
+
+/*
+ * 'User priority' is the nice value converted to something we
+ * can work with better when scaling various scheduler parameters,
+ * it's a [ 0 ... 39 ] range.
+ */
+#define USER_PRIO(p)           ((p)-MAX_RT_PRIO)
+#define TASK_USER_PRIO(p)      USER_PRIO((p)->static_prio)
+#define MAX_USER_PRIO          (USER_PRIO(MAX_PRIO))
+
+#endif /* _SCHED_PRIO_H */
index 34e4ebea8fce79efa8f1528747db18b7a11f75b4..6341f5be6e2474c0a7e30fdd75e3eae5b4286bf3 100644 (file)
@@ -1,24 +1,7 @@
 #ifndef _SCHED_RT_H
 #define _SCHED_RT_H
 
-/*
- * Priority of a process goes from 0..MAX_PRIO-1, valid RT
- * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
- * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
- * values are inverted: lower p->prio value means higher priority.
- *
- * The MAX_USER_RT_PRIO value allows the actual maximum
- * RT priority to be separate from the value exported to
- * user-space.  This allows kernel threads to set their
- * priority to a value higher than any user task. Note:
- * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
- */
-
-#define MAX_USER_RT_PRIO       100
-#define MAX_RT_PRIO            MAX_USER_RT_PRIO
-
-#define MAX_PRIO               (MAX_RT_PRIO + 40)
-#define DEFAULT_PRIO           (MAX_RT_PRIO + 20)
+#include <linux/sched/prio.h>
 
 static inline int rt_prio(int prio)
 {
@@ -35,6 +18,7 @@ static inline int rt_task(struct task_struct *p)
 #ifdef CONFIG_RT_MUTEXES
 extern int rt_mutex_getprio(struct task_struct *p);
 extern void rt_mutex_setprio(struct task_struct *p, int prio);
+extern int rt_mutex_check_prio(struct task_struct *task, int newprio);
 extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task);
 extern void rt_mutex_adjust_pi(struct task_struct *p);
 static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
@@ -46,6 +30,12 @@ static inline int rt_mutex_getprio(struct task_struct *p)
 {
        return p->normal_prio;
 }
+
+static inline int rt_mutex_check_prio(struct task_struct *task, int newprio)
+{
+       return 0;
+}
+
 static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
 {
        return NULL;
index 5623a7f965b7bbb07ab94a72351aec027ef4adb7..2fc42d191f79f77236b843a70775129c01207333 100644 (file)
@@ -1040,6 +1040,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Allocate a security structure to the xp->security field; the security
  *     field is initialized to NULL when the xfrm_policy is allocated.
  *     Return 0 if operation was successful (memory to allocate, legal context)
+ *     @gfp is to specify the context for the allocation
  * @xfrm_policy_clone_security:
  *     @old_ctx contains an existing xfrm_sec_ctx.
  *     @new_ctxp contains a new xfrm_sec_ctx being cloned from old.
@@ -1683,7 +1684,7 @@ struct security_operations {
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp,
-                       struct xfrm_user_sec_ctx *sec_ctx);
+                       struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
        int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
        void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
        int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
@@ -2859,7 +2860,8 @@ static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 
-int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx);
+int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                              struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
 int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp);
 void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
 int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
@@ -2877,7 +2879,9 @@ void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl);
 
 #else  /* CONFIG_SECURITY_NETWORK_XFRM */
 
-static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                                            struct xfrm_user_sec_ctx *sec_ctx,
+                                            gfp_t gfp)
 {
        return 0;
 }
index 3ebbbe7b6d05fadbccaf66bac9ad1d8cfe7c5c17..15ede6a823a6e2daa366551cd7bad13ac3dd5c03 100644 (file)
@@ -2451,8 +2451,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
                    unsigned int flags);
 void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
-void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
-                 int len, int hlen);
+int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
+                int len, int hlen);
 void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 void skb_scrub_packet(struct sk_buff *skb, bool xnet);
@@ -2725,7 +2725,7 @@ static inline void nf_reset(struct sk_buff *skb)
 
 static inline void nf_reset_trace(struct sk_buff *skb)
 {
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
        skb->nf_trace = 0;
 #endif
 }
@@ -2742,6 +2742,9 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
        dst->nf_bridge  = src->nf_bridge;
        nf_bridge_get(src->nf_bridge);
 #endif
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
+       dst->nf_trace = src->nf_trace;
+#endif
 }
 
 static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
index 9260abdd67df801e002f18faf3f17bd00d494867..b5b2df60299e25c5c33b3be39ff90090c974689f 100644 (file)
@@ -410,7 +410,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
  *
  * %GFP_NOWAIT - Allocation will not sleep.
  *
- * %GFP_THISNODE - Allocate node-local memory only.
+ * %__GFP_THISNODE - Allocate node-local memory only.
  *
  * %GFP_DMA - Allocation suitable for DMA.
  *   Should only be used for kmalloc() caches. Otherwise, use a
index 4203c66d88033269692fa38ce50aebe17fee9419..36c86ef51ff32acc482ee0a4b835fb8a186d1ecc 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/slab.h>
 #include <linux/kthread.h>
 #include <linux/completion.h>
+#include <linux/scatterlist.h>
+
+struct dma_chan;
 
 /*
  * INTERFACES between SPI master-side drivers and SPI infrastructure.
@@ -266,6 +269,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  * @auto_runtime_pm: the core should ensure a runtime PM reference is held
  *                   while the hardware is prepared, using the parent
  *                   device for the spidev
+ * @max_dma_len: Maximum length of a DMA transfer for the device.
  * @prepare_transfer_hardware: a message will soon arrive from the queue
  *     so the subsystem requests the driver to prepare the transfer hardware
  *     by issuing this call
@@ -348,6 +352,8 @@ struct spi_master {
 #define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full duplex */
 #define SPI_MASTER_NO_RX       BIT(1)          /* can't do buffer read */
 #define SPI_MASTER_NO_TX       BIT(2)          /* can't do buffer write */
+#define SPI_MASTER_MUST_RX      BIT(3)         /* requires rx */
+#define SPI_MASTER_MUST_TX      BIT(4)         /* requires tx */
 
        /* lock and mutex for SPI bus locking */
        spinlock_t              bus_lock_spinlock;
@@ -389,6 +395,17 @@ struct spi_master {
        /* called on release() to free memory provided by spi_master */
        void                    (*cleanup)(struct spi_device *spi);
 
+       /*
+        * Used to enable core support for DMA handling, if can_dma()
+        * exists and returns true then the transfer will be mapped
+        * prior to transfer_one() being called.  The driver should
+        * not modify or store xfer and dma_tx and dma_rx must be set
+        * while the device is prepared.
+        */
+       bool                    (*can_dma)(struct spi_master *master,
+                                          struct spi_device *spi,
+                                          struct spi_transfer *xfer);
+
        /*
         * These hooks are for drivers that want to use the generic
         * master transfer queueing mechanism. If these are used, the
@@ -407,7 +424,9 @@ struct spi_master {
        bool                            rt;
        bool                            auto_runtime_pm;
        bool                            cur_msg_prepared;
+       bool                            cur_msg_mapped;
        struct completion               xfer_completion;
+       size_t                          max_dma_len;
 
        int (*prepare_transfer_hardware)(struct spi_master *master);
        int (*transfer_one_message)(struct spi_master *master,
@@ -428,6 +447,14 @@ struct spi_master {
 
        /* gpio chip select */
        int                     *cs_gpios;
+
+       /* DMA channels for use with core dmaengine helpers */
+       struct dma_chan         *dma_tx;
+       struct dma_chan         *dma_rx;
+
+       /* dummy data for full duplex devices */
+       void                    *dummy_rx;
+       void                    *dummy_tx;
 };
 
 static inline void *spi_master_get_devdata(struct spi_master *master)
@@ -512,6 +539,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
  *     (optionally) changing the chipselect status, then starting
  *     the next transfer or completing this @spi_message.
  * @transfer_list: transfers are sequenced through @spi_message.transfers
+ * @tx_sg: Scatterlist for transmit, currently not for client use
+ * @rx_sg: Scatterlist for receive, currently not for client use
  *
  * SPI transfers always write the same number of bytes as they read.
  * Protocol drivers should always provide @rx_buf and/or @tx_buf.
@@ -579,6 +608,8 @@ struct spi_transfer {
 
        dma_addr_t      tx_dma;
        dma_addr_t      rx_dma;
+       struct sg_table tx_sg;
+       struct sg_table rx_sg;
 
        unsigned        cs_change:1;
        unsigned        tx_nbits:3;
index daebaba886aa230e759f2d55f880c3277e19e10f..85578d4be0343ce9ac0bd3f1a9bbb2d349533b44 100644 (file)
@@ -42,6 +42,6 @@ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
 
 /* start or stop queue processing */
 extern int spi_bitbang_start(struct spi_bitbang *spi);
-extern int spi_bitbang_stop(struct spi_bitbang *spi);
+extern void spi_bitbang_stop(struct spi_bitbang *spi);
 
 #endif /* __SPI_BITBANG_H */
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
new file mode 100644 (file)
index 0000000..91f5eab
--- /dev/null
@@ -0,0 +1,191 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _LINUX_SPMI_H
+#define _LINUX_SPMI_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* Maximum slave identifier */
+#define SPMI_MAX_SLAVE_ID              16
+
+/* SPMI Commands */
+#define SPMI_CMD_EXT_WRITE             0x00
+#define SPMI_CMD_RESET                 0x10
+#define SPMI_CMD_SLEEP                 0x11
+#define SPMI_CMD_SHUTDOWN              0x12
+#define SPMI_CMD_WAKEUP                        0x13
+#define SPMI_CMD_AUTHENTICATE          0x14
+#define SPMI_CMD_MSTR_READ             0x15
+#define SPMI_CMD_MSTR_WRITE            0x16
+#define SPMI_CMD_TRANSFER_BUS_OWNERSHIP        0x1A
+#define SPMI_CMD_DDB_MASTER_READ       0x1B
+#define SPMI_CMD_DDB_SLAVE_READ                0x1C
+#define SPMI_CMD_EXT_READ              0x20
+#define SPMI_CMD_EXT_WRITEL            0x30
+#define SPMI_CMD_EXT_READL             0x38
+#define SPMI_CMD_WRITE                 0x40
+#define SPMI_CMD_READ                  0x60
+#define SPMI_CMD_ZERO_WRITE            0x80
+
+/**
+ * struct spmi_device - Basic representation of an SPMI device
+ * @dev:       Driver model representation of the device.
+ * @ctrl:      SPMI controller managing the bus hosting this device.
+ * @usid:      This devices' Unique Slave IDentifier.
+ */
+struct spmi_device {
+       struct device           dev;
+       struct spmi_controller  *ctrl;
+       u8                      usid;
+};
+
+static inline struct spmi_device *to_spmi_device(struct device *d)
+{
+       return container_of(d, struct spmi_device, dev);
+}
+
+static inline void *spmi_device_get_drvdata(const struct spmi_device *sdev)
+{
+       return dev_get_drvdata(&sdev->dev);
+}
+
+static inline void spmi_device_set_drvdata(struct spmi_device *sdev, void *data)
+{
+       dev_set_drvdata(&sdev->dev, data);
+}
+
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl);
+
+static inline void spmi_device_put(struct spmi_device *sdev)
+{
+       if (sdev)
+               put_device(&sdev->dev);
+}
+
+int spmi_device_add(struct spmi_device *sdev);
+
+void spmi_device_remove(struct spmi_device *sdev);
+
+/**
+ * struct spmi_controller - interface to the SPMI master controller
+ * @dev:       Driver model representation of the device.
+ * @nr:                board-specific number identifier for this controller/bus
+ * @cmd:       sends a non-data command sequence on the SPMI bus.
+ * @read_cmd:  sends a register read command sequence on the SPMI bus.
+ * @write_cmd: sends a register write command sequence on the SPMI bus.
+ */
+struct spmi_controller {
+       struct device           dev;
+       unsigned int            nr;
+       int     (*cmd)(struct spmi_controller *ctrl, u8 opcode, u8 sid);
+       int     (*read_cmd)(struct spmi_controller *ctrl, u8 opcode,
+                           u8 sid, u16 addr, u8 *buf, size_t len);
+       int     (*write_cmd)(struct spmi_controller *ctrl, u8 opcode,
+                            u8 sid, u16 addr, const u8 *buf, size_t len);
+};
+
+static inline struct spmi_controller *to_spmi_controller(struct device *d)
+{
+       return container_of(d, struct spmi_controller, dev);
+}
+
+static inline
+void *spmi_controller_get_drvdata(const struct spmi_controller *ctrl)
+{
+       return dev_get_drvdata(&ctrl->dev);
+}
+
+static inline void spmi_controller_set_drvdata(struct spmi_controller *ctrl,
+                                              void *data)
+{
+       dev_set_drvdata(&ctrl->dev, data);
+}
+
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+                                             size_t size);
+
+/**
+ * spmi_controller_put() - decrement controller refcount
+ * @ctrl       SPMI controller.
+ */
+static inline void spmi_controller_put(struct spmi_controller *ctrl)
+{
+       if (ctrl)
+               put_device(&ctrl->dev);
+}
+
+int spmi_controller_add(struct spmi_controller *ctrl);
+void spmi_controller_remove(struct spmi_controller *ctrl);
+
+/**
+ * struct spmi_driver - SPMI slave device driver
+ * @driver:    SPMI device drivers should initialize name and owner field of
+ *             this structure.
+ * @probe:     binds this driver to a SPMI device.
+ * @remove:    unbinds this driver from the SPMI device.
+ * @shutdown:  standard shutdown callback used during powerdown/halt.
+ * @suspend:   standard suspend callback used during system suspend.
+ * @resume:    standard resume callback used during system resume.
+ *
+ * If PM runtime support is desired for a slave, a device driver can call
+ * pm_runtime_put() from their probe() routine (and a balancing
+ * pm_runtime_get() in remove()).  PM runtime support for a slave is
+ * implemented by issuing a SLEEP command to the slave on runtime_suspend(),
+ * transitioning the slave into the SLEEP state.  On runtime_resume(), a WAKEUP
+ * command is sent to the slave to bring it back to ACTIVE.
+ */
+struct spmi_driver {
+       struct device_driver driver;
+       int     (*probe)(struct spmi_device *sdev);
+       void    (*remove)(struct spmi_device *sdev);
+};
+
+static inline struct spmi_driver *to_spmi_driver(struct device_driver *d)
+{
+       return container_of(d, struct spmi_driver, driver);
+}
+
+int spmi_driver_register(struct spmi_driver *sdrv);
+
+/**
+ * spmi_driver_unregister() - unregister an SPMI client driver
+ * @sdrv:      the driver to unregister
+ */
+static inline void spmi_driver_unregister(struct spmi_driver *sdrv)
+{
+       if (sdrv)
+               driver_unregister(&sdrv->driver);
+}
+
+#define module_spmi_driver(__spmi_driver) \
+       module_driver(__spmi_driver, spmi_driver_register, \
+                       spmi_driver_unregister)
+
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf);
+int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf,
+                          size_t len);
+int spmi_ext_register_readl(struct spmi_device *sdev, u16 addr, u8 *buf,
+                           size_t len);
+int spmi_register_write(struct spmi_device *sdev, u8 addr, u8 data);
+int spmi_register_zero_write(struct spmi_device *sdev, u8 data);
+int spmi_ext_register_write(struct spmi_device *sdev, u8 addr,
+                           const u8 *buf, size_t len);
+int spmi_ext_register_writel(struct spmi_device *sdev, u16 addr,
+                            const u8 *buf, size_t len);
+int spmi_command_reset(struct spmi_device *sdev);
+int spmi_command_sleep(struct spmi_device *sdev);
+int spmi_command_wakeup(struct spmi_device *sdev);
+int spmi_command_shutdown(struct spmi_device *sdev);
+
+#endif
index 9b058eecd40390b914d705809a1aabac3eff132b..a2783cb5d2753f6c6eb04e48086f461abedb8b6f 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright (C) IBM Corporation, 2006
  * Copyright (C) Fujitsu, 2012
index a747a77ea584aafb124ae230862360c8dd0b6073..1e67b7a5968c77c2f9290e48801971adc9c0f3fc 100644 (file)
@@ -98,6 +98,8 @@ struct sigaltstack;
 #define __MAP(n,...) __MAP##n(__VA_ARGS__)
 
 #define __SC_DECL(t, a)        t a
+#define __TYPE_IS_L(t) (__same_type((t)0, 0L))
+#define __TYPE_IS_UL(t)        (__same_type((t)0, 0UL))
 #define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL))
 #define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
 #define __SC_CAST(t, a)        (t) a
diff --git a/include/linux/torture.h b/include/linux/torture.h
new file mode 100644 (file)
index 0000000..b2e2b46
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Common functions for in-kernel torture tests.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+ */
+
+#ifndef __LINUX_TORTURE_H
+#define __LINUX_TORTURE_H
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/seqlock.h>
+#include <linux/lockdep.h>
+#include <linux/completion.h>
+#include <linux/debugobjects.h>
+#include <linux/bug.h>
+#include <linux/compiler.h>
+
+/* Definitions for a non-string torture-test module parameter. */
+#define torture_param(type, name, init, msg) \
+       static type name = init; \
+       module_param(name, type, 0444); \
+       MODULE_PARM_DESC(name, msg);
+
+#define TORTURE_FLAG "-torture:"
+#define TOROUT_STRING(s) \
+       pr_alert("%s" TORTURE_FLAG s "\n", torture_type)
+#define VERBOSE_TOROUT_STRING(s) \
+       do { if (verbose) pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s); } while (0)
+#define VERBOSE_TOROUT_ERRSTRING(s) \
+       do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0)
+
+/* Definitions for a non-string torture-test module parameter. */
+#define torture_parm(type, name, init, msg) \
+       static type name = init; \
+       module_param(name, type, 0444); \
+       MODULE_PARM_DESC(name, msg);
+
+/* Definitions for online/offline exerciser. */
+int torture_onoff_init(long ooholdoff, long oointerval);
+char *torture_onoff_stats(char *page);
+bool torture_onoff_failures(void);
+
+/* Low-rider random number generator. */
+struct torture_random_state {
+       unsigned long trs_state;
+       long trs_count;
+};
+#define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 }
+unsigned long torture_random(struct torture_random_state *trsp);
+
+/* Task shuffler, which causes CPUs to occasionally go idle. */
+void torture_shuffle_task_register(struct task_struct *tp);
+int torture_shuffle_init(long shuffint);
+
+/* Test auto-shutdown handling. */
+void torture_shutdown_absorb(const char *title);
+int torture_shutdown_init(int ssecs, void (*cleanup)(void));
+
+/* Task stuttering, which forces load/no-load transitions. */
+void stutter_wait(const char *title);
+int torture_stutter_init(int s);
+
+/* Initialization and cleanup. */
+void torture_init_begin(char *ttype, bool v, int *runnable);
+void torture_init_end(void);
+bool torture_cleanup(void);
+bool torture_must_stop(void);
+bool torture_must_stop_irq(void);
+void torture_kthread_stopping(char *title);
+int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m,
+                            char *f, struct task_struct **tp);
+void _torture_stop_kthread(char *m, struct task_struct **tp);
+
+#define torture_create_kthread(n, arg, tp) \
+       _torture_create_kthread(n, (arg), #n, "Creating " #n " task", \
+                               "Failed to create " #n, &(tp))
+#define torture_stop_kthread(n, tp) \
+       _torture_stop_kthread("Stopping " #n " task", &(tp))
+
+#endif /* __LINUX_TORTURE_H */
index accc497f8d729160b0234756e96d99607cf67f33..7159a0a933df2b016db23cdcd87487c19d5829d0 100644 (file)
@@ -60,6 +60,12 @@ struct tp_module {
        unsigned int num_tracepoints;
        struct tracepoint * const *tracepoints_ptrs;
 };
+bool trace_module_has_bad_taint(struct module *mod);
+#else
+static inline bool trace_module_has_bad_taint(struct module *mod)
+{
+       return false;
+}
 #endif /* CONFIG_MODULES */
 
 struct tracepoint_iter {
index c3fa807459967286c0407c18da294ca6d95ced42..2c14d9cdd57aac88eb3121a4271b7c5fe3909a56 100644 (file)
@@ -88,6 +88,7 @@
 #define cdc_ncm_data_intf_is_mbim(x)  ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
 
 struct cdc_ncm_ctx {
+       struct usb_cdc_ncm_ntb_parameters ncm_parm;
        struct hrtimer tx_timer;
        struct tasklet_struct bh;
 
index e303eef94dd5cea92d16d7ae63aa35f5c3f1d4bb..0662e98fef72b21fdabb7d14ac1fd71f2066a140 100644 (file)
@@ -30,7 +30,7 @@ struct usbnet {
        struct driver_info      *driver_info;
        const char              *driver_name;
        void                    *driver_priv;
-       wait_queue_head_t       *wait;
+       wait_queue_head_t       wait;
        struct mutex            phy_mutex;
        unsigned char           suspend_count;
        unsigned char           pkt_cnt, pkt_err;
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
deleted file mode 100644 (file)
index ed5cdeb..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- *  Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or (at
- *  your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#ifndef _LINUX_VIDEO_OUTPUT_H
-#define _LINUX_VIDEO_OUTPUT_H
-#include <linux/device.h>
-#include <linux/err.h>
-struct output_device;
-struct output_properties {
-       int (*set_state)(struct output_device *);
-       int (*get_status)(struct output_device *);
-};
-struct output_device {
-       int request_state;
-       struct output_properties *props;
-       struct device dev;
-};
-#define to_output_device(obj) container_of(obj, struct output_device, dev)
-#if    defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE)
-struct output_device *video_output_register(const char *name,
-       struct device *dev,
-       void *devdata,
-       struct output_properties *op);
-void video_output_unregister(struct output_device *dev);
-#else
-static struct output_device *video_output_register(const char *name,
-        struct device *dev,
-        void *devdata,
-        struct output_properties *op)
-{
-       return ERR_PTR(-ENODEV);
-}
-static void video_output_unregister(struct output_device *dev)
-{
-       return;
-}
-#endif
-#endif
index 704f4f652d0af8b28406154678ee38b5f98298bf..1b22c42e9c2d4f03bb2e16b32fbeb0c397b3e034 100644 (file)
@@ -177,20 +177,10 @@ struct execute_work {
 #define DECLARE_DEFERRABLE_WORK(n, f)                                  \
        struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, TIMER_DEFERRABLE)
 
-/*
- * initialize a work item's function pointer
- */
-#define PREPARE_WORK(_work, _func)                                     \
-       do {                                                            \
-               (_work)->func = (_func);                                \
-       } while (0)
-
-#define PREPARE_DELAYED_WORK(_work, _func)                             \
-       PREPARE_WORK(&(_work)->work, (_func))
-
 #ifdef CONFIG_DEBUG_OBJECTS_WORK
 extern void __init_work(struct work_struct *work, int onstack);
 extern void destroy_work_on_stack(struct work_struct *work);
+extern void destroy_delayed_work_on_stack(struct delayed_work *work);
 static inline unsigned int work_static(struct work_struct *work)
 {
        return *work_data_bits(work) & WORK_STRUCT_STATIC;
@@ -198,6 +188,7 @@ static inline unsigned int work_static(struct work_struct *work)
 #else
 static inline void __init_work(struct work_struct *work, int onstack) { }
 static inline void destroy_work_on_stack(struct work_struct *work) { }
+static inline void destroy_delayed_work_on_stack(struct delayed_work *work) { }
 static inline unsigned int work_static(struct work_struct *work) { return 0; }
 #endif
 
@@ -217,7 +208,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
                (_work)->data = (atomic_long_t) WORK_DATA_INIT();       \
                lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0); \
                INIT_LIST_HEAD(&(_work)->entry);                        \
-               PREPARE_WORK((_work), (_func));                         \
+               (_work)->func = (_func);                                \
        } while (0)
 #else
 #define __INIT_WORK(_work, _func, _onstack)                            \
@@ -225,7 +216,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
                __init_work((_work), _onstack);                         \
                (_work)->data = (atomic_long_t) WORK_DATA_INIT();       \
                INIT_LIST_HEAD(&(_work)->entry);                        \
-               PREPARE_WORK((_work), (_func));                         \
+               (_work)->func = (_func);                                \
        } while (0)
 #endif
 
@@ -295,17 +286,11 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
  * Documentation/workqueue.txt.
  */
 enum {
-       /*
-        * All wqs are now non-reentrant making the following flag
-        * meaningless.  Will be removed.
-        */
-       WQ_NON_REENTRANT        = 1 << 0, /* DEPRECATED */
-
        WQ_UNBOUND              = 1 << 1, /* not bound to any cpu */
        WQ_FREEZABLE            = 1 << 2, /* freeze during suspend */
        WQ_MEM_RECLAIM          = 1 << 3, /* may be used for memory reclaim */
        WQ_HIGHPRI              = 1 << 4, /* high priority */
-       WQ_CPU_INTENSIVE        = 1 << 5, /* cpu instensive workqueue */
+       WQ_CPU_INTENSIVE        = 1 << 5, /* cpu intensive workqueue */
        WQ_SYSFS                = 1 << 6, /* visible in sysfs, see wq_sysfs_register() */
 
        /*
@@ -602,21 +587,6 @@ static inline bool keventd_up(void)
        return system_wq != NULL;
 }
 
-/*
- * Like above, but uses del_timer() instead of del_timer_sync(). This means,
- * if it returns 0 the timer function may be running and the queueing is in
- * progress.
- */
-static inline bool __deprecated __cancel_delayed_work(struct delayed_work *work)
-{
-       bool ret;
-
-       ret = del_timer(&work->timer);
-       if (ret)
-               work_clear_pending(&work->work);
-       return ret;
-}
-
 /* used to be different but now identical to flush_work(), deprecated */
 static inline bool __deprecated flush_work_sync(struct work_struct *work)
 {
index 9650a3ffd2d2328f11859adc4a3169ae41b25442..b4956a5fcc3f117e9e4199a5ad7af94894fea859 100644 (file)
 #define IF_PREFIX_AUTOCONF     0x02
 
 enum {
+       INET6_IFADDR_STATE_PREDAD,
        INET6_IFADDR_STATE_DAD,
        INET6_IFADDR_STATE_POSTDAD,
+       INET6_IFADDR_STATE_ERRDAD,
        INET6_IFADDR_STATE_UP,
        INET6_IFADDR_STATE_DEAD,
 };
@@ -58,7 +60,7 @@ struct inet6_ifaddr {
        unsigned long           cstamp; /* created timestamp */
        unsigned long           tstamp; /* updated timestamp */
 
-       struct timer_list       dad_timer;
+       struct delayed_work     dad_work;
 
        struct inet6_dev        *idev;
        struct rt6_info         *rt;
index 48ed75c21260b8dd17e681021311bb8dae4f2617..e77c10405d515da16071461fe9f7385d8ac08556 100644 (file)
@@ -129,6 +129,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
 int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
                      struct ip_tunnel_parm *p);
 void ip_tunnel_setup(struct net_device *dev, int net_id);
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t);
 
 /* Extract dsfield from inner protocol */
 static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
index 5c3f7c3624aa00214572c47cd3b6dbb3777d93ee..b9586a137cadd38e8a36abcd34018cfe9b680047 100644 (file)
@@ -1488,6 +1488,11 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
  */
 #define sock_owned_by_user(sk) ((sk)->sk_lock.owned)
 
+static inline void sock_release_ownership(struct sock *sk)
+{
+       sk->sk_lock.owned = 0;
+}
+
 /*
  * Macro so as to not evaluate some arguments when
  * lockdep is not enabled.
@@ -2186,7 +2191,6 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
 {
 #define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL)                      | \
                           (1UL << SOCK_RCVTSTAMP)                      | \
-                          (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)       | \
                           (1UL << SOCK_TIMESTAMPING_SOFTWARE)          | \
                           (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)      | \
                           (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE))
index 56fc366da6d5183b536648e949769a118ba33677..743accec6c76e056547102a0b429418b8450af65 100644 (file)
@@ -480,20 +480,21 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 #ifdef CONFIG_SYN_COOKIES
 #include <linux/ktime.h>
 
-/* Syncookies use a monotonic timer which increments every 64 seconds.
+/* Syncookies use a monotonic timer which increments every 60 seconds.
  * This counter is used both as a hash input and partially encoded into
  * the cookie value.  A cookie is only validated further if the delta
  * between the current counter value and the encoded one is less than this,
- * i.e. a sent cookie is valid only at most for 128 seconds (or less if
+ * i.e. a sent cookie is valid only at most for 2*60 seconds (or less if
  * the counter advances immediately after a cookie is generated).
  */
 #define MAX_SYNCOOKIE_AGE 2
 
 static inline u32 tcp_cookie_time(void)
 {
-       struct timespec now;
-       getnstimeofday(&now);
-       return now.tv_sec >> 6; /* 64 seconds granularity */
+       u64 val = get_jiffies_64();
+
+       do_div(val, 60 * HZ);
+       return val;
 }
 
 u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th,
@@ -1303,7 +1304,8 @@ struct tcp_fastopen_request {
        /* Fast Open cookie. Size 0 means a cookie request */
        struct tcp_fastopen_cookie      cookie;
        struct msghdr                   *data;  /* data in MSG_FASTOPEN */
-       u16                             copied; /* queued in tcp_connect() */
+       size_t                          size;
+       int                             copied; /* queued in tcp_connect() */
 };
 void tcp_free_fastopen_req(struct tcp_sock *tp);
 
index afa5730fb3bd2ff810f63f861f1b52b29e34c965..fb5654a8ca3cee1c65923c105f3760d607eaa1de 100644 (file)
@@ -1648,6 +1648,11 @@ static inline int xfrm_aevent_is_on(struct net *net)
 }
 #endif
 
+static inline int aead_len(struct xfrm_algo_aead *alg)
+{
+       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
 static inline int xfrm_alg_len(const struct xfrm_algo *alg)
 {
        return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
@@ -1686,6 +1691,12 @@ static inline int xfrm_replay_clone(struct xfrm_state *x,
        return 0;
 }
 
+static inline struct xfrm_algo_aead *xfrm_algo_aead_clone(struct xfrm_algo_aead *orig)
+{
+       return kmemdup(orig, aead_len(orig), GFP_KERNEL);
+}
+
+
 static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
 {
        return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
index f843dd8722a97eb9ca7106c6e09f8dd43a6e903c..ef7872c20da9e5f2d16c5a950b0abd0d9e9e53b2 100644 (file)
@@ -172,7 +172,6 @@ struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
         u8     port_no;        /* port number, if this is a PM (Port) */
-       int    pm_result;
 
        struct ata_port *ap;
        struct ata_host ata_host;
index 2a14f1f02d4f6766e236b288f6173ee7391e78a2..d3f5f818e0b901909f1ad8c92f8d0930b338cd78 100644 (file)
@@ -22,6 +22,7 @@
  *
  */
 
+#include <linux/device.h>
 #include <linux/sched.h>               /* wake_up() */
 #include <linux/mutex.h>               /* struct mutex */
 #include <linux/rwsem.h>               /* struct rw_semaphore */
 /* forward declarations */
 struct pci_dev;
 struct module;
-struct device;
-struct device_attribute;
+struct completion;
 
 /* device allocation stuff */
 
-#define SNDRV_DEV_TYPE_RANGE_SIZE              0x1000
-
-typedef int __bitwise snd_device_type_t;
-#define        SNDRV_DEV_TOPLEVEL      ((__force snd_device_type_t) 0)
-#define        SNDRV_DEV_CONTROL       ((__force snd_device_type_t) 1)
-#define        SNDRV_DEV_LOWLEVEL_PRE  ((__force snd_device_type_t) 2)
-#define        SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
-#define        SNDRV_DEV_PCM           ((__force snd_device_type_t) 0x1001)
-#define        SNDRV_DEV_RAWMIDI       ((__force snd_device_type_t) 0x1002)
-#define        SNDRV_DEV_TIMER         ((__force snd_device_type_t) 0x1003)
-#define        SNDRV_DEV_SEQUENCER     ((__force snd_device_type_t) 0x1004)
-#define        SNDRV_DEV_HWDEP         ((__force snd_device_type_t) 0x1005)
-#define        SNDRV_DEV_INFO          ((__force snd_device_type_t) 0x1006)
-#define        SNDRV_DEV_BUS           ((__force snd_device_type_t) 0x1007)
-#define        SNDRV_DEV_CODEC         ((__force snd_device_type_t) 0x1008)
-#define        SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
-#define        SNDRV_DEV_COMPRESS      ((__force snd_device_type_t) 0x100A)
-#define        SNDRV_DEV_LOWLEVEL      ((__force snd_device_type_t) 0x2000)
-
-typedef int __bitwise snd_device_state_t;
-#define        SNDRV_DEV_BUILD         ((__force snd_device_state_t) 0)
-#define        SNDRV_DEV_REGISTERED    ((__force snd_device_state_t) 1)
-#define        SNDRV_DEV_DISCONNECTED  ((__force snd_device_state_t) 2)
-
-typedef int __bitwise snd_device_cmd_t;
-#define        SNDRV_DEV_CMD_PRE       ((__force snd_device_cmd_t) 0)
-#define        SNDRV_DEV_CMD_NORMAL    ((__force snd_device_cmd_t) 1)  
-#define        SNDRV_DEV_CMD_POST      ((__force snd_device_cmd_t) 2)
+/* type of the object used in snd_device_*()
+ * this also defines the calling order
+ */
+enum snd_device_type {
+       SNDRV_DEV_LOWLEVEL,
+       SNDRV_DEV_CONTROL,
+       SNDRV_DEV_INFO,
+       SNDRV_DEV_BUS,
+       SNDRV_DEV_CODEC,
+       SNDRV_DEV_PCM,
+       SNDRV_DEV_COMPRESS,
+       SNDRV_DEV_RAWMIDI,
+       SNDRV_DEV_TIMER,
+       SNDRV_DEV_SEQUENCER,
+       SNDRV_DEV_HWDEP,
+       SNDRV_DEV_JACK,
+};
+
+enum snd_device_state {
+       SNDRV_DEV_BUILD,
+       SNDRV_DEV_REGISTERED,
+       SNDRV_DEV_DISCONNECTED,
+};
 
 struct snd_device;
 
@@ -86,8 +81,8 @@ struct snd_device_ops {
 struct snd_device {
        struct list_head list;          /* list of registered devices */
        struct snd_card *card;          /* card which holds this device */
-       snd_device_state_t state;       /* state of the device */
-       snd_device_type_t type;         /* device type */
+       enum snd_device_state state;    /* state of the device */
+       enum snd_device_type type;      /* device type */
        void *device_data;              /* device structure */
        struct snd_device_ops *ops;     /* operations */
 };
@@ -131,11 +126,10 @@ struct snd_card {
                                                                state */
        spinlock_t files_lock;          /* lock the files for this card */
        int shutdown;                   /* this card is going down */
-       int free_on_last_close;         /* free in context of file_release */
-       wait_queue_head_t shutdown_sleep;
-       atomic_t refcount;              /* refcount for disconnection */
+       struct completion *release_completion;
        struct device *dev;             /* device assigned to this card */
-       struct device *card_dev;        /* cardX object for sysfs */
+       struct device card_dev;         /* cardX object for sysfs */
+       bool registered;                /* card_dev is registered? */
 
 #ifdef CONFIG_PM
        unsigned int power_state;       /* power state */
@@ -149,6 +143,8 @@ struct snd_card {
 #endif
 };
 
+#define dev_to_snd_card(p)     container_of(p, struct snd_card, card_dev)
+
 #ifdef CONFIG_PM
 static inline void snd_power_lock(struct snd_card *card)
 {
@@ -197,7 +193,7 @@ struct snd_minor {
 /* return a device pointer linked to each sound device as a parent */
 static inline struct device *snd_card_get_device_link(struct snd_card *card)
 {
-       return card ? card->card_dev : NULL;
+       return card ? &card->card_dev : NULL;
 }
 
 /* sound.c */
@@ -244,13 +240,11 @@ static inline int snd_register_device(int type, struct snd_card *card, int dev,
 
 int snd_unregister_device(int type, struct snd_card *card, int dev);
 void *snd_lookup_minor_data(unsigned int minor, int type);
-int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
-                             struct device_attribute *attr);
+struct device *snd_get_device(int type, struct snd_card *card, int dev);
 
 #ifdef CONFIG_SND_OSSEMUL
 int snd_register_oss_device(int type, struct snd_card *card, int dev,
-                           const struct file_operations *f_ops, void *private_data,
-                           const char *name);
+                           const struct file_operations *f_ops, void *private_data);
 int snd_unregister_oss_device(int type, struct snd_card *card, int dev);
 void *snd_lookup_oss_minor_data(unsigned int minor, int type);
 #endif
@@ -284,9 +278,16 @@ int snd_card_locked(int card);
 extern int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int cmd);
 #endif
 
-int snd_card_create(int idx, const char *id,
-                   struct module *module, int extra_size,
-                   struct snd_card **card_ret);
+int snd_card_new(struct device *parent, int idx, const char *xid,
+                struct module *module, int extra_size,
+                struct snd_card **card_ret);
+
+static inline int __deprecated
+snd_card_create(int idx, const char *id, struct module *module, int extra_size,
+               struct snd_card **ret)
+{
+       return snd_card_new(NULL, idx, id, module, extra_size, ret);
+}
 
 int snd_card_disconnect(struct snd_card *card);
 int snd_card_free(struct snd_card *card);
@@ -298,20 +299,19 @@ int snd_card_info_done(void);
 int snd_component_add(struct snd_card *card, const char *component);
 int snd_card_file_add(struct snd_card *card, struct file *file);
 int snd_card_file_remove(struct snd_card *card, struct file *file);
-void snd_card_unref(struct snd_card *card);
+#define snd_card_unref(card)   put_device(&(card)->card_dev)
 
 #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
 
 /* device.c */
 
-int snd_device_new(struct snd_card *card, snd_device_type_t type,
+int snd_device_new(struct snd_card *card, enum snd_device_type type,
                   void *device_data, struct snd_device_ops *ops);
 int snd_device_register(struct snd_card *card, void *device_data);
 int snd_device_register_all(struct snd_card *card);
-int snd_device_disconnect(struct snd_card *card, void *device_data);
 int snd_device_disconnect_all(struct snd_card *card);
-int snd_device_free(struct snd_card *card, void *device_data);
-int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd);
+void snd_device_free(struct snd_card *card, void *device_data);
+void snd_device_free_all(struct snd_card *card);
 
 /* isadma.c */
 
@@ -433,7 +433,6 @@ static inline void snd_printdd(const char *format, ...) {}
 #define gameport_get_port_data(gp) (gp)->port_data
 #endif
 
-#ifdef CONFIG_PCI
 /* PCI quirk list helper */
 struct snd_pci_quirk {
        unsigned short subvendor;       /* PCI subvendor ID */
@@ -469,12 +468,26 @@ struct snd_pci_quirk {
 #define snd_pci_quirk_name(q)  ""
 #endif
 
+#ifdef CONFIG_PCI
 const struct snd_pci_quirk *
 snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
 
 const struct snd_pci_quirk *
 snd_pci_quirk_lookup_id(u16 vendor, u16 device,
                        const struct snd_pci_quirk *list);
+#else
+static inline const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+       return NULL;
+}
+
+static inline const struct snd_pci_quirk *
+snd_pci_quirk_lookup_id(u16 vendor, u16 device,
+                       const struct snd_pci_quirk *list)
+{
+       return NULL;
+}
 #endif
 
 #endif /* __SOUND_CORE_H */
index dfb42ca6d0436539ada89bcd063c26e5c4e85d86..c46908c1bb3f006268222f5c57af257aa3e76ef1 100644 (file)
 #define CCCA_CURRADDR_MASK     0x00ffffff      /* Current address of the selected channel              */
 #define CCCA_CURRADDR          0x18000008
 
-/* undefine CCR to avoid conflict with the definition for SH */
-#undef CCR
 #define CCR                    0x09            /* Cache control register                               */
 #define CCR_CACHEINVALIDSIZE   0x07190009
 #define CCR_CACHEINVALIDSIZE_MASK      0xfe000000      /* Number of invalid samples cache for this channel     */
index 8c05e47a409053c69ddec36b60aee44b84907330..ae04a3ec9c774e6ba41508e595535b92216dce8e 100644 (file)
@@ -60,7 +60,6 @@ struct snd_hwdep {
        int iface;
 
 #ifdef CONFIG_SND_OSSEMUL
-       char oss_dev[32];
        int oss_type;
        int ossreg;
 #endif
@@ -69,6 +68,8 @@ struct snd_hwdep {
        wait_queue_head_t open_wait;
        void *private_data;
        void (*private_free) (struct snd_hwdep *hwdep);
+       struct device *dev;
+       const struct attribute_group **groups;
 
        struct mutex open_mutex;
        int used;                       /* reference counter */
index 4883499ab38b07834dc6b4ee3fe085bf93b0efdf..b4d6697085fef71c2d31160c58ed70ff0f350686 100644 (file)
@@ -1141,4 +1141,12 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
        return 1ULL << (__force int) pcm_format;
 }
 
+/* printk helpers */
+#define pcm_err(pcm, fmt, args...) \
+       dev_err((pcm)->card->dev, fmt, ##args)
+#define pcm_warn(pcm, fmt, args...) \
+       dev_warn((pcm)->card->dev, fmt, ##args)
+#define pcm_dbg(pcm, fmt, args...) \
+       dev_dbg((pcm)->card->dev, fmt, ##args)
+
 #endif /* __SOUND_PCM_H */
index adf0885153f358ee5697d18e640e174c024e1b72..311dafe6cc4b508ecc372ba45d8f647d55b44f9c 100644 (file)
@@ -157,10 +157,8 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
 
 /* callbacks */
 
-void snd_rawmidi_receive_reset(struct snd_rawmidi_substream *substream);
 int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
                        const unsigned char *buffer, int count);
-void snd_rawmidi_transmit_reset(struct snd_rawmidi_substream *substream);
 int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream);
 int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                              unsigned char *buffer, int count);
index 6add6ccc811e508766e1656164ea9ee09dc50aeb..34a3c02a4576d502f56f4f0840953631a1a5033a 100644 (file)
  * B : SSI direction
  */
 #define RSND_SSI_CLK_PIN_SHARE         (1 << 31)
-#define RSND_SSI_SYNC                  (1 << 29) /* SSI34_sync etc */
-
 #define RSND_SSI_PLAY                  (1 << 24)
 
+#define RSND_SSI(_dma_id, _pio_irq, _flags)            \
+{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
 #define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags)       \
 { .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
 #define RSND_SSI_UNUSED \
 { .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
 
 struct rsnd_ssi_platform_info {
-       int dai_id;
+       int dai_id;     /* will be removed */
        int dma_id;
        int pio_irq;
        u32 flags;
@@ -55,9 +55,31 @@ struct rsnd_ssi_platform_info {
  */
 #define RSND_SCU_USE_HPBIF             (1 << 31) /* it needs RSND_SSI_DEPENDENT */
 
-struct rsnd_scu_platform_info {
+#define RSND_SRC(rate, _dma_id)                                                \
+{ .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, }
+#define RSND_SRC_SET(rate, _dma_id)            \
+       { .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, }
+#define RSND_SRC_UNUSED                                \
+       { .flags = 0, .convert_rate = 0, .dma_id = 0, }
+
+#define rsnd_scu_platform_info rsnd_src_platform_info
+#define src_info               scu_info
+#define src_info_nr            scu_info_nr
+
+struct rsnd_src_platform_info {
        u32 flags;
        u32 convert_rate; /* sampling rate convert */
+       int dma_id; /* for Gen2 SCU */
+};
+
+struct rsnd_dai_path_info {
+       struct rsnd_ssi_platform_info *ssi;
+       struct rsnd_src_platform_info *src;
+};
+
+struct rsnd_dai_platform_info {
+       struct rsnd_dai_path_info playback;
+       struct rsnd_dai_path_info capture;
 };
 
 /*
@@ -75,8 +97,10 @@ struct rcar_snd_info {
        u32 flags;
        struct rsnd_ssi_platform_info *ssi_info;
        int ssi_info_nr;
-       struct rsnd_scu_platform_info *scu_info;
-       int scu_info_nr;
+       struct rsnd_src_platform_info *src_info;
+       int src_info_nr;
+       struct rsnd_dai_platform_info *dai_info;
+       int dai_info_nr;
        int (*start)(int id);
        int (*stop)(int id);
 };
index 6c74527d4926b3e476428fb6327652d9ca22dfbb..9b0ac77177b6e3aa13156822a2c23f61635e56bd 100644 (file)
@@ -18,6 +18,8 @@ struct asoc_simple_dai {
        const char *name;
        unsigned int fmt;
        unsigned int sysclk;
+       int slots;
+       int slot_width;
 };
 
 struct asoc_simple_card_info {
@@ -29,10 +31,6 @@ struct asoc_simple_card_info {
        unsigned int daifmt;
        struct asoc_simple_dai cpu_dai;
        struct asoc_simple_dai codec_dai;
-
-       /* used in simple-card.c */
-       struct snd_soc_dai_link snd_link;
-       struct snd_soc_card snd_card;
 };
 
 #endif /* __SIMPLE_CARD_H */
index 71f27c403194f19ed26a189bfed3252f7177747b..fad76769f153d8cfdec2b796d892d6d0f3783798 100644 (file)
@@ -142,6 +142,8 @@ struct snd_soc_dai_ops {
         * Called by soc_card drivers, normally in their hw_params.
         */
        int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
+       int (*xlate_tdm_slot_mask)(unsigned int slots,
+               unsigned int *tx_mask, unsigned int *rx_mask);
        int (*set_tdm_slot)(struct snd_soc_dai *dai,
                unsigned int tx_mask, unsigned int rx_mask,
                int slots, int slot_width);
@@ -270,6 +272,7 @@ struct snd_soc_dai {
        /* parent platform/codec */
        struct snd_soc_platform *platform;
        struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
 
        struct snd_soc_card *card;
 
index 6e89ef6c11c1a42c853a8f87021bbf1244a14ffc..ef78f562f4a88b1c63bd3e6c4a19cc223fdf50f1 100644 (file)
@@ -108,13 +108,9 @@ struct device;
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_virt_mux, .name = wname, \
-       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
-       .kcontrol_news = wcontrols, .num_kcontrols = 1}
+       SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_value_mux, .name = wname, \
-       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
-       .kcontrol_news = wcontrols, .num_kcontrols = 1}
+       SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
@@ -172,10 +168,8 @@ struct device;
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_virt_mux, .name = wname, \
-       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
-       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
-       .event = wevent, .event_flags = wflags}
+       SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, wevent, \
+               wflags)
 
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
@@ -311,12 +305,8 @@ struct device;
        .get = snd_soc_dapm_get_enum_double, \
        .put = snd_soc_dapm_put_enum_double, \
        .private_value = (unsigned long)&xenum }
-#define SOC_DAPM_ENUM_VIRT(xname, xenum)                   \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_enum_double, \
-       .get = snd_soc_dapm_get_enum_virt, \
-       .put = snd_soc_dapm_put_enum_virt, \
-       .private_value = (unsigned long)&xenum }
+#define SOC_DAPM_ENUM_VIRT(xname, xenum) \
+       SOC_DAPM_ENUM(xname, xenum)
 #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
@@ -324,11 +314,7 @@ struct device;
        .put = xput, \
        .private_value = (unsigned long)&xenum }
 #define SOC_DAPM_VALUE_ENUM(xname, xenum) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_enum_double, \
-       .get = snd_soc_dapm_get_value_enum_double, \
-       .put = snd_soc_dapm_put_value_enum_double, \
-       .private_value = (unsigned long)&xenum }
+       SOC_DAPM_ENUM(xname, xenum)
 #define SOC_DAPM_PIN_SWITCH(xname) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \
        .info = snd_soc_dapm_info_pin_switch, \
@@ -392,14 +378,6 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
 int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
@@ -461,6 +439,7 @@ int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
                                const char *pin);
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
+int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
                                  const char *pin);
 int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
@@ -470,7 +449,6 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
 
 /* Mostly internal - should not normally be used */
-void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
 void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
 
 /* dapm path query */
@@ -484,8 +462,6 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
        snd_soc_dapm_output,            /* output pin */
        snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
-       snd_soc_dapm_virt_mux,                  /* virtual version of snd_soc_dapm_mux */
-       snd_soc_dapm_value_mux,                 /* selects 1 analog signal from many inputs */
        snd_soc_dapm_mixer,                     /* mixes several analog signals together */
        snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
        snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
index 9a001472b96a4bf8a11c8c129543060fdb75c869..0b83168d8ff45a2ff394057ef0d172ab783f84d8 100644 (file)
        ((unsigned long)&(struct soc_mixer_control) \
        {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
        .max = xmax, .platform_max = xmax, .invert = xinvert})
+#define SOC_DOUBLE_R_S_VALUE(xlreg, xrreg, xshift, xmin, xmax, xsign_bit, xinvert) \
+       ((unsigned long)&(struct soc_mixer_control) \
+       {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
+       .max = xmax, .min = xmin, .platform_max = xmax, .sign_bit = xsign_bit, \
+       .invert = xinvert})
 #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \
        ((unsigned long)&(struct soc_mixer_control) \
        {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
                {.reg = xreg, .rreg = xrreg, \
                .shift = xshift, .rshift = xshift, \
                .max = xmax, .min = xmin} }
+#define SOC_DOUBLE_R_S_TLV(xname, reg_left, reg_right, xshift, xmin, xmax, xsign_bit, xinvert, 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 = snd_soc_put_volsw, \
+       .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \
+                                           xmin, xmax, xsign_bit, xinvert) }
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {      .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
        .private_value = (unsigned long)&(struct soc_mixer_control) \
                {.reg = xreg, .min = xmin, .max = xmax, \
                 .platform_max = xmax} }
-#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
 {      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
-       .max = xmax, .texts = xtexts, \
-       .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0}
-#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
-       SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
-#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
-{      .max = xmax, .texts = xtexts }
-#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \
+       .items = xitems, .texts = xtexts, \
+       .mask = xitems ? roundup_pow_of_two(xitems) - 1 : 0}
+#define SOC_ENUM_SINGLE(xreg, xshift, xitems, xtexts) \
+       SOC_ENUM_DOUBLE(xreg, xshift, xshift, xitems, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xitems, xtexts) \
+{      .items = xitems, .texts = xtexts }
+#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
 {      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
-       .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues}
-#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \
-       SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues)
+       .mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
+#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
+       SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
+#define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
 #define SOC_ENUM(xname, xenum) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
        .info = snd_soc_info_enum_double, \
        .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
        .private_value = (unsigned long)&xenum }
 #define SOC_VALUE_ENUM(xname, xenum) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
-       .info = snd_soc_info_enum_double, \
-       .get = snd_soc_get_value_enum_double, \
-       .put = snd_soc_put_value_enum_double, \
-       .private_value = (unsigned long)&xenum }
+       SOC_ENUM(xname, xenum)
 #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
  * ARRAY_SIZE internally
  */
 #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \
-       struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
+       const struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
                                                ARRAY_SIZE(xtexts), xtexts)
 #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \
        SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
 #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \
-       struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
+       const struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
 #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \
-       struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
+       const struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
                                                        ARRAY_SIZE(xtexts), xtexts, xvalues)
 #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
        SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+#define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
+       const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
 
 /*
  * Component probe and remove ordering levels for components with runtime
@@ -340,12 +354,6 @@ typedef int (*hw_write_t)(void *,const char* ,int);
 
 extern struct snd_ac97_bus_ops *soc_ac97_ops;
 
-enum snd_soc_control_type {
-       SND_SOC_I2C = 1,
-       SND_SOC_SPI,
-       SND_SOC_REGMAP,
-};
-
 enum snd_soc_pcm_subclass {
        SND_SOC_PCM_CLASS_PCM   = 0,
        SND_SOC_PCM_CLASS_BE    = 1,
@@ -392,8 +400,7 @@ int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
 int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
                                    unsigned int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              int addr_bits, int data_bits,
-                              enum snd_soc_control_type control);
+                              struct regmap *regmap);
 int snd_soc_cache_sync(struct snd_soc_codec *codec);
 int snd_soc_cache_init(struct snd_soc_codec *codec);
 int snd_soc_cache_exit(struct snd_soc_codec *codec);
@@ -413,6 +420,10 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
 struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
                const char *dai_link);
 
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
+
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -496,10 +507,6 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
-int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
 #define snd_soc_info_bool_ext          snd_ctl_boolean_mono_info
@@ -600,7 +607,8 @@ struct snd_soc_jack_gpio {
        struct snd_soc_jack *jack;
        struct delayed_work work;
 
-       int (*jack_status_check)(void);
+       void *data;
+       int (*jack_status_check)(void *data);
 };
 
 struct snd_soc_jack {
@@ -656,12 +664,19 @@ struct snd_soc_component {
        const char *name;
        int id;
        struct device *dev;
+
+       unsigned int active;
+
+       unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
+
        struct list_head list;
 
        struct snd_soc_dai_driver *dai_drv;
        int num_dai;
 
        const struct snd_soc_component_driver *driver;
+
+       struct list_head dai_list;
 };
 
 /* SoC Audio Codec device */
@@ -683,7 +698,6 @@ struct snd_soc_codec {
 
        /* runtime */
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
-       unsigned int active;
        unsigned int cache_bypass:1; /* Suppress access to the cache */
        unsigned int suspended:1; /* Codec is in suspend PM state */
        unsigned int probed:1; /* Codec has been probed */
@@ -697,7 +711,6 @@ struct snd_soc_codec {
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
        hw_write_t hw_write;
-       unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
        void *reg_cache;
@@ -709,7 +722,6 @@ struct snd_soc_codec {
 
        /* dapm */
        struct snd_soc_dapm_context dapm;
-       unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_codec_root;
@@ -1067,6 +1079,7 @@ struct soc_mixer_control {
        int min, max, platform_max;
        int reg, rreg;
        unsigned int shift, rshift;
+       unsigned int sign_bit;
        unsigned int invert:1;
        unsigned int autodisable:1;
 };
@@ -1085,16 +1098,28 @@ struct soc_mreg_control {
 
 /* enumerated kcontrol */
 struct soc_enum {
-       unsigned short reg;
-       unsigned short reg2;
+       int reg;
        unsigned char shift_l;
        unsigned char shift_r;
-       unsigned int max;
+       unsigned int items;
        unsigned int mask;
        const char * const *texts;
        const unsigned int *values;
 };
 
+/**
+ * snd_soc_component_to_codec() - Casts a component to the CODEC it is embedded in
+ * @component: The component to cast to a CODEC
+ *
+ * This function must only be used on components that are known to be CODECs.
+ * Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_codec *snd_soc_component_to_codec(
+       struct snd_soc_component *component)
+{
+       return container_of(component, struct snd_soc_codec, component);
+}
+
 /* codec IO */
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
@@ -1168,11 +1193,51 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
        return 1;
 }
 
+static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e,
+       unsigned int val)
+{
+       unsigned int i;
+
+       if (!e->values)
+               return val;
+
+       for (i = 0; i < e->items; i++)
+               if (val == e->values[i])
+                       return i;
+
+       return 0;
+}
+
+static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e,
+       unsigned int item)
+{
+       if (!e->values)
+               return item;
+
+       return e->values[item];
+}
+
+static inline bool snd_soc_component_is_active(
+       struct snd_soc_component *component)
+{
+       return component->active != 0;
+}
+
+static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
+{
+       return snd_soc_component_is_active(&codec->component);
+}
+
 int snd_soc_util_init(void);
 void snd_soc_util_exit(void);
 
 int snd_soc_of_parse_card_name(struct snd_soc_card *card,
                               const char *propname);
+int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+                                         const char *propname);
+int snd_soc_of_parse_tdm_slot(struct device_node *np,
+                             unsigned int *slots,
+                             unsigned int *slot_width);
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname);
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
@@ -1188,4 +1253,15 @@ extern struct dentry *snd_soc_debugfs_root;
 
 extern const struct dev_pm_ops snd_soc_pm_ops;
 
+/* Helper functions */
+static inline void snd_soc_dapm_mutex_lock(struct snd_soc_dapm_context *dapm)
+{
+       mutex_lock(&dapm->card->dapm_mutex);
+}
+
+static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
+{
+       mutex_unlock(&dapm->card->dapm_mutex);
+}
+
 #endif
index ae5a17111968c7ca8bc8667a65d16393532ffbde..4483fadfa68d8fdc744743d6bc5bcd52de301608 100644 (file)
@@ -12,6 +12,7 @@ struct iscsit_transport {
        int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
        int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
        void (*iscsit_free_np)(struct iscsi_np *);
+       void (*iscsit_wait_conn)(struct iscsi_conn *);
        void (*iscsit_free_conn)(struct iscsi_conn *);
        int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
        int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
diff --git a/include/trace/events/hswadsp.h b/include/trace/events/hswadsp.h
new file mode 100644 (file)
index 0000000..0f78bbb
--- /dev/null
@@ -0,0 +1,384 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hswadsp
+
+#if !defined(_TRACE_HSWADSP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HSWADSP_H
+
+#include <linux/types.h>
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+struct sst_hsw;
+struct sst_hsw_stream;
+struct sst_hsw_ipc_stream_free_req;
+struct sst_hsw_ipc_volume_req;
+struct sst_hsw_ipc_stream_alloc_req;
+struct sst_hsw_audio_data_format_ipc;
+struct sst_hsw_ipc_stream_info_reply;
+struct sst_hsw_ipc_device_config_req;
+
+DECLARE_EVENT_CLASS(sst_irq,
+
+       TP_PROTO(uint32_t status, uint32_t mask),
+
+       TP_ARGS(status, mask),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   status          )
+               __field(        unsigned int,   mask            )
+       ),
+
+       TP_fast_assign(
+               __entry->status = status;
+               __entry->mask = mask;
+       ),
+
+       TP_printk("status 0x%8.8x mask 0x%8.8x",
+               (unsigned int)__entry->status, (unsigned int)__entry->mask)
+);
+
+DEFINE_EVENT(sst_irq, sst_irq_busy,
+
+       TP_PROTO(unsigned int status, unsigned int mask),
+
+       TP_ARGS(status, mask)
+
+);
+
+DEFINE_EVENT(sst_irq, sst_irq_done,
+
+       TP_PROTO(unsigned int status, unsigned int mask),
+
+       TP_ARGS(status, mask)
+
+);
+
+DECLARE_EVENT_CLASS(ipc,
+
+       TP_PROTO(const char *name, int val),
+
+       TP_ARGS(name, val),
+
+       TP_STRUCT__entry(
+               __string(       name,   name            )
+               __field(        unsigned int,   val     )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->val = val;
+       ),
+
+       TP_printk("%s 0x%8.8x", __get_str(name), (unsigned int)__entry->val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_request,
+
+       TP_PROTO(const char *name, int val),
+
+       TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_reply,
+
+       TP_PROTO(const char *name, int val),
+
+       TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_pending_reply,
+
+       TP_PROTO(const char *name, int val),
+
+       TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_notification,
+
+       TP_PROTO(const char *name, int val),
+
+       TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_error,
+
+       TP_PROTO(const char *name, int val),
+
+       TP_ARGS(name, val)
+
+);
+
+DECLARE_EVENT_CLASS(stream_position,
+
+       TP_PROTO(unsigned int id, unsigned int pos),
+
+       TP_ARGS(id, pos),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   id              )
+               __field(        unsigned int,   pos             )
+       ),
+
+       TP_fast_assign(
+               __entry->id = id;
+               __entry->pos = pos;
+       ),
+
+       TP_printk("id %d position 0x%x",
+               (unsigned int)__entry->id, (unsigned int)__entry->pos)
+);
+
+DEFINE_EVENT(stream_position, stream_read_position,
+
+       TP_PROTO(unsigned int id, unsigned int pos),
+
+       TP_ARGS(id, pos)
+
+);
+
+DEFINE_EVENT(stream_position, stream_write_position,
+
+       TP_PROTO(unsigned int id, unsigned int pos),
+
+       TP_ARGS(id, pos)
+
+);
+
+TRACE_EVENT(hsw_stream_buffer,
+
+       TP_PROTO(struct sst_hsw_stream *stream),
+
+       TP_ARGS(stream),
+
+       TP_STRUCT__entry(
+               __field(        int,    id      )
+               __field(        int,    pt_addr )
+               __field(        int,    num_pages       )
+               __field(        int,    ring_size       )
+               __field(        int,    ring_offset     )
+               __field(        int,    first_pfn       )
+       ),
+
+       TP_fast_assign(
+               __entry->id = stream->host_id;
+               __entry->pt_addr = stream->request.ringinfo.ring_pt_address;
+               __entry->num_pages = stream->request.ringinfo.num_pages;
+               __entry->ring_size = stream->request.ringinfo.ring_size;
+               __entry->ring_offset = stream->request.ringinfo.ring_offset;
+               __entry->first_pfn = stream->request.ringinfo.ring_first_pfn;
+       ),
+
+       TP_printk("stream %d ring addr 0x%x pages %d size 0x%x offset 0x%x PFN 0x%x",
+               (int) __entry->id,  (int)__entry->pt_addr,
+               (int)__entry->num_pages, (int)__entry->ring_size,
+               (int)__entry->ring_offset, (int)__entry->first_pfn)
+);
+
+TRACE_EVENT(hsw_stream_alloc_reply,
+
+       TP_PROTO(struct sst_hsw_stream *stream),
+
+       TP_ARGS(stream),
+
+       TP_STRUCT__entry(
+               __field(        int,    id      )
+               __field(        int,    stream_id       )
+               __field(        int,    mixer_id        )
+               __field(        int,    peak0   )
+               __field(        int,    peak1   )
+               __field(        int,    vol0    )
+               __field(        int,    vol1    )
+       ),
+
+       TP_fast_assign(
+               __entry->id = stream->host_id;
+               __entry->stream_id = stream->reply.stream_hw_id;
+               __entry->mixer_id = stream->reply.mixer_hw_id;
+               __entry->peak0 = stream->reply.peak_meter_register_address[0];
+               __entry->peak1 = stream->reply.peak_meter_register_address[1];
+               __entry->vol0 = stream->reply.volume_register_address[0];
+               __entry->vol1 = stream->reply.volume_register_address[1];
+       ),
+
+       TP_printk("stream %d hw id %d mixer %d peak 0x%x:0x%x vol 0x%x,0x%x",
+               (int) __entry->id, (int) __entry->stream_id, (int)__entry->mixer_id,
+               (int)__entry->peak0, (int)__entry->peak1,
+               (int)__entry->vol0, (int)__entry->vol1)
+);
+
+TRACE_EVENT(hsw_mixer_info_reply,
+
+       TP_PROTO(struct sst_hsw_ipc_stream_info_reply *reply),
+
+       TP_ARGS(reply),
+
+       TP_STRUCT__entry(
+               __field(        int,    mixer_id        )
+               __field(        int,    peak0   )
+               __field(        int,    peak1   )
+               __field(        int,    vol0    )
+               __field(        int,    vol1    )
+       ),
+
+       TP_fast_assign(
+               __entry->mixer_id = reply->mixer_hw_id;
+               __entry->peak0 = reply->peak_meter_register_address[0];
+               __entry->peak1 = reply->peak_meter_register_address[1];
+               __entry->vol0 = reply->volume_register_address[0];
+               __entry->vol1 = reply->volume_register_address[1];
+       ),
+
+       TP_printk("mixer id %d peak 0x%x:0x%x vol 0x%x,0x%x",
+               (int)__entry->mixer_id,
+               (int)__entry->peak0, (int)__entry->peak1,
+               (int)__entry->vol0, (int)__entry->vol1)
+);
+
+TRACE_EVENT(hsw_stream_data_format,
+
+       TP_PROTO(struct sst_hsw_stream *stream,
+               struct sst_hsw_audio_data_format_ipc *req),
+
+       TP_ARGS(stream, req),
+
+       TP_STRUCT__entry(
+               __field(        uint32_t,       id      )
+               __field(        uint32_t,       frequency       )
+               __field(        uint32_t,       bitdepth        )
+               __field(        uint32_t,       map     )
+               __field(        uint32_t,       config  )
+               __field(        uint32_t,       style   )
+               __field(        uint8_t,        ch_num  )
+               __field(        uint8_t,        valid_bit       )
+       ),
+
+       TP_fast_assign(
+               __entry->id = stream->host_id;
+               __entry->frequency = req->frequency;
+               __entry->bitdepth = req->bitdepth;
+               __entry->map = req->map;
+               __entry->config = req->config;
+               __entry->style = req->style;
+               __entry->ch_num = req->ch_num;
+               __entry->valid_bit = req->valid_bit;
+       ),
+
+       TP_printk("stream %d freq %d depth %d map 0x%x config 0x%x style 0x%x ch %d bits %d",
+               (int) __entry->id, (uint32_t)__entry->frequency,
+               (uint32_t)__entry->bitdepth, (uint32_t)__entry->map,
+               (uint32_t)__entry->config, (uint32_t)__entry->style,
+               (uint8_t)__entry->ch_num, (uint8_t)__entry->valid_bit)
+);
+
+TRACE_EVENT(hsw_stream_alloc_request,
+
+       TP_PROTO(struct sst_hsw_stream *stream,
+               struct sst_hsw_ipc_stream_alloc_req *req),
+
+       TP_ARGS(stream, req),
+
+       TP_STRUCT__entry(
+               __field(        uint32_t,       id      )
+               __field(        uint8_t,        path_id )
+               __field(        uint8_t,        stream_type     )
+               __field(        uint8_t,        format_id       )
+       ),
+
+       TP_fast_assign(
+               __entry->id = stream->host_id;
+               __entry->path_id = req->path_id;
+               __entry->stream_type = req->stream_type;
+               __entry->format_id = req->format_id;
+       ),
+
+       TP_printk("stream %d path %d type %d format %d",
+               (int) __entry->id, (uint8_t)__entry->path_id,
+               (uint8_t)__entry->stream_type, (uint8_t)__entry->format_id)
+);
+
+TRACE_EVENT(hsw_stream_free_req,
+
+       TP_PROTO(struct sst_hsw_stream *stream,
+               struct sst_hsw_ipc_stream_free_req *req),
+
+       TP_ARGS(stream, req),
+
+       TP_STRUCT__entry(
+               __field(        int,    id      )
+               __field(        int,    stream_id       )
+       ),
+
+       TP_fast_assign(
+               __entry->id = stream->host_id;
+               __entry->stream_id = req->stream_id;
+       ),
+
+       TP_printk("stream %d hw id %d",
+               (int) __entry->id, (int) __entry->stream_id)
+);
+
+TRACE_EVENT(hsw_volume_req,
+
+       TP_PROTO(struct sst_hsw_stream *stream,
+               struct sst_hsw_ipc_volume_req *req),
+
+       TP_ARGS(stream, req),
+
+       TP_STRUCT__entry(
+               __field(        int,    id      )
+               __field(        uint32_t,       channel )
+               __field(        uint32_t,       target_volume   )
+               __field(        uint64_t,       curve_duration  )
+               __field(        uint32_t,       curve_type      )
+       ),
+
+       TP_fast_assign(
+               __entry->id = stream->host_id;
+               __entry->channel = req->channel;
+               __entry->target_volume = req->target_volume;
+               __entry->curve_duration = req->curve_duration;
+               __entry->curve_type = req->curve_type;
+       ),
+
+       TP_printk("stream %d chan 0x%x vol %d duration %llu type %d",
+               (int) __entry->id, (uint32_t) __entry->channel,
+               (uint32_t)__entry->target_volume,
+               (uint64_t)__entry->curve_duration,
+               (uint32_t)__entry->curve_type)
+);
+
+TRACE_EVENT(hsw_device_config_req,
+
+       TP_PROTO(struct sst_hsw_ipc_device_config_req *req),
+
+       TP_ARGS(req),
+
+       TP_STRUCT__entry(
+               __field(        uint32_t,       ssp     )
+               __field(        uint32_t,       clock_freq      )
+               __field(        uint32_t,       mode    )
+               __field(        uint16_t,       clock_divider   )
+       ),
+
+       TP_fast_assign(
+               __entry->ssp = req->ssp_interface;
+               __entry->clock_freq = req->clock_frequency;
+               __entry->mode = req->mode;
+               __entry->clock_divider = req->clock_divider;
+       ),
+
+       TP_printk("SSP %d Freq %d mode %d div %d",
+               (uint32_t)__entry->ssp,
+               (uint32_t)__entry->clock_freq, (uint32_t)__entry->mode,
+               (uint32_t)__entry->clock_divider)
+);
+
+#endif /* _TRACE_HSWADSP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/intel-sst.h b/include/trace/events/intel-sst.h
new file mode 100644 (file)
index 0000000..76c72d3
--- /dev/null
@@ -0,0 +1,148 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM intel-sst
+
+#if !defined(_TRACE_INTEL_SST_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INTEL_SST_H
+
+#include <linux/types.h>
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(sst_ipc_msg,
+
+       TP_PROTO(unsigned int val),
+
+       TP_ARGS(val),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   val             )
+       ),
+
+       TP_fast_assign(
+               __entry->val = val;
+       ),
+
+       TP_printk("0x%8.8x", (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_tx,
+
+       TP_PROTO(unsigned int val),
+
+       TP_ARGS(val)
+
+);
+
+DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_rx,
+
+       TP_PROTO(unsigned int val),
+
+       TP_ARGS(val)
+
+);
+
+DECLARE_EVENT_CLASS(sst_ipc_mailbox,
+
+       TP_PROTO(unsigned int offset, unsigned int val),
+
+       TP_ARGS(offset, val),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   offset          )
+               __field(        unsigned int,   val             )
+       ),
+
+       TP_fast_assign(
+               __entry->offset = offset;
+               __entry->val = val;
+       ),
+
+       TP_printk(" 0x%4.4x = 0x%8.8x",
+               (unsigned int)__entry->offset, (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_rdata,
+
+       TP_PROTO(unsigned int offset, unsigned int val),
+
+       TP_ARGS(offset, val)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_wdata,
+
+       TP_PROTO(unsigned int offset, unsigned int val),
+
+       TP_ARGS(offset, val)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_rdata,
+
+       TP_PROTO(unsigned int offset, unsigned int val),
+
+       TP_ARGS(offset, val)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_wdata,
+
+       TP_PROTO(unsigned int offset, unsigned int val),
+
+       TP_ARGS(offset, val)
+
+);
+
+DECLARE_EVENT_CLASS(sst_ipc_mailbox_info,
+
+       TP_PROTO(unsigned int size),
+
+       TP_ARGS(size),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   size            )
+       ),
+
+       TP_fast_assign(
+               __entry->size = size;
+       ),
+
+       TP_printk("Mailbox bytes 0x%8.8x", (unsigned int)__entry->size)
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_read,
+
+       TP_PROTO(unsigned int size),
+
+       TP_ARGS(size)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_write,
+
+       TP_PROTO(unsigned int size),
+
+       TP_ARGS(size)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_read,
+
+       TP_PROTO(unsigned int size),
+
+       TP_ARGS(size)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_write,
+
+       TP_PROTO(unsigned int size),
+
+       TP_ARGS(size)
+
+);
+
+#endif /* _TRACE_SST_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index e5bf9a76f169681c356a1d14236d5e71d14bdb96..9a7e08d6125814406a7e2f5198e8abdaa8395877 100644 (file)
@@ -407,8 +407,8 @@ DECLARE_EVENT_CLASS(dev_pm_qos_request,
        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" }),
+                       { DEV_PM_QOS_RESUME_LATENCY, "DEV_PM_QOS_RESUME_LATENCY" },
+                       { DEV_PM_QOS_FLAGS, "DEV_PM_QOS_FLAGS" }),
                  __entry->new_value)
 );
 
index ddc179b7a1052aa6c3fb9df408e3b5ad9e50d792..1fef3e6e943632e6b2e1619c6536bc328a81eb8f 100644 (file)
@@ -83,7 +83,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                ),
 
        TP_fast_assign(
-               __entry->client_id = clnt->cl_clid;
+               __entry->client_id = clnt ? clnt->cl_clid : -1;
                __entry->task_id = task->tk_pid;
                __entry->action = action;
                __entry->runstate = task->tk_runstate;
@@ -91,7 +91,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                __entry->flags = task->tk_flags;
                ),
 
-       TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d action=%pf",
+       TP_printk("task:%u@%d flags=%4.4x state=%4.4lx status=%d action=%pf",
                __entry->task_id, __entry->client_id,
                __entry->flags,
                __entry->runstate,
index 1a8b28db37752707cb130566b6295eb3f8bc4b90..1ee19a24cc5f7170a3dab525767c669f3773dc7e 100644 (file)
@@ -310,15 +310,12 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = {    \
 #undef __array
 #define __array(type, item, len)                                       \
        do {                                                            \
-               mutex_lock(&event_storage_mutex);                       \
+               char *type_str = #type"["__stringify(len)"]";           \
                BUILD_BUG_ON(len > MAX_FILTER_STR_VAL);                 \
-               snprintf(event_storage, sizeof(event_storage),          \
-                        "%s[%d]", #type, len);                         \
-               ret = trace_define_field(event_call, event_storage, #item, \
+               ret = trace_define_field(event_call, type_str, #item,   \
                                 offsetof(typeof(field), item),         \
                                 sizeof(field.item),                    \
                                 is_signed_type(type), FILTER_OTHER);   \
-               mutex_unlock(&event_storage_mutex);                     \
                if (ret)                                                \
                        return ret;                                     \
        } while (0);
index dde8041f40d2e8a29a25a6205dd38577f2b46bce..6db66783d268d9a286a86b836c9277bd89f5ac13 100644 (file)
@@ -191,6 +191,7 @@ __SYSCALL(__NR_quotactl, sys_quotactl)
 
 /* fs/readdir.c */
 #define __NR_getdents64 61
+#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
 __SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64)
 
 /* fs/read_write.c */
index 3ce25b5d75a9facfd047a526d3c3af618169e488..6929571b79b0c396496991fc136a7ff811c9177d 100644 (file)
@@ -139,6 +139,7 @@ header-y += hid.h
 header-y += hiddev.h
 header-y += hidraw.h
 header-y += hpet.h
+header-y += hyperv.h
 header-y += hysdn_if.h
 header-y += i2c-dev.h
 header-y += i2c.h
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
new file mode 100644 (file)
index 0000000..9beb7c9
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ *
+ * Copyright (c) 2011, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ *   Haiyang Zhang <haiyangz@microsoft.com>
+ *   Hank Janssen  <hjanssen@microsoft.com>
+ *   K. Y. Srinivasan <kys@microsoft.com>
+ *
+ */
+
+#ifndef _UAPI_HYPERV_H
+#define _UAPI_HYPERV_H
+
+#include <linux/uuid.h>
+
+/*
+ * Framework version for util services.
+ */
+#define UTIL_FW_MINOR  0
+
+#define UTIL_WS2K8_FW_MAJOR  1
+#define UTIL_WS2K8_FW_VERSION     (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
+
+#define UTIL_FW_MAJOR  3
+#define UTIL_FW_VERSION     (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
+
+
+/*
+ * Implementation of host controlled snapshot of the guest.
+ */
+
+#define VSS_OP_REGISTER 128
+
+enum hv_vss_op {
+       VSS_OP_CREATE = 0,
+       VSS_OP_DELETE,
+       VSS_OP_HOT_BACKUP,
+       VSS_OP_GET_DM_INFO,
+       VSS_OP_BU_COMPLETE,
+       /*
+        * Following operations are only supported with IC version >= 5.0
+        */
+       VSS_OP_FREEZE, /* Freeze the file systems in the VM */
+       VSS_OP_THAW, /* Unfreeze the file systems */
+       VSS_OP_AUTO_RECOVER,
+       VSS_OP_COUNT /* Number of operations, must be last */
+};
+
+
+/*
+ * Header for all VSS messages.
+ */
+struct hv_vss_hdr {
+       __u8 operation;
+       __u8 reserved[7];
+} __attribute__((packed));
+
+
+/*
+ * Flag values for the hv_vss_check_feature. Linux supports only
+ * one value.
+ */
+#define VSS_HBU_NO_AUTO_RECOVERY       0x00000005
+
+struct hv_vss_check_feature {
+       __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_check_dm_info {
+       __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_msg {
+       union {
+               struct hv_vss_hdr vss_hdr;
+               int error;
+       };
+       union {
+               struct hv_vss_check_feature vss_cf;
+               struct hv_vss_check_dm_info dm_info;
+       };
+} __attribute__((packed));
+
+/*
+ * Implementation of a host to guest copy facility.
+ */
+
+#define FCOPY_VERSION_0 0
+#define FCOPY_CURRENT_VERSION FCOPY_VERSION_0
+#define W_MAX_PATH 260
+
+enum hv_fcopy_op {
+       START_FILE_COPY = 0,
+       WRITE_TO_FILE,
+       COMPLETE_FCOPY,
+       CANCEL_FCOPY,
+};
+
+struct hv_fcopy_hdr {
+       __u32 operation;
+       uuid_le service_id0; /* currently unused */
+       uuid_le service_id1; /* currently unused */
+} __attribute__((packed));
+
+#define OVER_WRITE     0x1
+#define CREATE_PATH    0x2
+
+struct hv_start_fcopy {
+       struct hv_fcopy_hdr hdr;
+       __u16 file_name[W_MAX_PATH];
+       __u16 path_name[W_MAX_PATH];
+       __u32 copy_flags;
+       __u64 file_size;
+} __attribute__((packed));
+
+/*
+ * The file is chunked into fragments.
+ */
+#define DATA_FRAGMENT  (6 * 1024)
+
+struct hv_do_fcopy {
+       struct hv_fcopy_hdr hdr;
+       __u64   offset;
+       __u32   size;
+       __u8    data[DATA_FRAGMENT];
+};
+
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ */
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note:  This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality.  Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note:  This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE          (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE            (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ *     Index           Key Name
+ *     0               FullyQualifiedDomainName
+ *     1               IntegrationServicesVersion
+ *     2               NetworkAddressIPv4
+ *     3               NetworkAddressIPv6
+ *     4               OSBuildNumber
+ *     5               OSName
+ *     6               OSMajorVersion
+ *     7               OSMinorVersion
+ *     8               OSVersion
+ *     9               ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+#define REG_U32 4
+#define REG_U64 8
+
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER        4
+
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+
+#define KVP_OP_REGISTER1 100
+
+enum hv_kvp_exchg_op {
+       KVP_OP_GET = 0,
+       KVP_OP_SET,
+       KVP_OP_DELETE,
+       KVP_OP_ENUMERATE,
+       KVP_OP_GET_IP_INFO,
+       KVP_OP_SET_IP_INFO,
+       KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+       KVP_POOL_EXTERNAL = 0,
+       KVP_POOL_GUEST,
+       KVP_POOL_AUTO,
+       KVP_POOL_AUTO_EXTERNAL,
+       KVP_POOL_AUTO_INTERNAL,
+       KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+/*
+ * Some Hyper-V status codes.
+ */
+
+#define HV_S_OK                                0x00000000
+#define HV_E_FAIL                      0x80004005
+#define HV_S_CONT                      0x80070103
+#define HV_ERROR_NOT_SUPPORTED         0x80070032
+#define HV_ERROR_MACHINE_LOCKED                0x800704F7
+#define HV_ERROR_DEVICE_NOT_CONNECTED  0x8007048F
+#define HV_INVALIDARG                  0x80070057
+#define HV_GUID_NOTFOUND               0x80041002
+
+#define ADDR_FAMILY_NONE       0x00
+#define ADDR_FAMILY_IPV4       0x01
+#define ADDR_FAMILY_IPV6       0x02
+
+#define MAX_ADAPTER_ID_SIZE    128
+#define MAX_IP_ADDR_SIZE       1024
+#define MAX_GATEWAY_SIZE       512
+
+
+struct hv_kvp_ipaddr_value {
+       __u16   adapter_id[MAX_ADAPTER_ID_SIZE];
+       __u8    addr_family;
+       __u8    dhcp_enabled;
+       __u16   ip_addr[MAX_IP_ADDR_SIZE];
+       __u16   sub_net[MAX_IP_ADDR_SIZE];
+       __u16   gate_way[MAX_GATEWAY_SIZE];
+       __u16   dns_addr[MAX_IP_ADDR_SIZE];
+} __attribute__((packed));
+
+
+struct hv_kvp_hdr {
+       __u8 operation;
+       __u8 pool;
+       __u16 pad;
+} __attribute__((packed));
+
+struct hv_kvp_exchg_msg_value {
+       __u32 value_type;
+       __u32 key_size;
+       __u32 value_size;
+       __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+       union {
+               __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+               __u32 value_u32;
+               __u64 value_u64;
+       };
+} __attribute__((packed));
+
+struct hv_kvp_msg_enumerate {
+       __u32 index;
+       struct hv_kvp_exchg_msg_value data;
+} __attribute__((packed));
+
+struct hv_kvp_msg_get {
+       struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_set {
+       struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_delete {
+       __u32 key_size;
+       __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_register {
+       __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_msg {
+       union {
+               struct hv_kvp_hdr       kvp_hdr;
+               int error;
+       };
+       union {
+               struct hv_kvp_msg_get           kvp_get;
+               struct hv_kvp_msg_set           kvp_set;
+               struct hv_kvp_msg_delete        kvp_delete;
+               struct hv_kvp_msg_enumerate     kvp_enum_data;
+               struct hv_kvp_ipaddr_value      kvp_ip_val;
+               struct hv_kvp_register          kvp_register;
+       } body;
+} __attribute__((packed));
+
+struct hv_kvp_ip_msg {
+       __u8 operation;
+       __u8 pool;
+       struct hv_kvp_ipaddr_value      kvp_ip_val;
+} __attribute__((packed));
+
+#endif /* _UAPI_HYPERV_H */
index 52d9ed01855fe4c67a5ab1d3b4908efc7eb66a8a..dd5f21e758057f0f3ac98ee0f04823aaffeaa53f 100644 (file)
 #define SPI_LOOP               0x20
 #define SPI_NO_CS              0x40
 #define SPI_READY              0x80
+#define SPI_TX_DUAL            0x100
+#define SPI_TX_QUAD            0x200
+#define SPI_RX_DUAL            0x400
+#define SPI_RX_QUAD            0x800
 
 /*---------------------------------------------------------------------------*/
 
@@ -92,7 +96,9 @@ struct spi_ioc_transfer {
        __u16           delay_usecs;
        __u8            bits_per_word;
        __u8            cs_change;
-       __u32           pad;
+       __u8            tx_nbits;
+       __u8            rx_nbits;
+       __u16           pad;
 
        /* If the contents of 'struct spi_ioc_transfer' ever change
         * incompatibly, then the ioctl number (currently 0) must change;
@@ -110,7 +116,7 @@ struct spi_ioc_transfer {
 #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
 
 
-/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
+/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */
 #define SPI_IOC_RD_MODE                        _IOR(SPI_IOC_MAGIC, 1, __u8)
 #define SPI_IOC_WR_MODE                        _IOW(SPI_IOC_MAGIC, 1, __u8)
 
@@ -126,6 +132,10 @@ struct spi_ioc_transfer {
 #define SPI_IOC_RD_MAX_SPEED_HZ                _IOR(SPI_IOC_MAGIC, 4, __u32)
 #define SPI_IOC_WR_MAX_SPEED_HZ                _IOW(SPI_IOC_MAGIC, 4, __u32)
 
+/* Read / Write of the SPI mode field */
+#define SPI_IOC_RD_MODE32              _IOR(SPI_IOC_MAGIC, 5, __u32)
+#define SPI_IOC_WR_MODE32              _IOW(SPI_IOC_MAGIC, 5, __u32)
+
 
 
 #endif /* SPIDEV_H */
index 009a797dd24272afbe761c33f237287c9420be33..d56cb03c1b491036c981582568d780303d3ca250 100644 (file)
@@ -1387,6 +1387,13 @@ config FUTEX
          support for "fast userspace mutexes".  The resulting kernel may not
          run glibc-based applications correctly.
 
+config HAVE_FUTEX_CMPXCHG
+       bool
+       help
+         Architectures should select this if futex_atomic_cmpxchg_inatomic()
+         is implemented and always working. This removes a couple of runtime
+         checks.
+
 config EPOLL
        bool "Enable eventpoll support" if EXPERT
        default y
index eb03090cdced5aac82787cf3154c2430b7410924..9c7fd4c9249f2c72395fcaf2ac953f782a3e2b59 100644 (file)
@@ -561,7 +561,6 @@ asmlinkage void __init start_kernel(void)
        init_timers();
        hrtimers_init();
        softirq_init();
-       acpi_early_init();
        timekeeping_init();
        time_init();
        sched_clock_postinit();
@@ -613,6 +612,7 @@ asmlinkage void __init start_kernel(void)
        calibrate_delay();
        pidmap_init();
        anon_vma_init();
+       acpi_early_init();
 #ifdef CONFIG_X86
        if (efi_enabled(EFI_RUNTIME_SERVICES))
                efi_enter_virtual_mode();
index f486b0096a67f32fe453cca13b40ad6268a76d45..98b9016cab6c84e4e86151458a5e9b8063ffc6f2 100644 (file)
@@ -430,9 +430,9 @@ COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
 }
 
 COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
-                      compat_ssize_t, msgsz, long, msgtyp, int, msgflg)
+                      compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
 {
-       return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, msgtyp,
+       return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
                         msgflg, compat_do_msg_fill);
 }
 
@@ -498,7 +498,7 @@ static inline int put_compat_msqid_ds(struct msqid64_ds *m,
        return err;
 }
 
-long compat_sys_msgctl(int first, int second, void __user *uptr)
+COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
 {
        int err, err2;
        struct msqid64_ds m64;
@@ -668,7 +668,7 @@ static inline int put_compat_shm_info(struct shm_info __user *ip,
        return err;
 }
 
-long compat_sys_shmctl(int first, int second, void __user *uptr)
+COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
 {
        void __user *p;
        struct shmid64_ds s64;
@@ -749,8 +749,9 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
        return err;
 }
 
-long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
-               unsigned nsops, const struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
+                      unsigned, nsops,
+                      const struct compat_timespec __user *, timeout)
 {
        struct timespec __user *ts64 = NULL;
        if (timeout) {
index 63d7c6de335bd3b4878f8f2cf65d1d9e3f7e9474..d5874729377296acc8a95cd0c27b7ab5eb903a76 100644 (file)
@@ -46,9 +46,9 @@ static inline int put_compat_mq_attr(const struct mq_attr *attr,
                | __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
 }
 
-asmlinkage long compat_sys_mq_open(const char __user *u_name,
-                       int oflag, compat_mode_t mode,
-                       struct compat_mq_attr __user *u_attr)
+COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
+                      int, oflag, compat_mode_t, mode,
+                      struct compat_mq_attr __user *, u_attr)
 {
        void __user *p = NULL;
        if (u_attr && oflag & O_CREAT) {
@@ -78,10 +78,10 @@ static int compat_prepare_timeout(struct timespec __user **p,
        return 0;
 }
 
-asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
-                       const char __user *u_msg_ptr,
-                       size_t msg_len, unsigned int msg_prio,
-                       const struct compat_timespec __user *u_abs_timeout)
+COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
+                      const char __user *, u_msg_ptr,
+                      compat_size_t, msg_len, unsigned int, msg_prio,
+                      const struct compat_timespec __user *, u_abs_timeout)
 {
        struct timespec __user *u_ts;
 
@@ -92,10 +92,10 @@ asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
                        msg_prio, u_ts);
 }
 
-asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
-                       char __user *u_msg_ptr,
-                       size_t msg_len, unsigned int __user *u_msg_prio,
-                       const struct compat_timespec __user *u_abs_timeout)
+COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
+                      char __user *, u_msg_ptr,
+                      compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
+                      const struct compat_timespec __user *, u_abs_timeout)
 {
        struct timespec __user *u_ts;
        if (compat_prepare_timeout(&u_ts, u_abs_timeout))
@@ -105,8 +105,8 @@ asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
                        u_msg_prio, u_ts);
 }
 
-asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
-                       const struct compat_sigevent __user *u_notification)
+COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
+                      const struct compat_sigevent __user *, u_notification)
 {
        struct sigevent __user *p = NULL;
        if (u_notification) {
@@ -122,9 +122,9 @@ asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
        return sys_mq_notify(mqdes, p);
 }
 
-asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
-                       const struct compat_mq_attr __user *u_mqstat,
-                       struct compat_mq_attr __user *u_omqstat)
+COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
+                      const struct compat_mq_attr __user *, u_mqstat,
+                      struct compat_mq_attr __user *, u_omqstat)
 {
        struct mq_attr mqstat;
        struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
index 245db1140ad66a2be47744f02ef0d80deea5006f..649853105a5d773d30fac9929327030cad118a67 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -901,6 +901,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                return -EINVAL;
 
        if (msgflg & MSG_COPY) {
+               if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
+                       return -EINVAL;
                copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
                if (IS_ERR(copy))
                        return PTR_ERR(copy);
index bc010ee272b6cfec39892e6cb04b98cc06995e1a..f2a8b6246ce935e9d4ae5aeddc314e3d281c8539 100644 (file)
@@ -18,11 +18,13 @@ CFLAGS_REMOVE_cgroup-debug.o = -pg
 CFLAGS_REMOVE_irq_work.o = -pg
 endif
 
+# cond_syscall is currently not LTO compatible
+CFLAGS_sys_ni.o = $(DISABLE_LTO)
+
 obj-y += sched/
 obj-y += locking/
 obj-y += power/
 obj-y += printk/
-obj-y += cpu/
 obj-y += irq/
 obj-y += rcu/
 
@@ -93,6 +95,7 @@ obj-$(CONFIG_PADATA) += padata.o
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_JUMP_LABEL) += jump_label.o
 obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
+obj-$(CONFIG_TORTURE_TEST) += torture.o
 
 $(obj)/configs.o: $(obj)/config_data.h
 
index 34c5a2310fbf9545eeff2e3fa803c8a361031bb3..95a20f3f52f1c9f35b7d6aa2cb0a8b7c05fdbc69 100644 (file)
@@ -182,7 +182,7 @@ struct audit_buffer {
 
 struct audit_reply {
        __u32 portid;
-       pid_t pid;
+       struct net *net;        
        struct sk_buff *skb;
 };
 
@@ -500,7 +500,7 @@ int audit_send_list(void *_dest)
 {
        struct audit_netlink_list *dest = _dest;
        struct sk_buff *skb;
-       struct net *net = get_net_ns_by_pid(dest->pid);
+       struct net *net = dest->net;
        struct audit_net *aunet = net_generic(net, audit_net_id);
 
        /* wait for parent to finish and send an ACK */
@@ -510,6 +510,7 @@ int audit_send_list(void *_dest)
        while ((skb = __skb_dequeue(&dest->q)) != NULL)
                netlink_unicast(aunet->nlsk, skb, dest->portid, 0);
 
+       put_net(net);
        kfree(dest);
 
        return 0;
@@ -543,7 +544,7 @@ out_kfree_skb:
 static int audit_send_reply_thread(void *arg)
 {
        struct audit_reply *reply = (struct audit_reply *)arg;
-       struct net *net = get_net_ns_by_pid(reply->pid);
+       struct net *net = reply->net;
        struct audit_net *aunet = net_generic(net, audit_net_id);
 
        mutex_lock(&audit_cmd_mutex);
@@ -552,12 +553,13 @@ static int audit_send_reply_thread(void *arg)
        /* Ignore failure. It'll only happen if the sender goes away,
           because our timeout is set to infinite. */
        netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0);
+       put_net(net);
        kfree(reply);
        return 0;
 }
 /**
  * audit_send_reply - send an audit reply message via netlink
- * @portid: netlink port to which to send reply
+ * @request_skb: skb of request we are replying to (used to target the reply)
  * @seq: sequence number
  * @type: audit message type
  * @done: done (last) flag
@@ -568,9 +570,11 @@ static int audit_send_reply_thread(void *arg)
  * Allocates an skb, builds the netlink message, and sends it to the port id.
  * No failure notifications.
  */
-static void audit_send_reply(__u32 portid, int seq, int type, int done,
+static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
                             int multi, const void *payload, int size)
 {
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
        struct sk_buff *skb;
        struct task_struct *tsk;
        struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
@@ -583,8 +587,8 @@ static void audit_send_reply(__u32 portid, int seq, int type, int done,
        if (!skb)
                goto out;
 
+       reply->net = get_net(net);
        reply->portid = portid;
-       reply->pid = task_pid_vnr(current);
        reply->skb = skb;
 
        tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
@@ -604,9 +608,19 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
        int err = 0;
 
        /* Only support the initial namespaces for now. */
+       /*
+        * We return ECONNREFUSED because it tricks userspace into thinking
+        * that audit was not configured into the kernel.  Lots of users
+        * configure their PAM stack (because that's what the distro does)
+        * to reject login if unable to send messages to audit.  If we return
+        * ECONNREFUSED the PAM stack thinks the kernel does not have audit
+        * configured in and will let login proceed.  If we return EPERM
+        * userspace will reject all logins.  This should be removed when we
+        * support non init namespaces!!
+        */
        if ((current_user_ns() != &init_user_ns) ||
            (task_active_pid_ns(current) != &init_pid_ns))
-               return -EPERM;
+               return -ECONNREFUSED;
 
        switch (msg_type) {
        case AUDIT_LIST:
@@ -673,8 +687,7 @@ static int audit_get_feature(struct sk_buff *skb)
 
        seq = nlmsg_hdr(skb)->nlmsg_seq;
 
-       audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
-                        &af, sizeof(af));
+       audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &af, sizeof(af));
 
        return 0;
 }
@@ -794,8 +807,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                s.backlog               = skb_queue_len(&audit_skb_queue);
                s.version               = AUDIT_VERSION_LATEST;
                s.backlog_wait_time     = audit_backlog_wait_time;
-               audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
-                                &s, sizeof(s));
+               audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_SET: {
@@ -905,7 +917,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                           seq, data, nlmsg_len(nlh));
                break;
        case AUDIT_LIST_RULES:
-               err = audit_list_rules_send(NETLINK_CB(skb).portid, seq);
+               err = audit_list_rules_send(skb, seq);
                break;
        case AUDIT_TRIM:
                audit_trim_trees();
@@ -970,8 +982,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        memcpy(sig_data->ctx, ctx, len);
                        security_release_secctx(ctx, len);
                }
-               audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_SIGNAL_INFO,
-                               0, 0, sig_data, sizeof(*sig_data) + len);
+               audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
+                                sig_data, sizeof(*sig_data) + len);
                kfree(sig_data);
                break;
        case AUDIT_TTY_GET: {
@@ -983,8 +995,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                s.log_passwd = tsk->signal->audit_tty_log_passwd;
                spin_unlock(&tsk->sighand->siglock);
 
-               audit_send_reply(NETLINK_CB(skb).portid, seq,
-                                AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
+               audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_TTY_SET: {
index 57cc64d67718903eebeab175030348df648b4f17..8df132214606f2b06e08e916196779b1aee64ad6 100644 (file)
@@ -247,7 +247,7 @@ extern void             audit_panic(const char *message);
 
 struct audit_netlink_list {
        __u32 portid;
-       pid_t pid;
+       struct net *net;
        struct sk_buff_head q;
 };
 
index 14a78cca384edb9cf8f36dc3f7fb5340c267c623..92062fd6cc8cec4deff933c04848782bfdcded11 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
 #include "audit.h"
 
 /*
@@ -1065,11 +1067,13 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
 
 /**
  * audit_list_rules_send - list the audit rules
- * @portid: target portid for netlink audit messages
+ * @request_skb: skb of request we are replying to (used to target the reply)
  * @seq: netlink audit message sequence (serial) number
  */
-int audit_list_rules_send(__u32 portid, int seq)
+int audit_list_rules_send(struct sk_buff *request_skb, int seq)
 {
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
        struct task_struct *tsk;
        struct audit_netlink_list *dest;
        int err = 0;
@@ -1083,8 +1087,8 @@ int audit_list_rules_send(__u32 portid, int seq)
        dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
        if (!dest)
                return -ENOMEM;
+       dest->net = get_net(net);
        dest->portid = portid;
-       dest->pid = task_pid_vnr(current);
        skb_queue_head_init(&dest->q);
 
        mutex_lock(&audit_filter_mutex);
index 105f273b6f86a74984d2b62b7d3ba19f95369a78..0c753ddd223bf9d543dfbb2d89915a08ab537f46 100644 (file)
@@ -4112,17 +4112,17 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
 
        err = percpu_ref_init(&css->refcnt, css_release);
        if (err)
-               goto err_free;
+               goto err_free_css;
 
        init_css(css, ss, cgrp);
 
        err = cgroup_populate_dir(cgrp, 1 << ss->subsys_id);
        if (err)
-               goto err_free;
+               goto err_free_percpu_ref;
 
        err = online_css(css);
        if (err)
-               goto err_free;
+               goto err_clear_dir;
 
        dget(cgrp->dentry);
        css_get(css->parent);
@@ -4138,8 +4138,11 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
 
        return 0;
 
-err_free:
+err_clear_dir:
+       cgroup_clear_dir(css->cgroup, 1 << css->ss->subsys_id);
+err_free_percpu_ref:
        percpu_ref_cancel_init(&css->refcnt);
+err_free_css:
        ss->css_free(css);
        return err;
 }
index 0a09e481b70b6e97519841f2eebf57da2e02d851..488ff8c4cf48ec071ad6cdb824fe60af735b5c8f 100644 (file)
@@ -110,8 +110,8 @@ static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
        return 0;
 }
 
-asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
-               struct timezone __user *tz)
+COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv,
+                      struct timezone __user *, tz)
 {
        if (tv) {
                struct timeval ktv;
@@ -127,8 +127,8 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
        return 0;
 }
 
-asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
-               struct timezone __user *tz)
+COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
+                      struct timezone __user *, tz)
 {
        struct timespec kts;
        struct timezone ktz;
@@ -236,8 +236,8 @@ static long compat_nanosleep_restart(struct restart_block *restart)
        return ret;
 }
 
-asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
-                                    struct compat_timespec __user *rmtp)
+COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
+                      struct compat_timespec __user *, rmtp)
 {
        struct timespec tu, rmt;
        mm_segment_t oldfs;
@@ -328,7 +328,7 @@ static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
        return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
 }
 
-asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
+COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)
 {
        if (tbuf) {
                struct tms tms;
@@ -354,7 +354,7 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
  * types that can be passed to put_user()/get_user().
  */
 
-asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
+COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set)
 {
        old_sigset_t s;
        long ret;
@@ -424,8 +424,8 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
 
 #endif
 
-asmlinkage long compat_sys_setrlimit(unsigned int resource,
-               struct compat_rlimit __user *rlim)
+COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource,
+                      struct compat_rlimit __user *, rlim)
 {
        struct rlimit r;
 
@@ -443,8 +443,8 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,
 
 #ifdef COMPAT_RLIM_OLD_INFINITY
 
-asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
-               struct compat_rlimit __user *rlim)
+COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
+                      struct compat_rlimit __user *, rlim)
 {
        struct rlimit r;
        int ret;
@@ -470,8 +470,8 @@ asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
 
 #endif
 
-asmlinkage long compat_sys_getrlimit(unsigned int resource,
-               struct compat_rlimit __user *rlim)
+COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource,
+                      struct compat_rlimit __user *, rlim)
 {
        struct rlimit r;
        int ret;
@@ -596,9 +596,9 @@ static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
        return compat_get_bitmap(k, user_mask_ptr, len * 8);
 }
 
-asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
-                                            unsigned int len,
-                                            compat_ulong_t __user *user_mask_ptr)
+COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid,
+                      unsigned int, len,
+                      compat_ulong_t __user *, user_mask_ptr)
 {
        cpumask_var_t new_mask;
        int retval;
@@ -616,8 +616,8 @@ out:
        return retval;
 }
 
-asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
-                                            compat_ulong_t __user *user_mask_ptr)
+COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t,  pid, unsigned int, len,
+                      compat_ulong_t __user *, user_mask_ptr)
 {
        int ret;
        cpumask_var_t mask;
@@ -662,9 +662,9 @@ int put_compat_itimerspec(struct compat_itimerspec __user *dst,
        return 0;
 }
 
-long compat_sys_timer_create(clockid_t which_clock,
-                       struct compat_sigevent __user *timer_event_spec,
-                       timer_t __user *created_timer_id)
+COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
+                      struct compat_sigevent __user *, timer_event_spec,
+                      timer_t __user *, created_timer_id)
 {
        struct sigevent __user *event = NULL;
 
@@ -680,9 +680,9 @@ long compat_sys_timer_create(clockid_t which_clock,
        return sys_timer_create(which_clock, event, created_timer_id);
 }
 
-long compat_sys_timer_settime(timer_t timer_id, int flags,
-                         struct compat_itimerspec __user *new,
-                         struct compat_itimerspec __user *old)
+COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
+                      struct compat_itimerspec __user *, new,
+                      struct compat_itimerspec __user *, old)
 {
        long err;
        mm_segment_t oldfs;
@@ -703,8 +703,8 @@ long compat_sys_timer_settime(timer_t timer_id, int flags,
        return err;
 }
 
-long compat_sys_timer_gettime(timer_t timer_id,
-               struct compat_itimerspec __user *setting)
+COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
+                      struct compat_itimerspec __user *, setting)
 {
        long err;
        mm_segment_t oldfs;
@@ -720,8 +720,8 @@ long compat_sys_timer_gettime(timer_t timer_id,
        return err;
 }
 
-long compat_sys_clock_settime(clockid_t which_clock,
-               struct compat_timespec __user *tp)
+COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock,
+                      struct compat_timespec __user *, tp)
 {
        long err;
        mm_segment_t oldfs;
@@ -737,8 +737,8 @@ long compat_sys_clock_settime(clockid_t which_clock,
        return err;
 }
 
-long compat_sys_clock_gettime(clockid_t which_clock,
-               struct compat_timespec __user *tp)
+COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
+                      struct compat_timespec __user *, tp)
 {
        long err;
        mm_segment_t oldfs;
@@ -754,8 +754,8 @@ long compat_sys_clock_gettime(clockid_t which_clock,
        return err;
 }
 
-long compat_sys_clock_adjtime(clockid_t which_clock,
-               struct compat_timex __user *utp)
+COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
+                      struct compat_timex __user *, utp)
 {
        struct timex txc;
        mm_segment_t oldfs;
@@ -777,8 +777,8 @@ long compat_sys_clock_adjtime(clockid_t which_clock,
        return ret;
 }
 
-long compat_sys_clock_getres(clockid_t which_clock,
-               struct compat_timespec __user *tp)
+COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
+                      struct compat_timespec __user *, tp)
 {
        long err;
        mm_segment_t oldfs;
@@ -818,9 +818,9 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)
        return err;
 }
 
-long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
-                           struct compat_timespec __user *rqtp,
-                           struct compat_timespec __user *rmtp)
+COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
+                      struct compat_timespec __user *, rqtp,
+                      struct compat_timespec __user *, rmtp)
 {
        long err;
        mm_segment_t oldfs;
@@ -1010,7 +1010,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
 
 /* compat_time_t is a 32 bit "long" and needs to get converted. */
 
-asmlinkage long compat_sys_time(compat_time_t __user * tloc)
+COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)
 {
        compat_time_t i;
        struct timeval tv;
@@ -1026,7 +1026,7 @@ asmlinkage long compat_sys_time(compat_time_t __user * tloc)
        return i;
 }
 
-asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
+COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
 {
        struct timespec tv;
        int err;
@@ -1046,7 +1046,7 @@ asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
 
 #endif /* __ARCH_WANT_COMPAT_SYS_TIME */
 
-asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
+COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp)
 {
        struct timex txc;
        int err, ret;
@@ -1065,11 +1065,11 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
 }
 
 #ifdef CONFIG_NUMA
-asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
-               compat_uptr_t __user *pages32,
-               const int __user *nodes,
-               int __user *status,
-               int flags)
+COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
+                      compat_uptr_t __user *, pages32,
+                      const int __user *, nodes,
+                      int __user *, status,
+                      int, flags)
 {
        const void __user * __user *pages;
        int i;
@@ -1085,10 +1085,10 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
        return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
 }
 
-asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
-                       compat_ulong_t maxnode,
-                       const compat_ulong_t __user *old_nodes,
-                       const compat_ulong_t __user *new_nodes)
+COMPAT_SYSCALL_DEFINE4(migrate_pages, compat_pid_t, pid,
+                      compat_ulong_t, maxnode,
+                      const compat_ulong_t __user *, old_nodes,
+                      const compat_ulong_t __user *, new_nodes)
 {
        unsigned long __user *old = NULL;
        unsigned long __user *new = NULL;
diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile
deleted file mode 100644 (file)
index 59ab052..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-y  = idle.o
diff --git a/kernel/cpu/idle.c b/kernel/cpu/idle.c
deleted file mode 100644 (file)
index 277f494..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Generic entry point for the idle threads
- */
-#include <linux/sched.h>
-#include <linux/cpu.h>
-#include <linux/tick.h>
-#include <linux/mm.h>
-#include <linux/stackprotector.h>
-
-#include <asm/tlb.h>
-
-#include <trace/events/power.h>
-
-static int __read_mostly cpu_idle_force_poll;
-
-void cpu_idle_poll_ctrl(bool enable)
-{
-       if (enable) {
-               cpu_idle_force_poll++;
-       } else {
-               cpu_idle_force_poll--;
-               WARN_ON_ONCE(cpu_idle_force_poll < 0);
-       }
-}
-
-#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP
-static int __init cpu_idle_poll_setup(char *__unused)
-{
-       cpu_idle_force_poll = 1;
-       return 1;
-}
-__setup("nohlt", cpu_idle_poll_setup);
-
-static int __init cpu_idle_nopoll_setup(char *__unused)
-{
-       cpu_idle_force_poll = 0;
-       return 1;
-}
-__setup("hlt", cpu_idle_nopoll_setup);
-#endif
-
-static inline int cpu_idle_poll(void)
-{
-       rcu_idle_enter();
-       trace_cpu_idle_rcuidle(0, smp_processor_id());
-       local_irq_enable();
-       while (!tif_need_resched())
-               cpu_relax();
-       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
-       rcu_idle_exit();
-       return 1;
-}
-
-/* Weak implementations for optional arch specific functions */
-void __weak arch_cpu_idle_prepare(void) { }
-void __weak arch_cpu_idle_enter(void) { }
-void __weak arch_cpu_idle_exit(void) { }
-void __weak arch_cpu_idle_dead(void) { }
-void __weak arch_cpu_idle(void)
-{
-       cpu_idle_force_poll = 1;
-       local_irq_enable();
-}
-
-/*
- * Generic idle loop implementation
- */
-static void cpu_idle_loop(void)
-{
-       while (1) {
-               tick_nohz_idle_enter();
-
-               while (!need_resched()) {
-                       check_pgt_cache();
-                       rmb();
-
-                       if (cpu_is_offline(smp_processor_id()))
-                               arch_cpu_idle_dead();
-
-                       local_irq_disable();
-                       arch_cpu_idle_enter();
-
-                       /*
-                        * In poll mode we reenable interrupts and spin.
-                        *
-                        * Also if we detected in the wakeup from idle
-                        * path that the tick broadcast device expired
-                        * for us, we don't want to go deep idle as we
-                        * know that the IPI is going to arrive right
-                        * away
-                        */
-                       if (cpu_idle_force_poll || tick_check_broadcast_expired()) {
-                               cpu_idle_poll();
-                       } else {
-                               if (!current_clr_polling_and_test()) {
-                                       stop_critical_timings();
-                                       rcu_idle_enter();
-                                       arch_cpu_idle();
-                                       WARN_ON_ONCE(irqs_disabled());
-                                       rcu_idle_exit();
-                                       start_critical_timings();
-                               } else {
-                                       local_irq_enable();
-                               }
-                               __current_set_polling();
-                       }
-                       arch_cpu_idle_exit();
-               }
-
-               /*
-                * Since we fell out of the loop above, we know
-                * TIF_NEED_RESCHED must be set, propagate it into
-                * PREEMPT_NEED_RESCHED.
-                *
-                * This is required because for polling idle loops we will
-                * not have had an IPI to fold the state for us.
-                */
-               preempt_set_need_resched();
-               tick_nohz_idle_exit();
-               schedule_preempt_disabled();
-       }
-}
-
-void cpu_startup_entry(enum cpuhp_state state)
-{
-       /*
-        * This #ifdef needs to die, but it's too late in the cycle to
-        * make this generic (arm and sh have never invoked the canary
-        * init for the non boot cpus!). Will be fixed in 3.11
-        */
-#ifdef CONFIG_X86
-       /*
-        * If we're the non-boot CPU, nothing set the stack canary up
-        * for us. The boot CPU already has it initialized but no harm
-        * in doing it again. This is a good place for updating it, as
-        * we wont ever return from this function (so the invalid
-        * canaries already on the stack wont ever trigger).
-        */
-       boot_init_stack_canary();
-#endif
-       __current_set_polling();
-       arch_cpu_idle_prepare();
-       cpu_idle_loop();
-}
index 4410ac6a55f1d9ae410976e3a8e7315acf88a61b..e6b1b66afe526acfa2a9ecbfc5bad9da76e8d9b4 100644 (file)
@@ -974,12 +974,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
  *    Temporarilly set tasks mems_allowed to target nodes of migration,
  *    so that the migration code can allocate pages on these nodes.
  *
- *    Call holding cpuset_mutex, so current's cpuset won't change
- *    during this call, as manage_mutex holds off any cpuset_attach()
- *    calls.  Therefore we don't need to take task_lock around the
- *    call to guarantee_online_mems(), as we know no one is changing
- *    our task's cpuset.
- *
  *    While the mm_struct we are migrating is typically from some
  *    other task, the task_struct mems_allowed that we are hacking
  *    is for our current task, which must allocate new pages for that
@@ -996,8 +990,10 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
 
        do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
 
+       rcu_read_lock();
        mems_cs = effective_nodemask_cpuset(task_cs(tsk));
        guarantee_online_mems(mems_cs, &tsk->mems_allowed);
+       rcu_read_unlock();
 }
 
 /*
@@ -2486,9 +2482,9 @@ int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 
        task_lock(current);
        cs = nearest_hardwall_ancestor(task_cs(current));
+       allowed = node_isset(node, cs->mems_allowed);
        task_unlock(current);
 
-       allowed = node_isset(node, cs->mems_allowed);
        mutex_unlock(&callback_mutex);
        return allowed;
 }
index 334b3980ffc14d396e25ccb11644f7f038cbe6e4..99982a70ddade1f728e18bd1af020b3600c4b8a2 100644 (file)
@@ -1035,7 +1035,7 @@ int dbg_io_get_char(void)
  * otherwise as a quick means to stop program execution and "break" into
  * the debugger.
  */
-void kgdb_breakpoint(void)
+noinline void kgdb_breakpoint(void)
 {
        atomic_inc(&kgdb_setting_breakpoint);
        wmb(); /* Sync point before breakpoint */
index fa0b2d4ad83c5f7a08dfecf27d16d33d928a80f2..661951ab8ae731a5094e1a29101bb7e0797794ed 100644 (file)
@@ -231,11 +231,29 @@ int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
 #define NR_ACCUMULATED_SAMPLES 128
 static DEFINE_PER_CPU(u64, running_sample_length);
 
-void perf_sample_event_took(u64 sample_len_ns)
+static void perf_duration_warn(struct irq_work *w)
 {
+       u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
        u64 avg_local_sample_len;
        u64 local_samples_len;
+
+       local_samples_len = __get_cpu_var(running_sample_length);
+       avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES;
+
+       printk_ratelimited(KERN_WARNING
+                       "perf interrupt took too long (%lld > %lld), lowering "
+                       "kernel.perf_event_max_sample_rate to %d\n",
+                       avg_local_sample_len, allowed_ns >> 1,
+                       sysctl_perf_event_sample_rate);
+}
+
+static DEFINE_IRQ_WORK(perf_duration_work, perf_duration_warn);
+
+void perf_sample_event_took(u64 sample_len_ns)
+{
        u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
+       u64 avg_local_sample_len;
+       u64 local_samples_len;
 
        if (allowed_ns == 0)
                return;
@@ -263,13 +281,14 @@ void perf_sample_event_took(u64 sample_len_ns)
        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 > %lld), lowering "
-                       "kernel.perf_event_max_sample_rate to %d\n",
-                       avg_local_sample_len, allowed_ns,
-                       sysctl_perf_event_sample_rate);
-
        update_perf_cpu_limits();
+
+       if (!irq_work_queue(&perf_duration_work)) {
+               early_printk("perf interrupt took too long (%lld > %lld), lowering "
+                            "kernel.perf_event_max_sample_rate to %d\n",
+                            avg_local_sample_len, allowed_ns >> 1,
+                            sysctl_perf_event_sample_rate);
+       }
 }
 
 static atomic64_t perf_event_id;
@@ -1714,7 +1733,7 @@ group_sched_in(struct perf_event *group_event,
               struct perf_event_context *ctx)
 {
        struct perf_event *event, *partial_group = NULL;
-       struct pmu *pmu = group_event->pmu;
+       struct pmu *pmu = ctx->pmu;
        u64 now = ctx->time;
        bool simulate = false;
 
@@ -2563,8 +2582,6 @@ static void perf_branch_stack_sched_in(struct task_struct *prev,
                if (cpuctx->ctx.nr_branch_stack > 0
                    && pmu->flush_branch_stack) {
 
-                       pmu = cpuctx->ctx.pmu;
-
                        perf_ctx_lock(cpuctx, cpuctx->task_ctx);
 
                        perf_pmu_disable(pmu);
@@ -6294,7 +6311,7 @@ static int perf_event_idx_default(struct perf_event *event)
  * Ensures all contexts with the same task_ctx_nr have the same
  * pmu_cpu_context too.
  */
-static void *find_pmu_context(int ctxn)
+static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
 {
        struct pmu *pmu;
 
index 763faf037ec1cccb135b98d1deccf339f69cd2e5..d8a6446adbcbebe00410d0c8b3cef7b5bfb4b1c9 100644 (file)
@@ -36,7 +36,7 @@ extern struct exception_table_entry __start___ex_table[];
 extern struct exception_table_entry __stop___ex_table[];
 
 /* Cleared by build time tools if the table is already sorted. */
-u32 __initdata main_extable_sort_needed = 1;
+u32 __initdata __visible main_extable_sort_needed = 1;
 
 /* Sort the kernel's built-in exception table */
 void __init sort_main_extable(void)
index a17621c6cd4272182a78083e736c5972c741ed7a..332688e5e7b4c93e55f3785ceb6beb70f4b2182f 100644 (file)
@@ -237,6 +237,7 @@ void __put_task_struct(struct task_struct *tsk)
        WARN_ON(atomic_read(&tsk->usage));
        WARN_ON(tsk == current);
 
+       task_numa_free(tsk);
        security_task_free(tsk);
        exit_creds(tsk);
        delayacct_tsk_free(tsk);
index 44a1261cb9ff63a33eec42136be4794a0752a0ac..67dacaf93e56c0edb12b74a84b40da9fe596ea49 100644 (file)
  * enqueue.
  */
 
+#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
 int __read_mostly futex_cmpxchg_enabled;
+#endif
 
 /*
  * Futex flags used to encode options to functions and preserve them across
@@ -234,6 +236,7 @@ static const struct futex_q futex_q_init = {
  * waiting on a futex.
  */
 struct futex_hash_bucket {
+       atomic_t waiters;
        spinlock_t lock;
        struct plist_head chain;
 } ____cacheline_aligned_in_smp;
@@ -253,22 +256,37 @@ static inline void futex_get_mm(union futex_key *key)
        smp_mb__after_atomic_inc();
 }
 
-static inline bool hb_waiters_pending(struct futex_hash_bucket *hb)
+/*
+ * Reflects a new waiter being added to the waitqueue.
+ */
+static inline void hb_waiters_inc(struct futex_hash_bucket *hb)
 {
 #ifdef CONFIG_SMP
+       atomic_inc(&hb->waiters);
        /*
-        * Tasks trying to enter the critical region are most likely
-        * potential waiters that will be added to the plist. Ensure
-        * that wakers won't miss to-be-slept tasks in the window between
-        * the wait call and the actual plist_add.
+        * Full barrier (A), see the ordering comment above.
         */
-       if (spin_is_locked(&hb->lock))
-               return true;
-       smp_rmb(); /* Make sure we check the lock state first */
+       smp_mb__after_atomic_inc();
+#endif
+}
+
+/*
+ * Reflects a waiter being removed from the waitqueue by wakeup
+ * paths.
+ */
+static inline void hb_waiters_dec(struct futex_hash_bucket *hb)
+{
+#ifdef CONFIG_SMP
+       atomic_dec(&hb->waiters);
+#endif
+}
 
-       return !plist_head_empty(&hb->chain);
+static inline int hb_waiters_pending(struct futex_hash_bucket *hb)
+{
+#ifdef CONFIG_SMP
+       return atomic_read(&hb->waiters);
 #else
-       return true;
+       return 1;
 #endif
 }
 
@@ -954,6 +972,7 @@ static void __unqueue_futex(struct futex_q *q)
 
        hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
        plist_del(&q->list, &hb->chain);
+       hb_waiters_dec(hb);
 }
 
 /*
@@ -1257,7 +1276,9 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
         */
        if (likely(&hb1->chain != &hb2->chain)) {
                plist_del(&q->list, &hb1->chain);
+               hb_waiters_dec(hb1);
                plist_add(&q->list, &hb2->chain);
+               hb_waiters_inc(hb2);
                q->lock_ptr = &hb2->lock;
        }
        get_futex_key_refs(key2);
@@ -1600,6 +1621,17 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
        struct futex_hash_bucket *hb;
 
        hb = hash_futex(&q->key);
+
+       /*
+        * Increment the counter before taking the lock so that
+        * a potential waker won't miss a to-be-slept task that is
+        * waiting for the spinlock. This is safe as all queue_lock()
+        * users end up calling queue_me(). Similarly, for housekeeping,
+        * decrement the counter at queue_unlock() when some error has
+        * occurred and we don't end up adding the task to the list.
+        */
+       hb_waiters_inc(hb);
+
        q->lock_ptr = &hb->lock;
 
        spin_lock(&hb->lock); /* implies MB (A) */
@@ -1611,6 +1643,7 @@ queue_unlock(struct futex_hash_bucket *hb)
        __releases(&hb->lock)
 {
        spin_unlock(&hb->lock);
+       hb_waiters_dec(hb);
 }
 
 /**
@@ -2342,6 +2375,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
                 * Unqueue the futex_q and determine which it was.
                 */
                plist_del(&q->list, &hb->chain);
+               hb_waiters_dec(hb);
 
                /* Handle spurious wakeups gracefully */
                ret = -EWOULDBLOCK;
@@ -2843,9 +2877,28 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
        return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
 
-static int __init futex_init(void)
+static void __init futex_detect_cmpxchg(void)
 {
+#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
        u32 curval;
+
+       /*
+        * This will fail and we want it. Some arch implementations do
+        * runtime detection of the futex_atomic_cmpxchg_inatomic()
+        * functionality. We want to know that before we call in any
+        * of the complex code paths. Also we want to prevent
+        * registration of robust lists in that case. NULL is
+        * guaranteed to fault and we get -EFAULT on functional
+        * implementation, the non-functional ones will return
+        * -ENOSYS.
+        */
+       if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
+               futex_cmpxchg_enabled = 1;
+#endif
+}
+
+static int __init futex_init(void)
+{
        unsigned int futex_shift;
        unsigned long i;
 
@@ -2861,20 +2914,11 @@ static int __init futex_init(void)
                                               &futex_shift, NULL,
                                               futex_hashsize, futex_hashsize);
        futex_hashsize = 1UL << futex_shift;
-       /*
-        * This will fail and we want it. Some arch implementations do
-        * runtime detection of the futex_atomic_cmpxchg_inatomic()
-        * functionality. We want to know that before we call in any
-        * of the complex code paths. Also we want to prevent
-        * registration of robust lists in that case. NULL is
-        * guaranteed to fault and we get -EFAULT on functional
-        * implementation, the non-functional ones will return
-        * -ENOSYS.
-        */
-       if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
-               futex_cmpxchg_enabled = 1;
+
+       futex_detect_cmpxchg();
 
        for (i = 0; i < futex_hashsize; i++) {
+               atomic_set(&futex_queues[i].waiters, 0);
                plist_head_init(&futex_queues[i].chain);
                spin_lock_init(&futex_queues[i].lock);
        }
index 09094361dce523fec7def28599b17c34bee16bec..d55092ceee2975c204bcb90e856f9b6504d577ac 100644 (file)
@@ -168,19 +168,6 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
        }
 }
 
-
-/*
- * Get the preferred target CPU for NOHZ
- */
-static int hrtimer_get_target(int this_cpu, int pinned)
-{
-#ifdef CONFIG_NO_HZ_COMMON
-       if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu))
-               return get_nohz_timer_target();
-#endif
-       return this_cpu;
-}
-
 /*
  * With HIGHRES=y we do not migrate the timer when it is expiring
  * before the next event on the target cpu because we cannot reprogram
@@ -214,7 +201,7 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
        struct hrtimer_clock_base *new_base;
        struct hrtimer_cpu_base *new_cpu_base;
        int this_cpu = smp_processor_id();
-       int cpu = hrtimer_get_target(this_cpu, pinned);
+       int cpu = get_nohz_timer_target(pinned);
        int basenum = base->index;
 
 again:
index dc04c166c54d7bc8e86ab87bec4075a3cc492e12..6397df2d6945b09ae853c1a75e4d18aa6da7096f 100644 (file)
@@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc)
        }
 }
 
+void unmask_threaded_irq(struct irq_desc *desc)
+{
+       struct irq_chip *chip = desc->irq_data.chip;
+
+       if (chip->flags & IRQCHIP_EOI_THREADED)
+               chip->irq_eoi(&desc->irq_data);
+
+       if (chip->irq_unmask) {
+               chip->irq_unmask(&desc->irq_data);
+               irq_state_clr_masked(desc);
+       }
+}
+
 /*
  *     handle_nested_irq - Handle a nested irq from a irq thread
  *     @irq:   the interrupt number
@@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc)
 static inline void preflow_handler(struct irq_desc *desc) { }
 #endif
 
+static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
+{
+       if (!(desc->istate & IRQS_ONESHOT)) {
+               chip->irq_eoi(&desc->irq_data);
+               return;
+       }
+       /*
+        * We need to unmask in the following cases:
+        * - Oneshot irq which did not wake the thread (caused by a
+        *   spurious interrupt or a primary handler handling it
+        *   completely).
+        */
+       if (!irqd_irq_disabled(&desc->irq_data) &&
+           irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
+               chip->irq_eoi(&desc->irq_data);
+               unmask_irq(desc);
+       } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
+               chip->irq_eoi(&desc->irq_data);
+       }
+}
+
 /**
  *     handle_fasteoi_irq - irq handler for transparent controllers
  *     @irq:   the interrupt number
@@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { }
 void
 handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
 {
+       struct irq_chip *chip = desc->irq_data.chip;
+
        raw_spin_lock(&desc->lock);
 
        if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
@@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        preflow_handler(desc);
        handle_irq_event(desc);
 
-       if (desc->istate & IRQS_ONESHOT)
-               cond_unmask_irq(desc);
+       cond_unmask_eoi_irq(desc, chip);
 
-out_eoi:
-       desc->irq_data.chip->irq_eoi(&desc->irq_data);
-out_unlock:
        raw_spin_unlock(&desc->lock);
        return;
 out:
-       if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
-               goto out_eoi;
-       goto out_unlock;
+       if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
+               chip->irq_eoi(&desc->irq_data);
+       raw_spin_unlock(&desc->lock);
 }
 
 /**
index 131ca176b4973c9b5f40ff8aa1ab471587ac71ae..635480270858448064b1afa54bf616f074744d60 100644 (file)
@@ -41,6 +41,7 @@ irqreturn_t no_action(int cpl, void *dev_id)
 {
        return IRQ_NONE;
 }
+EXPORT_SYMBOL_GPL(no_action);
 
 static void warn_no_thread(unsigned int irq, struct irqaction *action)
 {
@@ -51,7 +52,7 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
               "but no thread function available.", irq, action->name);
 }
 
-static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
+void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
 {
        /*
         * In case the thread crashed and was killed we just pretend that
@@ -157,7 +158,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
                                break;
                        }
 
-                       irq_wake_thread(desc, action);
+                       __irq_wake_thread(desc, action);
 
                        /* Fall through to add to randomness */
                case IRQ_HANDLED:
index 001fa5bab4902dcf403384ded269841c09d3ca6a..ddf1ffeb79f1e3ac5a5408465d4f31391525de13 100644 (file)
@@ -6,6 +6,7 @@
  * of this file for your non core code.
  */
 #include <linux/irqdesc.h>
+#include <linux/kernel_stat.h>
 
 #ifdef CONFIG_SPARSE_IRQ
 # define IRQ_BITMAP_BITS       (NR_IRQS + 8196)
@@ -73,6 +74,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
 extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
 extern void mask_irq(struct irq_desc *desc);
 extern void unmask_irq(struct irq_desc *desc);
+extern void unmask_threaded_irq(struct irq_desc *desc);
 
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 
@@ -82,6 +84,7 @@ irqreturn_t handle_irq_event(struct irq_desc *desc);
 /* Resending of interrupts :*/
 void check_irq_resend(struct irq_desc *desc, unsigned int irq);
 bool irq_wait_for_poll(struct irq_desc *desc);
+void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
 
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
@@ -179,3 +182,9 @@ static inline bool irqd_has_set(struct irq_data *d, unsigned int mask)
 {
        return d->state_use_accessors & mask;
 }
+
+static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc)
+{
+       __this_cpu_inc(*desc->kstat_irqs);
+       __this_cpu_inc(kstat.irqs_sum);
+}
index 8ab8e9390297a06ef7c4efc2a8ad502433b13879..a7174617616ba6b8f404a1c3f01cf8b7dd90cb4d 100644 (file)
@@ -489,6 +489,11 @@ void dynamic_irq_cleanup(unsigned int irq)
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
 
+void kstat_incr_irq_this_cpu(unsigned int irq)
+{
+       kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+}
+
 unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        struct irq_desc *desc = irq_to_desc(irq);
index cf68bb36fe5885dd2ba7b9c9ccef3c5165a320d3..f14033700c25cbc6872ccc2e60d33ee25a3493e9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/topology.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
index 481a13c43b1708d3501a7f686760573c4eab6a34..2486a4c1a710ba057c7f884faae19bff1fc6d31c 100644 (file)
@@ -32,24 +32,10 @@ static int __init setup_forced_irqthreads(char *arg)
 early_param("threadirqs", setup_forced_irqthreads);
 #endif
 
-/**
- *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
- *     @irq: interrupt number to wait for
- *
- *     This function waits for any pending IRQ handlers for this interrupt
- *     to complete before returning. If you use this function while
- *     holding a resource the IRQ handler may need you will deadlock.
- *
- *     This function may be called - with care - from IRQ context.
- */
-void synchronize_irq(unsigned int irq)
+static void __synchronize_hardirq(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        bool inprogress;
 
-       if (!desc)
-               return;
-
        do {
                unsigned long flags;
 
@@ -67,12 +53,56 @@ void synchronize_irq(unsigned int irq)
 
                /* Oops, that failed? */
        } while (inprogress);
+}
 
-       /*
-        * We made sure that no hardirq handler is running. Now verify
-        * that no threaded handlers are active.
-        */
-       wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
+/**
+ *     synchronize_hardirq - wait for pending hard IRQ handlers (on other CPUs)
+ *     @irq: interrupt number to wait for
+ *
+ *     This function waits for any pending hard IRQ handlers for this
+ *     interrupt to complete before returning. If you use this
+ *     function while holding a resource the IRQ handler may need you
+ *     will deadlock. It does not take associated threaded handlers
+ *     into account.
+ *
+ *     Do not use this for shutdown scenarios where you must be sure
+ *     that all parts (hardirq and threaded handler) have completed.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+void synchronize_hardirq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (desc)
+               __synchronize_hardirq(desc);
+}
+EXPORT_SYMBOL(synchronize_hardirq);
+
+/**
+ *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
+ *     @irq: interrupt number to wait for
+ *
+ *     This function waits for any pending IRQ handlers for this interrupt
+ *     to complete before returning. If you use this function while
+ *     holding a resource the IRQ handler may need you will deadlock.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+void synchronize_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (desc) {
+               __synchronize_hardirq(desc);
+               /*
+                * We made sure that no hardirq handler is
+                * running. Now verify that no threaded handlers are
+                * active.
+                */
+               wait_event(desc->wait_for_threads,
+                          !atomic_read(&desc->threads_active));
+       }
 }
 EXPORT_SYMBOL(synchronize_irq);
 
@@ -718,7 +748,7 @@ again:
 
        if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
            irqd_irq_masked(&desc->irq_data))
-               unmask_irq(desc);
+               unmask_threaded_irq(desc);
 
 out_unlock:
        raw_spin_unlock_irq(&desc->lock);
@@ -727,7 +757,7 @@ out_unlock:
 
 #ifdef CONFIG_SMP
 /*
- * Check whether we need to chasnge the affinity of the interrupt thread.
+ * Check whether we need to change the affinity of the interrupt thread.
  */
 static void
 irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
@@ -802,8 +832,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc,
 
 static void wake_threads_waitq(struct irq_desc *desc)
 {
-       if (atomic_dec_and_test(&desc->threads_active) &&
-           waitqueue_active(&desc->wait_for_threads))
+       if (atomic_dec_and_test(&desc->threads_active))
                wake_up(&desc->wait_for_threads);
 }
 
@@ -881,6 +910,33 @@ static int irq_thread(void *data)
        return 0;
 }
 
+/**
+ *     irq_wake_thread - wake the irq thread for the action identified by dev_id
+ *     @irq:           Interrupt line
+ *     @dev_id:        Device identity for which the thread should be woken
+ *
+ */
+void irq_wake_thread(unsigned int irq, void *dev_id)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct irqaction *action;
+       unsigned long flags;
+
+       if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
+               return;
+
+       raw_spin_lock_irqsave(&desc->lock, flags);
+       for (action = desc->action; action; action = action->next) {
+               if (action->dev_id == dev_id) {
+                       if (action->thread)
+                               __irq_wake_thread(desc, action);
+                       break;
+               }
+       }
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+}
+EXPORT_SYMBOL_GPL(irq_wake_thread);
+
 static void irq_setup_forced_threading(struct irqaction *new)
 {
        if (!force_irqthreads)
@@ -897,6 +953,23 @@ static void irq_setup_forced_threading(struct irqaction *new)
        }
 }
 
+static int irq_request_resources(struct irq_desc *desc)
+{
+       struct irq_data *d = &desc->irq_data;
+       struct irq_chip *c = d->chip;
+
+       return c->irq_request_resources ? c->irq_request_resources(d) : 0;
+}
+
+static void irq_release_resources(struct irq_desc *desc)
+{
+       struct irq_data *d = &desc->irq_data;
+       struct irq_chip *c = d->chip;
+
+       if (c->irq_release_resources)
+               c->irq_release_resources(d);
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -1092,6 +1165,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        }
 
        if (!shared) {
+               ret = irq_request_resources(desc);
+               if (ret) {
+                       pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
+                              new->name, irq, desc->irq_data.chip->name);
+                       goto out_mask;
+               }
+
                init_waitqueue_head(&desc->wait_for_threads);
 
                /* Setup the type (level, edge polarity) if configured: */
@@ -1262,8 +1342,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
        *action_ptr = action->next;
 
        /* If this was the last handler, shut down the IRQ line: */
-       if (!desc->action)
+       if (!desc->action) {
                irq_shutdown(desc);
+               irq_release_resources(desc);
+       }
 
 #ifdef CONFIG_SMP
        /* make sure affinity_hint is cleaned up */
index 36f6ee181b0c4313a7632f6914341cacd26989b0..ac1ba2f110321fe637b2f5538c0ac568dbafc10e 100644 (file)
@@ -324,15 +324,15 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
 
 #ifdef CONFIG_SMP
        /* create /proc/irq/<irq>/smp_affinity */
-       proc_create_data("smp_affinity", 0600, desc->dir,
+       proc_create_data("smp_affinity", 0644, desc->dir,
                         &irq_affinity_proc_fops, (void *)(long)irq);
 
        /* create /proc/irq/<irq>/affinity_hint */
-       proc_create_data("affinity_hint", 0400, desc->dir,
+       proc_create_data("affinity_hint", 0444, desc->dir,
                         &irq_affinity_hint_proc_fops, (void *)(long)irq);
 
        /* create /proc/irq/<irq>/smp_affinity_list */
-       proc_create_data("smp_affinity_list", 0600, desc->dir,
+       proc_create_data("smp_affinity_list", 0644, desc->dir,
                         &irq_affinity_list_proc_fops, (void *)(long)irq);
 
        proc_create_data("node", 0444, desc->dir,
@@ -372,7 +372,7 @@ void unregister_handler_proc(unsigned int irq, struct irqaction *action)
 static void register_default_affinity_proc(void)
 {
 #ifdef CONFIG_SMP
-       proc_create("irq/default_smp_affinity", 0600, NULL,
+       proc_create("irq/default_smp_affinity", 0644, NULL,
                    &default_affinity_proc_fops);
 #endif
 }
index 55fcce6065cf6bc3213829fd8188cae90b61b778..a82170e2fa78e50fbefa29c6cf71b1eccadae175 100644 (file)
@@ -61,11 +61,11 @@ void __weak arch_irq_work_raise(void)
  *
  * Can be re-enqueued while the callback is still in progress.
  */
-void irq_work_queue(struct irq_work *work)
+bool irq_work_queue(struct irq_work *work)
 {
        /* Only queue if not already pending */
        if (!irq_work_claim(work))
-               return;
+               return false;
 
        /* Queue the entry and raise the IPI if needed. */
        preempt_disable();
@@ -83,6 +83,8 @@ void irq_work_queue(struct irq_work *work)
        }
 
        preempt_enable();
+
+       return true;
 }
 EXPORT_SYMBOL_GPL(irq_work_queue);
 
index 60bafbed06abd7a7b2defd0c031ca18b7287a37e..45601cf41bee0106ff37a7ef5112cfd065c4a7bc 100644 (file)
@@ -1039,10 +1039,10 @@ void __weak crash_unmap_reserved_pages(void)
 {}
 
 #ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_kexec_load(unsigned long entry,
-                               unsigned long nr_segments,
-                               struct compat_kexec_segment __user *segments,
-                               unsigned long flags)
+COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
+                      compat_ulong_t, nr_segments,
+                      struct compat_kexec_segment __user *, segments,
+                      compat_ulong_t, flags)
 {
        struct compat_kexec_segment in;
        struct kexec_segment out, __user *ksegments;
index d945a949760f0ec4a9fd09313e30fb5f651bc39a..e660964086e2e46d1066e143d29c21887f712d5d 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/sched.h>
 #include <linux/capability.h>
 
+#include <linux/rcupdate.h>    /* rcu_expedited */
+
 #define KERNEL_ATTR_RO(_name) \
 static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
 
index baab8e5e7f66acd327f71afd40fbd7530803a449..306a76b51e0f4308a1ef680e006e07333e98d3c0 100644 (file)
@@ -1,5 +1,5 @@
 
-obj-y += mutex.o semaphore.o rwsem.o lglock.o
+obj-y += mutex.o semaphore.o rwsem.o lglock.o mcs_spinlock.o
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_lockdep.o = -pg
@@ -23,3 +23,4 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem-xadd.o
 obj-$(CONFIG_PERCPU_RWSEM) += percpu-rwsem.o
+obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o
index eb8a54783fa0f47bb9b51568ec9dfed3d51cc48d..b0e9467922e1a476bfe1d4d8503ac7623affcaea 100644 (file)
@@ -1936,12 +1936,12 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
 
        for (;;) {
                int distance = curr->lockdep_depth - depth + 1;
-               hlock = curr->held_locks + depth-1;
+               hlock = curr->held_locks + depth - 1;
                /*
                 * Only non-recursive-read entries get new dependencies
                 * added:
                 */
-               if (hlock->read != 2) {
+               if (hlock->read != 2 && hlock->check) {
                        if (!check_prev_add(curr, hlock, next,
                                                distance, trylock_loop))
                                return 0;
@@ -2098,7 +2098,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
         * (If lookup_chain_cache() returns with 1 it acquires
         * graph_lock for us)
         */
-       if (!hlock->trylock && (hlock->check == 2) &&
+       if (!hlock->trylock && hlock->check &&
            lookup_chain_cache(curr, hlock, chain_key)) {
                /*
                 * Check whether last held lock:
@@ -2517,7 +2517,7 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
 
                BUG_ON(usage_bit >= LOCK_USAGE_STATES);
 
-               if (hlock_class(hlock)->key == __lockdep_no_validate__.subkeys)
+               if (!hlock->check)
                        continue;
 
                if (!mark_lock(curr, hlock, usage_bit))
@@ -2557,7 +2557,7 @@ static void __trace_hardirqs_on_caller(unsigned long ip)
        debug_atomic_inc(hardirqs_on_events);
 }
 
-void trace_hardirqs_on_caller(unsigned long ip)
+__visible void trace_hardirqs_on_caller(unsigned long ip)
 {
        time_hardirqs_on(CALLER_ADDR0, ip);
 
@@ -2610,7 +2610,7 @@ EXPORT_SYMBOL(trace_hardirqs_on);
 /*
  * Hardirqs were disabled:
  */
-void trace_hardirqs_off_caller(unsigned long ip)
+__visible void trace_hardirqs_off_caller(unsigned long ip)
 {
        struct task_struct *curr = current;
 
@@ -3055,9 +3055,6 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        int class_idx;
        u64 chain_key;
 
-       if (!prove_locking)
-               check = 1;
-
        if (unlikely(!debug_locks))
                return 0;
 
@@ -3069,8 +3066,8 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
                return 0;
 
-       if (lock->key == &__lockdep_no_validate__)
-               check = 1;
+       if (!prove_locking || lock->key == &__lockdep_no_validate__)
+               check = 0;
 
        if (subclass < NR_LOCKDEP_CACHING_CLASSES)
                class = lock->class_cache[subclass];
@@ -3138,7 +3135,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        hlock->holdtime_stamp = lockstat_clock();
 #endif
 
-       if (check == 2 && !mark_irqflags(curr, hlock))
+       if (check && !mark_irqflags(curr, hlock))
                return 0;
 
        /* mark it as used: */
@@ -4191,7 +4188,7 @@ void debug_show_held_locks(struct task_struct *task)
 }
 EXPORT_SYMBOL_GPL(debug_show_held_locks);
 
-void lockdep_sys_exit(void)
+asmlinkage void lockdep_sys_exit(void)
 {
        struct task_struct *curr = current;
 
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
new file mode 100644 (file)
index 0000000..f26b1a1
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * Module-based torture test facility for locking
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright (C) IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@us.ibm.com>
+ *     Based on kernel/rcu/torture.c.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/trace_clock.h>
+#include <asm/byteorder.h>
+#include <linux/torture.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
+
+torture_param(int, nwriters_stress, -1,
+            "Number of write-locking stress-test threads");
+torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
+torture_param(int, onoff_interval, 0,
+            "Time between CPU hotplugs (s), 0=disable");
+torture_param(int, shuffle_interval, 3,
+            "Number of jiffies between shuffles, 0=disable");
+torture_param(int, shutdown_secs, 0, "Shutdown time (j), <= zero to disable.");
+torture_param(int, stat_interval, 60,
+            "Number of seconds between stats printk()s");
+torture_param(int, stutter, 5, "Number of jiffies to run/halt test, 0=disable");
+torture_param(bool, verbose, true,
+            "Enable verbose debugging printk()s");
+
+static char *torture_type = "spin_lock";
+module_param(torture_type, charp, 0444);
+MODULE_PARM_DESC(torture_type,
+                "Type of lock to torture (spin_lock, spin_lock_irq, ...)");
+
+static atomic_t n_lock_torture_errors;
+
+static struct task_struct *stats_task;
+static struct task_struct **writer_tasks;
+
+static int nrealwriters_stress;
+static bool lock_is_write_held;
+
+struct lock_writer_stress_stats {
+       long n_write_lock_fail;
+       long n_write_lock_acquired;
+};
+static struct lock_writer_stress_stats *lwsa;
+
+#if defined(MODULE) || defined(CONFIG_LOCK_TORTURE_TEST_RUNNABLE)
+#define LOCKTORTURE_RUNNABLE_INIT 1
+#else
+#define LOCKTORTURE_RUNNABLE_INIT 0
+#endif
+int locktorture_runnable = LOCKTORTURE_RUNNABLE_INIT;
+module_param(locktorture_runnable, int, 0444);
+MODULE_PARM_DESC(locktorture_runnable, "Start locktorture at boot");
+
+/* Forward reference. */
+static void lock_torture_cleanup(void);
+
+/*
+ * Operations vector for selecting different types of tests.
+ */
+struct lock_torture_ops {
+       void (*init)(void);
+       int (*writelock)(void);
+       void (*write_delay)(struct torture_random_state *trsp);
+       void (*writeunlock)(void);
+       unsigned long flags;
+       const char *name;
+};
+
+static struct lock_torture_ops *cur_ops;
+
+/*
+ * Definitions for lock torture testing.
+ */
+
+static int torture_lock_busted_write_lock(void)
+{
+       return 0;  /* BUGGY, do not use in real life!!! */
+}
+
+static void torture_lock_busted_write_delay(struct torture_random_state *trsp)
+{
+       const unsigned long longdelay_us = 100;
+
+       /* We want a long delay occasionally to force massive contention.  */
+       if (!(torture_random(trsp) %
+             (nrealwriters_stress * 2000 * longdelay_us)))
+               mdelay(longdelay_us);
+#ifdef CONFIG_PREEMPT
+       if (!(torture_random(trsp) % (nrealwriters_stress * 20000)))
+               preempt_schedule();  /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_lock_busted_write_unlock(void)
+{
+         /* BUGGY, do not use in real life!!! */
+}
+
+static struct lock_torture_ops lock_busted_ops = {
+       .writelock      = torture_lock_busted_write_lock,
+       .write_delay    = torture_lock_busted_write_delay,
+       .writeunlock    = torture_lock_busted_write_unlock,
+       .name           = "lock_busted"
+};
+
+static DEFINE_SPINLOCK(torture_spinlock);
+
+static int torture_spin_lock_write_lock(void) __acquires(torture_spinlock)
+{
+       spin_lock(&torture_spinlock);
+       return 0;
+}
+
+static void torture_spin_lock_write_delay(struct torture_random_state *trsp)
+{
+       const unsigned long shortdelay_us = 2;
+       const unsigned long longdelay_us = 100;
+
+       /* We want a short delay mostly to emulate likely code, and
+        * we want a long delay occasionally to force massive contention.
+        */
+       if (!(torture_random(trsp) %
+             (nrealwriters_stress * 2000 * longdelay_us)))
+               mdelay(longdelay_us);
+       if (!(torture_random(trsp) %
+             (nrealwriters_stress * 2 * shortdelay_us)))
+               udelay(shortdelay_us);
+#ifdef CONFIG_PREEMPT
+       if (!(torture_random(trsp) % (nrealwriters_stress * 20000)))
+               preempt_schedule();  /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_spin_lock_write_unlock(void) __releases(torture_spinlock)
+{
+       spin_unlock(&torture_spinlock);
+}
+
+static struct lock_torture_ops spin_lock_ops = {
+       .writelock      = torture_spin_lock_write_lock,
+       .write_delay    = torture_spin_lock_write_delay,
+       .writeunlock    = torture_spin_lock_write_unlock,
+       .name           = "spin_lock"
+};
+
+static int torture_spin_lock_write_lock_irq(void)
+__acquires(torture_spinlock_irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&torture_spinlock, flags);
+       cur_ops->flags = flags;
+       return 0;
+}
+
+static void torture_lock_spin_write_unlock_irq(void)
+__releases(torture_spinlock)
+{
+       spin_unlock_irqrestore(&torture_spinlock, cur_ops->flags);
+}
+
+static struct lock_torture_ops spin_lock_irq_ops = {
+       .writelock      = torture_spin_lock_write_lock_irq,
+       .write_delay    = torture_spin_lock_write_delay,
+       .writeunlock    = torture_lock_spin_write_unlock_irq,
+       .name           = "spin_lock_irq"
+};
+
+/*
+ * Lock torture writer kthread.  Repeatedly acquires and releases
+ * the lock, checking for duplicate acquisitions.
+ */
+static int lock_torture_writer(void *arg)
+{
+       struct lock_writer_stress_stats *lwsp = arg;
+       static DEFINE_TORTURE_RANDOM(rand);
+
+       VERBOSE_TOROUT_STRING("lock_torture_writer task started");
+       set_user_nice(current, 19);
+
+       do {
+               schedule_timeout_uninterruptible(1);
+               cur_ops->writelock();
+               if (WARN_ON_ONCE(lock_is_write_held))
+                       lwsp->n_write_lock_fail++;
+               lock_is_write_held = 1;
+               lwsp->n_write_lock_acquired++;
+               cur_ops->write_delay(&rand);
+               lock_is_write_held = 0;
+               cur_ops->writeunlock();
+               stutter_wait("lock_torture_writer");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("lock_torture_writer");
+       return 0;
+}
+
+/*
+ * Create an lock-torture-statistics message in the specified buffer.
+ */
+static void lock_torture_printk(char *page)
+{
+       bool fail = 0;
+       int i;
+       long max = 0;
+       long min = lwsa[0].n_write_lock_acquired;
+       long long sum = 0;
+
+       for (i = 0; i < nrealwriters_stress; i++) {
+               if (lwsa[i].n_write_lock_fail)
+                       fail = true;
+               sum += lwsa[i].n_write_lock_acquired;
+               if (max < lwsa[i].n_write_lock_fail)
+                       max = lwsa[i].n_write_lock_fail;
+               if (min > lwsa[i].n_write_lock_fail)
+                       min = lwsa[i].n_write_lock_fail;
+       }
+       page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
+       page += sprintf(page,
+                       "Writes:  Total: %lld  Max/Min: %ld/%ld %s  Fail: %d %s\n",
+                       sum, max, min, max / 2 > min ? "???" : "",
+                       fail, fail ? "!!!" : "");
+       if (fail)
+               atomic_inc(&n_lock_torture_errors);
+}
+
+/*
+ * Print torture statistics.  Caller must ensure that there is only one
+ * call to this function at a given time!!!  This is normally accomplished
+ * by relying on the module system to only have one copy of the module
+ * loaded, and then by giving the lock_torture_stats kthread full control
+ * (or the init/cleanup functions when lock_torture_stats thread is not
+ * running).
+ */
+static void lock_torture_stats_print(void)
+{
+       int size = nrealwriters_stress * 200 + 8192;
+       char *buf;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               pr_err("lock_torture_stats_print: Out of memory, need: %d",
+                      size);
+               return;
+       }
+       lock_torture_printk(buf);
+       pr_alert("%s", buf);
+       kfree(buf);
+}
+
+/*
+ * Periodically prints torture statistics, if periodic statistics printing
+ * was specified via the stat_interval module parameter.
+ *
+ * No need to worry about fullstop here, since this one doesn't reference
+ * volatile state or register callbacks.
+ */
+static int lock_torture_stats(void *arg)
+{
+       VERBOSE_TOROUT_STRING("lock_torture_stats task started");
+       do {
+               schedule_timeout_interruptible(stat_interval * HZ);
+               lock_torture_stats_print();
+               torture_shutdown_absorb("lock_torture_stats");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("lock_torture_stats");
+       return 0;
+}
+
+static inline void
+lock_torture_print_module_parms(struct lock_torture_ops *cur_ops,
+                               const char *tag)
+{
+       pr_alert("%s" TORTURE_FLAG
+                "--- %s: nwriters_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n",
+                torture_type, tag, nrealwriters_stress, stat_interval, verbose,
+                shuffle_interval, stutter, shutdown_secs,
+                onoff_interval, onoff_holdoff);
+}
+
+static void lock_torture_cleanup(void)
+{
+       int i;
+
+       if (torture_cleanup())
+               return;
+
+       if (writer_tasks) {
+               for (i = 0; i < nrealwriters_stress; i++)
+                       torture_stop_kthread(lock_torture_writer,
+                                            writer_tasks[i]);
+               kfree(writer_tasks);
+               writer_tasks = NULL;
+       }
+
+       torture_stop_kthread(lock_torture_stats, stats_task);
+       lock_torture_stats_print();  /* -After- the stats thread is stopped! */
+
+       if (atomic_read(&n_lock_torture_errors))
+               lock_torture_print_module_parms(cur_ops,
+                                               "End of test: FAILURE");
+       else if (torture_onoff_failures())
+               lock_torture_print_module_parms(cur_ops,
+                                               "End of test: LOCK_HOTPLUG");
+       else
+               lock_torture_print_module_parms(cur_ops,
+                                               "End of test: SUCCESS");
+}
+
+static int __init lock_torture_init(void)
+{
+       int i;
+       int firsterr = 0;
+       static struct lock_torture_ops *torture_ops[] = {
+               &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops,
+       };
+
+       torture_init_begin(torture_type, verbose, &locktorture_runnable);
+
+       /* Process args and tell the world that the torturer is on the job. */
+       for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
+               cur_ops = torture_ops[i];
+               if (strcmp(torture_type, cur_ops->name) == 0)
+                       break;
+       }
+       if (i == ARRAY_SIZE(torture_ops)) {
+               pr_alert("lock-torture: invalid torture type: \"%s\"\n",
+                        torture_type);
+               pr_alert("lock-torture types:");
+               for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
+                       pr_alert(" %s", torture_ops[i]->name);
+               pr_alert("\n");
+               torture_init_end();
+               return -EINVAL;
+       }
+       if (cur_ops->init)
+               cur_ops->init(); /* no "goto unwind" prior to this point!!! */
+
+       if (nwriters_stress >= 0)
+               nrealwriters_stress = nwriters_stress;
+       else
+               nrealwriters_stress = 2 * num_online_cpus();
+       lock_torture_print_module_parms(cur_ops, "Start of test");
+
+       /* Initialize the statistics so that each run gets its own numbers. */
+
+       lock_is_write_held = 0;
+       lwsa = kmalloc(sizeof(*lwsa) * nrealwriters_stress, GFP_KERNEL);
+       if (lwsa == NULL) {
+               VERBOSE_TOROUT_STRING("lwsa: Out of memory");
+               firsterr = -ENOMEM;
+               goto unwind;
+       }
+       for (i = 0; i < nrealwriters_stress; i++) {
+               lwsa[i].n_write_lock_fail = 0;
+               lwsa[i].n_write_lock_acquired = 0;
+       }
+
+       /* Start up the kthreads. */
+
+       if (onoff_interval > 0) {
+               firsterr = torture_onoff_init(onoff_holdoff * HZ,
+                                             onoff_interval * HZ);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (shuffle_interval > 0) {
+               firsterr = torture_shuffle_init(shuffle_interval);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (shutdown_secs > 0) {
+               firsterr = torture_shutdown_init(shutdown_secs,
+                                                lock_torture_cleanup);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (stutter > 0) {
+               firsterr = torture_stutter_init(stutter);
+               if (firsterr)
+                       goto unwind;
+       }
+
+       writer_tasks = kzalloc(nrealwriters_stress * sizeof(writer_tasks[0]),
+                              GFP_KERNEL);
+       if (writer_tasks == NULL) {
+               VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory");
+               firsterr = -ENOMEM;
+               goto unwind;
+       }
+       for (i = 0; i < nrealwriters_stress; i++) {
+               firsterr = torture_create_kthread(lock_torture_writer, &lwsa[i],
+                                                 writer_tasks[i]);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (stat_interval > 0) {
+               firsterr = torture_create_kthread(lock_torture_stats, NULL,
+                                                 stats_task);
+               if (firsterr)
+                       goto unwind;
+       }
+       torture_init_end();
+       return 0;
+
+unwind:
+       torture_init_end();
+       lock_torture_cleanup();
+       return firsterr;
+}
+
+module_init(lock_torture_init);
+module_exit(lock_torture_cleanup);
diff --git a/kernel/locking/mcs_spinlock.c b/kernel/locking/mcs_spinlock.c
new file mode 100644 (file)
index 0000000..838dc9e
--- /dev/null
@@ -0,0 +1,178 @@
+
+#include <linux/percpu.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include "mcs_spinlock.h"
+
+#ifdef CONFIG_SMP
+
+/*
+ * An MCS like lock especially tailored for optimistic spinning for sleeping
+ * lock implementations (mutex, rwsem, etc).
+ *
+ * Using a single mcs node per CPU is safe because sleeping locks should not be
+ * called from interrupt context and we have preemption disabled while
+ * spinning.
+ */
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct optimistic_spin_queue, osq_node);
+
+/*
+ * Get a stable @node->next pointer, either for unlock() or unqueue() purposes.
+ * Can return NULL in case we were the last queued and we updated @lock instead.
+ */
+static inline struct optimistic_spin_queue *
+osq_wait_next(struct optimistic_spin_queue **lock,
+             struct optimistic_spin_queue *node,
+             struct optimistic_spin_queue *prev)
+{
+       struct optimistic_spin_queue *next = NULL;
+
+       for (;;) {
+               if (*lock == node && cmpxchg(lock, node, prev) == node) {
+                       /*
+                        * We were the last queued, we moved @lock back. @prev
+                        * will now observe @lock and will complete its
+                        * unlock()/unqueue().
+                        */
+                       break;
+               }
+
+               /*
+                * We must xchg() the @node->next value, because if we were to
+                * leave it in, a concurrent unlock()/unqueue() from
+                * @node->next might complete Step-A and think its @prev is
+                * still valid.
+                *
+                * If the concurrent unlock()/unqueue() wins the race, we'll
+                * wait for either @lock to point to us, through its Step-B, or
+                * wait for a new @node->next from its Step-C.
+                */
+               if (node->next) {
+                       next = xchg(&node->next, NULL);
+                       if (next)
+                               break;
+               }
+
+               arch_mutex_cpu_relax();
+       }
+
+       return next;
+}
+
+bool osq_lock(struct optimistic_spin_queue **lock)
+{
+       struct optimistic_spin_queue *node = this_cpu_ptr(&osq_node);
+       struct optimistic_spin_queue *prev, *next;
+
+       node->locked = 0;
+       node->next = NULL;
+
+       node->prev = prev = xchg(lock, node);
+       if (likely(prev == NULL))
+               return true;
+
+       ACCESS_ONCE(prev->next) = node;
+
+       /*
+        * Normally @prev is untouchable after the above store; because at that
+        * moment unlock can proceed and wipe the node element from stack.
+        *
+        * However, since our nodes are static per-cpu storage, we're
+        * guaranteed their existence -- this allows us to apply
+        * cmpxchg in an attempt to undo our queueing.
+        */
+
+       while (!smp_load_acquire(&node->locked)) {
+               /*
+                * If we need to reschedule bail... so we can block.
+                */
+               if (need_resched())
+                       goto unqueue;
+
+               arch_mutex_cpu_relax();
+       }
+       return true;
+
+unqueue:
+       /*
+        * Step - A  -- stabilize @prev
+        *
+        * Undo our @prev->next assignment; this will make @prev's
+        * unlock()/unqueue() wait for a next pointer since @lock points to us
+        * (or later).
+        */
+
+       for (;;) {
+               if (prev->next == node &&
+                   cmpxchg(&prev->next, node, NULL) == node)
+                       break;
+
+               /*
+                * We can only fail the cmpxchg() racing against an unlock(),
+                * in which case we should observe @node->locked becomming
+                * true.
+                */
+               if (smp_load_acquire(&node->locked))
+                       return true;
+
+               arch_mutex_cpu_relax();
+
+               /*
+                * Or we race against a concurrent unqueue()'s step-B, in which
+                * case its step-C will write us a new @node->prev pointer.
+                */
+               prev = ACCESS_ONCE(node->prev);
+       }
+
+       /*
+        * Step - B -- stabilize @next
+        *
+        * Similar to unlock(), wait for @node->next or move @lock from @node
+        * back to @prev.
+        */
+
+       next = osq_wait_next(lock, node, prev);
+       if (!next)
+               return false;
+
+       /*
+        * Step - C -- unlink
+        *
+        * @prev is stable because its still waiting for a new @prev->next
+        * pointer, @next is stable because our @node->next pointer is NULL and
+        * it will wait in Step-A.
+        */
+
+       ACCESS_ONCE(next->prev) = prev;
+       ACCESS_ONCE(prev->next) = next;
+
+       return false;
+}
+
+void osq_unlock(struct optimistic_spin_queue **lock)
+{
+       struct optimistic_spin_queue *node = this_cpu_ptr(&osq_node);
+       struct optimistic_spin_queue *next;
+
+       /*
+        * Fast path for the uncontended case.
+        */
+       if (likely(cmpxchg(lock, node, NULL) == node))
+               return;
+
+       /*
+        * Second most likely case.
+        */
+       next = xchg(&node->next, NULL);
+       if (next) {
+               ACCESS_ONCE(next->locked) = 1;
+               return;
+       }
+
+       next = osq_wait_next(lock, node, NULL);
+       if (next)
+               ACCESS_ONCE(next->locked) = 1;
+}
+
+#endif
+
diff --git a/kernel/locking/mcs_spinlock.h b/kernel/locking/mcs_spinlock.h
new file mode 100644 (file)
index 0000000..a2dbac4
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * MCS lock defines
+ *
+ * This file contains the main data structure and API definitions of MCS lock.
+ *
+ * The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spin-lock
+ * with the desirable properties of being fair, and with each cpu trying
+ * to acquire the lock spinning on a local variable.
+ * It avoids expensive cache bouncings that common test-and-set spin-lock
+ * implementations incur.
+ */
+#ifndef __LINUX_MCS_SPINLOCK_H
+#define __LINUX_MCS_SPINLOCK_H
+
+#include <asm/mcs_spinlock.h>
+
+struct mcs_spinlock {
+       struct mcs_spinlock *next;
+       int locked; /* 1 if lock acquired */
+};
+
+#ifndef arch_mcs_spin_lock_contended
+/*
+ * Using smp_load_acquire() provides a memory barrier that ensures
+ * subsequent operations happen after the lock is acquired.
+ */
+#define arch_mcs_spin_lock_contended(l)                                        \
+do {                                                                   \
+       while (!(smp_load_acquire(l)))                                  \
+               arch_mutex_cpu_relax();                                 \
+} while (0)
+#endif
+
+#ifndef arch_mcs_spin_unlock_contended
+/*
+ * smp_store_release() provides a memory barrier to ensure all
+ * operations in the critical section has been completed before
+ * unlocking.
+ */
+#define arch_mcs_spin_unlock_contended(l)                              \
+       smp_store_release((l), 1)
+#endif
+
+/*
+ * Note: the smp_load_acquire/smp_store_release pair is not
+ * sufficient to form a full memory barrier across
+ * cpus for many architectures (except x86) for mcs_unlock and mcs_lock.
+ * For applications that need a full barrier across multiple cpus
+ * with mcs_unlock and mcs_lock pair, smp_mb__after_unlock_lock() should be
+ * used after mcs_lock.
+ */
+
+/*
+ * In order to acquire the lock, the caller should declare a local node and
+ * pass a reference of the node to this function in addition to the lock.
+ * If the lock has already been acquired, then this will proceed to spin
+ * on this node->locked until the previous lock holder sets the node->locked
+ * in mcs_spin_unlock().
+ *
+ * We don't inline mcs_spin_lock() so that perf can correctly account for the
+ * time spent in this lock function.
+ */
+static inline
+void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+       struct mcs_spinlock *prev;
+
+       /* Init node */
+       node->locked = 0;
+       node->next   = NULL;
+
+       prev = xchg(lock, node);
+       if (likely(prev == NULL)) {
+               /*
+                * Lock acquired, don't need to set node->locked to 1. Threads
+                * only spin on its own node->locked value for lock acquisition.
+                * However, since this thread can immediately acquire the lock
+                * and does not proceed to spin on its own node->locked, this
+                * value won't be used. If a debug mode is needed to
+                * audit lock status, then set node->locked value here.
+                */
+               return;
+       }
+       ACCESS_ONCE(prev->next) = node;
+
+       /* Wait until the lock holder passes the lock down. */
+       arch_mcs_spin_lock_contended(&node->locked);
+}
+
+/*
+ * Releases the lock. The caller should pass in the corresponding node that
+ * was used to acquire the lock.
+ */
+static inline
+void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+       struct mcs_spinlock *next = ACCESS_ONCE(node->next);
+
+       if (likely(!next)) {
+               /*
+                * Release the lock by setting it to NULL
+                */
+               if (likely(cmpxchg(lock, node, NULL) == node))
+                       return;
+               /* Wait until the next pointer is set */
+               while (!(next = ACCESS_ONCE(node->next)))
+                       arch_mutex_cpu_relax();
+       }
+
+       /* Pass lock to next waiter. */
+       arch_mcs_spin_unlock_contended(&next->locked);
+}
+
+/*
+ * Cancellable version of the MCS lock above.
+ *
+ * Intended for adaptive spinning of sleeping locks:
+ * mutex_lock()/rwsem_down_{read,write}() etc.
+ */
+
+struct optimistic_spin_queue {
+       struct optimistic_spin_queue *next, *prev;
+       int locked; /* 1 if lock acquired */
+};
+
+extern bool osq_lock(struct optimistic_spin_queue **lock);
+extern void osq_unlock(struct optimistic_spin_queue **lock);
+
+#endif /* __LINUX_MCS_SPINLOCK_H */
index faf6f5b53e775eefbc7ee4ea734ff0998be68d01..e1191c996c59cbe3b3d2aecb7b54fd570cef17b6 100644 (file)
@@ -83,6 +83,12 @@ void debug_mutex_unlock(struct mutex *lock)
 
        DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);
        mutex_clear_owner(lock);
+
+       /*
+        * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug
+        * mutexes so that we can do it here after we've verified state.
+        */
+       atomic_set(&lock->count, 1);
 }
 
 void debug_mutex_init(struct mutex *lock, const char *name,
index 4dd6e4c219de9316593b61daae8e17cf8dc5d874..bc73d33c6760e174fd1bb2c8319c0faf5abc221f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/debug_locks.h>
+#include "mcs_spinlock.h"
 
 /*
  * In the DEBUG case we are using the "NULL fastpath" for mutexes,
 #ifdef CONFIG_DEBUG_MUTEXES
 # include "mutex-debug.h"
 # include <asm-generic/mutex-null.h>
+/*
+ * Must be 0 for the debug case so we do not do the unlock outside of the
+ * wait_lock region. debug_mutex_unlock() will do the actual unlock in this
+ * case.
+ */
+# undef __mutex_slowpath_needs_to_unlock
+# define  __mutex_slowpath_needs_to_unlock()   0
 #else
 # include "mutex.h"
 # include <asm/mutex.h>
@@ -52,7 +60,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
        INIT_LIST_HEAD(&lock->wait_list);
        mutex_clear_owner(lock);
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
-       lock->spin_mlock = NULL;
+       lock->osq = NULL;
 #endif
 
        debug_mutex_init(lock, name, key);
@@ -67,8 +75,7 @@ EXPORT_SYMBOL(__mutex_init);
  * We also put the fastpath first in the kernel image, to make sure the
  * branch is predicted by the CPU as default-untaken.
  */
-static __used noinline void __sched
-__mutex_lock_slowpath(atomic_t *lock_count);
+__visible void __sched __mutex_lock_slowpath(atomic_t *lock_count);
 
 /**
  * mutex_lock - acquire the mutex
@@ -111,54 +118,7 @@ EXPORT_SYMBOL(mutex_lock);
  * more or less simultaneously, the spinners need to acquire a MCS lock
  * first before spinning on the owner field.
  *
- * We don't inline mspin_lock() so that perf can correctly account for the
- * time spent in this lock function.
  */
-struct mspin_node {
-       struct mspin_node *next ;
-       int               locked;       /* 1 if lock acquired */
-};
-#define        MLOCK(mutex)    ((struct mspin_node **)&((mutex)->spin_mlock))
-
-static noinline
-void mspin_lock(struct mspin_node **lock, struct mspin_node *node)
-{
-       struct mspin_node *prev;
-
-       /* Init node */
-       node->locked = 0;
-       node->next   = NULL;
-
-       prev = xchg(lock, node);
-       if (likely(prev == NULL)) {
-               /* Lock acquired */
-               node->locked = 1;
-               return;
-       }
-       ACCESS_ONCE(prev->next) = node;
-       smp_wmb();
-       /* Wait until the lock holder passes the lock down */
-       while (!ACCESS_ONCE(node->locked))
-               arch_mutex_cpu_relax();
-}
-
-static void mspin_unlock(struct mspin_node **lock, struct mspin_node *node)
-{
-       struct mspin_node *next = ACCESS_ONCE(node->next);
-
-       if (likely(!next)) {
-               /*
-                * Release the lock by setting it to NULL
-                */
-               if (cmpxchg(lock, node, NULL) == node)
-                       return;
-               /* Wait until the next pointer is set */
-               while (!(next = ACCESS_ONCE(node->next)))
-                       arch_mutex_cpu_relax();
-       }
-       ACCESS_ONCE(next->locked) = 1;
-       smp_wmb();
-}
 
 /*
  * Mutex spinning code migrated from kernel/sched/core.c
@@ -212,6 +172,9 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
        struct task_struct *owner;
        int retval = 1;
 
+       if (need_resched())
+               return 0;
+
        rcu_read_lock();
        owner = ACCESS_ONCE(lock->owner);
        if (owner)
@@ -225,7 +188,8 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
 }
 #endif
 
-static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
+__visible __used noinline
+void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
 
 /**
  * mutex_unlock - release the mutex
@@ -446,9 +410,11 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
        if (!mutex_can_spin_on_owner(lock))
                goto slowpath;
 
+       if (!osq_lock(&lock->osq))
+               goto slowpath;
+
        for (;;) {
                struct task_struct *owner;
-               struct mspin_node  node;
 
                if (use_ww_ctx && ww_ctx->acquired > 0) {
                        struct ww_mutex *ww;
@@ -463,19 +429,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                         * performed the optimistic spinning cannot be done.
                         */
                        if (ACCESS_ONCE(ww->ctx))
-                               goto slowpath;
+                               break;
                }
 
                /*
                 * If there's an owner, wait for it to either
                 * release the lock or go to sleep.
                 */
-               mspin_lock(MLOCK(lock), &node);
                owner = ACCESS_ONCE(lock->owner);
-               if (owner && !mutex_spin_on_owner(lock, owner)) {
-                       mspin_unlock(MLOCK(lock), &node);
-                       goto slowpath;
-               }
+               if (owner && !mutex_spin_on_owner(lock, owner))
+                       break;
 
                if ((atomic_read(&lock->count) == 1) &&
                    (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
@@ -488,11 +451,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                        }
 
                        mutex_set_owner(lock);
-                       mspin_unlock(MLOCK(lock), &node);
+                       osq_unlock(&lock->osq);
                        preempt_enable();
                        return 0;
                }
-               mspin_unlock(MLOCK(lock), &node);
 
                /*
                 * When there's no owner, we might have preempted between the
@@ -501,7 +463,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * the owner complete.
                 */
                if (!owner && (need_resched() || rt_task(task)))
-                       goto slowpath;
+                       break;
 
                /*
                 * The cpu_relax() call is a compiler barrier which forces
@@ -511,7 +473,15 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 */
                arch_mutex_cpu_relax();
        }
+       osq_unlock(&lock->osq);
 slowpath:
+       /*
+        * If we fell out of the spin path because of need_resched(),
+        * reschedule now, before we try-lock the mutex. This avoids getting
+        * scheduled out right after we obtained the mutex.
+        */
+       if (need_resched())
+               schedule_preempt_disabled();
 #endif
        spin_lock_mutex(&lock->wait_lock, flags);
 
@@ -717,10 +687,6 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
        struct mutex *lock = container_of(lock_count, struct mutex, count);
        unsigned long flags;
 
-       spin_lock_mutex(&lock->wait_lock, flags);
-       mutex_release(&lock->dep_map, nested, _RET_IP_);
-       debug_mutex_unlock(lock);
-
        /*
         * some architectures leave the lock unlocked in the fastpath failure
         * case, others need to leave it locked. In the later case we have to
@@ -729,6 +695,10 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
        if (__mutex_slowpath_needs_to_unlock())
                atomic_set(&lock->count, 1);
 
+       spin_lock_mutex(&lock->wait_lock, flags);
+       mutex_release(&lock->dep_map, nested, _RET_IP_);
+       debug_mutex_unlock(lock);
+
        if (!list_empty(&lock->wait_list)) {
                /* get the first entry from the wait-list: */
                struct mutex_waiter *waiter =
@@ -746,7 +716,7 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
 /*
  * Release the lock, slowpath:
  */
-static __used noinline void
+__visible void
 __mutex_unlock_slowpath(atomic_t *lock_count)
 {
        __mutex_unlock_common_slowpath(lock_count, 1);
@@ -803,7 +773,7 @@ int __sched mutex_lock_killable(struct mutex *lock)
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
-static __used noinline void __sched
+__visible void __sched
 __mutex_lock_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
index 2e960a2bab81a06ae90d7c48edba6a670d16ebaf..aa4dff04b594c2b058ba2193ef44644ff8dd54dc 100644 (file)
@@ -212,6 +212,18 @@ struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
        return task_top_pi_waiter(task)->task;
 }
 
+/*
+ * Called by sched_setscheduler() to check whether the priority change
+ * is overruled by a possible priority boosting.
+ */
+int rt_mutex_check_prio(struct task_struct *task, int newprio)
+{
+       if (!task_has_pi_waiters(task))
+               return 0;
+
+       return task_top_pi_waiter(task)->task->prio <= newprio;
+}
+
 /*
  * Adjust the priority of a task, after its pi_waiters got modified.
  *
index 19c5fa95e0b4d7d06587d5fc5feb2ff0295f1efe..1d66e08e897d166cf70bc2f41cdc3c3bbb57cf45 100644 (file)
@@ -143,6 +143,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type)
 /*
  * wait for the read lock to be granted
  */
+__visible
 struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
 {
        long count, adjustment = -RWSEM_ACTIVE_READ_BIAS;
@@ -190,6 +191,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
 /*
  * wait until we successfully acquire the write lock
  */
+__visible
 struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
 {
        long count, adjustment = -RWSEM_ACTIVE_WRITE_BIAS;
@@ -252,6 +254,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
  * handle waking up a waiter on the semaphore
  * - up_read/up_write has decremented the active part of count if we come here
  */
+__visible
 struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
 {
        unsigned long flags;
@@ -272,6 +275,7 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
  * - caller incremented waiting part of count and discovered it still negative
  * - just wake up any readers at the front of the queue
  */
+__visible
 struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
 {
        unsigned long flags;
index d24fcf29cb64c16029857a89dbcdeaa1ef9d724a..8dc7f5e80dd8f75273ef15df03a14615de1579d4 100644 (file)
@@ -1015,7 +1015,7 @@ static size_t module_flags_taint(struct module *mod, char *buf)
                buf[l++] = 'C';
        /*
         * TAINT_FORCED_RMMOD: could be added.
-        * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
+        * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
         * apply to modules.
         */
        return l;
@@ -1948,6 +1948,10 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
 
                switch (sym[i].st_shndx) {
                case SHN_COMMON:
+                       /* Ignore common symbols */
+                       if (!strncmp(name, "__gnu_lto", 9))
+                               break;
+
                        /* We compiled with -fno-common.  These are not
                           supposed to happen.  */
                        pr_debug("Common symbol: %s\n", name);
index 2d5cc4ccff7f4b79f734bf12ea769fb14a2346b2..db4c8b08a50cef986f48f0e537f1b622d4e8b19a 100644 (file)
@@ -309,7 +309,7 @@ int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
         * racy then it does not matter what the result of the test
         * is, we re-check the list after having taken the lock anyway:
         */
-       if (rcu_dereference_raw(nh->head)) {
+       if (rcu_access_pointer(nh->head)) {
                down_read(&nh->rwsem);
                ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
                                        nr_calls);
index 6d6300375090e7b2345353174d85ed09f6f35ce4..cca8a913ae7c8d6314fda34a1f3853a364e32cfd 100644 (file)
@@ -199,7 +199,7 @@ struct tnt {
 static const struct tnt tnts[] = {
        { TAINT_PROPRIETARY_MODULE,     'P', 'G' },
        { TAINT_FORCED_MODULE,          'F', ' ' },
-       { TAINT_UNSAFE_SMP,             'S', ' ' },
+       { TAINT_CPU_OUT_OF_SPEC,        'S', ' ' },
        { TAINT_FORCED_RMMOD,           'R', ' ' },
        { TAINT_MACHINE_CHECK,          'M', ' ' },
        { TAINT_BAD_PAGE,               'B', ' ' },
@@ -459,7 +459,7 @@ EXPORT_SYMBOL(warn_slowpath_null);
  * Called when gcc's -fstack-protector feature is used, and
  * gcc detects corruption of the on-stack canary value
  */
-void __stack_chk_fail(void)
+__visible void __stack_chk_fail(void)
 {
        panic("stack-protector: Kernel stack is corrupted in: %p\n",
                __builtin_return_address(0));
index 37170d4dd9a61d1ad1171d106c61af8d59393f85..f4f2073711d34891645be8dfc997645342c043e4 100644 (file)
@@ -973,16 +973,20 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
 static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
                            const char *buf, size_t n)
 {
-       unsigned int maj, min;
        dev_t res;
-       int ret = -EINVAL;
+       int len = n;
+       char *name;
 
-       if (sscanf(buf, "%u:%u", &maj, &min) != 2)
-               goto out;
+       if (len && buf[len-1] == '\n')
+               len--;
+       name = kstrndup(buf, len, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
 
-       res = MKDEV(maj,min);
-       if (maj != MAJOR(res) || min != MINOR(res))
-               goto out;
+       res = name_to_dev_t(name);
+       kfree(name);
+       if (!res)
+               return -EINVAL;
 
        lock_system_sleep();
        swsusp_resume_device = res;
@@ -990,9 +994,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
        printk(KERN_INFO "PM: Starting manual resume from disk\n");
        noresume = 0;
        software_resume();
-       ret = n;
- out:
-       return ret;
+       return n;
 }
 
 power_attr(resume);
index 1d1bf630e6e900d5354413a6176b60b6a948a979..6271bc4073ef24ffd68f38d8348340cc9ff43eb3 100644 (file)
@@ -282,8 +282,8 @@ struct kobject *power_kobj;
  *     state - control system power state.
  *
  *     show() returns what states are supported, which is hard-coded to
- *     'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
- *     'disk' (Suspend-to-Disk).
+ *     'freeze' (Low-Power Idle), 'standby' (Power-On Suspend),
+ *     'mem' (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
  *
  *     store() accepts one of those strings, translates it into the
  *     proper enumerated value, and initiates a suspend transition.
index 7d4b7ffb3c1d4371f19e81fe83c67ea88ac83759..1ca753106557f4d7de3f6586f86fe8f33593851b 100644 (file)
@@ -49,6 +49,8 @@ static inline char *check_image_kernel(struct swsusp_info *info)
  */
 #define SPARE_PAGES    ((1024 * 1024) >> PAGE_SHIFT)
 
+asmlinkage int swsusp_save(void);
+
 /* kernel/power/hibernate.c */
 extern bool freezer_test_done;
 
index 8dff9b48075af3f61eeab3531b3ad706b88718e4..884b77058864cd3596dd6f67d5d8c1dda77dedaf 100644 (file)
@@ -66,6 +66,7 @@ static struct pm_qos_constraints cpu_dma_constraints = {
        .list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
        .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
        .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+       .no_constraint_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
        .type = PM_QOS_MIN,
        .notifiers = &cpu_dma_lat_notifier,
 };
@@ -79,6 +80,7 @@ static struct pm_qos_constraints network_lat_constraints = {
        .list = PLIST_HEAD_INIT(network_lat_constraints.list),
        .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
        .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+       .no_constraint_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
        .type = PM_QOS_MIN,
        .notifiers = &network_lat_notifier,
 };
@@ -93,6 +95,7 @@ static struct pm_qos_constraints network_tput_constraints = {
        .list = PLIST_HEAD_INIT(network_tput_constraints.list),
        .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
        .default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+       .no_constraint_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
        .type = PM_QOS_MAX,
        .notifiers = &network_throughput_notifier,
 };
@@ -128,7 +131,7 @@ static const struct file_operations pm_qos_power_fops = {
 static inline int pm_qos_get_value(struct pm_qos_constraints *c)
 {
        if (plist_head_empty(&c->list))
-               return c->default_value;
+               return c->no_constraint_value;
 
        switch (c->type) {
        case PM_QOS_MIN:
@@ -170,6 +173,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
 {
        unsigned long flags;
        int prev_value, curr_value, new_value;
+       int ret;
 
        spin_lock_irqsave(&pm_qos_lock, flags);
        prev_value = pm_qos_get_value(c);
@@ -205,13 +209,15 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
 
        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,
-                                            NULL);
-               return 1;
+               ret = 1;
+               if (c->notifiers)
+                       blocking_notifier_call_chain(c->notifiers,
+                                                    (unsigned long)curr_value,
+                                                    NULL);
        } else {
-               return 0;
+               ret = 0;
        }
+       return ret;
 }
 
 /**
index d9f61a145802df2393f6041e935d00ea3f15ff8f..149e745eaa528800cd64a07bd8aacdbe6dd63ea0 100644 (file)
@@ -1268,7 +1268,7 @@ static void free_unnecessary_pages(void)
  * [number of saveable pages] - [number of pages that can be freed in theory]
  *
  * where the second term is the sum of (1) reclaimable slab pages, (2) active
- * and (3) inactive anonymouns pages, (4) active and (5) inactive file pages,
+ * and (3) inactive anonymous pages, (4) active and (5) inactive file pages,
  * minus mapped file pages.
  */
 static unsigned long minimum_image_size(unsigned long saveable)
index 62ee437b5c7ea362de8573dd18fcee1ef6286221..90b3d9366d1a7d51338484b95b9a1084aa2992b8 100644 (file)
@@ -39,7 +39,7 @@ static const struct platform_suspend_ops *suspend_ops;
 
 static bool need_suspend_ops(suspend_state_t state)
 {
-       return !!(state > PM_SUSPEND_FREEZE);
+       return state > PM_SUSPEND_FREEZE;
 }
 
 static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
index 8f50de394d22b30090d1cf62cd3fd3069d451d57..019069c84ff6b6d351b0259f0c5203ebd18ee41d 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/rbtree.h>
 #include <linux/slab.h>
 
+#include "power.h"
+
 static DEFINE_MUTEX(wakelocks_lock);
 
 struct wakelock {
index 6631e1ef55ab0970f095b42ec350982abd8d9678..ebdd9c1a86b4dfd7840df57c64f13f72a1401156 100644 (file)
@@ -549,14 +549,14 @@ static int create_hash_tables(void)
                struct page *page;
 
                page = alloc_pages_exact_node(node,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
                per_cpu(cpu_profile_hits, cpu)[1]
                                = (struct profile_hit *)page_address(page);
                page = alloc_pages_exact_node(node,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
index 1f4bcb3cc21cee5bcfd1b4e13a77eeff2af23a2b..adf98622cb32bdf0b995d25ca0c4477c098e9bcc 100644 (file)
@@ -1180,8 +1180,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
        return ret;
 }
 
-asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
-                                 compat_long_t addr, compat_long_t data)
+COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid,
+                      compat_long_t, addr, compat_long_t, data)
 {
        struct task_struct *child;
        long ret;
index 01e9ec37a3e39af2d7e5d889a770b099dc1eb473..807ccfbf69b3359fe85b736efd14d7050e5e4990 100644 (file)
@@ -1,5 +1,5 @@
 obj-y += update.o srcu.o
-obj-$(CONFIG_RCU_TORTURE_TEST) += torture.o
+obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_TREE_RCU) += tree.o
 obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o
 obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
index 79c3877e9c5b83e089ef319a2e72a9aaddde6fa3..bfda2726ca454112569433a85a9467a20f5d7a45 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2011
  *
@@ -23,6 +23,7 @@
 #ifndef __LINUX_RCU_H
 #define __LINUX_RCU_H
 
+#include <trace/events/rcu.h>
 #ifdef CONFIG_RCU_TRACE
 #define RCU_TRACE(stmt) stmt
 #else /* #ifdef CONFIG_RCU_TRACE */
@@ -116,8 +117,6 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
        }
 }
 
-extern int rcu_expedited;
-
 #ifdef CONFIG_RCU_STALL_COMMON
 
 extern int rcu_cpu_stall_suppress;
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
new file mode 100644 (file)
index 0000000..bd30bc6
--- /dev/null
@@ -0,0 +1,1582 @@
+/*
+ * Read-Copy Update module-based torture test facility
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright (C) IBM Corporation, 2005, 2006
+ *
+ * Authors: Paul E. McKenney <paulmck@us.ibm.com>
+ *       Josh Triplett <josh@freedesktop.org>
+ *
+ * See also:  Documentation/RCU/torture.txt
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/srcu.h>
+#include <linux/slab.h>
+#include <linux/trace_clock.h>
+#include <asm/byteorder.h>
+#include <linux/torture.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
+
+
+torture_param(int, fqs_duration, 0,
+             "Duration of fqs bursts (us), 0 to disable");
+torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
+torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)");
+torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
+torture_param(bool, gp_normal, false,
+            "Use normal (non-expedited) GP wait primitives");
+torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers");
+torture_param(int, n_barrier_cbs, 0,
+            "# of callbacks/kthreads for barrier testing");
+torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads");
+torture_param(int, nreaders, -1, "Number of RCU reader threads");
+torture_param(int, object_debug, 0,
+            "Enable debug-object double call_rcu() testing");
+torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
+torture_param(int, onoff_interval, 0,
+            "Time between CPU hotplugs (s), 0=disable");
+torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles");
+torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
+torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
+torture_param(int, stall_cpu_holdoff, 10,
+            "Time to wait before starting stall (s).");
+torture_param(int, stat_interval, 60,
+            "Number of seconds between stats printk()s");
+torture_param(int, stutter, 5, "Number of seconds to run/halt test");
+torture_param(int, test_boost, 1, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
+torture_param(int, test_boost_duration, 4,
+            "Duration of each boost test, seconds.");
+torture_param(int, test_boost_interval, 7,
+            "Interval between boost tests, seconds.");
+torture_param(bool, test_no_idle_hz, true,
+            "Test support for tickless idle CPUs");
+torture_param(bool, verbose, true,
+            "Enable verbose debugging printk()s");
+
+static char *torture_type = "rcu";
+module_param(torture_type, charp, 0444);
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
+
+static int nrealreaders;
+static struct task_struct *writer_task;
+static struct task_struct **fakewriter_tasks;
+static struct task_struct **reader_tasks;
+static struct task_struct *stats_task;
+static struct task_struct *fqs_task;
+static struct task_struct *boost_tasks[NR_CPUS];
+static struct task_struct *stall_task;
+static struct task_struct **barrier_cbs_tasks;
+static struct task_struct *barrier_task;
+
+#define RCU_TORTURE_PIPE_LEN 10
+
+struct rcu_torture {
+       struct rcu_head rtort_rcu;
+       int rtort_pipe_count;
+       struct list_head rtort_free;
+       int rtort_mbtest;
+};
+
+static LIST_HEAD(rcu_torture_freelist);
+static struct rcu_torture __rcu *rcu_torture_current;
+static unsigned long rcu_torture_current_version;
+static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
+static DEFINE_SPINLOCK(rcu_torture_lock);
+static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1],
+                     rcu_torture_count) = { 0 };
+static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1],
+                     rcu_torture_batch) = { 0 };
+static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
+static atomic_t n_rcu_torture_alloc;
+static atomic_t n_rcu_torture_alloc_fail;
+static atomic_t n_rcu_torture_free;
+static atomic_t n_rcu_torture_mberror;
+static atomic_t n_rcu_torture_error;
+static long n_rcu_torture_barrier_error;
+static long n_rcu_torture_boost_ktrerror;
+static long n_rcu_torture_boost_rterror;
+static long n_rcu_torture_boost_failure;
+static long n_rcu_torture_boosts;
+static long n_rcu_torture_timers;
+static long n_barrier_attempts;
+static long n_barrier_successes;
+static struct list_head rcu_torture_removed;
+
+#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
+#define RCUTORTURE_RUNNABLE_INIT 1
+#else
+#define RCUTORTURE_RUNNABLE_INIT 0
+#endif
+int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
+module_param(rcutorture_runnable, int, 0444);
+MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot");
+
+#if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU)
+#define rcu_can_boost() 1
+#else /* #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
+#define rcu_can_boost() 0
+#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
+
+#ifdef CONFIG_RCU_TRACE
+static u64 notrace rcu_trace_clock_local(void)
+{
+       u64 ts = trace_clock_local();
+       unsigned long __maybe_unused ts_rem = do_div(ts, NSEC_PER_USEC);
+       return ts;
+}
+#else /* #ifdef CONFIG_RCU_TRACE */
+static u64 notrace rcu_trace_clock_local(void)
+{
+       return 0ULL;
+}
+#endif /* #else #ifdef CONFIG_RCU_TRACE */
+
+static unsigned long boost_starttime;  /* jiffies of next boost test start. */
+DEFINE_MUTEX(boost_mutex);             /* protect setting boost_starttime */
+                                       /*  and boost task create/destroy. */
+static atomic_t barrier_cbs_count;     /* Barrier callbacks registered. */
+static bool barrier_phase;             /* Test phase. */
+static atomic_t barrier_cbs_invoked;   /* Barrier callbacks invoked. */
+static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
+static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
+
+/*
+ * Allocate an element from the rcu_tortures pool.
+ */
+static struct rcu_torture *
+rcu_torture_alloc(void)
+{
+       struct list_head *p;
+
+       spin_lock_bh(&rcu_torture_lock);
+       if (list_empty(&rcu_torture_freelist)) {
+               atomic_inc(&n_rcu_torture_alloc_fail);
+               spin_unlock_bh(&rcu_torture_lock);
+               return NULL;
+       }
+       atomic_inc(&n_rcu_torture_alloc);
+       p = rcu_torture_freelist.next;
+       list_del_init(p);
+       spin_unlock_bh(&rcu_torture_lock);
+       return container_of(p, struct rcu_torture, rtort_free);
+}
+
+/*
+ * Free an element to the rcu_tortures pool.
+ */
+static void
+rcu_torture_free(struct rcu_torture *p)
+{
+       atomic_inc(&n_rcu_torture_free);
+       spin_lock_bh(&rcu_torture_lock);
+       list_add_tail(&p->rtort_free, &rcu_torture_freelist);
+       spin_unlock_bh(&rcu_torture_lock);
+}
+
+/*
+ * Operations vector for selecting different types of tests.
+ */
+
+struct rcu_torture_ops {
+       void (*init)(void);
+       int (*readlock)(void);
+       void (*read_delay)(struct torture_random_state *rrsp);
+       void (*readunlock)(int idx);
+       int (*completed)(void);
+       void (*deferred_free)(struct rcu_torture *p);
+       void (*sync)(void);
+       void (*exp_sync)(void);
+       void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
+       void (*cb_barrier)(void);
+       void (*fqs)(void);
+       void (*stats)(char *page);
+       int irq_capable;
+       int can_boost;
+       const char *name;
+};
+
+static struct rcu_torture_ops *cur_ops;
+
+/*
+ * Definitions for rcu torture testing.
+ */
+
+static int rcu_torture_read_lock(void) __acquires(RCU)
+{
+       rcu_read_lock();
+       return 0;
+}
+
+static void rcu_read_delay(struct torture_random_state *rrsp)
+{
+       const unsigned long shortdelay_us = 200;
+       const unsigned long longdelay_ms = 50;
+
+       /* We want a short delay sometimes to make a reader delay the grace
+        * period, and we want a long delay occasionally to trigger
+        * force_quiescent_state. */
+
+       if (!(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
+               mdelay(longdelay_ms);
+       if (!(torture_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
+               udelay(shortdelay_us);
+#ifdef CONFIG_PREEMPT
+       if (!preempt_count() &&
+           !(torture_random(rrsp) % (nrealreaders * 20000)))
+               preempt_schedule();  /* No QS if preempt_disable() in effect */
+#endif
+}
+
+static void rcu_torture_read_unlock(int idx) __releases(RCU)
+{
+       rcu_read_unlock();
+}
+
+static int rcu_torture_completed(void)
+{
+       return rcu_batches_completed();
+}
+
+static void
+rcu_torture_cb(struct rcu_head *p)
+{
+       int i;
+       struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
+
+       if (torture_must_stop_irq()) {
+               /* Test is ending, just drop callbacks on the floor. */
+               /* The next initialization will pick up the pieces. */
+               return;
+       }
+       i = rp->rtort_pipe_count;
+       if (i > RCU_TORTURE_PIPE_LEN)
+               i = RCU_TORTURE_PIPE_LEN;
+       atomic_inc(&rcu_torture_wcount[i]);
+       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+               rp->rtort_mbtest = 0;
+               rcu_torture_free(rp);
+       } else {
+               cur_ops->deferred_free(rp);
+       }
+}
+
+static int rcu_no_completed(void)
+{
+       return 0;
+}
+
+static void rcu_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static void rcu_sync_torture_init(void)
+{
+       INIT_LIST_HEAD(&rcu_torture_removed);
+}
+
+static struct rcu_torture_ops rcu_ops = {
+       .init           = rcu_sync_torture_init,
+       .readlock       = rcu_torture_read_lock,
+       .read_delay     = rcu_read_delay,
+       .readunlock     = rcu_torture_read_unlock,
+       .completed      = rcu_torture_completed,
+       .deferred_free  = rcu_torture_deferred_free,
+       .sync           = synchronize_rcu,
+       .exp_sync       = synchronize_rcu_expedited,
+       .call           = call_rcu,
+       .cb_barrier     = rcu_barrier,
+       .fqs            = rcu_force_quiescent_state,
+       .stats          = NULL,
+       .irq_capable    = 1,
+       .can_boost      = rcu_can_boost(),
+       .name           = "rcu"
+};
+
+/*
+ * Definitions for rcu_bh torture testing.
+ */
+
+static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
+{
+       rcu_read_lock_bh();
+       return 0;
+}
+
+static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
+{
+       rcu_read_unlock_bh();
+}
+
+static int rcu_bh_torture_completed(void)
+{
+       return rcu_batches_completed_bh();
+}
+
+static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops rcu_bh_ops = {
+       .init           = rcu_sync_torture_init,
+       .readlock       = rcu_bh_torture_read_lock,
+       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
+       .readunlock     = rcu_bh_torture_read_unlock,
+       .completed      = rcu_bh_torture_completed,
+       .deferred_free  = rcu_bh_torture_deferred_free,
+       .sync           = synchronize_rcu_bh,
+       .exp_sync       = synchronize_rcu_bh_expedited,
+       .call           = call_rcu_bh,
+       .cb_barrier     = rcu_barrier_bh,
+       .fqs            = rcu_bh_force_quiescent_state,
+       .stats          = NULL,
+       .irq_capable    = 1,
+       .name           = "rcu_bh"
+};
+
+/*
+ * Don't even think about trying any of these in real life!!!
+ * The names includes "busted", and they really means it!
+ * The only purpose of these functions is to provide a buggy RCU
+ * implementation to make sure that rcutorture correctly emits
+ * buggy-RCU error messages.
+ */
+static void rcu_busted_torture_deferred_free(struct rcu_torture *p)
+{
+       /* This is a deliberate bug for testing purposes only! */
+       rcu_torture_cb(&p->rtort_rcu);
+}
+
+static void synchronize_rcu_busted(void)
+{
+       /* This is a deliberate bug for testing purposes only! */
+}
+
+static void
+call_rcu_busted(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+       /* This is a deliberate bug for testing purposes only! */
+       func(head);
+}
+
+static struct rcu_torture_ops rcu_busted_ops = {
+       .init           = rcu_sync_torture_init,
+       .readlock       = rcu_torture_read_lock,
+       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
+       .readunlock     = rcu_torture_read_unlock,
+       .completed      = rcu_no_completed,
+       .deferred_free  = rcu_busted_torture_deferred_free,
+       .sync           = synchronize_rcu_busted,
+       .exp_sync       = synchronize_rcu_busted,
+       .call           = call_rcu_busted,
+       .cb_barrier     = NULL,
+       .fqs            = NULL,
+       .stats          = NULL,
+       .irq_capable    = 1,
+       .name           = "rcu_busted"
+};
+
+/*
+ * Definitions for srcu torture testing.
+ */
+
+DEFINE_STATIC_SRCU(srcu_ctl);
+
+static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
+{
+       return srcu_read_lock(&srcu_ctl);
+}
+
+static void srcu_read_delay(struct torture_random_state *rrsp)
+{
+       long delay;
+       const long uspertick = 1000000 / HZ;
+       const long longdelay = 10;
+
+       /* We want there to be long-running readers, but not all the time. */
+
+       delay = torture_random(rrsp) %
+               (nrealreaders * 2 * longdelay * uspertick);
+       if (!delay)
+               schedule_timeout_interruptible(longdelay);
+       else
+               rcu_read_delay(rrsp);
+}
+
+static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
+{
+       srcu_read_unlock(&srcu_ctl, idx);
+}
+
+static int srcu_torture_completed(void)
+{
+       return srcu_batches_completed(&srcu_ctl);
+}
+
+static void srcu_torture_deferred_free(struct rcu_torture *rp)
+{
+       call_srcu(&srcu_ctl, &rp->rtort_rcu, rcu_torture_cb);
+}
+
+static void srcu_torture_synchronize(void)
+{
+       synchronize_srcu(&srcu_ctl);
+}
+
+static void srcu_torture_call(struct rcu_head *head,
+                             void (*func)(struct rcu_head *head))
+{
+       call_srcu(&srcu_ctl, head, func);
+}
+
+static void srcu_torture_barrier(void)
+{
+       srcu_barrier(&srcu_ctl);
+}
+
+static void srcu_torture_stats(char *page)
+{
+       int cpu;
+       int idx = srcu_ctl.completed & 0x1;
+
+       page += sprintf(page, "%s%s per-CPU(idx=%d):",
+                      torture_type, TORTURE_FLAG, idx);
+       for_each_possible_cpu(cpu) {
+               page += sprintf(page, " %d(%lu,%lu)", cpu,
+                              per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
+                              per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
+       }
+       sprintf(page, "\n");
+}
+
+static void srcu_torture_synchronize_expedited(void)
+{
+       synchronize_srcu_expedited(&srcu_ctl);
+}
+
+static struct rcu_torture_ops srcu_ops = {
+       .init           = rcu_sync_torture_init,
+       .readlock       = srcu_torture_read_lock,
+       .read_delay     = srcu_read_delay,
+       .readunlock     = srcu_torture_read_unlock,
+       .completed      = srcu_torture_completed,
+       .deferred_free  = srcu_torture_deferred_free,
+       .sync           = srcu_torture_synchronize,
+       .exp_sync       = srcu_torture_synchronize_expedited,
+       .call           = srcu_torture_call,
+       .cb_barrier     = srcu_torture_barrier,
+       .stats          = srcu_torture_stats,
+       .name           = "srcu"
+};
+
+/*
+ * Definitions for sched torture testing.
+ */
+
+static int sched_torture_read_lock(void)
+{
+       preempt_disable();
+       return 0;
+}
+
+static void sched_torture_read_unlock(int idx)
+{
+       preempt_enable();
+}
+
+static void rcu_sched_torture_deferred_free(struct rcu_torture *p)
+{
+       call_rcu_sched(&p->rtort_rcu, rcu_torture_cb);
+}
+
+static struct rcu_torture_ops sched_ops = {
+       .init           = rcu_sync_torture_init,
+       .readlock       = sched_torture_read_lock,
+       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
+       .readunlock     = sched_torture_read_unlock,
+       .completed      = rcu_no_completed,
+       .deferred_free  = rcu_sched_torture_deferred_free,
+       .sync           = synchronize_sched,
+       .exp_sync       = synchronize_sched_expedited,
+       .call           = call_rcu_sched,
+       .cb_barrier     = rcu_barrier_sched,
+       .fqs            = rcu_sched_force_quiescent_state,
+       .stats          = NULL,
+       .irq_capable    = 1,
+       .name           = "sched"
+};
+
+/*
+ * RCU torture priority-boost testing.  Runs one real-time thread per
+ * CPU for moderate bursts, repeatedly registering RCU callbacks and
+ * spinning waiting for them to be invoked.  If a given callback takes
+ * too long to be invoked, we assume that priority inversion has occurred.
+ */
+
+struct rcu_boost_inflight {
+       struct rcu_head rcu;
+       int inflight;
+};
+
+static void rcu_torture_boost_cb(struct rcu_head *head)
+{
+       struct rcu_boost_inflight *rbip =
+               container_of(head, struct rcu_boost_inflight, rcu);
+
+       smp_mb(); /* Ensure RCU-core accesses precede clearing ->inflight */
+       rbip->inflight = 0;
+}
+
+static int rcu_torture_boost(void *arg)
+{
+       unsigned long call_rcu_time;
+       unsigned long endtime;
+       unsigned long oldstarttime;
+       struct rcu_boost_inflight rbi = { .inflight = 0 };
+       struct sched_param sp;
+
+       VERBOSE_TOROUT_STRING("rcu_torture_boost started");
+
+       /* Set real-time priority. */
+       sp.sched_priority = 1;
+       if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) {
+               VERBOSE_TOROUT_STRING("rcu_torture_boost RT prio failed!");
+               n_rcu_torture_boost_rterror++;
+       }
+
+       init_rcu_head_on_stack(&rbi.rcu);
+       /* Each pass through the following loop does one boost-test cycle. */
+       do {
+               /* Wait for the next test interval. */
+               oldstarttime = boost_starttime;
+               while (ULONG_CMP_LT(jiffies, oldstarttime)) {
+                       schedule_timeout_interruptible(oldstarttime - jiffies);
+                       stutter_wait("rcu_torture_boost");
+                       if (torture_must_stop())
+                               goto checkwait;
+               }
+
+               /* Do one boost-test interval. */
+               endtime = oldstarttime + test_boost_duration * HZ;
+               call_rcu_time = jiffies;
+               while (ULONG_CMP_LT(jiffies, endtime)) {
+                       /* If we don't have a callback in flight, post one. */
+                       if (!rbi.inflight) {
+                               smp_mb(); /* RCU core before ->inflight = 1. */
+                               rbi.inflight = 1;
+                               call_rcu(&rbi.rcu, rcu_torture_boost_cb);
+                               if (jiffies - call_rcu_time >
+                                        test_boost_duration * HZ - HZ / 2) {
+                                       VERBOSE_TOROUT_STRING("rcu_torture_boost boosting failed");
+                                       n_rcu_torture_boost_failure++;
+                               }
+                               call_rcu_time = jiffies;
+                       }
+                       cond_resched();
+                       stutter_wait("rcu_torture_boost");
+                       if (torture_must_stop())
+                               goto checkwait;
+               }
+
+               /*
+                * Set the start time of the next test interval.
+                * Yes, this is vulnerable to long delays, but such
+                * delays simply cause a false negative for the next
+                * interval.  Besides, we are running at RT priority,
+                * so delays should be relatively rare.
+                */
+               while (oldstarttime == boost_starttime &&
+                      !kthread_should_stop()) {
+                       if (mutex_trylock(&boost_mutex)) {
+                               boost_starttime = jiffies +
+                                                 test_boost_interval * HZ;
+                               n_rcu_torture_boosts++;
+                               mutex_unlock(&boost_mutex);
+                               break;
+                       }
+                       schedule_timeout_uninterruptible(1);
+               }
+
+               /* Go do the stutter. */
+checkwait:     stutter_wait("rcu_torture_boost");
+       } while (!torture_must_stop());
+
+       /* Clean up and exit. */
+       while (!kthread_should_stop() || rbi.inflight) {
+               torture_shutdown_absorb("rcu_torture_boost");
+               schedule_timeout_uninterruptible(1);
+       }
+       smp_mb(); /* order accesses to ->inflight before stack-frame death. */
+       destroy_rcu_head_on_stack(&rbi.rcu);
+       torture_kthread_stopping("rcu_torture_boost");
+       return 0;
+}
+
+/*
+ * RCU torture force-quiescent-state kthread.  Repeatedly induces
+ * bursts of calls to force_quiescent_state(), increasing the probability
+ * of occurrence of some important types of race conditions.
+ */
+static int
+rcu_torture_fqs(void *arg)
+{
+       unsigned long fqs_resume_time;
+       int fqs_burst_remaining;
+
+       VERBOSE_TOROUT_STRING("rcu_torture_fqs task started");
+       do {
+               fqs_resume_time = jiffies + fqs_stutter * HZ;
+               while (ULONG_CMP_LT(jiffies, fqs_resume_time) &&
+                      !kthread_should_stop()) {
+                       schedule_timeout_interruptible(1);
+               }
+               fqs_burst_remaining = fqs_duration;
+               while (fqs_burst_remaining > 0 &&
+                      !kthread_should_stop()) {
+                       cur_ops->fqs();
+                       udelay(fqs_holdoff);
+                       fqs_burst_remaining -= fqs_holdoff;
+               }
+               stutter_wait("rcu_torture_fqs");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("rcu_torture_fqs");
+       return 0;
+}
+
+/*
+ * RCU torture writer kthread.  Repeatedly substitutes a new structure
+ * for that pointed to by rcu_torture_current, freeing the old structure
+ * after a series of grace periods (the "pipeline").
+ */
+static int
+rcu_torture_writer(void *arg)
+{
+       bool exp;
+       int i;
+       struct rcu_torture *rp;
+       struct rcu_torture *rp1;
+       struct rcu_torture *old_rp;
+       static DEFINE_TORTURE_RANDOM(rand);
+
+       VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
+       set_user_nice(current, MAX_NICE);
+
+       do {
+               schedule_timeout_uninterruptible(1);
+               rp = rcu_torture_alloc();
+               if (rp == NULL)
+                       continue;
+               rp->rtort_pipe_count = 0;
+               udelay(torture_random(&rand) & 0x3ff);
+               old_rp = rcu_dereference_check(rcu_torture_current,
+                                              current == writer_task);
+               rp->rtort_mbtest = 1;
+               rcu_assign_pointer(rcu_torture_current, rp);
+               smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */
+               if (old_rp) {
+                       i = old_rp->rtort_pipe_count;
+                       if (i > RCU_TORTURE_PIPE_LEN)
+                               i = RCU_TORTURE_PIPE_LEN;
+                       atomic_inc(&rcu_torture_wcount[i]);
+                       old_rp->rtort_pipe_count++;
+                       if (gp_normal == gp_exp)
+                               exp = !!(torture_random(&rand) & 0x80);
+                       else
+                               exp = gp_exp;
+                       if (!exp) {
+                               cur_ops->deferred_free(old_rp);
+                       } else {
+                               cur_ops->exp_sync();
+                               list_add(&old_rp->rtort_free,
+                                        &rcu_torture_removed);
+                               list_for_each_entry_safe(rp, rp1,
+                                                        &rcu_torture_removed,
+                                                        rtort_free) {
+                                       i = rp->rtort_pipe_count;
+                                       if (i > RCU_TORTURE_PIPE_LEN)
+                                               i = RCU_TORTURE_PIPE_LEN;
+                                       atomic_inc(&rcu_torture_wcount[i]);
+                                       if (++rp->rtort_pipe_count >=
+                                           RCU_TORTURE_PIPE_LEN) {
+                                               rp->rtort_mbtest = 0;
+                                               list_del(&rp->rtort_free);
+                                               rcu_torture_free(rp);
+                                       }
+                                }
+                       }
+               }
+               rcutorture_record_progress(++rcu_torture_current_version);
+               stutter_wait("rcu_torture_writer");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("rcu_torture_writer");
+       return 0;
+}
+
+/*
+ * RCU torture fake writer kthread.  Repeatedly calls sync, with a random
+ * delay between calls.
+ */
+static int
+rcu_torture_fakewriter(void *arg)
+{
+       DEFINE_TORTURE_RANDOM(rand);
+
+       VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task started");
+       set_user_nice(current, MAX_NICE);
+
+       do {
+               schedule_timeout_uninterruptible(1 + torture_random(&rand)%10);
+               udelay(torture_random(&rand) & 0x3ff);
+               if (cur_ops->cb_barrier != NULL &&
+                   torture_random(&rand) % (nfakewriters * 8) == 0) {
+                       cur_ops->cb_barrier();
+               } else if (gp_normal == gp_exp) {
+                       if (torture_random(&rand) & 0x80)
+                               cur_ops->sync();
+                       else
+                               cur_ops->exp_sync();
+               } else if (gp_normal) {
+                       cur_ops->sync();
+               } else {
+                       cur_ops->exp_sync();
+               }
+               stutter_wait("rcu_torture_fakewriter");
+       } while (!torture_must_stop());
+
+       torture_kthread_stopping("rcu_torture_fakewriter");
+       return 0;
+}
+
+void rcutorture_trace_dump(void)
+{
+       static atomic_t beenhere = ATOMIC_INIT(0);
+
+       if (atomic_read(&beenhere))
+               return;
+       if (atomic_xchg(&beenhere, 1) != 0)
+               return;
+       ftrace_dump(DUMP_ALL);
+}
+
+/*
+ * RCU torture reader from timer handler.  Dereferences rcu_torture_current,
+ * incrementing the corresponding element of the pipeline array.  The
+ * counter in the element should never be greater than 1, otherwise, the
+ * RCU implementation is broken.
+ */
+static void rcu_torture_timer(unsigned long unused)
+{
+       int idx;
+       int completed;
+       int completed_end;
+       static DEFINE_TORTURE_RANDOM(rand);
+       static DEFINE_SPINLOCK(rand_lock);
+       struct rcu_torture *p;
+       int pipe_count;
+       unsigned long long ts;
+
+       idx = cur_ops->readlock();
+       completed = cur_ops->completed();
+       ts = rcu_trace_clock_local();
+       p = rcu_dereference_check(rcu_torture_current,
+                                 rcu_read_lock_bh_held() ||
+                                 rcu_read_lock_sched_held() ||
+                                 srcu_read_lock_held(&srcu_ctl));
+       if (p == NULL) {
+               /* Leave because rcu_torture_writer is not yet underway */
+               cur_ops->readunlock(idx);
+               return;
+       }
+       if (p->rtort_mbtest == 0)
+               atomic_inc(&n_rcu_torture_mberror);
+       spin_lock(&rand_lock);
+       cur_ops->read_delay(&rand);
+       n_rcu_torture_timers++;
+       spin_unlock(&rand_lock);
+       preempt_disable();
+       pipe_count = p->rtort_pipe_count;
+       if (pipe_count > RCU_TORTURE_PIPE_LEN) {
+               /* Should not happen, but... */
+               pipe_count = RCU_TORTURE_PIPE_LEN;
+       }
+       completed_end = cur_ops->completed();
+       if (pipe_count > 1) {
+               do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts,
+                                         completed, completed_end);
+               rcutorture_trace_dump();
+       }
+       __this_cpu_inc(rcu_torture_count[pipe_count]);
+       completed = completed_end - completed;
+       if (completed > RCU_TORTURE_PIPE_LEN) {
+               /* Should not happen, but... */
+               completed = RCU_TORTURE_PIPE_LEN;
+       }
+       __this_cpu_inc(rcu_torture_batch[completed]);
+       preempt_enable();
+       cur_ops->readunlock(idx);
+}
+
+/*
+ * RCU torture reader kthread.  Repeatedly dereferences rcu_torture_current,
+ * incrementing the corresponding element of the pipeline array.  The
+ * counter in the element should never be greater than 1, otherwise, the
+ * RCU implementation is broken.
+ */
+static int
+rcu_torture_reader(void *arg)
+{
+       int completed;
+       int completed_end;
+       int idx;
+       DEFINE_TORTURE_RANDOM(rand);
+       struct rcu_torture *p;
+       int pipe_count;
+       struct timer_list t;
+       unsigned long long ts;
+
+       VERBOSE_TOROUT_STRING("rcu_torture_reader task started");
+       set_user_nice(current, MAX_NICE);
+       if (irqreader && cur_ops->irq_capable)
+               setup_timer_on_stack(&t, rcu_torture_timer, 0);
+
+       do {
+               if (irqreader && cur_ops->irq_capable) {
+                       if (!timer_pending(&t))
+                               mod_timer(&t, jiffies + 1);
+               }
+               idx = cur_ops->readlock();
+               completed = cur_ops->completed();
+               ts = rcu_trace_clock_local();
+               p = rcu_dereference_check(rcu_torture_current,
+                                         rcu_read_lock_bh_held() ||
+                                         rcu_read_lock_sched_held() ||
+                                         srcu_read_lock_held(&srcu_ctl));
+               if (p == NULL) {
+                       /* Wait for rcu_torture_writer to get underway */
+                       cur_ops->readunlock(idx);
+                       schedule_timeout_interruptible(HZ);
+                       continue;
+               }
+               if (p->rtort_mbtest == 0)
+                       atomic_inc(&n_rcu_torture_mberror);
+               cur_ops->read_delay(&rand);
+               preempt_disable();
+               pipe_count = p->rtort_pipe_count;
+               if (pipe_count > RCU_TORTURE_PIPE_LEN) {
+                       /* Should not happen, but... */
+                       pipe_count = RCU_TORTURE_PIPE_LEN;
+               }
+               completed_end = cur_ops->completed();
+               if (pipe_count > 1) {
+                       do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu,
+                                                 ts, completed, completed_end);
+                       rcutorture_trace_dump();
+               }
+               __this_cpu_inc(rcu_torture_count[pipe_count]);
+               completed = completed_end - completed;
+               if (completed > RCU_TORTURE_PIPE_LEN) {
+                       /* Should not happen, but... */
+                       completed = RCU_TORTURE_PIPE_LEN;
+               }
+               __this_cpu_inc(rcu_torture_batch[completed]);
+               preempt_enable();
+               cur_ops->readunlock(idx);
+               schedule();
+               stutter_wait("rcu_torture_reader");
+       } while (!torture_must_stop());
+       if (irqreader && cur_ops->irq_capable)
+               del_timer_sync(&t);
+       torture_kthread_stopping("rcu_torture_reader");
+       return 0;
+}
+
+/*
+ * Create an RCU-torture statistics message in the specified buffer.
+ */
+static void
+rcu_torture_printk(char *page)
+{
+       int cpu;
+       int i;
+       long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
+       long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
+
+       for_each_possible_cpu(cpu) {
+               for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
+                       pipesummary[i] += per_cpu(rcu_torture_count, cpu)[i];
+                       batchsummary[i] += per_cpu(rcu_torture_batch, cpu)[i];
+               }
+       }
+       for (i = RCU_TORTURE_PIPE_LEN - 1; i >= 0; i--) {
+               if (pipesummary[i] != 0)
+                       break;
+       }
+       page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
+       page += sprintf(page,
+                      "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d ",
+                      rcu_torture_current,
+                      rcu_torture_current_version,
+                      list_empty(&rcu_torture_freelist),
+                      atomic_read(&n_rcu_torture_alloc),
+                      atomic_read(&n_rcu_torture_alloc_fail),
+                      atomic_read(&n_rcu_torture_free));
+       page += sprintf(page, "rtmbe: %d rtbke: %ld rtbre: %ld ",
+                      atomic_read(&n_rcu_torture_mberror),
+                      n_rcu_torture_boost_ktrerror,
+                      n_rcu_torture_boost_rterror);
+       page += sprintf(page, "rtbf: %ld rtb: %ld nt: %ld ",
+                      n_rcu_torture_boost_failure,
+                      n_rcu_torture_boosts,
+                      n_rcu_torture_timers);
+       page = torture_onoff_stats(page);
+       page += sprintf(page, "barrier: %ld/%ld:%ld",
+                      n_barrier_successes,
+                      n_barrier_attempts,
+                      n_rcu_torture_barrier_error);
+       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
+       if (atomic_read(&n_rcu_torture_mberror) != 0 ||
+           n_rcu_torture_barrier_error != 0 ||
+           n_rcu_torture_boost_ktrerror != 0 ||
+           n_rcu_torture_boost_rterror != 0 ||
+           n_rcu_torture_boost_failure != 0 ||
+           i > 1) {
+               page += sprintf(page, "!!! ");
+               atomic_inc(&n_rcu_torture_error);
+               WARN_ON_ONCE(1);
+       }
+       page += sprintf(page, "Reader Pipe: ");
+       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
+               page += sprintf(page, " %ld", pipesummary[i]);
+       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
+       page += sprintf(page, "Reader Batch: ");
+       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
+               page += sprintf(page, " %ld", batchsummary[i]);
+       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
+       page += sprintf(page, "Free-Block Circulation: ");
+       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
+               page += sprintf(page, " %d",
+                              atomic_read(&rcu_torture_wcount[i]));
+       }
+       page += sprintf(page, "\n");
+       if (cur_ops->stats)
+               cur_ops->stats(page);
+}
+
+/*
+ * Print torture statistics.  Caller must ensure that there is only
+ * one call to this function at a given time!!!  This is normally
+ * accomplished by relying on the module system to only have one copy
+ * of the module loaded, and then by giving the rcu_torture_stats
+ * kthread full control (or the init/cleanup functions when rcu_torture_stats
+ * thread is not running).
+ */
+static void
+rcu_torture_stats_print(void)
+{
+       int size = nr_cpu_ids * 200 + 8192;
+       char *buf;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               pr_err("rcu-torture: Out of memory, need: %d", size);
+               return;
+       }
+       rcu_torture_printk(buf);
+       pr_alert("%s", buf);
+       kfree(buf);
+}
+
+/*
+ * Periodically prints torture statistics, if periodic statistics printing
+ * was specified via the stat_interval module parameter.
+ */
+static int
+rcu_torture_stats(void *arg)
+{
+       VERBOSE_TOROUT_STRING("rcu_torture_stats task started");
+       do {
+               schedule_timeout_interruptible(stat_interval * HZ);
+               rcu_torture_stats_print();
+               torture_shutdown_absorb("rcu_torture_stats");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("rcu_torture_stats");
+       return 0;
+}
+
+static inline void
+rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
+{
+       pr_alert("%s" TORTURE_FLAG
+                "--- %s: nreaders=%d nfakewriters=%d "
+                "stat_interval=%d verbose=%d test_no_idle_hz=%d "
+                "shuffle_interval=%d stutter=%d irqreader=%d "
+                "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
+                "test_boost=%d/%d test_boost_interval=%d "
+                "test_boost_duration=%d shutdown_secs=%d "
+                "stall_cpu=%d stall_cpu_holdoff=%d "
+                "n_barrier_cbs=%d "
+                "onoff_interval=%d onoff_holdoff=%d\n",
+                torture_type, tag, nrealreaders, nfakewriters,
+                stat_interval, verbose, test_no_idle_hz, shuffle_interval,
+                stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
+                test_boost, cur_ops->can_boost,
+                test_boost_interval, test_boost_duration, shutdown_secs,
+                stall_cpu, stall_cpu_holdoff,
+                n_barrier_cbs,
+                onoff_interval, onoff_holdoff);
+}
+
+static void rcutorture_booster_cleanup(int cpu)
+{
+       struct task_struct *t;
+
+       if (boost_tasks[cpu] == NULL)
+               return;
+       mutex_lock(&boost_mutex);
+       t = boost_tasks[cpu];
+       boost_tasks[cpu] = NULL;
+       mutex_unlock(&boost_mutex);
+
+       /* This must be outside of the mutex, otherwise deadlock! */
+       torture_stop_kthread(rcu_torture_boost, t);
+}
+
+static int rcutorture_booster_init(int cpu)
+{
+       int retval;
+
+       if (boost_tasks[cpu] != NULL)
+               return 0;  /* Already created, nothing more to do. */
+
+       /* Don't allow time recalculation while creating a new task. */
+       mutex_lock(&boost_mutex);
+       VERBOSE_TOROUT_STRING("Creating rcu_torture_boost task");
+       boost_tasks[cpu] = kthread_create_on_node(rcu_torture_boost, NULL,
+                                                 cpu_to_node(cpu),
+                                                 "rcu_torture_boost");
+       if (IS_ERR(boost_tasks[cpu])) {
+               retval = PTR_ERR(boost_tasks[cpu]);
+               VERBOSE_TOROUT_STRING("rcu_torture_boost task create failed");
+               n_rcu_torture_boost_ktrerror++;
+               boost_tasks[cpu] = NULL;
+               mutex_unlock(&boost_mutex);
+               return retval;
+       }
+       kthread_bind(boost_tasks[cpu], cpu);
+       wake_up_process(boost_tasks[cpu]);
+       mutex_unlock(&boost_mutex);
+       return 0;
+}
+
+/*
+ * CPU-stall kthread.  It waits as specified by stall_cpu_holdoff, then
+ * induces a CPU stall for the time specified by stall_cpu.
+ */
+static int rcu_torture_stall(void *args)
+{
+       unsigned long stop_at;
+
+       VERBOSE_TOROUT_STRING("rcu_torture_stall task started");
+       if (stall_cpu_holdoff > 0) {
+               VERBOSE_TOROUT_STRING("rcu_torture_stall begin holdoff");
+               schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
+               VERBOSE_TOROUT_STRING("rcu_torture_stall end holdoff");
+       }
+       if (!kthread_should_stop()) {
+               stop_at = get_seconds() + stall_cpu;
+               /* RCU CPU stall is expected behavior in following code. */
+               pr_alert("rcu_torture_stall start.\n");
+               rcu_read_lock();
+               preempt_disable();
+               while (ULONG_CMP_LT(get_seconds(), stop_at))
+                       continue;  /* Induce RCU CPU stall warning. */
+               preempt_enable();
+               rcu_read_unlock();
+               pr_alert("rcu_torture_stall end.\n");
+       }
+       torture_shutdown_absorb("rcu_torture_stall");
+       while (!kthread_should_stop())
+               schedule_timeout_interruptible(10 * HZ);
+       return 0;
+}
+
+/* Spawn CPU-stall kthread, if stall_cpu specified. */
+static int __init rcu_torture_stall_init(void)
+{
+       if (stall_cpu <= 0)
+               return 0;
+       return torture_create_kthread(rcu_torture_stall, NULL, stall_task);
+}
+
+/* Callback function for RCU barrier testing. */
+void rcu_torture_barrier_cbf(struct rcu_head *rcu)
+{
+       atomic_inc(&barrier_cbs_invoked);
+}
+
+/* kthread function to register callbacks used to test RCU barriers. */
+static int rcu_torture_barrier_cbs(void *arg)
+{
+       long myid = (long)arg;
+       bool lastphase = 0;
+       bool newphase;
+       struct rcu_head rcu;
+
+       init_rcu_head_on_stack(&rcu);
+       VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task started");
+       set_user_nice(current, MAX_NICE);
+       do {
+               wait_event(barrier_cbs_wq[myid],
+                          (newphase =
+                           ACCESS_ONCE(barrier_phase)) != lastphase ||
+                          torture_must_stop());
+               lastphase = newphase;
+               smp_mb(); /* ensure barrier_phase load before ->call(). */
+               if (torture_must_stop())
+                       break;
+               cur_ops->call(&rcu, rcu_torture_barrier_cbf);
+               if (atomic_dec_and_test(&barrier_cbs_count))
+                       wake_up(&barrier_wq);
+       } while (!torture_must_stop());
+       cur_ops->cb_barrier();
+       destroy_rcu_head_on_stack(&rcu);
+       torture_kthread_stopping("rcu_torture_barrier_cbs");
+       return 0;
+}
+
+/* kthread function to drive and coordinate RCU barrier testing. */
+static int rcu_torture_barrier(void *arg)
+{
+       int i;
+
+       VERBOSE_TOROUT_STRING("rcu_torture_barrier task starting");
+       do {
+               atomic_set(&barrier_cbs_invoked, 0);
+               atomic_set(&barrier_cbs_count, n_barrier_cbs);
+               smp_mb(); /* Ensure barrier_phase after prior assignments. */
+               barrier_phase = !barrier_phase;
+               for (i = 0; i < n_barrier_cbs; i++)
+                       wake_up(&barrier_cbs_wq[i]);
+               wait_event(barrier_wq,
+                          atomic_read(&barrier_cbs_count) == 0 ||
+                          torture_must_stop());
+               if (torture_must_stop())
+                       break;
+               n_barrier_attempts++;
+               cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */
+               if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) {
+                       n_rcu_torture_barrier_error++;
+                       WARN_ON_ONCE(1);
+               }
+               n_barrier_successes++;
+               schedule_timeout_interruptible(HZ / 10);
+       } while (!torture_must_stop());
+       torture_kthread_stopping("rcu_torture_barrier");
+       return 0;
+}
+
+/* Initialize RCU barrier testing. */
+static int rcu_torture_barrier_init(void)
+{
+       int i;
+       int ret;
+
+       if (n_barrier_cbs == 0)
+               return 0;
+       if (cur_ops->call == NULL || cur_ops->cb_barrier == NULL) {
+               pr_alert("%s" TORTURE_FLAG
+                        " Call or barrier ops missing for %s,\n",
+                        torture_type, cur_ops->name);
+               pr_alert("%s" TORTURE_FLAG
+                        " RCU barrier testing omitted from run.\n",
+                        torture_type);
+               return 0;
+       }
+       atomic_set(&barrier_cbs_count, 0);
+       atomic_set(&barrier_cbs_invoked, 0);
+       barrier_cbs_tasks =
+               kzalloc(n_barrier_cbs * sizeof(barrier_cbs_tasks[0]),
+                       GFP_KERNEL);
+       barrier_cbs_wq =
+               kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]),
+                       GFP_KERNEL);
+       if (barrier_cbs_tasks == NULL || !barrier_cbs_wq)
+               return -ENOMEM;
+       for (i = 0; i < n_barrier_cbs; i++) {
+               init_waitqueue_head(&barrier_cbs_wq[i]);
+               ret = torture_create_kthread(rcu_torture_barrier_cbs,
+                                            (void *)(long)i,
+                                            barrier_cbs_tasks[i]);
+               if (ret)
+                       return ret;
+       }
+       return torture_create_kthread(rcu_torture_barrier, NULL, barrier_task);
+}
+
+/* Clean up after RCU barrier testing. */
+static void rcu_torture_barrier_cleanup(void)
+{
+       int i;
+
+       torture_stop_kthread(rcu_torture_barrier, barrier_task);
+       if (barrier_cbs_tasks != NULL) {
+               for (i = 0; i < n_barrier_cbs; i++)
+                       torture_stop_kthread(rcu_torture_barrier_cbs,
+                                            barrier_cbs_tasks[i]);
+               kfree(barrier_cbs_tasks);
+               barrier_cbs_tasks = NULL;
+       }
+       if (barrier_cbs_wq != NULL) {
+               kfree(barrier_cbs_wq);
+               barrier_cbs_wq = NULL;
+       }
+}
+
+static int rcutorture_cpu_notify(struct notifier_block *self,
+                                unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_DOWN_FAILED:
+               (void)rcutorture_booster_init(cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+               rcutorture_booster_cleanup(cpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rcutorture_cpu_nb = {
+       .notifier_call = rcutorture_cpu_notify,
+};
+
+static void
+rcu_torture_cleanup(void)
+{
+       int i;
+
+       rcutorture_record_test_transition();
+       if (torture_cleanup()) {
+               if (cur_ops->cb_barrier != NULL)
+                       cur_ops->cb_barrier();
+               return;
+       }
+
+       rcu_torture_barrier_cleanup();
+       torture_stop_kthread(rcu_torture_stall, stall_task);
+       torture_stop_kthread(rcu_torture_writer, writer_task);
+
+       if (reader_tasks) {
+               for (i = 0; i < nrealreaders; i++)
+                       torture_stop_kthread(rcu_torture_reader,
+                                            reader_tasks[i]);
+               kfree(reader_tasks);
+       }
+       rcu_torture_current = NULL;
+
+       if (fakewriter_tasks) {
+               for (i = 0; i < nfakewriters; i++) {
+                       torture_stop_kthread(rcu_torture_fakewriter,
+                                            fakewriter_tasks[i]);
+               }
+               kfree(fakewriter_tasks);
+               fakewriter_tasks = NULL;
+       }
+
+       torture_stop_kthread(rcu_torture_stats, stats_task);
+       torture_stop_kthread(rcu_torture_fqs, fqs_task);
+       if ((test_boost == 1 && cur_ops->can_boost) ||
+           test_boost == 2) {
+               unregister_cpu_notifier(&rcutorture_cpu_nb);
+               for_each_possible_cpu(i)
+                       rcutorture_booster_cleanup(i);
+       }
+
+       /* Wait for all RCU callbacks to fire.  */
+
+       if (cur_ops->cb_barrier != NULL)
+               cur_ops->cb_barrier();
+
+       rcu_torture_stats_print();  /* -After- the stats thread is stopped! */
+
+       if (atomic_read(&n_rcu_torture_error) || n_rcu_torture_barrier_error)
+               rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
+       else if (torture_onoff_failures())
+               rcu_torture_print_module_parms(cur_ops,
+                                              "End of test: RCU_HOTPLUG");
+       else
+               rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
+}
+
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+       /*
+        * This -might- happen due to race conditions, but is unlikely.
+        * The scenario that leads to this happening is that the
+        * first of the pair of duplicate callbacks is queued,
+        * someone else starts a grace period that includes that
+        * callback, then the second of the pair must wait for the
+        * next grace period.  Unlikely, but can happen.  If it
+        * does happen, the debug-objects subsystem won't have splatted.
+        */
+       pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+       struct rcu_head rh1;
+       struct rcu_head rh2;
+
+       init_rcu_head_on_stack(&rh1);
+       init_rcu_head_on_stack(&rh2);
+       pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+
+       /* Try to queue the rh2 pair of callbacks for the same grace period. */
+       preempt_disable(); /* Prevent preemption from interrupting test. */
+       rcu_read_lock(); /* Make it impossible to finish a grace period. */
+       call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
+       local_irq_disable(); /* Make it harder to start a new grace period. */
+       call_rcu(&rh2, rcu_torture_leak_cb);
+       call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
+       local_irq_enable();
+       rcu_read_unlock();
+       preempt_enable();
+
+       /* Wait for them all to get done so we can safely return. */
+       rcu_barrier();
+       pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+       destroy_rcu_head_on_stack(&rh1);
+       destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+       pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}
+
+static int __init
+rcu_torture_init(void)
+{
+       int i;
+       int cpu;
+       int firsterr = 0;
+       static struct rcu_torture_ops *torture_ops[] = {
+               &rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &sched_ops,
+       };
+
+       torture_init_begin(torture_type, verbose, &rcutorture_runnable);
+
+       /* Process args and tell the world that the torturer is on the job. */
+       for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
+               cur_ops = torture_ops[i];
+               if (strcmp(torture_type, cur_ops->name) == 0)
+                       break;
+       }
+       if (i == ARRAY_SIZE(torture_ops)) {
+               pr_alert("rcu-torture: invalid torture type: \"%s\"\n",
+                        torture_type);
+               pr_alert("rcu-torture types:");
+               for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
+                       pr_alert(" %s", torture_ops[i]->name);
+               pr_alert("\n");
+               torture_init_end();
+               return -EINVAL;
+       }
+       if (cur_ops->fqs == NULL && fqs_duration != 0) {
+               pr_alert("rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled.\n");
+               fqs_duration = 0;
+       }
+       if (cur_ops->init)
+               cur_ops->init(); /* no "goto unwind" prior to this point!!! */
+
+       if (nreaders >= 0)
+               nrealreaders = nreaders;
+       else
+               nrealreaders = 2 * num_online_cpus();
+       rcu_torture_print_module_parms(cur_ops, "Start of test");
+
+       /* Set up the freelist. */
+
+       INIT_LIST_HEAD(&rcu_torture_freelist);
+       for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
+               rcu_tortures[i].rtort_mbtest = 0;
+               list_add_tail(&rcu_tortures[i].rtort_free,
+                             &rcu_torture_freelist);
+       }
+
+       /* Initialize the statistics so that each run gets its own numbers. */
+
+       rcu_torture_current = NULL;
+       rcu_torture_current_version = 0;
+       atomic_set(&n_rcu_torture_alloc, 0);
+       atomic_set(&n_rcu_torture_alloc_fail, 0);
+       atomic_set(&n_rcu_torture_free, 0);
+       atomic_set(&n_rcu_torture_mberror, 0);
+       atomic_set(&n_rcu_torture_error, 0);
+       n_rcu_torture_barrier_error = 0;
+       n_rcu_torture_boost_ktrerror = 0;
+       n_rcu_torture_boost_rterror = 0;
+       n_rcu_torture_boost_failure = 0;
+       n_rcu_torture_boosts = 0;
+       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
+               atomic_set(&rcu_torture_wcount[i], 0);
+       for_each_possible_cpu(cpu) {
+               for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
+                       per_cpu(rcu_torture_count, cpu)[i] = 0;
+                       per_cpu(rcu_torture_batch, cpu)[i] = 0;
+               }
+       }
+
+       /* Start up the kthreads. */
+
+       firsterr = torture_create_kthread(rcu_torture_writer, NULL,
+                                         writer_task);
+       if (firsterr)
+               goto unwind;
+       fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
+                                  GFP_KERNEL);
+       if (fakewriter_tasks == NULL) {
+               VERBOSE_TOROUT_ERRSTRING("out of memory");
+               firsterr = -ENOMEM;
+               goto unwind;
+       }
+       for (i = 0; i < nfakewriters; i++) {
+               firsterr = torture_create_kthread(rcu_torture_fakewriter,
+                                                 NULL, fakewriter_tasks[i]);
+               if (firsterr)
+                       goto unwind;
+       }
+       reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
+                              GFP_KERNEL);
+       if (reader_tasks == NULL) {
+               VERBOSE_TOROUT_ERRSTRING("out of memory");
+               firsterr = -ENOMEM;
+               goto unwind;
+       }
+       for (i = 0; i < nrealreaders; i++) {
+               firsterr = torture_create_kthread(rcu_torture_reader, NULL,
+                                                 reader_tasks[i]);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (stat_interval > 0) {
+               firsterr = torture_create_kthread(rcu_torture_stats, NULL,
+                                                 stats_task);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (test_no_idle_hz) {
+               firsterr = torture_shuffle_init(shuffle_interval * HZ);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (stutter < 0)
+               stutter = 0;
+       if (stutter) {
+               firsterr = torture_stutter_init(stutter * HZ);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (fqs_duration < 0)
+               fqs_duration = 0;
+       if (fqs_duration) {
+               /* Create the fqs thread */
+               torture_create_kthread(rcu_torture_fqs, NULL, fqs_task);
+               if (firsterr)
+                       goto unwind;
+       }
+       if (test_boost_interval < 1)
+               test_boost_interval = 1;
+       if (test_boost_duration < 2)
+               test_boost_duration = 2;
+       if ((test_boost == 1 && cur_ops->can_boost) ||
+           test_boost == 2) {
+
+               boost_starttime = jiffies + test_boost_interval * HZ;
+               register_cpu_notifier(&rcutorture_cpu_nb);
+               for_each_possible_cpu(i) {
+                       if (cpu_is_offline(i))
+                               continue;  /* Heuristic: CPU can go offline. */
+                       firsterr = rcutorture_booster_init(i);
+                       if (firsterr)
+                               goto unwind;
+               }
+       }
+       firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup);
+       if (firsterr)
+               goto unwind;
+       firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ);
+       if (firsterr)
+               goto unwind;
+       firsterr = rcu_torture_stall_init();
+       if (firsterr)
+               goto unwind;
+       firsterr = rcu_torture_barrier_init();
+       if (firsterr)
+               goto unwind;
+       if (object_debug)
+               rcu_test_debug_objects();
+       rcutorture_record_test_transition();
+       torture_init_end();
+       return 0;
+
+unwind:
+       torture_init_end();
+       rcu_torture_cleanup();
+       return firsterr;
+}
+
+module_init(rcu_torture_init);
+module_exit(rcu_torture_cleanup);
index 3318d82843841971f4926d8a8f9eb9a375e2eab3..c639556f3fa06234dcc34517826fbf0420641e56 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright (C) IBM Corporation, 2006
  * Copyright (C) Fujitsu, 2012
@@ -36,8 +36,6 @@
 #include <linux/delay.h>
 #include <linux/srcu.h>
 
-#include <trace/events/rcu.h>
-
 #include "rcu.h"
 
 /*
@@ -398,7 +396,7 @@ void call_srcu(struct srcu_struct *sp, struct rcu_head *head,
        rcu_batch_queue(&sp->batch_queue, head);
        if (!sp->running) {
                sp->running = true;
-               schedule_delayed_work(&sp->work, 0);
+               queue_delayed_work(system_power_efficient_wq, &sp->work, 0);
        }
        spin_unlock_irqrestore(&sp->queue_lock, flags);
 }
@@ -674,7 +672,8 @@ static void srcu_reschedule(struct srcu_struct *sp)
        }
 
        if (pending)
-               schedule_delayed_work(&sp->work, SRCU_INTERVAL);
+               queue_delayed_work(system_power_efficient_wq,
+                                  &sp->work, SRCU_INTERVAL);
 }
 
 /*
index 1254f312d02483f524319ee5ab9d2e1a13f48678..d9efcc13008c00201c130f87135348c7238118ff 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
  *
 #include <linux/prefetch.h>
 #include <linux/ftrace_event.h>
 
-#ifdef CONFIG_RCU_TRACE
-#include <trace/events/rcu.h>
-#endif /* #else #ifdef CONFIG_RCU_TRACE */
-
 #include "rcu.h"
 
 /* Forward declarations for tiny_plugin.h. */
index 280d06cae3524160833d3441b5de5af3462798c7..4315285205626f7c27c38c774a4522a12b04adcf 100644 (file)
@@ -14,8 +14,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright (c) 2010 Linaro
  *
diff --git a/kernel/rcu/torture.c b/kernel/rcu/torture.c
deleted file mode 100644 (file)
index 732f8ae..0000000
+++ /dev/null
@@ -1,2148 +0,0 @@
-/*
- * Read-Copy Update module-based torture test facility
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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.
- *
- * Copyright (C) IBM Corporation, 2005, 2006
- *
- * Authors: Paul E. McKenney <paulmck@us.ibm.com>
- *       Josh Triplett <josh@freedesktop.org>
- *
- * See also:  Documentation/RCU/torture.txt
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/smp.h>
-#include <linux/rcupdate.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/atomic.h>
-#include <linux/bitops.h>
-#include <linux/completion.h>
-#include <linux/moduleparam.h>
-#include <linux/percpu.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/freezer.h>
-#include <linux/cpu.h>
-#include <linux/delay.h>
-#include <linux/stat.h>
-#include <linux/srcu.h>
-#include <linux/slab.h>
-#include <linux/trace_clock.h>
-#include <asm/byteorder.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
-
-MODULE_ALIAS("rcutorture");
-#ifdef MODULE_PARAM_PREFIX
-#undef MODULE_PARAM_PREFIX
-#endif
-#define MODULE_PARAM_PREFIX "rcutorture."
-
-static int fqs_duration;
-module_param(fqs_duration, int, 0444);
-MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us), 0 to disable");
-static int fqs_holdoff;
-module_param(fqs_holdoff, int, 0444);
-MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
-static int fqs_stutter = 3;
-module_param(fqs_stutter, int, 0444);
-MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
-static bool gp_exp;
-module_param(gp_exp, bool, 0444);
-MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives");
-static bool gp_normal;
-module_param(gp_normal, bool, 0444);
-MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
-static int irqreader = 1;
-module_param(irqreader, int, 0444);
-MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
-static int n_barrier_cbs;
-module_param(n_barrier_cbs, int, 0444);
-MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
-static int nfakewriters = 4;
-module_param(nfakewriters, int, 0444);
-MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-static int nreaders = -1;
-module_param(nreaders, int, 0444);
-MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-static int object_debug;
-module_param(object_debug, int, 0444);
-MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
-static int onoff_holdoff;
-module_param(onoff_holdoff, int, 0444);
-MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
-static int onoff_interval;
-module_param(onoff_interval, int, 0444);
-MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
-static int shuffle_interval = 3;
-module_param(shuffle_interval, int, 0444);
-MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-static int shutdown_secs;
-module_param(shutdown_secs, int, 0444);
-MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), <= zero to disable.");
-static int stall_cpu;
-module_param(stall_cpu, int, 0444);
-MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
-static int stall_cpu_holdoff = 10;
-module_param(stall_cpu_holdoff, int, 0444);
-MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
-static int stat_interval = 60;
-module_param(stat_interval, int, 0644);
-MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-static int stutter = 5;
-module_param(stutter, int, 0444);
-MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
-static int test_boost = 1;
-module_param(test_boost, int, 0444);
-MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-static int test_boost_duration = 4;
-module_param(test_boost_duration, int, 0444);
-MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
-static int test_boost_interval = 7;
-module_param(test_boost_interval, int, 0444);
-MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
-static bool test_no_idle_hz = true;
-module_param(test_no_idle_hz, bool, 0444);
-MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-static char *torture_type = "rcu";
-module_param(torture_type, charp, 0444);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
-static bool verbose;
-module_param(verbose, bool, 0444);
-MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-
-#define TORTURE_FLAG "-torture:"
-#define PRINTK_STRING(s) \
-       do { pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0)
-#define VERBOSE_PRINTK_STRING(s) \
-       do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0)
-#define VERBOSE_PRINTK_ERRSTRING(s) \
-       do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
-
-static int nrealreaders;
-static struct task_struct *writer_task;
-static struct task_struct **fakewriter_tasks;
-static struct task_struct **reader_tasks;
-static struct task_struct *stats_task;
-static struct task_struct *shuffler_task;
-static struct task_struct *stutter_task;
-static struct task_struct *fqs_task;
-static struct task_struct *boost_tasks[NR_CPUS];
-static struct task_struct *shutdown_task;
-#ifdef CONFIG_HOTPLUG_CPU
-static struct task_struct *onoff_task;
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-static struct task_struct *stall_task;
-static struct task_struct **barrier_cbs_tasks;
-static struct task_struct *barrier_task;
-
-#define RCU_TORTURE_PIPE_LEN 10
-
-struct rcu_torture {
-       struct rcu_head rtort_rcu;
-       int rtort_pipe_count;
-       struct list_head rtort_free;
-       int rtort_mbtest;
-};
-
-static LIST_HEAD(rcu_torture_freelist);
-static struct rcu_torture __rcu *rcu_torture_current;
-static unsigned long rcu_torture_current_version;
-static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
-static DEFINE_SPINLOCK(rcu_torture_lock);
-static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
-       { 0 };
-static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
-       { 0 };
-static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
-static atomic_t n_rcu_torture_alloc;
-static atomic_t n_rcu_torture_alloc_fail;
-static atomic_t n_rcu_torture_free;
-static atomic_t n_rcu_torture_mberror;
-static atomic_t n_rcu_torture_error;
-static long n_rcu_torture_barrier_error;
-static long n_rcu_torture_boost_ktrerror;
-static long n_rcu_torture_boost_rterror;
-static long n_rcu_torture_boost_failure;
-static long n_rcu_torture_boosts;
-static long n_rcu_torture_timers;
-static long n_offline_attempts;
-static long n_offline_successes;
-static unsigned long sum_offline;
-static int min_offline = -1;
-static int max_offline;
-static long n_online_attempts;
-static long n_online_successes;
-static unsigned long sum_online;
-static int min_online = -1;
-static int max_online;
-static long n_barrier_attempts;
-static long n_barrier_successes;
-static struct list_head rcu_torture_removed;
-static cpumask_var_t shuffle_tmp_mask;
-
-static int stutter_pause_test;
-
-#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
-#define RCUTORTURE_RUNNABLE_INIT 1
-#else
-#define RCUTORTURE_RUNNABLE_INIT 0
-#endif
-int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
-module_param(rcutorture_runnable, int, 0444);
-MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot");
-
-#if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU)
-#define rcu_can_boost() 1
-#else /* #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
-#define rcu_can_boost() 0
-#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
-
-#ifdef CONFIG_RCU_TRACE
-static u64 notrace rcu_trace_clock_local(void)
-{
-       u64 ts = trace_clock_local();
-       unsigned long __maybe_unused ts_rem = do_div(ts, NSEC_PER_USEC);
-       return ts;
-}
-#else /* #ifdef CONFIG_RCU_TRACE */
-static u64 notrace rcu_trace_clock_local(void)
-{
-       return 0ULL;
-}
-#endif /* #else #ifdef CONFIG_RCU_TRACE */
-
-static unsigned long shutdown_time;    /* jiffies to system shutdown. */
-static unsigned long boost_starttime;  /* jiffies of next boost test start. */
-DEFINE_MUTEX(boost_mutex);             /* protect setting boost_starttime */
-                                       /*  and boost task create/destroy. */
-static atomic_t barrier_cbs_count;     /* Barrier callbacks registered. */
-static bool barrier_phase;             /* Test phase. */
-static atomic_t barrier_cbs_invoked;   /* Barrier callbacks invoked. */
-static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
-static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
-
-/* Mediate rmmod and system shutdown.  Concurrent rmmod & shutdown illegal! */
-
-#define FULLSTOP_DONTSTOP 0    /* Normal operation. */
-#define FULLSTOP_SHUTDOWN 1    /* System shutdown with rcutorture running. */
-#define FULLSTOP_RMMOD    2    /* Normal rmmod of rcutorture. */
-static int fullstop = FULLSTOP_RMMOD;
-/*
- * Protect fullstop transitions and spawning of kthreads.
- */
-static DEFINE_MUTEX(fullstop_mutex);
-
-/* Forward reference. */
-static void rcu_torture_cleanup(void);
-
-/*
- * Detect and respond to a system shutdown.
- */
-static int
-rcutorture_shutdown_notify(struct notifier_block *unused1,
-                          unsigned long unused2, void *unused3)
-{
-       mutex_lock(&fullstop_mutex);
-       if (fullstop == FULLSTOP_DONTSTOP)
-               fullstop = FULLSTOP_SHUTDOWN;
-       else
-               pr_warn(/* but going down anyway, so... */
-                      "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
-       mutex_unlock(&fullstop_mutex);
-       return NOTIFY_DONE;
-}
-
-/*
- * Absorb kthreads into a kernel function that won't return, so that
- * they won't ever access module text or data again.
- */
-static void rcutorture_shutdown_absorb(const char *title)
-{
-       if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
-               pr_notice(
-                      "rcutorture thread %s parking due to system shutdown\n",
-                      title);
-               schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
-       }
-}
-
-/*
- * Allocate an element from the rcu_tortures pool.
- */
-static struct rcu_torture *
-rcu_torture_alloc(void)
-{
-       struct list_head *p;
-
-       spin_lock_bh(&rcu_torture_lock);
-       if (list_empty(&rcu_torture_freelist)) {
-               atomic_inc(&n_rcu_torture_alloc_fail);
-               spin_unlock_bh(&rcu_torture_lock);
-               return NULL;
-       }
-       atomic_inc(&n_rcu_torture_alloc);
-       p = rcu_torture_freelist.next;
-       list_del_init(p);
-       spin_unlock_bh(&rcu_torture_lock);
-       return container_of(p, struct rcu_torture, rtort_free);
-}
-
-/*
- * Free an element to the rcu_tortures pool.
- */
-static void
-rcu_torture_free(struct rcu_torture *p)
-{
-       atomic_inc(&n_rcu_torture_free);
-       spin_lock_bh(&rcu_torture_lock);
-       list_add_tail(&p->rtort_free, &rcu_torture_freelist);
-       spin_unlock_bh(&rcu_torture_lock);
-}
-
-struct rcu_random_state {
-       unsigned long rrs_state;
-       long rrs_count;
-};
-
-#define RCU_RANDOM_MULT 39916801  /* prime */
-#define RCU_RANDOM_ADD 479001701 /* prime */
-#define RCU_RANDOM_REFRESH 10000
-
-#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
-
-/*
- * Crude but fast random-number generator.  Uses a linear congruential
- * generator, with occasional help from cpu_clock().
- */
-static unsigned long
-rcu_random(struct rcu_random_state *rrsp)
-{
-       if (--rrsp->rrs_count < 0) {
-               rrsp->rrs_state += (unsigned long)local_clock();
-               rrsp->rrs_count = RCU_RANDOM_REFRESH;
-       }
-       rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
-       return swahw32(rrsp->rrs_state);
-}
-
-static void
-rcu_stutter_wait(const char *title)
-{
-       while (stutter_pause_test || !rcutorture_runnable) {
-               if (rcutorture_runnable)
-                       schedule_timeout_interruptible(1);
-               else
-                       schedule_timeout_interruptible(round_jiffies_relative(HZ));
-               rcutorture_shutdown_absorb(title);
-       }
-}
-
-/*
- * Operations vector for selecting different types of tests.
- */
-
-struct rcu_torture_ops {
-       void (*init)(void);
-       int (*readlock)(void);
-       void (*read_delay)(struct rcu_random_state *rrsp);
-       void (*readunlock)(int idx);
-       int (*completed)(void);
-       void (*deferred_free)(struct rcu_torture *p);
-       void (*sync)(void);
-       void (*exp_sync)(void);
-       void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
-       void (*cb_barrier)(void);
-       void (*fqs)(void);
-       void (*stats)(char *page);
-       int irq_capable;
-       int can_boost;
-       const char *name;
-};
-
-static struct rcu_torture_ops *cur_ops;
-
-/*
- * Definitions for rcu torture testing.
- */
-
-static int rcu_torture_read_lock(void) __acquires(RCU)
-{
-       rcu_read_lock();
-       return 0;
-}
-
-static void rcu_read_delay(struct rcu_random_state *rrsp)
-{
-       const unsigned long shortdelay_us = 200;
-       const unsigned long longdelay_ms = 50;
-
-       /* We want a short delay sometimes to make a reader delay the grace
-        * period, and we want a long delay occasionally to trigger
-        * force_quiescent_state. */
-
-       if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
-               mdelay(longdelay_ms);
-       if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
-               udelay(shortdelay_us);
-#ifdef CONFIG_PREEMPT
-       if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000)))
-               preempt_schedule();  /* No QS if preempt_disable() in effect */
-#endif
-}
-
-static void rcu_torture_read_unlock(int idx) __releases(RCU)
-{
-       rcu_read_unlock();
-}
-
-static int rcu_torture_completed(void)
-{
-       return rcu_batches_completed();
-}
-
-static void
-rcu_torture_cb(struct rcu_head *p)
-{
-       int i;
-       struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
-
-       if (fullstop != FULLSTOP_DONTSTOP) {
-               /* Test is ending, just drop callbacks on the floor. */
-               /* The next initialization will pick up the pieces. */
-               return;
-       }
-       i = rp->rtort_pipe_count;
-       if (i > RCU_TORTURE_PIPE_LEN)
-               i = RCU_TORTURE_PIPE_LEN;
-       atomic_inc(&rcu_torture_wcount[i]);
-       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
-               rp->rtort_mbtest = 0;
-               rcu_torture_free(rp);
-       } else {
-               cur_ops->deferred_free(rp);
-       }
-}
-
-static int rcu_no_completed(void)
-{
-       return 0;
-}
-
-static void rcu_torture_deferred_free(struct rcu_torture *p)
-{
-       call_rcu(&p->rtort_rcu, rcu_torture_cb);
-}
-
-static void rcu_sync_torture_init(void)
-{
-       INIT_LIST_HEAD(&rcu_torture_removed);
-}
-
-static struct rcu_torture_ops rcu_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = rcu_torture_read_lock,
-       .read_delay     = rcu_read_delay,
-       .readunlock     = rcu_torture_read_unlock,
-       .completed      = rcu_torture_completed,
-       .deferred_free  = rcu_torture_deferred_free,
-       .sync           = synchronize_rcu,
-       .exp_sync       = synchronize_rcu_expedited,
-       .call           = call_rcu,
-       .cb_barrier     = rcu_barrier,
-       .fqs            = rcu_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .can_boost      = rcu_can_boost(),
-       .name           = "rcu"
-};
-
-/*
- * Definitions for rcu_bh torture testing.
- */
-
-static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
-{
-       rcu_read_lock_bh();
-       return 0;
-}
-
-static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
-{
-       rcu_read_unlock_bh();
-}
-
-static int rcu_bh_torture_completed(void)
-{
-       return rcu_batches_completed_bh();
-}
-
-static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
-{
-       call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
-}
-
-static struct rcu_torture_ops rcu_bh_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = rcu_bh_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = rcu_bh_torture_read_unlock,
-       .completed      = rcu_bh_torture_completed,
-       .deferred_free  = rcu_bh_torture_deferred_free,
-       .sync           = synchronize_rcu_bh,
-       .exp_sync       = synchronize_rcu_bh_expedited,
-       .call           = call_rcu_bh,
-       .cb_barrier     = rcu_barrier_bh,
-       .fqs            = rcu_bh_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .name           = "rcu_bh"
-};
-
-/*
- * Definitions for srcu torture testing.
- */
-
-DEFINE_STATIC_SRCU(srcu_ctl);
-
-static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
-{
-       return srcu_read_lock(&srcu_ctl);
-}
-
-static void srcu_read_delay(struct rcu_random_state *rrsp)
-{
-       long delay;
-       const long uspertick = 1000000 / HZ;
-       const long longdelay = 10;
-
-       /* We want there to be long-running readers, but not all the time. */
-
-       delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
-       if (!delay)
-               schedule_timeout_interruptible(longdelay);
-       else
-               rcu_read_delay(rrsp);
-}
-
-static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
-{
-       srcu_read_unlock(&srcu_ctl, idx);
-}
-
-static int srcu_torture_completed(void)
-{
-       return srcu_batches_completed(&srcu_ctl);
-}
-
-static void srcu_torture_deferred_free(struct rcu_torture *rp)
-{
-       call_srcu(&srcu_ctl, &rp->rtort_rcu, rcu_torture_cb);
-}
-
-static void srcu_torture_synchronize(void)
-{
-       synchronize_srcu(&srcu_ctl);
-}
-
-static void srcu_torture_call(struct rcu_head *head,
-                             void (*func)(struct rcu_head *head))
-{
-       call_srcu(&srcu_ctl, head, func);
-}
-
-static void srcu_torture_barrier(void)
-{
-       srcu_barrier(&srcu_ctl);
-}
-
-static void srcu_torture_stats(char *page)
-{
-       int cpu;
-       int idx = srcu_ctl.completed & 0x1;
-
-       page += sprintf(page, "%s%s per-CPU(idx=%d):",
-                      torture_type, TORTURE_FLAG, idx);
-       for_each_possible_cpu(cpu) {
-               page += sprintf(page, " %d(%lu,%lu)", cpu,
-                              per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
-                              per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
-       }
-       sprintf(page, "\n");
-}
-
-static void srcu_torture_synchronize_expedited(void)
-{
-       synchronize_srcu_expedited(&srcu_ctl);
-}
-
-static struct rcu_torture_ops srcu_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = srcu_torture_read_lock,
-       .read_delay     = srcu_read_delay,
-       .readunlock     = srcu_torture_read_unlock,
-       .completed      = srcu_torture_completed,
-       .deferred_free  = srcu_torture_deferred_free,
-       .sync           = srcu_torture_synchronize,
-       .exp_sync       = srcu_torture_synchronize_expedited,
-       .call           = srcu_torture_call,
-       .cb_barrier     = srcu_torture_barrier,
-       .stats          = srcu_torture_stats,
-       .name           = "srcu"
-};
-
-/*
- * Definitions for sched torture testing.
- */
-
-static int sched_torture_read_lock(void)
-{
-       preempt_disable();
-       return 0;
-}
-
-static void sched_torture_read_unlock(int idx)
-{
-       preempt_enable();
-}
-
-static void rcu_sched_torture_deferred_free(struct rcu_torture *p)
-{
-       call_rcu_sched(&p->rtort_rcu, rcu_torture_cb);
-}
-
-static struct rcu_torture_ops sched_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = sched_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = sched_torture_read_unlock,
-       .completed      = rcu_no_completed,
-       .deferred_free  = rcu_sched_torture_deferred_free,
-       .sync           = synchronize_sched,
-       .exp_sync       = synchronize_sched_expedited,
-       .call           = call_rcu_sched,
-       .cb_barrier     = rcu_barrier_sched,
-       .fqs            = rcu_sched_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .name           = "sched"
-};
-
-/*
- * RCU torture priority-boost testing.  Runs one real-time thread per
- * CPU for moderate bursts, repeatedly registering RCU callbacks and
- * spinning waiting for them to be invoked.  If a given callback takes
- * too long to be invoked, we assume that priority inversion has occurred.
- */
-
-struct rcu_boost_inflight {
-       struct rcu_head rcu;
-       int inflight;
-};
-
-static void rcu_torture_boost_cb(struct rcu_head *head)
-{
-       struct rcu_boost_inflight *rbip =
-               container_of(head, struct rcu_boost_inflight, rcu);
-
-       smp_mb(); /* Ensure RCU-core accesses precede clearing ->inflight */
-       rbip->inflight = 0;
-}
-
-static int rcu_torture_boost(void *arg)
-{
-       unsigned long call_rcu_time;
-       unsigned long endtime;
-       unsigned long oldstarttime;
-       struct rcu_boost_inflight rbi = { .inflight = 0 };
-       struct sched_param sp;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_boost started");
-
-       /* Set real-time priority. */
-       sp.sched_priority = 1;
-       if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) {
-               VERBOSE_PRINTK_STRING("rcu_torture_boost RT prio failed!");
-               n_rcu_torture_boost_rterror++;
-       }
-
-       init_rcu_head_on_stack(&rbi.rcu);
-       /* Each pass through the following loop does one boost-test cycle. */
-       do {
-               /* Wait for the next test interval. */
-               oldstarttime = boost_starttime;
-               while (ULONG_CMP_LT(jiffies, oldstarttime)) {
-                       schedule_timeout_interruptible(oldstarttime - jiffies);
-                       rcu_stutter_wait("rcu_torture_boost");
-                       if (kthread_should_stop() ||
-                           fullstop != FULLSTOP_DONTSTOP)
-                               goto checkwait;
-               }
-
-               /* Do one boost-test interval. */
-               endtime = oldstarttime + test_boost_duration * HZ;
-               call_rcu_time = jiffies;
-               while (ULONG_CMP_LT(jiffies, endtime)) {
-                       /* If we don't have a callback in flight, post one. */
-                       if (!rbi.inflight) {
-                               smp_mb(); /* RCU core before ->inflight = 1. */
-                               rbi.inflight = 1;
-                               call_rcu(&rbi.rcu, rcu_torture_boost_cb);
-                               if (jiffies - call_rcu_time >
-                                        test_boost_duration * HZ - HZ / 2) {
-                                       VERBOSE_PRINTK_STRING("rcu_torture_boost boosting failed");
-                                       n_rcu_torture_boost_failure++;
-                               }
-                               call_rcu_time = jiffies;
-                       }
-                       cond_resched();
-                       rcu_stutter_wait("rcu_torture_boost");
-                       if (kthread_should_stop() ||
-                           fullstop != FULLSTOP_DONTSTOP)
-                               goto checkwait;
-               }
-
-               /*
-                * Set the start time of the next test interval.
-                * Yes, this is vulnerable to long delays, but such
-                * delays simply cause a false negative for the next
-                * interval.  Besides, we are running at RT priority,
-                * so delays should be relatively rare.
-                */
-               while (oldstarttime == boost_starttime &&
-                      !kthread_should_stop()) {
-                       if (mutex_trylock(&boost_mutex)) {
-                               boost_starttime = jiffies +
-                                                 test_boost_interval * HZ;
-                               n_rcu_torture_boosts++;
-                               mutex_unlock(&boost_mutex);
-                               break;
-                       }
-                       schedule_timeout_uninterruptible(1);
-               }
-
-               /* Go do the stutter. */
-checkwait:     rcu_stutter_wait("rcu_torture_boost");
-       } while (!kthread_should_stop() && fullstop  == FULLSTOP_DONTSTOP);
-
-       /* Clean up and exit. */
-       VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_boost");
-       while (!kthread_should_stop() || rbi.inflight)
-               schedule_timeout_uninterruptible(1);
-       smp_mb(); /* order accesses to ->inflight before stack-frame death. */
-       destroy_rcu_head_on_stack(&rbi.rcu);
-       return 0;
-}
-
-/*
- * RCU torture force-quiescent-state kthread.  Repeatedly induces
- * bursts of calls to force_quiescent_state(), increasing the probability
- * of occurrence of some important types of race conditions.
- */
-static int
-rcu_torture_fqs(void *arg)
-{
-       unsigned long fqs_resume_time;
-       int fqs_burst_remaining;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_fqs task started");
-       do {
-               fqs_resume_time = jiffies + fqs_stutter * HZ;
-               while (ULONG_CMP_LT(jiffies, fqs_resume_time) &&
-                      !kthread_should_stop()) {
-                       schedule_timeout_interruptible(1);
-               }
-               fqs_burst_remaining = fqs_duration;
-               while (fqs_burst_remaining > 0 &&
-                      !kthread_should_stop()) {
-                       cur_ops->fqs();
-                       udelay(fqs_holdoff);
-                       fqs_burst_remaining -= fqs_holdoff;
-               }
-               rcu_stutter_wait("rcu_torture_fqs");
-       } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
-       VERBOSE_PRINTK_STRING("rcu_torture_fqs task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_fqs");
-       while (!kthread_should_stop())
-               schedule_timeout_uninterruptible(1);
-       return 0;
-}
-
-/*
- * RCU torture writer kthread.  Repeatedly substitutes a new structure
- * for that pointed to by rcu_torture_current, freeing the old structure
- * after a series of grace periods (the "pipeline").
- */
-static int
-rcu_torture_writer(void *arg)
-{
-       bool exp;
-       int i;
-       struct rcu_torture *rp;
-       struct rcu_torture *rp1;
-       struct rcu_torture *old_rp;
-       static DEFINE_RCU_RANDOM(rand);
-
-       VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
-       set_user_nice(current, 19);
-
-       do {
-               schedule_timeout_uninterruptible(1);
-               rp = rcu_torture_alloc();
-               if (rp == NULL)
-                       continue;
-               rp->rtort_pipe_count = 0;
-               udelay(rcu_random(&rand) & 0x3ff);
-               old_rp = rcu_dereference_check(rcu_torture_current,
-                                              current == writer_task);
-               rp->rtort_mbtest = 1;
-               rcu_assign_pointer(rcu_torture_current, rp);
-               smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */
-               if (old_rp) {
-                       i = old_rp->rtort_pipe_count;
-                       if (i > RCU_TORTURE_PIPE_LEN)
-                               i = RCU_TORTURE_PIPE_LEN;
-                       atomic_inc(&rcu_torture_wcount[i]);
-                       old_rp->rtort_pipe_count++;
-                       if (gp_normal == gp_exp)
-                               exp = !!(rcu_random(&rand) & 0x80);
-                       else
-                               exp = gp_exp;
-                       if (!exp) {
-                               cur_ops->deferred_free(old_rp);
-                       } else {
-                               cur_ops->exp_sync();
-                               list_add(&old_rp->rtort_free,
-                                        &rcu_torture_removed);
-                               list_for_each_entry_safe(rp, rp1,
-                                                        &rcu_torture_removed,
-                                                        rtort_free) {
-                                       i = rp->rtort_pipe_count;
-                                       if (i > RCU_TORTURE_PIPE_LEN)
-                                               i = RCU_TORTURE_PIPE_LEN;
-                                       atomic_inc(&rcu_torture_wcount[i]);
-                                       if (++rp->rtort_pipe_count >=
-                                           RCU_TORTURE_PIPE_LEN) {
-                                               rp->rtort_mbtest = 0;
-                                               list_del(&rp->rtort_free);
-                                               rcu_torture_free(rp);
-                                       }
-                                }
-                       }
-               }
-               rcutorture_record_progress(++rcu_torture_current_version);
-               rcu_stutter_wait("rcu_torture_writer");
-       } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
-       VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_writer");
-       while (!kthread_should_stop())
-               schedule_timeout_uninterruptible(1);
-       return 0;
-}
-
-/*
- * RCU torture fake writer kthread.  Repeatedly calls sync, with a random
- * delay between calls.
- */
-static int
-rcu_torture_fakewriter(void *arg)
-{
-       DEFINE_RCU_RANDOM(rand);
-
-       VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
-       set_user_nice(current, 19);
-
-       do {
-               schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
-               udelay(rcu_random(&rand) & 0x3ff);
-               if (cur_ops->cb_barrier != NULL &&
-                   rcu_random(&rand) % (nfakewriters * 8) == 0) {
-                       cur_ops->cb_barrier();
-               } else if (gp_normal == gp_exp) {
-                       if (rcu_random(&rand) & 0x80)
-                               cur_ops->sync();
-                       else
-                               cur_ops->exp_sync();
-               } else if (gp_normal) {
-                       cur_ops->sync();
-               } else {
-                       cur_ops->exp_sync();
-               }
-               rcu_stutter_wait("rcu_torture_fakewriter");
-       } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
-
-       VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_fakewriter");
-       while (!kthread_should_stop())
-               schedule_timeout_uninterruptible(1);
-       return 0;
-}
-
-void rcutorture_trace_dump(void)
-{
-       static atomic_t beenhere = ATOMIC_INIT(0);
-
-       if (atomic_read(&beenhere))
-               return;
-       if (atomic_xchg(&beenhere, 1) != 0)
-               return;
-       ftrace_dump(DUMP_ALL);
-}
-
-/*
- * RCU torture reader from timer handler.  Dereferences rcu_torture_current,
- * incrementing the corresponding element of the pipeline array.  The
- * counter in the element should never be greater than 1, otherwise, the
- * RCU implementation is broken.
- */
-static void rcu_torture_timer(unsigned long unused)
-{
-       int idx;
-       int completed;
-       int completed_end;
-       static DEFINE_RCU_RANDOM(rand);
-       static DEFINE_SPINLOCK(rand_lock);
-       struct rcu_torture *p;
-       int pipe_count;
-       unsigned long long ts;
-
-       idx = cur_ops->readlock();
-       completed = cur_ops->completed();
-       ts = rcu_trace_clock_local();
-       p = rcu_dereference_check(rcu_torture_current,
-                                 rcu_read_lock_bh_held() ||
-                                 rcu_read_lock_sched_held() ||
-                                 srcu_read_lock_held(&srcu_ctl));
-       if (p == NULL) {
-               /* Leave because rcu_torture_writer is not yet underway */
-               cur_ops->readunlock(idx);
-               return;
-       }
-       if (p->rtort_mbtest == 0)
-               atomic_inc(&n_rcu_torture_mberror);
-       spin_lock(&rand_lock);
-       cur_ops->read_delay(&rand);
-       n_rcu_torture_timers++;
-       spin_unlock(&rand_lock);
-       preempt_disable();
-       pipe_count = p->rtort_pipe_count;
-       if (pipe_count > RCU_TORTURE_PIPE_LEN) {
-               /* Should not happen, but... */
-               pipe_count = RCU_TORTURE_PIPE_LEN;
-       }
-       completed_end = cur_ops->completed();
-       if (pipe_count > 1) {
-               do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts,
-                                         completed, completed_end);
-               rcutorture_trace_dump();
-       }
-       __this_cpu_inc(rcu_torture_count[pipe_count]);
-       completed = completed_end - completed;
-       if (completed > RCU_TORTURE_PIPE_LEN) {
-               /* Should not happen, but... */
-               completed = RCU_TORTURE_PIPE_LEN;
-       }
-       __this_cpu_inc(rcu_torture_batch[completed]);
-       preempt_enable();
-       cur_ops->readunlock(idx);
-}
-
-/*
- * RCU torture reader kthread.  Repeatedly dereferences rcu_torture_current,
- * incrementing the corresponding element of the pipeline array.  The
- * counter in the element should never be greater than 1, otherwise, the
- * RCU implementation is broken.
- */
-static int
-rcu_torture_reader(void *arg)
-{
-       int completed;
-       int completed_end;
-       int idx;
-       DEFINE_RCU_RANDOM(rand);
-       struct rcu_torture *p;
-       int pipe_count;
-       struct timer_list t;
-       unsigned long long ts;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
-       set_user_nice(current, 19);
-       if (irqreader && cur_ops->irq_capable)
-               setup_timer_on_stack(&t, rcu_torture_timer, 0);
-
-       do {
-               if (irqreader && cur_ops->irq_capable) {
-                       if (!timer_pending(&t))
-                               mod_timer(&t, jiffies + 1);
-               }
-               idx = cur_ops->readlock();
-               completed = cur_ops->completed();
-               ts = rcu_trace_clock_local();
-               p = rcu_dereference_check(rcu_torture_current,
-                                         rcu_read_lock_bh_held() ||
-                                         rcu_read_lock_sched_held() ||
-                                         srcu_read_lock_held(&srcu_ctl));
-               if (p == NULL) {
-                       /* Wait for rcu_torture_writer to get underway */
-                       cur_ops->readunlock(idx);
-                       schedule_timeout_interruptible(HZ);
-                       continue;
-               }
-               if (p->rtort_mbtest == 0)
-                       atomic_inc(&n_rcu_torture_mberror);
-               cur_ops->read_delay(&rand);
-               preempt_disable();
-               pipe_count = p->rtort_pipe_count;
-               if (pipe_count > RCU_TORTURE_PIPE_LEN) {
-                       /* Should not happen, but... */
-                       pipe_count = RCU_TORTURE_PIPE_LEN;
-               }
-               completed_end = cur_ops->completed();
-               if (pipe_count > 1) {
-                       do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu,
-                                                 ts, completed, completed_end);
-                       rcutorture_trace_dump();
-               }
-               __this_cpu_inc(rcu_torture_count[pipe_count]);
-               completed = completed_end - completed;
-               if (completed > RCU_TORTURE_PIPE_LEN) {
-                       /* Should not happen, but... */
-                       completed = RCU_TORTURE_PIPE_LEN;
-               }
-               __this_cpu_inc(rcu_torture_batch[completed]);
-               preempt_enable();
-               cur_ops->readunlock(idx);
-               schedule();
-               rcu_stutter_wait("rcu_torture_reader");
-       } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
-       VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_reader");
-       if (irqreader && cur_ops->irq_capable)
-               del_timer_sync(&t);
-       while (!kthread_should_stop())
-               schedule_timeout_uninterruptible(1);
-       return 0;
-}
-
-/*
- * Create an RCU-torture statistics message in the specified buffer.
- */
-static void
-rcu_torture_printk(char *page)
-{
-       int cpu;
-       int i;
-       long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
-       long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
-
-       for_each_possible_cpu(cpu) {
-               for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
-                       pipesummary[i] += per_cpu(rcu_torture_count, cpu)[i];
-                       batchsummary[i] += per_cpu(rcu_torture_batch, cpu)[i];
-               }
-       }
-       for (i = RCU_TORTURE_PIPE_LEN - 1; i >= 0; i--) {
-               if (pipesummary[i] != 0)
-                       break;
-       }
-       page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
-       page += sprintf(page,
-                      "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d ",
-                      rcu_torture_current,
-                      rcu_torture_current_version,
-                      list_empty(&rcu_torture_freelist),
-                      atomic_read(&n_rcu_torture_alloc),
-                      atomic_read(&n_rcu_torture_alloc_fail),
-                      atomic_read(&n_rcu_torture_free));
-       page += sprintf(page, "rtmbe: %d rtbke: %ld rtbre: %ld ",
-                      atomic_read(&n_rcu_torture_mberror),
-                      n_rcu_torture_boost_ktrerror,
-                      n_rcu_torture_boost_rterror);
-       page += sprintf(page, "rtbf: %ld rtb: %ld nt: %ld ",
-                      n_rcu_torture_boost_failure,
-                      n_rcu_torture_boosts,
-                      n_rcu_torture_timers);
-       page += sprintf(page,
-                      "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
-                      n_online_successes, n_online_attempts,
-                      n_offline_successes, n_offline_attempts,
-                      min_online, max_online,
-                      min_offline, max_offline,
-                      sum_online, sum_offline, HZ);
-       page += sprintf(page, "barrier: %ld/%ld:%ld",
-                      n_barrier_successes,
-                      n_barrier_attempts,
-                      n_rcu_torture_barrier_error);
-       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
-       if (atomic_read(&n_rcu_torture_mberror) != 0 ||
-           n_rcu_torture_barrier_error != 0 ||
-           n_rcu_torture_boost_ktrerror != 0 ||
-           n_rcu_torture_boost_rterror != 0 ||
-           n_rcu_torture_boost_failure != 0 ||
-           i > 1) {
-               page += sprintf(page, "!!! ");
-               atomic_inc(&n_rcu_torture_error);
-               WARN_ON_ONCE(1);
-       }
-       page += sprintf(page, "Reader Pipe: ");
-       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
-               page += sprintf(page, " %ld", pipesummary[i]);
-       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
-       page += sprintf(page, "Reader Batch: ");
-       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
-               page += sprintf(page, " %ld", batchsummary[i]);
-       page += sprintf(page, "\n%s%s ", torture_type, TORTURE_FLAG);
-       page += sprintf(page, "Free-Block Circulation: ");
-       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
-               page += sprintf(page, " %d",
-                              atomic_read(&rcu_torture_wcount[i]));
-       }
-       page += sprintf(page, "\n");
-       if (cur_ops->stats)
-               cur_ops->stats(page);
-}
-
-/*
- * Print torture statistics.  Caller must ensure that there is only
- * one call to this function at a given time!!!  This is normally
- * accomplished by relying on the module system to only have one copy
- * of the module loaded, and then by giving the rcu_torture_stats
- * kthread full control (or the init/cleanup functions when rcu_torture_stats
- * thread is not running).
- */
-static void
-rcu_torture_stats_print(void)
-{
-       int size = nr_cpu_ids * 200 + 8192;
-       char *buf;
-
-       buf = kmalloc(size, GFP_KERNEL);
-       if (!buf) {
-               pr_err("rcu-torture: Out of memory, need: %d", size);
-               return;
-       }
-       rcu_torture_printk(buf);
-       pr_alert("%s", buf);
-       kfree(buf);
-}
-
-/*
- * Periodically prints torture statistics, if periodic statistics printing
- * was specified via the stat_interval module parameter.
- *
- * No need to worry about fullstop here, since this one doesn't reference
- * volatile state or register callbacks.
- */
-static int
-rcu_torture_stats(void *arg)
-{
-       VERBOSE_PRINTK_STRING("rcu_torture_stats task started");
-       do {
-               schedule_timeout_interruptible(stat_interval * HZ);
-               rcu_torture_stats_print();
-               rcutorture_shutdown_absorb("rcu_torture_stats");
-       } while (!kthread_should_stop());
-       VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
-       return 0;
-}
-
-static int rcu_idle_cpu;       /* Force all torture tasks off this CPU */
-
-/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
- * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
- */
-static void rcu_torture_shuffle_tasks(void)
-{
-       int i;
-
-       cpumask_setall(shuffle_tmp_mask);
-       get_online_cpus();
-
-       /* No point in shuffling if there is only one online CPU (ex: UP) */
-       if (num_online_cpus() == 1) {
-               put_online_cpus();
-               return;
-       }
-
-       if (rcu_idle_cpu != -1)
-               cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
-
-       set_cpus_allowed_ptr(current, shuffle_tmp_mask);
-
-       if (reader_tasks) {
-               for (i = 0; i < nrealreaders; i++)
-                       if (reader_tasks[i])
-                               set_cpus_allowed_ptr(reader_tasks[i],
-                                                    shuffle_tmp_mask);
-       }
-       if (fakewriter_tasks) {
-               for (i = 0; i < nfakewriters; i++)
-                       if (fakewriter_tasks[i])
-                               set_cpus_allowed_ptr(fakewriter_tasks[i],
-                                                    shuffle_tmp_mask);
-       }
-       if (writer_task)
-               set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
-       if (stats_task)
-               set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
-       if (stutter_task)
-               set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask);
-       if (fqs_task)
-               set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask);
-       if (shutdown_task)
-               set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask);
-#ifdef CONFIG_HOTPLUG_CPU
-       if (onoff_task)
-               set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask);
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-       if (stall_task)
-               set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask);
-       if (barrier_cbs_tasks)
-               for (i = 0; i < n_barrier_cbs; i++)
-                       if (barrier_cbs_tasks[i])
-                               set_cpus_allowed_ptr(barrier_cbs_tasks[i],
-                                                    shuffle_tmp_mask);
-       if (barrier_task)
-               set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask);
-
-       if (rcu_idle_cpu == -1)
-               rcu_idle_cpu = num_online_cpus() - 1;
-       else
-               rcu_idle_cpu--;
-
-       put_online_cpus();
-}
-
-/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
- * system to become idle at a time and cut off its timer ticks. This is meant
- * to test the support for such tickless idle CPU in RCU.
- */
-static int
-rcu_torture_shuffle(void *arg)
-{
-       VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
-       do {
-               schedule_timeout_interruptible(shuffle_interval * HZ);
-               rcu_torture_shuffle_tasks();
-               rcutorture_shutdown_absorb("rcu_torture_shuffle");
-       } while (!kthread_should_stop());
-       VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
-       return 0;
-}
-
-/* Cause the rcutorture test to "stutter", starting and stopping all
- * threads periodically.
- */
-static int
-rcu_torture_stutter(void *arg)
-{
-       VERBOSE_PRINTK_STRING("rcu_torture_stutter task started");
-       do {
-               schedule_timeout_interruptible(stutter * HZ);
-               stutter_pause_test = 1;
-               if (!kthread_should_stop())
-                       schedule_timeout_interruptible(stutter * HZ);
-               stutter_pause_test = 0;
-               rcutorture_shutdown_absorb("rcu_torture_stutter");
-       } while (!kthread_should_stop());
-       VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
-       return 0;
-}
-
-static inline void
-rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
-{
-       pr_alert("%s" TORTURE_FLAG
-                "--- %s: nreaders=%d nfakewriters=%d "
-                "stat_interval=%d verbose=%d test_no_idle_hz=%d "
-                "shuffle_interval=%d stutter=%d irqreader=%d "
-                "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
-                "test_boost=%d/%d test_boost_interval=%d "
-                "test_boost_duration=%d shutdown_secs=%d "
-                "stall_cpu=%d stall_cpu_holdoff=%d "
-                "n_barrier_cbs=%d "
-                "onoff_interval=%d onoff_holdoff=%d\n",
-                torture_type, tag, nrealreaders, nfakewriters,
-                stat_interval, verbose, test_no_idle_hz, shuffle_interval,
-                stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
-                test_boost, cur_ops->can_boost,
-                test_boost_interval, test_boost_duration, shutdown_secs,
-                stall_cpu, stall_cpu_holdoff,
-                n_barrier_cbs,
-                onoff_interval, onoff_holdoff);
-}
-
-static struct notifier_block rcutorture_shutdown_nb = {
-       .notifier_call = rcutorture_shutdown_notify,
-};
-
-static void rcutorture_booster_cleanup(int cpu)
-{
-       struct task_struct *t;
-
-       if (boost_tasks[cpu] == NULL)
-               return;
-       mutex_lock(&boost_mutex);
-       VERBOSE_PRINTK_STRING("Stopping rcu_torture_boost task");
-       t = boost_tasks[cpu];
-       boost_tasks[cpu] = NULL;
-       mutex_unlock(&boost_mutex);
-
-       /* This must be outside of the mutex, otherwise deadlock! */
-       kthread_stop(t);
-       boost_tasks[cpu] = NULL;
-}
-
-static int rcutorture_booster_init(int cpu)
-{
-       int retval;
-
-       if (boost_tasks[cpu] != NULL)
-               return 0;  /* Already created, nothing more to do. */
-
-       /* Don't allow time recalculation while creating a new task. */
-       mutex_lock(&boost_mutex);
-       VERBOSE_PRINTK_STRING("Creating rcu_torture_boost task");
-       boost_tasks[cpu] = kthread_create_on_node(rcu_torture_boost, NULL,
-                                                 cpu_to_node(cpu),
-                                                 "rcu_torture_boost");
-       if (IS_ERR(boost_tasks[cpu])) {
-               retval = PTR_ERR(boost_tasks[cpu]);
-               VERBOSE_PRINTK_STRING("rcu_torture_boost task create failed");
-               n_rcu_torture_boost_ktrerror++;
-               boost_tasks[cpu] = NULL;
-               mutex_unlock(&boost_mutex);
-               return retval;
-       }
-       kthread_bind(boost_tasks[cpu], cpu);
-       wake_up_process(boost_tasks[cpu]);
-       mutex_unlock(&boost_mutex);
-       return 0;
-}
-
-/*
- * Cause the rcutorture test to shutdown the system after the test has
- * run for the time specified by the shutdown_secs module parameter.
- */
-static int
-rcu_torture_shutdown(void *arg)
-{
-       long delta;
-       unsigned long jiffies_snap;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_shutdown task started");
-       jiffies_snap = ACCESS_ONCE(jiffies);
-       while (ULONG_CMP_LT(jiffies_snap, shutdown_time) &&
-              !kthread_should_stop()) {
-               delta = shutdown_time - jiffies_snap;
-               if (verbose)
-                       pr_alert("%s" TORTURE_FLAG
-                                "rcu_torture_shutdown task: %lu jiffies remaining\n",
-                                torture_type, delta);
-               schedule_timeout_interruptible(delta);
-               jiffies_snap = ACCESS_ONCE(jiffies);
-       }
-       if (kthread_should_stop()) {
-               VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping");
-               return 0;
-       }
-
-       /* OK, shut down the system. */
-
-       VERBOSE_PRINTK_STRING("rcu_torture_shutdown task shutting down system");
-       shutdown_task = NULL;   /* Avoid self-kill deadlock. */
-       rcu_torture_cleanup();  /* Get the success/failure message. */
-       kernel_power_off();     /* Shut down the system. */
-       return 0;
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-/*
- * Execute random CPU-hotplug operations at the interval specified
- * by the onoff_interval.
- */
-static int
-rcu_torture_onoff(void *arg)
-{
-       int cpu;
-       unsigned long delta;
-       int maxcpu = -1;
-       DEFINE_RCU_RANDOM(rand);
-       int ret;
-       unsigned long starttime;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_onoff task started");
-       for_each_online_cpu(cpu)
-               maxcpu = cpu;
-       WARN_ON(maxcpu < 0);
-       if (onoff_holdoff > 0) {
-               VERBOSE_PRINTK_STRING("rcu_torture_onoff begin holdoff");
-               schedule_timeout_interruptible(onoff_holdoff * HZ);
-               VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff");
-       }
-       while (!kthread_should_stop()) {
-               cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1);
-               if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
-                       if (verbose)
-                               pr_alert("%s" TORTURE_FLAG
-                                        "rcu_torture_onoff task: offlining %d\n",
-                                        torture_type, cpu);
-                       starttime = jiffies;
-                       n_offline_attempts++;
-                       ret = cpu_down(cpu);
-                       if (ret) {
-                               if (verbose)
-                                       pr_alert("%s" TORTURE_FLAG
-                                                "rcu_torture_onoff task: offline %d failed: errno %d\n",
-                                                torture_type, cpu, ret);
-                       } else {
-                               if (verbose)
-                                       pr_alert("%s" TORTURE_FLAG
-                                                "rcu_torture_onoff task: offlined %d\n",
-                                                torture_type, cpu);
-                               n_offline_successes++;
-                               delta = jiffies - starttime;
-                               sum_offline += delta;
-                               if (min_offline < 0) {
-                                       min_offline = delta;
-                                       max_offline = delta;
-                               }
-                               if (min_offline > delta)
-                                       min_offline = delta;
-                               if (max_offline < delta)
-                                       max_offline = delta;
-                       }
-               } else if (cpu_is_hotpluggable(cpu)) {
-                       if (verbose)
-                               pr_alert("%s" TORTURE_FLAG
-                                        "rcu_torture_onoff task: onlining %d\n",
-                                        torture_type, cpu);
-                       starttime = jiffies;
-                       n_online_attempts++;
-                       ret = cpu_up(cpu);
-                       if (ret) {
-                               if (verbose)
-                                       pr_alert("%s" TORTURE_FLAG
-                                                "rcu_torture_onoff task: online %d failed: errno %d\n",
-                                                torture_type, cpu, ret);
-                       } else {
-                               if (verbose)
-                                       pr_alert("%s" TORTURE_FLAG
-                                                "rcu_torture_onoff task: onlined %d\n",
-                                                torture_type, cpu);
-                               n_online_successes++;
-                               delta = jiffies - starttime;
-                               sum_online += delta;
-                               if (min_online < 0) {
-                                       min_online = delta;
-                                       max_online = delta;
-                               }
-                               if (min_online > delta)
-                                       min_online = delta;
-                               if (max_online < delta)
-                                       max_online = delta;
-                       }
-               }
-               schedule_timeout_interruptible(onoff_interval * HZ);
-       }
-       VERBOSE_PRINTK_STRING("rcu_torture_onoff task stopping");
-       return 0;
-}
-
-static int
-rcu_torture_onoff_init(void)
-{
-       int ret;
-
-       if (onoff_interval <= 0)
-               return 0;
-       onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff");
-       if (IS_ERR(onoff_task)) {
-               ret = PTR_ERR(onoff_task);
-               onoff_task = NULL;
-               return ret;
-       }
-       return 0;
-}
-
-static void rcu_torture_onoff_cleanup(void)
-{
-       if (onoff_task == NULL)
-               return;
-       VERBOSE_PRINTK_STRING("Stopping rcu_torture_onoff task");
-       kthread_stop(onoff_task);
-       onoff_task = NULL;
-}
-
-#else /* #ifdef CONFIG_HOTPLUG_CPU */
-
-static int
-rcu_torture_onoff_init(void)
-{
-       return 0;
-}
-
-static void rcu_torture_onoff_cleanup(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
-
-/*
- * CPU-stall kthread.  It waits as specified by stall_cpu_holdoff, then
- * induces a CPU stall for the time specified by stall_cpu.
- */
-static int rcu_torture_stall(void *args)
-{
-       unsigned long stop_at;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_stall task started");
-       if (stall_cpu_holdoff > 0) {
-               VERBOSE_PRINTK_STRING("rcu_torture_stall begin holdoff");
-               schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
-               VERBOSE_PRINTK_STRING("rcu_torture_stall end holdoff");
-       }
-       if (!kthread_should_stop()) {
-               stop_at = get_seconds() + stall_cpu;
-               /* RCU CPU stall is expected behavior in following code. */
-               pr_alert("rcu_torture_stall start.\n");
-               rcu_read_lock();
-               preempt_disable();
-               while (ULONG_CMP_LT(get_seconds(), stop_at))
-                       continue;  /* Induce RCU CPU stall warning. */
-               preempt_enable();
-               rcu_read_unlock();
-               pr_alert("rcu_torture_stall end.\n");
-       }
-       rcutorture_shutdown_absorb("rcu_torture_stall");
-       while (!kthread_should_stop())
-               schedule_timeout_interruptible(10 * HZ);
-       return 0;
-}
-
-/* Spawn CPU-stall kthread, if stall_cpu specified. */
-static int __init rcu_torture_stall_init(void)
-{
-       int ret;
-
-       if (stall_cpu <= 0)
-               return 0;
-       stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall");
-       if (IS_ERR(stall_task)) {
-               ret = PTR_ERR(stall_task);
-               stall_task = NULL;
-               return ret;
-       }
-       return 0;
-}
-
-/* Clean up after the CPU-stall kthread, if one was spawned. */
-static void rcu_torture_stall_cleanup(void)
-{
-       if (stall_task == NULL)
-               return;
-       VERBOSE_PRINTK_STRING("Stopping rcu_torture_stall_task.");
-       kthread_stop(stall_task);
-       stall_task = NULL;
-}
-
-/* Callback function for RCU barrier testing. */
-void rcu_torture_barrier_cbf(struct rcu_head *rcu)
-{
-       atomic_inc(&barrier_cbs_invoked);
-}
-
-/* kthread function to register callbacks used to test RCU barriers. */
-static int rcu_torture_barrier_cbs(void *arg)
-{
-       long myid = (long)arg;
-       bool lastphase = 0;
-       bool newphase;
-       struct rcu_head rcu;
-
-       init_rcu_head_on_stack(&rcu);
-       VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task started");
-       set_user_nice(current, 19);
-       do {
-               wait_event(barrier_cbs_wq[myid],
-                          (newphase =
-                           ACCESS_ONCE(barrier_phase)) != lastphase ||
-                          kthread_should_stop() ||
-                          fullstop != FULLSTOP_DONTSTOP);
-               lastphase = newphase;
-               smp_mb(); /* ensure barrier_phase load before ->call(). */
-               if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
-                       break;
-               cur_ops->call(&rcu, rcu_torture_barrier_cbf);
-               if (atomic_dec_and_test(&barrier_cbs_count))
-                       wake_up(&barrier_wq);
-       } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
-       VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_barrier_cbs");
-       while (!kthread_should_stop())
-               schedule_timeout_interruptible(1);
-       cur_ops->cb_barrier();
-       destroy_rcu_head_on_stack(&rcu);
-       return 0;
-}
-
-/* kthread function to drive and coordinate RCU barrier testing. */
-static int rcu_torture_barrier(void *arg)
-{
-       int i;
-
-       VERBOSE_PRINTK_STRING("rcu_torture_barrier task starting");
-       do {
-               atomic_set(&barrier_cbs_invoked, 0);
-               atomic_set(&barrier_cbs_count, n_barrier_cbs);
-               smp_mb(); /* Ensure barrier_phase after prior assignments. */
-               barrier_phase = !barrier_phase;
-               for (i = 0; i < n_barrier_cbs; i++)
-                       wake_up(&barrier_cbs_wq[i]);
-               wait_event(barrier_wq,
-                          atomic_read(&barrier_cbs_count) == 0 ||
-                          kthread_should_stop() ||
-                          fullstop != FULLSTOP_DONTSTOP);
-               if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
-                       break;
-               n_barrier_attempts++;
-               cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */
-               if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) {
-                       n_rcu_torture_barrier_error++;
-                       WARN_ON_ONCE(1);
-               }
-               n_barrier_successes++;
-               schedule_timeout_interruptible(HZ / 10);
-       } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
-       VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping");
-       rcutorture_shutdown_absorb("rcu_torture_barrier");
-       while (!kthread_should_stop())
-               schedule_timeout_interruptible(1);
-       return 0;
-}
-
-/* Initialize RCU barrier testing. */
-static int rcu_torture_barrier_init(void)
-{
-       int i;
-       int ret;
-
-       if (n_barrier_cbs == 0)
-               return 0;
-       if (cur_ops->call == NULL || cur_ops->cb_barrier == NULL) {
-               pr_alert("%s" TORTURE_FLAG
-                        " Call or barrier ops missing for %s,\n",
-                        torture_type, cur_ops->name);
-               pr_alert("%s" TORTURE_FLAG
-                        " RCU barrier testing omitted from run.\n",
-                        torture_type);
-               return 0;
-       }
-       atomic_set(&barrier_cbs_count, 0);
-       atomic_set(&barrier_cbs_invoked, 0);
-       barrier_cbs_tasks =
-               kzalloc(n_barrier_cbs * sizeof(barrier_cbs_tasks[0]),
-                       GFP_KERNEL);
-       barrier_cbs_wq =
-               kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]),
-                       GFP_KERNEL);
-       if (barrier_cbs_tasks == NULL || !barrier_cbs_wq)
-               return -ENOMEM;
-       for (i = 0; i < n_barrier_cbs; i++) {
-               init_waitqueue_head(&barrier_cbs_wq[i]);
-               barrier_cbs_tasks[i] = kthread_run(rcu_torture_barrier_cbs,
-                                                  (void *)(long)i,
-                                                  "rcu_torture_barrier_cbs");
-               if (IS_ERR(barrier_cbs_tasks[i])) {
-                       ret = PTR_ERR(barrier_cbs_tasks[i]);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier_cbs");
-                       barrier_cbs_tasks[i] = NULL;
-                       return ret;
-               }
-       }
-       barrier_task = kthread_run(rcu_torture_barrier, NULL,
-                                  "rcu_torture_barrier");
-       if (IS_ERR(barrier_task)) {
-               ret = PTR_ERR(barrier_task);
-               VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier");
-               barrier_task = NULL;
-       }
-       return 0;
-}
-
-/* Clean up after RCU barrier testing. */
-static void rcu_torture_barrier_cleanup(void)
-{
-       int i;
-
-       if (barrier_task != NULL) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier task");
-               kthread_stop(barrier_task);
-               barrier_task = NULL;
-       }
-       if (barrier_cbs_tasks != NULL) {
-               for (i = 0; i < n_barrier_cbs; i++) {
-                       if (barrier_cbs_tasks[i] != NULL) {
-                               VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier_cbs task");
-                               kthread_stop(barrier_cbs_tasks[i]);
-                               barrier_cbs_tasks[i] = NULL;
-                       }
-               }
-               kfree(barrier_cbs_tasks);
-               barrier_cbs_tasks = NULL;
-       }
-       if (barrier_cbs_wq != NULL) {
-               kfree(barrier_cbs_wq);
-               barrier_cbs_wq = NULL;
-       }
-}
-
-static int rcutorture_cpu_notify(struct notifier_block *self,
-                                unsigned long action, void *hcpu)
-{
-       long cpu = (long)hcpu;
-
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_DOWN_FAILED:
-               (void)rcutorture_booster_init(cpu);
-               break;
-       case CPU_DOWN_PREPARE:
-               rcutorture_booster_cleanup(cpu);
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block rcutorture_cpu_nb = {
-       .notifier_call = rcutorture_cpu_notify,
-};
-
-static void
-rcu_torture_cleanup(void)
-{
-       int i;
-
-       mutex_lock(&fullstop_mutex);
-       rcutorture_record_test_transition();
-       if (fullstop == FULLSTOP_SHUTDOWN) {
-               pr_warn(/* but going down anyway, so... */
-                      "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
-               mutex_unlock(&fullstop_mutex);
-               schedule_timeout_uninterruptible(10);
-               if (cur_ops->cb_barrier != NULL)
-                       cur_ops->cb_barrier();
-               return;
-       }
-       fullstop = FULLSTOP_RMMOD;
-       mutex_unlock(&fullstop_mutex);
-       unregister_reboot_notifier(&rcutorture_shutdown_nb);
-       rcu_torture_barrier_cleanup();
-       rcu_torture_stall_cleanup();
-       if (stutter_task) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
-               kthread_stop(stutter_task);
-       }
-       stutter_task = NULL;
-       if (shuffler_task) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
-               kthread_stop(shuffler_task);
-               free_cpumask_var(shuffle_tmp_mask);
-       }
-       shuffler_task = NULL;
-
-       if (writer_task) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
-               kthread_stop(writer_task);
-       }
-       writer_task = NULL;
-
-       if (reader_tasks) {
-               for (i = 0; i < nrealreaders; i++) {
-                       if (reader_tasks[i]) {
-                               VERBOSE_PRINTK_STRING(
-                                       "Stopping rcu_torture_reader task");
-                               kthread_stop(reader_tasks[i]);
-                       }
-                       reader_tasks[i] = NULL;
-               }
-               kfree(reader_tasks);
-               reader_tasks = NULL;
-       }
-       rcu_torture_current = NULL;
-
-       if (fakewriter_tasks) {
-               for (i = 0; i < nfakewriters; i++) {
-                       if (fakewriter_tasks[i]) {
-                               VERBOSE_PRINTK_STRING(
-                                       "Stopping rcu_torture_fakewriter task");
-                               kthread_stop(fakewriter_tasks[i]);
-                       }
-                       fakewriter_tasks[i] = NULL;
-               }
-               kfree(fakewriter_tasks);
-               fakewriter_tasks = NULL;
-       }
-
-       if (stats_task) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
-               kthread_stop(stats_task);
-       }
-       stats_task = NULL;
-
-       if (fqs_task) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task");
-               kthread_stop(fqs_task);
-       }
-       fqs_task = NULL;
-       if ((test_boost == 1 && cur_ops->can_boost) ||
-           test_boost == 2) {
-               unregister_cpu_notifier(&rcutorture_cpu_nb);
-               for_each_possible_cpu(i)
-                       rcutorture_booster_cleanup(i);
-       }
-       if (shutdown_task != NULL) {
-               VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task");
-               kthread_stop(shutdown_task);
-       }
-       shutdown_task = NULL;
-       rcu_torture_onoff_cleanup();
-
-       /* Wait for all RCU callbacks to fire.  */
-
-       if (cur_ops->cb_barrier != NULL)
-               cur_ops->cb_barrier();
-
-       rcu_torture_stats_print();  /* -After- the stats thread is stopped! */
-
-       if (atomic_read(&n_rcu_torture_error) || n_rcu_torture_barrier_error)
-               rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
-       else if (n_online_successes != n_online_attempts ||
-                n_offline_successes != n_offline_attempts)
-               rcu_torture_print_module_parms(cur_ops,
-                                              "End of test: RCU_HOTPLUG");
-       else
-               rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
-}
-
-#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
-static void rcu_torture_leak_cb(struct rcu_head *rhp)
-{
-}
-
-static void rcu_torture_err_cb(struct rcu_head *rhp)
-{
-       /*
-        * This -might- happen due to race conditions, but is unlikely.
-        * The scenario that leads to this happening is that the
-        * first of the pair of duplicate callbacks is queued,
-        * someone else starts a grace period that includes that
-        * callback, then the second of the pair must wait for the
-        * next grace period.  Unlikely, but can happen.  If it
-        * does happen, the debug-objects subsystem won't have splatted.
-        */
-       pr_alert("rcutorture: duplicated callback was invoked.\n");
-}
-#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-
-/*
- * Verify that double-free causes debug-objects to complain, but only
- * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
- * cannot be carried out.
- */
-static void rcu_test_debug_objects(void)
-{
-#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
-       struct rcu_head rh1;
-       struct rcu_head rh2;
-
-       init_rcu_head_on_stack(&rh1);
-       init_rcu_head_on_stack(&rh2);
-       pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
-
-       /* Try to queue the rh2 pair of callbacks for the same grace period. */
-       preempt_disable(); /* Prevent preemption from interrupting test. */
-       rcu_read_lock(); /* Make it impossible to finish a grace period. */
-       call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
-       local_irq_disable(); /* Make it harder to start a new grace period. */
-       call_rcu(&rh2, rcu_torture_leak_cb);
-       call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
-       local_irq_enable();
-       rcu_read_unlock();
-       preempt_enable();
-
-       /* Wait for them all to get done so we can safely return. */
-       rcu_barrier();
-       pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
-       destroy_rcu_head_on_stack(&rh1);
-       destroy_rcu_head_on_stack(&rh2);
-#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-       pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
-#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-}
-
-static int __init
-rcu_torture_init(void)
-{
-       int i;
-       int cpu;
-       int firsterr = 0;
-       int retval;
-       static struct rcu_torture_ops *torture_ops[] = {
-               &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops,
-       };
-
-       mutex_lock(&fullstop_mutex);
-
-       /* Process args and tell the world that the torturer is on the job. */
-       for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
-               cur_ops = torture_ops[i];
-               if (strcmp(torture_type, cur_ops->name) == 0)
-                       break;
-       }
-       if (i == ARRAY_SIZE(torture_ops)) {
-               pr_alert("rcu-torture: invalid torture type: \"%s\"\n",
-                        torture_type);
-               pr_alert("rcu-torture types:");
-               for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
-                       pr_alert(" %s", torture_ops[i]->name);
-               pr_alert("\n");
-               mutex_unlock(&fullstop_mutex);
-               return -EINVAL;
-       }
-       if (cur_ops->fqs == NULL && fqs_duration != 0) {
-               pr_alert("rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled.\n");
-               fqs_duration = 0;
-       }
-       if (cur_ops->init)
-               cur_ops->init(); /* no "goto unwind" prior to this point!!! */
-
-       if (nreaders >= 0)
-               nrealreaders = nreaders;
-       else
-               nrealreaders = 2 * num_online_cpus();
-       rcu_torture_print_module_parms(cur_ops, "Start of test");
-       fullstop = FULLSTOP_DONTSTOP;
-
-       /* Set up the freelist. */
-
-       INIT_LIST_HEAD(&rcu_torture_freelist);
-       for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
-               rcu_tortures[i].rtort_mbtest = 0;
-               list_add_tail(&rcu_tortures[i].rtort_free,
-                             &rcu_torture_freelist);
-       }
-
-       /* Initialize the statistics so that each run gets its own numbers. */
-
-       rcu_torture_current = NULL;
-       rcu_torture_current_version = 0;
-       atomic_set(&n_rcu_torture_alloc, 0);
-       atomic_set(&n_rcu_torture_alloc_fail, 0);
-       atomic_set(&n_rcu_torture_free, 0);
-       atomic_set(&n_rcu_torture_mberror, 0);
-       atomic_set(&n_rcu_torture_error, 0);
-       n_rcu_torture_barrier_error = 0;
-       n_rcu_torture_boost_ktrerror = 0;
-       n_rcu_torture_boost_rterror = 0;
-       n_rcu_torture_boost_failure = 0;
-       n_rcu_torture_boosts = 0;
-       for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
-               atomic_set(&rcu_torture_wcount[i], 0);
-       for_each_possible_cpu(cpu) {
-               for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
-                       per_cpu(rcu_torture_count, cpu)[i] = 0;
-                       per_cpu(rcu_torture_batch, cpu)[i] = 0;
-               }
-       }
-
-       /* Start up the kthreads. */
-
-       VERBOSE_PRINTK_STRING("Creating rcu_torture_writer task");
-       writer_task = kthread_create(rcu_torture_writer, NULL,
-                                    "rcu_torture_writer");
-       if (IS_ERR(writer_task)) {
-               firsterr = PTR_ERR(writer_task);
-               VERBOSE_PRINTK_ERRSTRING("Failed to create writer");
-               writer_task = NULL;
-               goto unwind;
-       }
-       wake_up_process(writer_task);
-       fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
-                                  GFP_KERNEL);
-       if (fakewriter_tasks == NULL) {
-               VERBOSE_PRINTK_ERRSTRING("out of memory");
-               firsterr = -ENOMEM;
-               goto unwind;
-       }
-       for (i = 0; i < nfakewriters; i++) {
-               VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
-               fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
-                                                 "rcu_torture_fakewriter");
-               if (IS_ERR(fakewriter_tasks[i])) {
-                       firsterr = PTR_ERR(fakewriter_tasks[i]);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
-                       fakewriter_tasks[i] = NULL;
-                       goto unwind;
-               }
-       }
-       reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
-                              GFP_KERNEL);
-       if (reader_tasks == NULL) {
-               VERBOSE_PRINTK_ERRSTRING("out of memory");
-               firsterr = -ENOMEM;
-               goto unwind;
-       }
-       for (i = 0; i < nrealreaders; i++) {
-               VERBOSE_PRINTK_STRING("Creating rcu_torture_reader task");
-               reader_tasks[i] = kthread_run(rcu_torture_reader, NULL,
-                                             "rcu_torture_reader");
-               if (IS_ERR(reader_tasks[i])) {
-                       firsterr = PTR_ERR(reader_tasks[i]);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create reader");
-                       reader_tasks[i] = NULL;
-                       goto unwind;
-               }
-       }
-       if (stat_interval > 0) {
-               VERBOSE_PRINTK_STRING("Creating rcu_torture_stats task");
-               stats_task = kthread_run(rcu_torture_stats, NULL,
-                                       "rcu_torture_stats");
-               if (IS_ERR(stats_task)) {
-                       firsterr = PTR_ERR(stats_task);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create stats");
-                       stats_task = NULL;
-                       goto unwind;
-               }
-       }
-       if (test_no_idle_hz) {
-               rcu_idle_cpu = num_online_cpus() - 1;
-
-               if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
-                       firsterr = -ENOMEM;
-                       VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask");
-                       goto unwind;
-               }
-
-               /* Create the shuffler thread */
-               shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
-                                         "rcu_torture_shuffle");
-               if (IS_ERR(shuffler_task)) {
-                       free_cpumask_var(shuffle_tmp_mask);
-                       firsterr = PTR_ERR(shuffler_task);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
-                       shuffler_task = NULL;
-                       goto unwind;
-               }
-       }
-       if (stutter < 0)
-               stutter = 0;
-       if (stutter) {
-               /* Create the stutter thread */
-               stutter_task = kthread_run(rcu_torture_stutter, NULL,
-                                         "rcu_torture_stutter");
-               if (IS_ERR(stutter_task)) {
-                       firsterr = PTR_ERR(stutter_task);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create stutter");
-                       stutter_task = NULL;
-                       goto unwind;
-               }
-       }
-       if (fqs_duration < 0)
-               fqs_duration = 0;
-       if (fqs_duration) {
-               /* Create the stutter thread */
-               fqs_task = kthread_run(rcu_torture_fqs, NULL,
-                                      "rcu_torture_fqs");
-               if (IS_ERR(fqs_task)) {
-                       firsterr = PTR_ERR(fqs_task);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create fqs");
-                       fqs_task = NULL;
-                       goto unwind;
-               }
-       }
-       if (test_boost_interval < 1)
-               test_boost_interval = 1;
-       if (test_boost_duration < 2)
-               test_boost_duration = 2;
-       if ((test_boost == 1 && cur_ops->can_boost) ||
-           test_boost == 2) {
-
-               boost_starttime = jiffies + test_boost_interval * HZ;
-               register_cpu_notifier(&rcutorture_cpu_nb);
-               for_each_possible_cpu(i) {
-                       if (cpu_is_offline(i))
-                               continue;  /* Heuristic: CPU can go offline. */
-                       retval = rcutorture_booster_init(i);
-                       if (retval < 0) {
-                               firsterr = retval;
-                               goto unwind;
-                       }
-               }
-       }
-       if (shutdown_secs > 0) {
-               shutdown_time = jiffies + shutdown_secs * HZ;
-               shutdown_task = kthread_create(rcu_torture_shutdown, NULL,
-                                              "rcu_torture_shutdown");
-               if (IS_ERR(shutdown_task)) {
-                       firsterr = PTR_ERR(shutdown_task);
-                       VERBOSE_PRINTK_ERRSTRING("Failed to create shutdown");
-                       shutdown_task = NULL;
-                       goto unwind;
-               }
-               wake_up_process(shutdown_task);
-       }
-       i = rcu_torture_onoff_init();
-       if (i != 0) {
-               firsterr = i;
-               goto unwind;
-       }
-       register_reboot_notifier(&rcutorture_shutdown_nb);
-       i = rcu_torture_stall_init();
-       if (i != 0) {
-               firsterr = i;
-               goto unwind;
-       }
-       retval = rcu_torture_barrier_init();
-       if (retval != 0) {
-               firsterr = retval;
-               goto unwind;
-       }
-       if (object_debug)
-               rcu_test_debug_objects();
-       rcutorture_record_test_transition();
-       mutex_unlock(&fullstop_mutex);
-       return 0;
-
-unwind:
-       mutex_unlock(&fullstop_mutex);
-       rcu_torture_cleanup();
-       return firsterr;
-}
-
-module_init(rcu_torture_init);
-module_exit(rcu_torture_cleanup);
index b3d116cd072d7bd24803a52c8d6b478930bd6b8b..0c47e300210ad61c3d79854426150fd5246f5750 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
  *
@@ -58,8 +58,6 @@
 #include <linux/suspend.h>
 
 #include "tree.h"
-#include <trace/events/rcu.h>
-
 #include "rcu.h"
 
 MODULE_ALIAS("rcutree");
@@ -837,7 +835,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,
         * to the next.  Only do this for the primary flavor of RCU.
         */
        if (rdp->rsp == rcu_state &&
-           ULONG_CMP_GE(ACCESS_ONCE(jiffies), rdp->rsp->jiffies_resched)) {
+           ULONG_CMP_GE(jiffies, rdp->rsp->jiffies_resched)) {
                rdp->rsp->jiffies_resched += 5;
                resched_cpu(rdp->cpu);
        }
@@ -847,7 +845,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,
 
 static void record_gp_stall_check_time(struct rcu_state *rsp)
 {
-       unsigned long j = ACCESS_ONCE(jiffies);
+       unsigned long j = jiffies;
        unsigned long j1;
 
        rsp->gp_start = j;
@@ -1005,7 +1003,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
 
        if (rcu_cpu_stall_suppress || !rcu_gp_in_progress(rsp))
                return;
-       j = ACCESS_ONCE(jiffies);
+       j = jiffies;
 
        /*
         * Lots of memory barriers to reject false positives.
@@ -1423,13 +1421,14 @@ static int rcu_gp_init(struct rcu_state *rsp)
 
        /* Advance to a new grace period and initialize state. */
        record_gp_stall_check_time(rsp);
-       smp_wmb(); /* Record GP times before starting GP. */
-       rsp->gpnum++;
+       /* Record GP times before starting GP, hence smp_store_release(). */
+       smp_store_release(&rsp->gpnum, rsp->gpnum + 1);
        trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start"));
        raw_spin_unlock_irq(&rnp->lock);
 
        /* Exclude any concurrent CPU-hotplug operations. */
        mutex_lock(&rsp->onoff_mutex);
+       smp_mb__after_unlock_lock(); /* ->gpnum increment before GP! */
 
        /*
         * Set the quiescent-state-needed bits in all the rcu_node
@@ -1557,10 +1556,11 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
        }
        rnp = rcu_get_root(rsp);
        raw_spin_lock_irq(&rnp->lock);
-       smp_mb__after_unlock_lock();
+       smp_mb__after_unlock_lock(); /* Order GP before ->completed update. */
        rcu_nocb_gp_set(rnp, nocb);
 
-       rsp->completed = rsp->gpnum; /* Declare grace period done. */
+       /* Declare grace period done. */
+       ACCESS_ONCE(rsp->completed) = rsp->gpnum;
        trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end"));
        rsp->fqs_state = RCU_GP_IDLE;
        rdp = this_cpu_ptr(rsp->rda);
@@ -2304,7 +2304,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
                if (rnp_old != NULL)
                        raw_spin_unlock(&rnp_old->fqslock);
                if (ret) {
-                       rsp->n_force_qs_lh++;
+                       ACCESS_ONCE(rsp->n_force_qs_lh)++;
                        return;
                }
                rnp_old = rnp;
@@ -2316,7 +2316,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
        smp_mb__after_unlock_lock();
        raw_spin_unlock(&rnp_old->fqslock);
        if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
-               rsp->n_force_qs_lh++;
+               ACCESS_ONCE(rsp->n_force_qs_lh)++;
                raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
                return;  /* Someone beat us to it. */
        }
@@ -2639,6 +2639,58 @@ void synchronize_rcu_bh(void)
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
 
+/**
+ * get_state_synchronize_rcu - Snapshot current RCU state
+ *
+ * Returns a cookie that is used by a later call to cond_synchronize_rcu()
+ * to determine whether or not a full grace period has elapsed in the
+ * meantime.
+ */
+unsigned long get_state_synchronize_rcu(void)
+{
+       /*
+        * Any prior manipulation of RCU-protected data must happen
+        * before the load from ->gpnum.
+        */
+       smp_mb();  /* ^^^ */
+
+       /*
+        * Make sure this load happens before the purportedly
+        * time-consuming work between get_state_synchronize_rcu()
+        * and cond_synchronize_rcu().
+        */
+       return smp_load_acquire(&rcu_state->gpnum);
+}
+EXPORT_SYMBOL_GPL(get_state_synchronize_rcu);
+
+/**
+ * cond_synchronize_rcu - Conditionally wait for an RCU grace period
+ *
+ * @oldstate: return value from earlier call to get_state_synchronize_rcu()
+ *
+ * If a full RCU grace period has elapsed since the earlier call to
+ * get_state_synchronize_rcu(), just return.  Otherwise, invoke
+ * synchronize_rcu() to wait for a full grace period.
+ *
+ * Yes, this function does not take counter wrap into account.  But
+ * counter wrap is harmless.  If the counter wraps, we have waited for
+ * more than 2 billion grace periods (and way more on a 64-bit system!),
+ * so waiting for one additional grace period should be just fine.
+ */
+void cond_synchronize_rcu(unsigned long oldstate)
+{
+       unsigned long newstate;
+
+       /*
+        * Ensure that this load happens before any RCU-destructive
+        * actions the caller might carry out after we return.
+        */
+       newstate = smp_load_acquire(&rcu_state->completed);
+       if (ULONG_CMP_GE(oldstate, newstate))
+               synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(cond_synchronize_rcu);
+
 static int synchronize_sched_expedited_cpu_stop(void *data)
 {
        /*
@@ -2880,7 +2932,7 @@ static int rcu_pending(int cpu)
  * non-NULL, store an indication of whether all callbacks are lazy.
  * (If there are no callbacks, all of them are deemed to be lazy.)
  */
-static int rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
+static int __maybe_unused rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
 {
        bool al = true;
        bool hc = false;
index 8c19873f1ac9b7eda78d55595dae0913b4ad45e3..75dc3c39a02a110b3d0f7b6b3b0557806f883094 100644 (file)
@@ -13,8 +13,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
  *
index 6e2ef4b2b920bc3db08ececbc37d74cf83b8dc14..962d1d589929e2b9c8350bd4432d96c4e31017f2 100644 (file)
@@ -14,8 +14,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright Red Hat, 2009
  * Copyright IBM Corporation, 2009
@@ -1586,11 +1586,13 @@ static void rcu_prepare_kthreads(int cpu)
  * Because we not have RCU_FAST_NO_HZ, just check whether this CPU needs
  * any flavor of RCU.
  */
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
 int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
 {
        *delta_jiffies = ULONG_MAX;
        return rcu_cpu_has_callbacks(cpu, NULL);
 }
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
 
 /*
  * Because we do not have RCU_FAST_NO_HZ, don't bother cleaning up
@@ -1656,7 +1658,7 @@ extern int tick_nohz_active;
  * only if it has been awhile since the last time we did so.  Afterwards,
  * if there are any callbacks ready for immediate invocation, return true.
  */
-static bool rcu_try_advance_all_cbs(void)
+static bool __maybe_unused rcu_try_advance_all_cbs(void)
 {
        bool cbs_ready = false;
        struct rcu_data *rdp;
@@ -1696,6 +1698,7 @@ static bool rcu_try_advance_all_cbs(void)
  *
  * The caller must have disabled interrupts.
  */
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
 int rcu_needs_cpu(int cpu, unsigned long *dj)
 {
        struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
@@ -1726,6 +1729,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj)
        }
        return 0;
 }
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
 
 /*
  * Prepare a CPU for idle from an RCU perspective.  The first major task
@@ -1739,6 +1743,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj)
  */
 static void rcu_prepare_for_idle(int cpu)
 {
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
        struct rcu_data *rdp;
        struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
        struct rcu_node *rnp;
@@ -1790,6 +1795,7 @@ static void rcu_prepare_for_idle(int cpu)
                rcu_accelerate_cbs(rsp, rnp, rdp);
                raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
        }
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
 }
 
 /*
@@ -1799,11 +1805,12 @@ static void rcu_prepare_for_idle(int cpu)
  */
 static void rcu_cleanup_after_idle(int cpu)
 {
-
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
        if (rcu_is_nocb_cpu(cpu))
                return;
        if (rcu_try_advance_all_cbs())
                invoke_rcu_core();
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
 }
 
 /*
@@ -2101,6 +2108,7 @@ static void rcu_init_one_nocb(struct rcu_node *rnp)
        init_waitqueue_head(&rnp->nocb_gp_wq[1]);
 }
 
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
 /* Is the specified CPU a no-CPUs CPU? */
 bool rcu_is_nocb_cpu(int cpu)
 {
@@ -2108,6 +2116,7 @@ bool rcu_is_nocb_cpu(int cpu)
                return cpumask_test_cpu(cpu, rcu_nocb_mask);
        return false;
 }
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
 
 /*
  * Enqueue the specified string of rcu_head structures onto the specified
@@ -2893,7 +2902,7 @@ static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
  * CPU unless the grace period has extended for too long.
  *
  * This code relies on the fact that all NO_HZ_FULL CPUs are also
- * CONFIG_RCU_NOCB_CPUs.
+ * CONFIG_RCU_NOCB_CPU CPUs.
  */
 static bool rcu_nohz_full_cpu(struct rcu_state *rsp)
 {
index 4def475336d412bcbfd8aa4e34a600e0f8b62d41..5cdc62e1beeb635a36ee87098a7f38110a651382 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2008
  *
@@ -273,7 +273,7 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
        seq_printf(m, "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n",
                   rsp->n_force_qs, rsp->n_force_qs_ngp,
                   rsp->n_force_qs - rsp->n_force_qs_ngp,
-                  rsp->n_force_qs_lh, rsp->qlen_lazy, rsp->qlen);
+                  ACCESS_ONCE(rsp->n_force_qs_lh), rsp->qlen_lazy, rsp->qlen);
        for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < rcu_num_nodes; rnp++) {
                if (rnp->level != level) {
                        seq_puts(m, "\n");
index c54609faf233ba21a49835d32a9132eb56853f14..4c0a9b0af469a1f5fa3242d594653fee0f004505 100644 (file)
@@ -12,8 +12,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
  *
  * Copyright IBM Corporation, 2001
  *
@@ -49,7 +49,6 @@
 #include <linux/module.h>
 
 #define CREATE_TRACE_POINTS
-#include <trace/events/rcu.h>
 
 #include "rcu.h"
 
index 3f285dce9347191537b8d13f8db53f869d4744ad..673061c06da182dbe02993d6f332168f8b3b3c96 100644 (file)
@@ -432,11 +432,6 @@ static void resource_clip(struct resource *res, resource_size_t min,
                res->end = max;
 }
 
-static bool resource_contains(struct resource *res1, struct resource *res2)
-{
-       return res1->start <= res2->start && res1->end >= res2->end;
-}
-
 /*
  * Find empty slot in the resource tree with the given range and
  * alignment constraints
@@ -471,10 +466,11 @@ static int __find_resource(struct resource *root, struct resource *old,
                arch_remove_reservations(&tmp);
 
                /* Check for overflow after ALIGN() */
-               avail = *new;
                avail.start = ALIGN(tmp.start, constraint->align);
                avail.end = tmp.end;
+               avail.flags = new->flags & ~IORESOURCE_UNSET;
                if (avail.start >= tmp.start) {
+                       alloc.flags = avail.flags;
                        alloc.start = constraint->alignf(constraint->alignf_data, &avail,
                                        size, constraint->align);
                        alloc.end = alloc.start + size - 1;
@@ -949,8 +945,8 @@ struct resource * __request_region(struct resource *parent,
        res->name = name;
        res->start = start;
        res->end = start + n - 1;
-       res->flags = IORESOURCE_BUSY;
-       res->flags |= flags;
+       res->flags = resource_type(parent);
+       res->flags |= IORESOURCE_BUSY | flags;
 
        write_lock(&resource_lock);
 
index 9a95c8c2af2af0e9fb62c794926df3f1775a9dbe..ab32b7b0db5c6b30b4cc64e61e6a857fb51c87e6 100644 (file)
@@ -13,7 +13,7 @@ endif
 
 obj-y += core.o proc.o clock.o cputime.o
 obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o
-obj-y += wait.o completion.o
+obj-y += wait.o completion.o idle.o
 obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o
 obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
 obj-$(CONFIG_SCHEDSTATS) += stats.o
index 4a073539c58e69992ed2133a73444ceffc9cd3fa..e73efba98301f77715c5e5e17b8e65a98bbb3769 100644 (file)
@@ -203,7 +203,7 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
        struct autogroup *ag;
        int err;
 
-       if (nice < -20 || nice > 19)
+       if (nice < MIN_NICE || nice > MAX_NICE)
                return -EINVAL;
 
        err = security_task_setnice(current, nice);
index 43c2bcc35761e40c9342522b4fa87b92cdefd8f4..b30a2924ef1429a60152a40101ec4828c5e23268 100644 (file)
@@ -301,14 +301,14 @@ u64 sched_clock_cpu(int cpu)
        if (unlikely(!sched_clock_running))
                return 0ull;
 
-       preempt_disable();
+       preempt_disable_notrace();
        scd = cpu_sdc(cpu);
 
        if (cpu != smp_processor_id())
                clock = sched_clock_remote(scd);
        else
                clock = sched_clock_local(scd);
-       preempt_enable();
+       preempt_enable_notrace();
 
        return clock;
 }
index 6edbef296ece25a6ee68facac279445414692368..3c4d096544ce4179c24403d0c41b3758c1842eab 100644 (file)
@@ -555,12 +555,15 @@ void resched_cpu(int cpu)
  * selecting an idle cpu will add more delays to the timers than intended
  * (as that cpu's timer base may not be uptodate wrt jiffies etc).
  */
-int get_nohz_timer_target(void)
+int get_nohz_timer_target(int pinned)
 {
        int cpu = smp_processor_id();
        int i;
        struct sched_domain *sd;
 
+       if (pinned || !get_sysctl_timer_migration() || !idle_cpu(cpu))
+               return cpu;
+
        rcu_read_lock();
        for_each_domain(cpu, sd) {
                for_each_cpu(i, sched_domain_span(sd)) {
@@ -823,19 +826,13 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
 #endif
 #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
        if (static_key_false((&paravirt_steal_rq_enabled))) {
-               u64 st;
-
                steal = paravirt_steal_clock(cpu_of(rq));
                steal -= rq->prev_steal_time_rq;
 
                if (unlikely(steal > delta))
                        steal = delta;
 
-               st = steal_ticks(steal);
-               steal = st * TICK_NSEC;
-
                rq->prev_steal_time_rq += steal;
-
                delta -= steal;
        }
 #endif
@@ -1745,8 +1742,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
        p->numa_scan_seq = p->mm ? p->mm->numa_scan_seq : 0;
        p->numa_scan_period = sysctl_numa_balancing_scan_delay;
        p->numa_work.next = &p->numa_work;
-       p->numa_faults = NULL;
-       p->numa_faults_buffer = NULL;
+       p->numa_faults_memory = NULL;
+       p->numa_faults_buffer_memory = NULL;
+       p->last_task_numa_placement = 0;
+       p->last_sum_exec_runtime = 0;
 
        INIT_LIST_HEAD(&p->numa_entry);
        p->numa_group = NULL;
@@ -2149,8 +2148,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
        if (mm)
                mmdrop(mm);
        if (unlikely(prev_state == TASK_DEAD)) {
-               task_numa_free(prev);
-
                if (prev->sched_class->task_dead)
                        prev->sched_class->task_dead(prev);
 
@@ -2167,13 +2164,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
 
 #ifdef CONFIG_SMP
 
-/* assumes rq->lock is held */
-static inline void pre_schedule(struct rq *rq, struct task_struct *prev)
-{
-       if (prev->sched_class->pre_schedule)
-               prev->sched_class->pre_schedule(rq, prev);
-}
-
 /* rq->lock is NOT held, but preemption is disabled */
 static inline void post_schedule(struct rq *rq)
 {
@@ -2191,10 +2181,6 @@ static inline void post_schedule(struct rq *rq)
 
 #else
 
-static inline void pre_schedule(struct rq *rq, struct task_struct *p)
-{
-}
-
 static inline void post_schedule(struct rq *rq)
 {
 }
@@ -2510,8 +2496,13 @@ void __kprobes preempt_count_add(int val)
        DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
                                PREEMPT_MASK - 10);
 #endif
-       if (preempt_count() == val)
-               trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
+       if (preempt_count() == val) {
+               unsigned long ip = get_parent_ip(CALLER_ADDR1);
+#ifdef CONFIG_DEBUG_PREEMPT
+               current->preempt_disable_ip = ip;
+#endif
+               trace_preempt_off(CALLER_ADDR0, ip);
+       }
 }
 EXPORT_SYMBOL(preempt_count_add);
 
@@ -2554,6 +2545,13 @@ static noinline void __schedule_bug(struct task_struct *prev)
        print_modules();
        if (irqs_disabled())
                print_irqtrace_events(prev);
+#ifdef CONFIG_DEBUG_PREEMPT
+       if (in_atomic_preempt_off()) {
+               pr_err("Preemption disabled at:");
+               print_ip_sym(current->preempt_disable_ip);
+               pr_cont("\n");
+       }
+#endif
        dump_stack();
        add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
 }
@@ -2577,36 +2575,34 @@ static inline void schedule_debug(struct task_struct *prev)
        schedstat_inc(this_rq(), sched_count);
 }
 
-static void put_prev_task(struct rq *rq, struct task_struct *prev)
-{
-       if (prev->on_rq || rq->skip_clock_update < 0)
-               update_rq_clock(rq);
-       prev->sched_class->put_prev_task(rq, prev);
-}
-
 /*
  * Pick up the highest-prio task:
  */
 static inline struct task_struct *
-pick_next_task(struct rq *rq)
+pick_next_task(struct rq *rq, struct task_struct *prev)
 {
-       const struct sched_class *class;
+       const struct sched_class *class = &fair_sched_class;
        struct task_struct *p;
 
        /*
         * Optimization: we know that if all tasks are in
         * the fair class we can call that function directly:
         */
-       if (likely(rq->nr_running == rq->cfs.h_nr_running)) {
-               p = fair_sched_class.pick_next_task(rq);
-               if (likely(p))
+       if (likely(prev->sched_class == class &&
+                  rq->nr_running == rq->cfs.h_nr_running)) {
+               p = fair_sched_class.pick_next_task(rq, prev);
+               if (likely(p && p != RETRY_TASK))
                        return p;
        }
 
+again:
        for_each_class(class) {
-               p = class->pick_next_task(rq);
-               if (p)
+               p = class->pick_next_task(rq, prev);
+               if (p) {
+                       if (unlikely(p == RETRY_TASK))
+                               goto again;
                        return p;
+               }
        }
 
        BUG(); /* the idle class will always have a runnable task */
@@ -2700,13 +2696,10 @@ need_resched:
                switch_count = &prev->nvcsw;
        }
 
-       pre_schedule(rq, prev);
-
-       if (unlikely(!rq->nr_running))
-               idle_balance(cpu, rq);
+       if (prev->on_rq || rq->skip_clock_update < 0)
+               update_rq_clock(rq);
 
-       put_prev_task(rq, prev);
-       next = pick_next_task(rq);
+       next = pick_next_task(rq, prev);
        clear_tsk_need_resched(prev);
        clear_preempt_need_resched();
        rq->skip_clock_update = 0;
@@ -2908,7 +2901,8 @@ EXPORT_SYMBOL(sleep_on_timeout);
  * This function changes the 'effective' priority of a task. It does
  * not touch ->normal_prio like __setscheduler().
  *
- * Used by the rt_mutex code to implement priority inheritance logic.
+ * Used by the rt_mutex code to implement priority inheritance
+ * logic. Call site only calls if the priority of the task changed.
  */
 void rt_mutex_setprio(struct task_struct *p, int prio)
 {
@@ -2998,7 +2992,7 @@ void set_user_nice(struct task_struct *p, long nice)
        unsigned long flags;
        struct rq *rq;
 
-       if (TASK_NICE(p) == nice || nice < -20 || nice > 19)
+       if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
                return;
        /*
         * We have to be careful, if called from sys_setpriority(),
@@ -3076,11 +3070,11 @@ SYSCALL_DEFINE1(nice, int, increment)
        if (increment > 40)
                increment = 40;
 
-       nice = TASK_NICE(current) + increment;
-       if (nice < -20)
-               nice = -20;
-       if (nice > 19)
-               nice = 19;
+       nice = task_nice(current) + increment;
+       if (nice < MIN_NICE)
+               nice = MIN_NICE;
+       if (nice > MAX_NICE)
+               nice = MAX_NICE;
 
        if (increment < 0 && !can_nice(current, nice))
                return -EPERM;
@@ -3108,18 +3102,6 @@ int task_prio(const struct task_struct *p)
        return p->prio - MAX_RT_PRIO;
 }
 
-/**
- * task_nice - return the nice value of a given task.
- * @p: the task in question.
- *
- * Return: The nice value [ -20 ... 0 ... 19 ].
- */
-int task_nice(const struct task_struct *p)
-{
-       return TASK_NICE(p);
-}
-EXPORT_SYMBOL(task_nice);
-
 /**
  * idle_cpu - is a given cpu idle currently?
  * @cpu: the processor in question.
@@ -3189,9 +3171,8 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr)
        dl_se->dl_new = 1;
 }
 
-/* Actually do priority change: must hold pi & rq lock. */
-static void __setscheduler(struct rq *rq, struct task_struct *p,
-                          const struct sched_attr *attr)
+static void __setscheduler_params(struct task_struct *p,
+               const struct sched_attr *attr)
 {
        int policy = attr->sched_policy;
 
@@ -3211,9 +3192,21 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
         * getparam()/getattr() don't report silly values for !rt tasks.
         */
        p->rt_priority = attr->sched_priority;
-
        p->normal_prio = normal_prio(p);
-       p->prio = rt_mutex_getprio(p);
+       set_load_weight(p);
+}
+
+/* Actually do priority change: must hold pi & rq lock. */
+static void __setscheduler(struct rq *rq, struct task_struct *p,
+                          const struct sched_attr *attr)
+{
+       __setscheduler_params(p, attr);
+
+       /*
+        * If we get here, there was no pi waiters boosting the
+        * task. It is safe to use the normal prio.
+        */
+       p->prio = normal_prio(p);
 
        if (dl_prio(p->prio))
                p->sched_class = &dl_sched_class;
@@ -3221,8 +3214,6 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
                p->sched_class = &rt_sched_class;
        else
                p->sched_class = &fair_sched_class;
-
-       set_load_weight(p);
 }
 
 static void
@@ -3275,6 +3266,8 @@ static int __sched_setscheduler(struct task_struct *p,
                                const struct sched_attr *attr,
                                bool user)
 {
+       int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 :
+                     MAX_RT_PRIO - 1 - attr->sched_priority;
        int retval, oldprio, oldpolicy = -1, on_rq, running;
        int policy = attr->sched_policy;
        unsigned long flags;
@@ -3319,7 +3312,7 @@ recheck:
         */
        if (user && !capable(CAP_SYS_NICE)) {
                if (fair_policy(policy)) {
-                       if (attr->sched_nice < TASK_NICE(p) &&
+                       if (attr->sched_nice < task_nice(p) &&
                            !can_nice(p, attr->sched_nice))
                                return -EPERM;
                }
@@ -3338,12 +3331,21 @@ recheck:
                                return -EPERM;
                }
 
+                /*
+                 * Can't set/change SCHED_DEADLINE policy at all for now
+                 * (safest behavior); in the future we would like to allow
+                 * unprivileged DL tasks to increase their relative deadline
+                 * or reduce their runtime (both ways reducing utilization)
+                 */
+               if (dl_policy(policy))
+                       return -EPERM;
+
                /*
                 * Treat SCHED_IDLE as nice 20. Only allow a switch to
                 * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
                 */
                if (p->policy == SCHED_IDLE && policy != SCHED_IDLE) {
-                       if (!can_nice(p, TASK_NICE(p)))
+                       if (!can_nice(p, task_nice(p)))
                                return -EPERM;
                }
 
@@ -3380,16 +3382,18 @@ recheck:
        }
 
        /*
-        * If not changing anything there's no need to proceed further:
+        * If not changing anything there's no need to proceed further,
+        * but store a possible modification of reset_on_fork.
         */
        if (unlikely(policy == p->policy)) {
-               if (fair_policy(policy) && attr->sched_nice != TASK_NICE(p))
+               if (fair_policy(policy) && attr->sched_nice != task_nice(p))
                        goto change;
                if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
                        goto change;
                if (dl_policy(policy))
                        goto change;
 
+               p->sched_reset_on_fork = reset_on_fork;
                task_rq_unlock(rq, p, &flags);
                return 0;
        }
@@ -3443,6 +3447,24 @@ change:
                return -EBUSY;
        }
 
+       p->sched_reset_on_fork = reset_on_fork;
+       oldprio = p->prio;
+
+       /*
+        * Special case for priority boosted tasks.
+        *
+        * If the new priority is lower or equal (user space view)
+        * than the current (boosted) priority, we just store the new
+        * normal parameters and do not touch the scheduler class and
+        * the runqueue. This will be done when the task deboost
+        * itself.
+        */
+       if (rt_mutex_check_prio(p, newprio)) {
+               __setscheduler_params(p, attr);
+               task_rq_unlock(rq, p, &flags);
+               return 0;
+       }
+
        on_rq = p->on_rq;
        running = task_current(rq, p);
        if (on_rq)
@@ -3450,16 +3472,18 @@ change:
        if (running)
                p->sched_class->put_prev_task(rq, p);
 
-       p->sched_reset_on_fork = reset_on_fork;
-
-       oldprio = p->prio;
        prev_class = p->sched_class;
        __setscheduler(rq, p, attr);
 
        if (running)
                p->sched_class->set_curr_task(rq);
-       if (on_rq)
-               enqueue_task(rq, p, 0);
+       if (on_rq) {
+               /*
+                * We enqueue to tail when the priority of a task is
+                * increased (user space view).
+                */
+               enqueue_task(rq, p, oldprio <= p->prio ? ENQUEUE_HEAD : 0);
+       }
 
        check_class_changed(rq, p, prev_class, oldprio);
        task_rq_unlock(rq, p, &flags);
@@ -3615,7 +3639,7 @@ static int sched_copy_attr(struct sched_attr __user *uattr,
         * XXX: do we want to be lenient like existing syscalls; or do we want
         * to be strict and return an error on out-of-bounds values?
         */
-       attr->sched_nice = clamp(attr->sched_nice, -20, 19);
+       attr->sched_nice = clamp(attr->sched_nice, MIN_NICE, MAX_NICE);
 
 out:
        return ret;
@@ -3836,7 +3860,7 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
        else if (task_has_rt_policy(p))
                attr.sched_priority = p->rt_priority;
        else
-               attr.sched_nice = TASK_NICE(p);
+               attr.sched_nice = task_nice(p);
 
        rcu_read_unlock();
 
@@ -4474,6 +4498,7 @@ void init_idle(struct task_struct *idle, int cpu)
        rcu_read_unlock();
 
        rq->curr = rq->idle = idle;
+       idle->on_rq = 1;
 #if defined(CONFIG_SMP)
        idle->on_cpu = 1;
 #endif
@@ -4693,8 +4718,10 @@ void idle_task_exit(void)
 
        BUG_ON(cpu_online(smp_processor_id()));
 
-       if (mm != &init_mm)
+       if (mm != &init_mm) {
                switch_mm(mm, &init_mm, current);
+               finish_arch_post_lock_switch();
+       }
        mmdrop(mm);
 }
 
@@ -4712,6 +4739,22 @@ static void calc_load_migrate(struct rq *rq)
                atomic_long_add(delta, &calc_load_tasks);
 }
 
+static void put_prev_task_fake(struct rq *rq, struct task_struct *prev)
+{
+}
+
+static const struct sched_class fake_sched_class = {
+       .put_prev_task = put_prev_task_fake,
+};
+
+static struct task_struct fake_task = {
+       /*
+        * Avoid pull_{rt,dl}_task()
+        */
+       .prio = MAX_PRIO + 1,
+       .sched_class = &fake_sched_class,
+};
+
 /*
  * Migrate all tasks from the rq, sleeping tasks will be migrated by
  * try_to_wake_up()->select_task_rq().
@@ -4752,7 +4795,7 @@ static void migrate_tasks(unsigned int dead_cpu)
                if (rq->nr_running == 1)
                        break;
 
-               next = pick_next_task(rq);
+               next = pick_next_task(rq, &fake_task);
                BUG_ON(!next);
                next->sched_class->put_prev_task(rq, next);
 
@@ -4842,7 +4885,7 @@ set_table_entry(struct ctl_table *entry,
 static struct ctl_table *
 sd_alloc_ctl_domain_table(struct sched_domain *sd)
 {
-       struct ctl_table *table = sd_alloc_ctl_entry(13);
+       struct ctl_table *table = sd_alloc_ctl_entry(14);
 
        if (table == NULL)
                return NULL;
@@ -4870,9 +4913,12 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
                sizeof(int), 0644, proc_dointvec_minmax, false);
        set_table_entry(&table[10], "flags", &sd->flags,
                sizeof(int), 0644, proc_dointvec_minmax, false);
-       set_table_entry(&table[11], "name", sd->name,
+       set_table_entry(&table[11], "max_newidle_lb_cost",
+               &sd->max_newidle_lb_cost,
+               sizeof(long), 0644, proc_doulongvec_minmax, false);
+       set_table_entry(&table[12], "name", sd->name,
                CORENAME_MAX_SIZE, 0444, proc_dostring, false);
-       /* &table[12] is terminator */
+       /* &table[13] is terminator */
 
        return table;
 }
@@ -6849,7 +6895,6 @@ void __init sched_init(void)
 
                rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
 #ifdef CONFIG_RT_GROUP_SCHED
-               INIT_LIST_HEAD(&rq->leaf_rt_rq_list);
                init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
 #endif
 
@@ -6938,7 +6983,8 @@ void __might_sleep(const char *file, int line, int preempt_offset)
        static unsigned long prev_jiffy;        /* ratelimiting */
 
        rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
-       if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) ||
+       if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
+            !is_idle_task(current)) ||
            system_state != SYSTEM_RUNNING || oops_in_progress)
                return;
        if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
@@ -6956,6 +7002,13 @@ void __might_sleep(const char *file, int line, int preempt_offset)
        debug_show_held_locks(current);
        if (irqs_disabled())
                print_irqtrace_events(current);
+#ifdef CONFIG_DEBUG_PREEMPT
+       if (!preempt_count_equals(preempt_offset)) {
+               pr_err("Preemption disabled at:");
+               print_ip_sym(current->preempt_disable_ip);
+               pr_cont("\n");
+       }
+#endif
        dump_stack();
 }
 EXPORT_SYMBOL(__might_sleep);
@@ -7009,7 +7062,7 @@ void normalize_rt_tasks(void)
                         * Renice negative nice level userspace
                         * tasks back to 0:
                         */
-                       if (TASK_NICE(p) < 0 && p->mm)
+                       if (task_nice(p) < 0 && p->mm)
                                set_user_nice(p, 0);
                        continue;
                }
index 5b8838b56d1c8dee47354f3a1a697263678d00ea..5b9bb42b2d47e760f3a7cd17af24ba37d2cf07ea 100644 (file)
@@ -70,7 +70,7 @@ static void cpudl_heapify(struct cpudl *cp, int idx)
 
 static void cpudl_change_key(struct cpudl *cp, int idx, u64 new_dl)
 {
-       WARN_ON(!cpu_present(idx) || idx == IDX_INVALID);
+       WARN_ON(idx == IDX_INVALID || !cpu_present(idx));
 
        if (dl_time_before(new_dl, cp->elements[idx].dl)) {
                cp->elements[idx].dl = new_dl;
@@ -117,7 +117,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
        }
 
 out:
-       WARN_ON(!cpu_present(best_cpu) && best_cpu != -1);
+       WARN_ON(best_cpu != -1 && !cpu_present(best_cpu));
 
        return best_cpu;
 }
index 99947919e30bc68963d3bfa937ebad8a2c90ba87..a95097cb4591b5bfa2466adb5600895e782fc661 100644 (file)
@@ -142,7 +142,7 @@ void account_user_time(struct task_struct *p, cputime_t cputime,
        p->utimescaled += cputime_scaled;
        account_group_user_time(p, cputime);
 
-       index = (TASK_NICE(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
+       index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
 
        /* Add user time to cpustat. */
        task_group_account_field(p, index, (__force u64) cputime);
@@ -169,7 +169,7 @@ static void account_guest_time(struct task_struct *p, cputime_t cputime,
        p->gtime += cputime;
 
        /* Add guest time to cpustat. */
-       if (TASK_NICE(p) > 0) {
+       if (task_nice(p) > 0) {
                cpustat[CPUTIME_NICE] += (__force u64) cputime;
                cpustat[CPUTIME_GUEST_NICE] += (__force u64) cputime;
        } else {
@@ -258,16 +258,22 @@ static __always_inline bool steal_account_process_tick(void)
 {
 #ifdef CONFIG_PARAVIRT
        if (static_key_false(&paravirt_steal_enabled)) {
-               u64 steal, st = 0;
+               u64 steal;
+               cputime_t steal_ct;
 
                steal = paravirt_steal_clock(smp_processor_id());
                steal -= this_rq()->prev_steal_time;
 
-               st = steal_ticks(steal);
-               this_rq()->prev_steal_time += st * TICK_NSEC;
+               /*
+                * cputime_t may be less precise than nsecs (eg: if it's
+                * based on jiffies). Lets cast the result to cputime
+                * granularity and account the rest on the next rounds.
+                */
+               steal_ct = nsecs_to_cputime(steal);
+               this_rq()->prev_steal_time += cputime_to_nsecs(steal_ct);
 
-               account_steal_time(st);
-               return st;
+               account_steal_time(steal_ct);
+               return steal_ct;
        }
 #endif
        return false;
index 15cbc17fbf84d57ac52aa9b752d9552a4b4335ee..27ef409255253367d35fd598ddb01550612df040 100644 (file)
@@ -135,7 +135,6 @@ static void update_dl_migration(struct dl_rq *dl_rq)
 static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
        struct task_struct *p = dl_task_of(dl_se);
-       dl_rq = &rq_of_dl_rq(dl_rq)->dl;
 
        if (p->nr_cpus_allowed > 1)
                dl_rq->dl_nr_migratory++;
@@ -146,7 +145,6 @@ static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 static void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
        struct task_struct *p = dl_task_of(dl_se);
-       dl_rq = &rq_of_dl_rq(dl_rq)->dl;
 
        if (p->nr_cpus_allowed > 1)
                dl_rq->dl_nr_migratory--;
@@ -212,6 +210,16 @@ static inline int has_pushable_dl_tasks(struct rq *rq)
 
 static int push_dl_task(struct rq *rq);
 
+static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev)
+{
+       return dl_task(prev);
+}
+
+static inline void set_post_schedule(struct rq *rq)
+{
+       rq->post_schedule = has_pushable_dl_tasks(rq);
+}
+
 #else
 
 static inline
@@ -234,6 +242,19 @@ void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
 }
 
+static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev)
+{
+       return false;
+}
+
+static inline int pull_dl_task(struct rq *rq)
+{
+       return 0;
+}
+
+static inline void set_post_schedule(struct rq *rq)
+{
+}
 #endif /* CONFIG_SMP */
 
 static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags);
@@ -564,6 +585,8 @@ int dl_runtime_exceeded(struct rq *rq, struct sched_dl_entity *dl_se)
        return 1;
 }
 
+extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
+
 /*
  * Update the current task's runtime statistics (provided it is still
  * a -deadline task and has not been removed from the dl_rq).
@@ -586,8 +609,8 @@ static void update_curr_dl(struct rq *rq)
         * approach need further study.
         */
        delta_exec = rq_clock_task(rq) - curr->se.exec_start;
-       if (unlikely((s64)delta_exec < 0))
-               delta_exec = 0;
+       if (unlikely((s64)delta_exec <= 0))
+               return;
 
        schedstat_set(curr->se.statistics.exec_max,
                      max(curr->se.statistics.exec_max, delta_exec));
@@ -627,11 +650,13 @@ static void update_curr_dl(struct rq *rq)
                struct rt_rq *rt_rq = &rq->rt;
 
                raw_spin_lock(&rt_rq->rt_runtime_lock);
-               rt_rq->rt_time += delta_exec;
                /*
                 * We'll let actual RT tasks worry about the overflow here, we
-                * have our own CBS to keep us inline -- see above.
+                * have our own CBS to keep us inline; only account when RT
+                * bandwidth is relevant.
                 */
+               if (sched_rt_bandwidth_account(rt_rq))
+                       rt_rq->rt_time += delta_exec;
                raw_spin_unlock(&rt_rq->rt_runtime_lock);
        }
 }
@@ -940,6 +965,8 @@ static void check_preempt_equal_dl(struct rq *rq, struct task_struct *p)
        resched_task(rq->curr);
 }
 
+static int pull_dl_task(struct rq *this_rq);
+
 #endif /* CONFIG_SMP */
 
 /*
@@ -986,7 +1013,7 @@ static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq,
        return rb_entry(left, struct sched_dl_entity, rb_node);
 }
 
-struct task_struct *pick_next_task_dl(struct rq *rq)
+struct task_struct *pick_next_task_dl(struct rq *rq, struct task_struct *prev)
 {
        struct sched_dl_entity *dl_se;
        struct task_struct *p;
@@ -994,9 +1021,20 @@ struct task_struct *pick_next_task_dl(struct rq *rq)
 
        dl_rq = &rq->dl;
 
+       if (need_pull_dl_task(rq, prev))
+               pull_dl_task(rq);
+       /*
+        * When prev is DL, we may throttle it in put_prev_task().
+        * So, we update time before we check for dl_nr_running.
+        */
+       if (prev->sched_class == &dl_sched_class)
+               update_curr_dl(rq);
+
        if (unlikely(!dl_rq->dl_nr_running))
                return NULL;
 
+       put_prev_task(rq, prev);
+
        dl_se = pick_next_dl_entity(rq, dl_rq);
        BUG_ON(!dl_se);
 
@@ -1011,9 +1049,7 @@ struct task_struct *pick_next_task_dl(struct rq *rq)
                start_hrtick_dl(rq, p);
 #endif
 
-#ifdef CONFIG_SMP
-       rq->post_schedule = has_pushable_dl_tasks(rq);
-#endif /* CONFIG_SMP */
+       set_post_schedule(rq);
 
        return p;
 }
@@ -1422,13 +1458,6 @@ skip:
        return ret;
 }
 
-static void pre_schedule_dl(struct rq *rq, struct task_struct *prev)
-{
-       /* Try to pull other tasks here */
-       if (dl_task(prev))
-               pull_dl_task(rq);
-}
-
 static void post_schedule_dl(struct rq *rq)
 {
        push_dl_tasks(rq);
@@ -1556,7 +1585,7 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
        if (unlikely(p->dl.dl_throttled))
                return;
 
-       if (p->on_rq || rq->curr != p) {
+       if (p->on_rq && rq->curr != p) {
 #ifdef CONFIG_SMP
                if (rq->dl.overloaded && push_dl_task(rq) && rq != task_rq(p))
                        /* Only reschedule if pushing failed */
@@ -1621,7 +1650,6 @@ const struct sched_class dl_sched_class = {
        .set_cpus_allowed       = set_cpus_allowed_dl,
        .rq_online              = rq_online_dl,
        .rq_offline             = rq_offline_dl,
-       .pre_schedule           = pre_schedule_dl,
        .post_schedule          = post_schedule_dl,
        .task_woken             = task_woken_dl,
 #endif
index dd52e7ffb10ed3e16dd36ca01a08e9438fcd7872..f3344c31632aee78050316de3138fbe69280d027 100644 (file)
@@ -321,6 +321,7 @@ do {                                                                        \
        P(sched_goidle);
 #ifdef CONFIG_SMP
        P64(avg_idle);
+       P64(max_idle_balance_cost);
 #endif
 
        P(ttwu_count);
@@ -533,15 +534,15 @@ static void sched_show_numa(struct task_struct *p, struct seq_file *m)
                        unsigned long nr_faults = -1;
                        int cpu_current, home_node;
 
-                       if (p->numa_faults)
-                               nr_faults = p->numa_faults[2*node + i];
+                       if (p->numa_faults_memory)
+                               nr_faults = p->numa_faults_memory[2*node + i];
 
                        cpu_current = !i ? (task_node(p) == node) :
                                (pol && node_isset(node, pol->v.nodes));
 
                        home_node = (p->numa_preferred_nid == node);
 
-                       SEQ_printf(m, "numa_faults, %d, %d, %d, %d, %ld\n",
+                       SEQ_printf(m, "numa_faults_memory, %d, %d, %d, %d, %ld\n",
                                i, node, cpu_current, home_node, nr_faults);
                }
        }
index 78157099b167c64f034c8c3348c02eaeb41c888a..7e9bd0b1fa9ef1aa16880a5a10601374c7bb618b 100644 (file)
@@ -322,13 +322,13 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
        list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
 
 /* Do the two (enqueued) entities belong to the same group ? */
-static inline int
+static inline struct cfs_rq *
 is_same_group(struct sched_entity *se, struct sched_entity *pse)
 {
        if (se->cfs_rq == pse->cfs_rq)
-               return 1;
+               return se->cfs_rq;
 
-       return 0;
+       return NULL;
 }
 
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
@@ -336,17 +336,6 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se)
        return se->parent;
 }
 
-/* return depth at which a sched entity is present in the hierarchy */
-static inline int depth_se(struct sched_entity *se)
-{
-       int depth = 0;
-
-       for_each_sched_entity(se)
-               depth++;
-
-       return depth;
-}
-
 static void
 find_matching_se(struct sched_entity **se, struct sched_entity **pse)
 {
@@ -360,8 +349,8 @@ find_matching_se(struct sched_entity **se, struct sched_entity **pse)
         */
 
        /* First walk up until both entities are at same depth */
-       se_depth = depth_se(*se);
-       pse_depth = depth_se(*pse);
+       se_depth = (*se)->depth;
+       pse_depth = (*pse)->depth;
 
        while (se_depth > pse_depth) {
                se_depth--;
@@ -426,12 +415,6 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 #define for_each_leaf_cfs_rq(rq, cfs_rq) \
                for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
 
-static inline int
-is_same_group(struct sched_entity *se, struct sched_entity *pse)
-{
-       return 1;
-}
-
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
 {
        return NULL;
@@ -819,14 +802,6 @@ unsigned int sysctl_numa_balancing_scan_size = 256;
 /* Scan @scan_size MB every @scan_period after an initial @scan_delay in ms */
 unsigned int sysctl_numa_balancing_scan_delay = 1000;
 
-/*
- * After skipping a page migration on a shared page, skip N more numa page
- * migrations unconditionally. This reduces the number of NUMA migrations
- * in shared memory workloads, and has the effect of pulling tasks towards
- * where their memory lives, over pulling the memory towards the task.
- */
-unsigned int sysctl_numa_balancing_migrate_deferred = 16;
-
 static unsigned int task_nr_scan_windows(struct task_struct *p)
 {
        unsigned long rss = 0;
@@ -893,10 +868,26 @@ struct numa_group {
        struct list_head task_list;
 
        struct rcu_head rcu;
+       nodemask_t active_nodes;
        unsigned long total_faults;
+       /*
+        * Faults_cpu is used to decide whether memory should move
+        * towards the CPU. As a consequence, these stats are weighted
+        * more by CPU use than by memory faults.
+        */
+       unsigned long *faults_cpu;
        unsigned long faults[0];
 };
 
+/* Shared or private faults. */
+#define NR_NUMA_HINT_FAULT_TYPES 2
+
+/* Memory and CPU locality */
+#define NR_NUMA_HINT_FAULT_STATS (NR_NUMA_HINT_FAULT_TYPES * 2)
+
+/* Averaged statistics, and temporary buffers. */
+#define NR_NUMA_HINT_FAULT_BUCKETS (NR_NUMA_HINT_FAULT_STATS * 2)
+
 pid_t task_numa_group_id(struct task_struct *p)
 {
        return p->numa_group ? p->numa_group->gid : 0;
@@ -904,16 +895,16 @@ pid_t task_numa_group_id(struct task_struct *p)
 
 static inline int task_faults_idx(int nid, int priv)
 {
-       return 2 * nid + priv;
+       return NR_NUMA_HINT_FAULT_TYPES * nid + priv;
 }
 
 static inline unsigned long task_faults(struct task_struct *p, int nid)
 {
-       if (!p->numa_faults)
+       if (!p->numa_faults_memory)
                return 0;
 
-       return p->numa_faults[task_faults_idx(nid, 0)] +
-               p->numa_faults[task_faults_idx(nid, 1)];
+       return p->numa_faults_memory[task_faults_idx(nid, 0)] +
+               p->numa_faults_memory[task_faults_idx(nid, 1)];
 }
 
 static inline unsigned long group_faults(struct task_struct *p, int nid)
@@ -925,6 +916,12 @@ static inline unsigned long group_faults(struct task_struct *p, int nid)
                p->numa_group->faults[task_faults_idx(nid, 1)];
 }
 
+static inline unsigned long group_faults_cpu(struct numa_group *group, int nid)
+{
+       return group->faults_cpu[task_faults_idx(nid, 0)] +
+               group->faults_cpu[task_faults_idx(nid, 1)];
+}
+
 /*
  * These return the fraction of accesses done by a particular task, or
  * task group, on a particular numa node.  The group weight is given a
@@ -935,7 +932,7 @@ static inline unsigned long task_weight(struct task_struct *p, int nid)
 {
        unsigned long total_faults;
 
-       if (!p->numa_faults)
+       if (!p->numa_faults_memory)
                return 0;
 
        total_faults = p->total_numa_faults;
@@ -954,6 +951,69 @@ static inline unsigned long group_weight(struct task_struct *p, int nid)
        return 1000 * group_faults(p, nid) / p->numa_group->total_faults;
 }
 
+bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
+                               int src_nid, int dst_cpu)
+{
+       struct numa_group *ng = p->numa_group;
+       int dst_nid = cpu_to_node(dst_cpu);
+       int last_cpupid, this_cpupid;
+
+       this_cpupid = cpu_pid_to_cpupid(dst_cpu, current->pid);
+
+       /*
+        * Multi-stage node selection is used in conjunction with a periodic
+        * migration fault to build a temporal task<->page relation. By using
+        * a two-stage filter we remove short/unlikely relations.
+        *
+        * Using P(p) ~ n_p / n_t as per frequentist probability, we can equate
+        * a task's usage of a particular page (n_p) per total usage of this
+        * page (n_t) (in a given time-span) to a probability.
+        *
+        * Our periodic faults will sample this probability and getting the
+        * same result twice in a row, given these samples are fully
+        * independent, is then given by P(n)^2, provided our sample period
+        * is sufficiently short compared to the usage pattern.
+        *
+        * This quadric squishes small probabilities, making it less likely we
+        * act on an unlikely task<->page relation.
+        */
+       last_cpupid = page_cpupid_xchg_last(page, this_cpupid);
+       if (!cpupid_pid_unset(last_cpupid) &&
+                               cpupid_to_nid(last_cpupid) != dst_nid)
+               return false;
+
+       /* Always allow migrate on private faults */
+       if (cpupid_match_pid(p, last_cpupid))
+               return true;
+
+       /* A shared fault, but p->numa_group has not been set up yet. */
+       if (!ng)
+               return true;
+
+       /*
+        * Do not migrate if the destination is not a node that
+        * is actively used by this numa group.
+        */
+       if (!node_isset(dst_nid, ng->active_nodes))
+               return false;
+
+       /*
+        * Source is a node that is not actively used by this
+        * numa group, while the destination is. Migrate.
+        */
+       if (!node_isset(src_nid, ng->active_nodes))
+               return true;
+
+       /*
+        * Both source and destination are nodes in active
+        * use by this numa group. Maximize memory bandwidth
+        * by migrating from more heavily used groups, to less
+        * heavily used ones, spreading the load around.
+        * Use a 1/4 hysteresis to avoid spurious page movement.
+        */
+       return group_faults(p, dst_nid) < (group_faults(p, src_nid) * 3 / 4);
+}
+
 static unsigned long weighted_cpuload(const int cpu);
 static unsigned long source_load(int cpu, int type);
 static unsigned long target_load(int cpu, int type);
@@ -1267,7 +1327,7 @@ static int task_numa_migrate(struct task_struct *p)
 static void numa_migrate_preferred(struct task_struct *p)
 {
        /* This task has no NUMA fault statistics yet */
-       if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults))
+       if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults_memory))
                return;
 
        /* Periodically retry migrating the task to the preferred node */
@@ -1281,6 +1341,38 @@ static void numa_migrate_preferred(struct task_struct *p)
        task_numa_migrate(p);
 }
 
+/*
+ * Find the nodes on which the workload is actively running. We do this by
+ * tracking the nodes from which NUMA hinting faults are triggered. This can
+ * be different from the set of nodes where the workload's memory is currently
+ * located.
+ *
+ * The bitmask is used to make smarter decisions on when to do NUMA page
+ * migrations, To prevent flip-flopping, and excessive page migrations, nodes
+ * are added when they cause over 6/16 of the maximum number of faults, but
+ * only removed when they drop below 3/16.
+ */
+static void update_numa_active_node_mask(struct numa_group *numa_group)
+{
+       unsigned long faults, max_faults = 0;
+       int nid;
+
+       for_each_online_node(nid) {
+               faults = group_faults_cpu(numa_group, nid);
+               if (faults > max_faults)
+                       max_faults = faults;
+       }
+
+       for_each_online_node(nid) {
+               faults = group_faults_cpu(numa_group, nid);
+               if (!node_isset(nid, numa_group->active_nodes)) {
+                       if (faults > max_faults * 6 / 16)
+                               node_set(nid, numa_group->active_nodes);
+               } else if (faults < max_faults * 3 / 16)
+                       node_clear(nid, numa_group->active_nodes);
+       }
+}
+
 /*
  * When adapting the scan rate, the period is divided into NUMA_PERIOD_SLOTS
  * increments. The more local the fault statistics are, the higher the scan
@@ -1355,11 +1447,41 @@ static void update_task_scan_period(struct task_struct *p,
        memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality));
 }
 
+/*
+ * Get the fraction of time the task has been running since the last
+ * NUMA placement cycle. The scheduler keeps similar statistics, but
+ * decays those on a 32ms period, which is orders of magnitude off
+ * from the dozens-of-seconds NUMA balancing period. Use the scheduler
+ * stats only if the task is so new there are no NUMA statistics yet.
+ */
+static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period)
+{
+       u64 runtime, delta, now;
+       /* Use the start of this time slice to avoid calculations. */
+       now = p->se.exec_start;
+       runtime = p->se.sum_exec_runtime;
+
+       if (p->last_task_numa_placement) {
+               delta = runtime - p->last_sum_exec_runtime;
+               *period = now - p->last_task_numa_placement;
+       } else {
+               delta = p->se.avg.runnable_avg_sum;
+               *period = p->se.avg.runnable_avg_period;
+       }
+
+       p->last_sum_exec_runtime = runtime;
+       p->last_task_numa_placement = now;
+
+       return delta;
+}
+
 static void task_numa_placement(struct task_struct *p)
 {
        int seq, nid, max_nid = -1, max_group_nid = -1;
        unsigned long max_faults = 0, max_group_faults = 0;
        unsigned long fault_types[2] = { 0, 0 };
+       unsigned long total_faults;
+       u64 runtime, period;
        spinlock_t *group_lock = NULL;
 
        seq = ACCESS_ONCE(p->mm->numa_scan_seq);
@@ -1368,6 +1490,10 @@ static void task_numa_placement(struct task_struct *p)
        p->numa_scan_seq = seq;
        p->numa_scan_period_max = task_scan_max(p);
 
+       total_faults = p->numa_faults_locality[0] +
+                      p->numa_faults_locality[1];
+       runtime = numa_get_avg_runtime(p, &period);
+
        /* If the task is part of a group prevent parallel updates to group stats */
        if (p->numa_group) {
                group_lock = &p->numa_group->lock;
@@ -1379,24 +1505,37 @@ static void task_numa_placement(struct task_struct *p)
                unsigned long faults = 0, group_faults = 0;
                int priv, i;
 
-               for (priv = 0; priv < 2; priv++) {
-                       long diff;
+               for (priv = 0; priv < NR_NUMA_HINT_FAULT_TYPES; priv++) {
+                       long diff, f_diff, f_weight;
 
                        i = task_faults_idx(nid, priv);
-                       diff = -p->numa_faults[i];
 
                        /* Decay existing window, copy faults since last scan */
-                       p->numa_faults[i] >>= 1;
-                       p->numa_faults[i] += p->numa_faults_buffer[i];
-                       fault_types[priv] += p->numa_faults_buffer[i];
-                       p->numa_faults_buffer[i] = 0;
+                       diff = p->numa_faults_buffer_memory[i] - p->numa_faults_memory[i] / 2;
+                       fault_types[priv] += p->numa_faults_buffer_memory[i];
+                       p->numa_faults_buffer_memory[i] = 0;
 
-                       faults += p->numa_faults[i];
-                       diff += p->numa_faults[i];
+                       /*
+                        * Normalize the faults_from, so all tasks in a group
+                        * count according to CPU use, instead of by the raw
+                        * number of faults. Tasks with little runtime have
+                        * little over-all impact on throughput, and thus their
+                        * faults are less important.
+                        */
+                       f_weight = div64_u64(runtime << 16, period + 1);
+                       f_weight = (f_weight * p->numa_faults_buffer_cpu[i]) /
+                                  (total_faults + 1);
+                       f_diff = f_weight - p->numa_faults_cpu[i] / 2;
+                       p->numa_faults_buffer_cpu[i] = 0;
+
+                       p->numa_faults_memory[i] += diff;
+                       p->numa_faults_cpu[i] += f_diff;
+                       faults += p->numa_faults_memory[i];
                        p->total_numa_faults += diff;
                        if (p->numa_group) {
                                /* safe because we can only change our own group */
                                p->numa_group->faults[i] += diff;
+                               p->numa_group->faults_cpu[i] += f_diff;
                                p->numa_group->total_faults += diff;
                                group_faults += p->numa_group->faults[i];
                        }
@@ -1416,6 +1555,7 @@ static void task_numa_placement(struct task_struct *p)
        update_task_scan_period(p, fault_types[0], fault_types[1]);
 
        if (p->numa_group) {
+               update_numa_active_node_mask(p->numa_group);
                /*
                 * If the preferred task and group nids are different,
                 * iterate over the nodes again to find the best place.
@@ -1465,7 +1605,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
 
        if (unlikely(!p->numa_group)) {
                unsigned int size = sizeof(struct numa_group) +
-                                   2*nr_node_ids*sizeof(unsigned long);
+                                   4*nr_node_ids*sizeof(unsigned long);
 
                grp = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
                if (!grp)
@@ -1475,9 +1615,14 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
                spin_lock_init(&grp->lock);
                INIT_LIST_HEAD(&grp->task_list);
                grp->gid = p->pid;
+               /* Second half of the array tracks nids where faults happen */
+               grp->faults_cpu = grp->faults + NR_NUMA_HINT_FAULT_TYPES *
+                                               nr_node_ids;
+
+               node_set(task_node(current), grp->active_nodes);
 
-               for (i = 0; i < 2*nr_node_ids; i++)
-                       grp->faults[i] = p->numa_faults[i];
+               for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
+                       grp->faults[i] = p->numa_faults_memory[i];
 
                grp->total_faults = p->total_numa_faults;
 
@@ -1534,9 +1679,9 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
 
        double_lock(&my_grp->lock, &grp->lock);
 
-       for (i = 0; i < 2*nr_node_ids; i++) {
-               my_grp->faults[i] -= p->numa_faults[i];
-               grp->faults[i] += p->numa_faults[i];
+       for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) {
+               my_grp->faults[i] -= p->numa_faults_memory[i];
+               grp->faults[i] += p->numa_faults_memory[i];
        }
        my_grp->total_faults -= p->total_numa_faults;
        grp->total_faults += p->total_numa_faults;
@@ -1562,12 +1707,12 @@ void task_numa_free(struct task_struct *p)
 {
        struct numa_group *grp = p->numa_group;
        int i;
-       void *numa_faults = p->numa_faults;
+       void *numa_faults = p->numa_faults_memory;
 
        if (grp) {
                spin_lock(&grp->lock);
-               for (i = 0; i < 2*nr_node_ids; i++)
-                       grp->faults[i] -= p->numa_faults[i];
+               for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
+                       grp->faults[i] -= p->numa_faults_memory[i];
                grp->total_faults -= p->total_numa_faults;
 
                list_del(&p->numa_entry);
@@ -1577,18 +1722,21 @@ void task_numa_free(struct task_struct *p)
                put_numa_group(grp);
        }
 
-       p->numa_faults = NULL;
-       p->numa_faults_buffer = NULL;
+       p->numa_faults_memory = NULL;
+       p->numa_faults_buffer_memory = NULL;
+       p->numa_faults_cpu= NULL;
+       p->numa_faults_buffer_cpu = NULL;
        kfree(numa_faults);
 }
 
 /*
  * Got a PROT_NONE fault for a page on @node.
  */
-void task_numa_fault(int last_cpupid, int node, int pages, int flags)
+void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
 {
        struct task_struct *p = current;
        bool migrated = flags & TNF_MIGRATED;
+       int cpu_node = task_node(current);
        int priv;
 
        if (!numabalancing_enabled)
@@ -1603,16 +1751,24 @@ void task_numa_fault(int last_cpupid, int node, int pages, int flags)
                return;
 
        /* Allocate buffer to track faults on a per-node basis */
-       if (unlikely(!p->numa_faults)) {
-               int size = sizeof(*p->numa_faults) * 2 * nr_node_ids;
+       if (unlikely(!p->numa_faults_memory)) {
+               int size = sizeof(*p->numa_faults_memory) *
+                          NR_NUMA_HINT_FAULT_BUCKETS * nr_node_ids;
 
-               /* numa_faults and numa_faults_buffer share the allocation */
-               p->numa_faults = kzalloc(size * 2, GFP_KERNEL|__GFP_NOWARN);
-               if (!p->numa_faults)
+               p->numa_faults_memory = kzalloc(size, GFP_KERNEL|__GFP_NOWARN);
+               if (!p->numa_faults_memory)
                        return;
 
-               BUG_ON(p->numa_faults_buffer);
-               p->numa_faults_buffer = p->numa_faults + (2 * nr_node_ids);
+               BUG_ON(p->numa_faults_buffer_memory);
+               /*
+                * The averaged statistics, shared & private, memory & cpu,
+                * occupy the first half of the array. The second half of the
+                * array is for current counters, which are averaged into the
+                * first set by task_numa_placement.
+                */
+               p->numa_faults_cpu = p->numa_faults_memory + (2 * nr_node_ids);
+               p->numa_faults_buffer_memory = p->numa_faults_memory + (4 * nr_node_ids);
+               p->numa_faults_buffer_cpu = p->numa_faults_memory + (6 * nr_node_ids);
                p->total_numa_faults = 0;
                memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality));
        }
@@ -1641,7 +1797,8 @@ void task_numa_fault(int last_cpupid, int node, int pages, int flags)
        if (migrated)
                p->numa_pages_migrated += pages;
 
-       p->numa_faults_buffer[task_faults_idx(node, priv)] += pages;
+       p->numa_faults_buffer_memory[task_faults_idx(mem_node, priv)] += pages;
+       p->numa_faults_buffer_cpu[task_faults_idx(cpu_node, priv)] += pages;
        p->numa_faults_locality[!!(flags & TNF_FAULT_LOCAL)] += pages;
 }
 
@@ -2219,13 +2376,20 @@ static inline void __update_group_entity_contrib(struct sched_entity *se)
                se->avg.load_avg_contrib >>= NICE_0_SHIFT;
        }
 }
-#else
+
+static inline void update_rq_runnable_avg(struct rq *rq, int runnable)
+{
+       __update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable);
+       __update_tg_runnable_avg(&rq->avg, &rq->cfs);
+}
+#else /* CONFIG_FAIR_GROUP_SCHED */
 static inline void __update_cfs_rq_tg_load_contrib(struct cfs_rq *cfs_rq,
                                                 int force_update) {}
 static inline void __update_tg_runnable_avg(struct sched_avg *sa,
                                                  struct cfs_rq *cfs_rq) {}
 static inline void __update_group_entity_contrib(struct sched_entity *se) {}
-#endif
+static inline void update_rq_runnable_avg(struct rq *rq, int runnable) {}
+#endif /* CONFIG_FAIR_GROUP_SCHED */
 
 static inline void __update_task_entity_contrib(struct sched_entity *se)
 {
@@ -2323,12 +2487,6 @@ static void update_cfs_rq_blocked_load(struct cfs_rq *cfs_rq, int force_update)
        __update_cfs_rq_tg_load_contrib(cfs_rq, force_update);
 }
 
-static inline void update_rq_runnable_avg(struct rq *rq, int runnable)
-{
-       __update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable);
-       __update_tg_runnable_avg(&rq->avg, &rq->cfs);
-}
-
 /* Add the load generated by se into cfs_rq's child load-average */
 static inline void enqueue_entity_load_avg(struct cfs_rq *cfs_rq,
                                                  struct sched_entity *se,
@@ -2416,7 +2574,10 @@ void idle_exit_fair(struct rq *this_rq)
        update_rq_runnable_avg(this_rq, 0);
 }
 
-#else
+static int idle_balance(struct rq *this_rq);
+
+#else /* CONFIG_SMP */
+
 static inline void update_entity_load_avg(struct sched_entity *se,
                                          int update_cfs_rq) {}
 static inline void update_rq_runnable_avg(struct rq *rq, int runnable) {}
@@ -2428,7 +2589,13 @@ static inline void dequeue_entity_load_avg(struct cfs_rq *cfs_rq,
                                           int sleep) {}
 static inline void update_cfs_rq_blocked_load(struct cfs_rq *cfs_rq,
                                              int force_update) {}
-#endif
+
+static inline int idle_balance(struct rq *rq)
+{
+       return 0;
+}
+
+#endif /* CONFIG_SMP */
 
 static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
@@ -2578,10 +2745,10 @@ static void __clear_buddies_last(struct sched_entity *se)
 {
        for_each_sched_entity(se) {
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
-               if (cfs_rq->last == se)
-                       cfs_rq->last = NULL;
-               else
+               if (cfs_rq->last != se)
                        break;
+
+               cfs_rq->last = NULL;
        }
 }
 
@@ -2589,10 +2756,10 @@ static void __clear_buddies_next(struct sched_entity *se)
 {
        for_each_sched_entity(se) {
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
-               if (cfs_rq->next == se)
-                       cfs_rq->next = NULL;
-               else
+               if (cfs_rq->next != se)
                        break;
+
+               cfs_rq->next = NULL;
        }
 }
 
@@ -2600,10 +2767,10 @@ static void __clear_buddies_skip(struct sched_entity *se)
 {
        for_each_sched_entity(se) {
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
-               if (cfs_rq->skip == se)
-                       cfs_rq->skip = NULL;
-               else
+               if (cfs_rq->skip != se)
                        break;
+
+               cfs_rq->skip = NULL;
        }
 }
 
@@ -2746,17 +2913,36 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
  * 3) pick the "last" process, for cache locality
  * 4) do not run the "skip" process, if something else is available
  */
-static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
+static struct sched_entity *
+pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
 {
-       struct sched_entity *se = __pick_first_entity(cfs_rq);
-       struct sched_entity *left = se;
+       struct sched_entity *left = __pick_first_entity(cfs_rq);
+       struct sched_entity *se;
+
+       /*
+        * If curr is set we have to see if its left of the leftmost entity
+        * still in the tree, provided there was anything in the tree at all.
+        */
+       if (!left || (curr && entity_before(curr, left)))
+               left = curr;
+
+       se = left; /* ideally we run the leftmost entity */
 
        /*
         * Avoid running the skip buddy, if running something else can
         * be done without getting too unfair.
         */
        if (cfs_rq->skip == se) {
-               struct sched_entity *second = __pick_next_entity(se);
+               struct sched_entity *second;
+
+               if (se == curr) {
+                       second = __pick_first_entity(cfs_rq);
+               } else {
+                       second = __pick_next_entity(se);
+                       if (!second || (curr && entity_before(curr, second)))
+                               second = curr;
+               }
+
                if (second && wakeup_preempt_entity(second, left) < 1)
                        se = second;
        }
@@ -2778,7 +2964,7 @@ static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
        return se;
 }
 
-static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq);
+static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq);
 
 static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
 {
@@ -3433,22 +3619,23 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq)
 }
 
 /* conditionally throttle active cfs_rq's from put_prev_entity() */
-static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq)
+static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq)
 {
        if (!cfs_bandwidth_used())
-               return;
+               return false;
 
        if (likely(!cfs_rq->runtime_enabled || cfs_rq->runtime_remaining > 0))
-               return;
+               return false;
 
        /*
         * it's possible for a throttled entity to be forced into a running
         * state (e.g. set_curr_task), in this case we're finished.
         */
        if (cfs_rq_throttled(cfs_rq))
-               return;
+               return true;
 
        throttle_cfs_rq(cfs_rq);
+       return true;
 }
 
 static enum hrtimer_restart sched_cfs_slack_timer(struct hrtimer *timer)
@@ -3558,7 +3745,7 @@ static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
 }
 
 static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {}
-static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
+static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) { return false; }
 static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {}
 static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
 
@@ -4213,13 +4400,14 @@ done:
 }
 
 /*
- * sched_balance_self: balance the current task (running on cpu) in domains
- * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
- * SD_BALANCE_EXEC.
+ * select_task_rq_fair: Select target runqueue for the waking task in domains
+ * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
+ * SD_BALANCE_FORK, or SD_BALANCE_EXEC.
  *
- * Balance, ie. select the least loaded group.
+ * Balances load by selecting the idlest cpu in the idlest group, or under
+ * certain conditions an idle sibling cpu if the domain has SD_WAKE_AFFINE set.
  *
- * Returns the target CPU number, or the same CPU if no balancing is needed.
+ * Returns the target cpu number.
  *
  * preempt must be disabled.
  */
@@ -4494,26 +4682,124 @@ preempt:
                set_last_buddy(se);
 }
 
-static struct task_struct *pick_next_task_fair(struct rq *rq)
+static struct task_struct *
+pick_next_task_fair(struct rq *rq, struct task_struct *prev)
 {
-       struct task_struct *p;
        struct cfs_rq *cfs_rq = &rq->cfs;
        struct sched_entity *se;
+       struct task_struct *p;
+       int new_tasks;
 
+again:
+#ifdef CONFIG_FAIR_GROUP_SCHED
        if (!cfs_rq->nr_running)
-               return NULL;
+               goto idle;
+
+       if (prev->sched_class != &fair_sched_class)
+               goto simple;
+
+       /*
+        * Because of the set_next_buddy() in dequeue_task_fair() it is rather
+        * likely that a next task is from the same cgroup as the current.
+        *
+        * Therefore attempt to avoid putting and setting the entire cgroup
+        * hierarchy, only change the part that actually changes.
+        */
+
+       do {
+               struct sched_entity *curr = cfs_rq->curr;
+
+               /*
+                * Since we got here without doing put_prev_entity() we also
+                * have to consider cfs_rq->curr. If it is still a runnable
+                * entity, update_curr() will update its vruntime, otherwise
+                * forget we've ever seen it.
+                */
+               if (curr && curr->on_rq)
+                       update_curr(cfs_rq);
+               else
+                       curr = NULL;
+
+               /*
+                * This call to check_cfs_rq_runtime() will do the throttle and
+                * dequeue its entity in the parent(s). Therefore the 'simple'
+                * nr_running test will indeed be correct.
+                */
+               if (unlikely(check_cfs_rq_runtime(cfs_rq)))
+                       goto simple;
+
+               se = pick_next_entity(cfs_rq, curr);
+               cfs_rq = group_cfs_rq(se);
+       } while (cfs_rq);
+
+       p = task_of(se);
+
+       /*
+        * Since we haven't yet done put_prev_entity and if the selected task
+        * is a different task than we started out with, try and touch the
+        * least amount of cfs_rqs.
+        */
+       if (prev != p) {
+               struct sched_entity *pse = &prev->se;
+
+               while (!(cfs_rq = is_same_group(se, pse))) {
+                       int se_depth = se->depth;
+                       int pse_depth = pse->depth;
+
+                       if (se_depth <= pse_depth) {
+                               put_prev_entity(cfs_rq_of(pse), pse);
+                               pse = parent_entity(pse);
+                       }
+                       if (se_depth >= pse_depth) {
+                               set_next_entity(cfs_rq_of(se), se);
+                               se = parent_entity(se);
+                       }
+               }
+
+               put_prev_entity(cfs_rq, pse);
+               set_next_entity(cfs_rq, se);
+       }
+
+       if (hrtick_enabled(rq))
+               hrtick_start_fair(rq, p);
+
+       return p;
+simple:
+       cfs_rq = &rq->cfs;
+#endif
+
+       if (!cfs_rq->nr_running)
+               goto idle;
+
+       put_prev_task(rq, prev);
 
        do {
-               se = pick_next_entity(cfs_rq);
+               se = pick_next_entity(cfs_rq, NULL);
                set_next_entity(cfs_rq, se);
                cfs_rq = group_cfs_rq(se);
        } while (cfs_rq);
 
        p = task_of(se);
+
        if (hrtick_enabled(rq))
                hrtick_start_fair(rq, p);
 
        return p;
+
+idle:
+       new_tasks = idle_balance(rq);
+       /*
+        * Because idle_balance() releases (and re-acquires) rq->lock, it is
+        * possible for any higher priority task to appear. In that case we
+        * must re-start the pick_next_entity() loop.
+        */
+       if (new_tasks < 0)
+               return RETRY_TASK;
+
+       if (new_tasks > 0)
+               goto again;
+
+       return NULL;
 }
 
 /*
@@ -4751,7 +5037,7 @@ static void move_task(struct task_struct *p, struct lb_env *env)
  * Is this task likely cache-hot:
  */
 static int
-task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
+task_hot(struct task_struct *p, u64 now)
 {
        s64 delta;
 
@@ -4785,7 +5071,7 @@ static bool migrate_improves_locality(struct task_struct *p, struct lb_env *env)
 {
        int src_nid, dst_nid;
 
-       if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults ||
+       if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults_memory ||
            !(env->sd->flags & SD_NUMA)) {
                return false;
        }
@@ -4816,7 +5102,7 @@ static bool migrate_degrades_locality(struct task_struct *p, struct lb_env *env)
        if (!sched_feat(NUMA) || !sched_feat(NUMA_RESIST_LOWER))
                return false;
 
-       if (!p->numa_faults || !(env->sd->flags & SD_NUMA))
+       if (!p->numa_faults_memory || !(env->sd->flags & SD_NUMA))
                return false;
 
        src_nid = cpu_to_node(env->src_cpu);
@@ -4912,7 +5198,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
         * 2) task is cache cold, or
         * 3) too many balance attempts have failed.
         */
-       tsk_cache_hot = task_hot(p, rq_clock_task(env->src_rq), env->sd);
+       tsk_cache_hot = task_hot(p, rq_clock_task(env->src_rq));
        if (!tsk_cache_hot)
                tsk_cache_hot = migrate_degrades_locality(p, env);
 
@@ -5775,12 +6061,10 @@ void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
        pwr_now /= SCHED_POWER_SCALE;
 
        /* Amount of load we'd subtract */
-       tmp = (busiest->load_per_task * SCHED_POWER_SCALE) /
-               busiest->group_power;
-       if (busiest->avg_load > tmp) {
+       if (busiest->avg_load > scaled_busy_load_per_task) {
                pwr_move += busiest->group_power *
                            min(busiest->load_per_task,
-                               busiest->avg_load - tmp);
+                               busiest->avg_load - scaled_busy_load_per_task);
        }
 
        /* Amount of load we'd add */
@@ -6359,17 +6643,23 @@ out:
  * idle_balance is called by schedule() if this_cpu is about to become
  * idle. Attempts to pull tasks from other CPUs.
  */
-void idle_balance(int this_cpu, struct rq *this_rq)
+static int idle_balance(struct rq *this_rq)
 {
        struct sched_domain *sd;
        int pulled_task = 0;
        unsigned long next_balance = jiffies + HZ;
        u64 curr_cost = 0;
+       int this_cpu = this_rq->cpu;
 
+       idle_enter_fair(this_rq);
+       /*
+        * We must set idle_stamp _before_ calling idle_balance(), such that we
+        * measure the duration of idle_balance() as idle time.
+        */
        this_rq->idle_stamp = rq_clock(this_rq);
 
        if (this_rq->avg_idle < sysctl_sched_migration_cost)
-               return;
+               goto out;
 
        /*
         * Drop the rq->lock, but keep IRQ/preempt disabled.
@@ -6407,15 +6697,22 @@ void idle_balance(int this_cpu, struct rq *this_rq)
                interval = msecs_to_jiffies(sd->balance_interval);
                if (time_after(next_balance, sd->last_balance + interval))
                        next_balance = sd->last_balance + interval;
-               if (pulled_task) {
-                       this_rq->idle_stamp = 0;
+               if (pulled_task)
                        break;
-               }
        }
        rcu_read_unlock();
 
        raw_spin_lock(&this_rq->lock);
 
+       /*
+        * While browsing the domains, we released the rq lock.
+        * A task could have be enqueued in the meantime
+        */
+       if (this_rq->cfs.h_nr_running && !pulled_task) {
+               pulled_task = 1;
+               goto out;
+       }
+
        if (pulled_task || time_after(jiffies, this_rq->next_balance)) {
                /*
                 * We are going idle. next_balance may be set based on
@@ -6426,6 +6723,20 @@ void idle_balance(int this_cpu, struct rq *this_rq)
 
        if (curr_cost > this_rq->max_idle_balance_cost)
                this_rq->max_idle_balance_cost = curr_cost;
+
+out:
+       /* Is there a task of a high priority class? */
+       if (this_rq->nr_running != this_rq->cfs.h_nr_running &&
+           (this_rq->dl.dl_nr_running ||
+            (this_rq->rt.rt_nr_running && !rt_rq_throttled(&this_rq->rt))))
+               pulled_task = -1;
+
+       if (pulled_task) {
+               idle_exit_fair(this_rq);
+               this_rq->idle_stamp = 0;
+       }
+
+       return pulled_task;
 }
 
 /*
@@ -6496,6 +6807,11 @@ out_unlock:
        return 0;
 }
 
+static inline int on_null_domain(struct rq *rq)
+{
+       return unlikely(!rcu_dereference_sched(rq->sd));
+}
+
 #ifdef CONFIG_NO_HZ_COMMON
 /*
  * idle load balancing details
@@ -6550,8 +6866,13 @@ static void nohz_balancer_kick(void)
 static inline void nohz_balance_exit_idle(int cpu)
 {
        if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
-               cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
-               atomic_dec(&nohz.nr_cpus);
+               /*
+                * Completely isolated CPUs don't ever set, so we must test.
+                */
+               if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
+                       cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
+                       atomic_dec(&nohz.nr_cpus);
+               }
                clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
        }
 }
@@ -6605,6 +6926,12 @@ void nohz_balance_enter_idle(int cpu)
        if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
                return;
 
+       /*
+        * If we're a completely isolated CPU, we don't play.
+        */
+       if (on_null_domain(cpu_rq(cpu)))
+               return;
+
        cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
        atomic_inc(&nohz.nr_cpus);
        set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
@@ -6867,11 +7194,6 @@ static void run_rebalance_domains(struct softirq_action *h)
        nohz_idle_balance(this_rq, idle);
 }
 
-static inline int on_null_domain(struct rq *rq)
-{
-       return !rcu_dereference_sched(rq->sd);
-}
-
 /*
  * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
  */
@@ -7001,15 +7323,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
        struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
        /*
-        * Ensure the task's vruntime is normalized, so that when its
+        * Ensure the task's vruntime is normalized, so that when it's
         * switched back to the fair class the enqueue_entity(.flags=0) will
         * do the right thing.
         *
-        * If it was on_rq, then the dequeue_entity(.flags=0) will already
-        * have normalized the vruntime, if it was !on_rq, then only when
+        * If it's on_rq, then the dequeue_entity(.flags=0) will already
+        * have normalized the vruntime, if it's !on_rq, then only when
         * the task is sleeping will it still have non-normalized vruntime.
         */
-       if (!se->on_rq && p->state != TASK_RUNNING) {
+       if (!p->on_rq && p->state != TASK_RUNNING) {
                /*
                 * Fix up our vruntime so that the current sleep doesn't
                 * cause 'unlimited' sleep bonus.
@@ -7036,7 +7358,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
  */
 static void switched_to_fair(struct rq *rq, struct task_struct *p)
 {
-       if (!p->se.on_rq)
+       struct sched_entity *se = &p->se;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       /*
+        * Since the real-depth could have been changed (only FAIR
+        * class maintain depth value), reset depth properly.
+        */
+       se->depth = se->parent ? se->parent->depth + 1 : 0;
+#endif
+       if (!se->on_rq)
                return;
 
        /*
@@ -7084,7 +7414,9 @@ void init_cfs_rq(struct cfs_rq *cfs_rq)
 #ifdef CONFIG_FAIR_GROUP_SCHED
 static void task_move_group_fair(struct task_struct *p, int on_rq)
 {
+       struct sched_entity *se = &p->se;
        struct cfs_rq *cfs_rq;
+
        /*
         * If the task was not on the rq at the time of this cgroup movement
         * it must have been asleep, sleeping tasks keep their ->vruntime
@@ -7110,23 +7442,24 @@ static void task_move_group_fair(struct task_struct *p, int on_rq)
         * To prevent boost or penalty in the new cfs_rq caused by delta
         * min_vruntime between the two cfs_rqs, we skip vruntime adjustment.
         */
-       if (!on_rq && (!p->se.sum_exec_runtime || p->state == TASK_WAKING))
+       if (!on_rq && (!se->sum_exec_runtime || p->state == TASK_WAKING))
                on_rq = 1;
 
        if (!on_rq)
-               p->se.vruntime -= cfs_rq_of(&p->se)->min_vruntime;
+               se->vruntime -= cfs_rq_of(se)->min_vruntime;
        set_task_rq(p, task_cpu(p));
+       se->depth = se->parent ? se->parent->depth + 1 : 0;
        if (!on_rq) {
-               cfs_rq = cfs_rq_of(&p->se);
-               p->se.vruntime += cfs_rq->min_vruntime;
+               cfs_rq = cfs_rq_of(se);
+               se->vruntime += cfs_rq->min_vruntime;
 #ifdef CONFIG_SMP
                /*
                 * migrate_task_rq_fair() will have removed our previous
                 * contribution, but we must synchronize for ongoing future
                 * decay.
                 */
-               p->se.avg.decay_count = atomic64_read(&cfs_rq->decay_counter);
-               cfs_rq->blocked_load_avg += p->se.avg.load_avg_contrib;
+               se->avg.decay_count = atomic64_read(&cfs_rq->decay_counter);
+               cfs_rq->blocked_load_avg += se->avg.load_avg_contrib;
 #endif
        }
 }
@@ -7222,10 +7555,13 @@ void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
        if (!se)
                return;
 
-       if (!parent)
+       if (!parent) {
                se->cfs_rq = &rq->cfs;
-       else
+               se->depth = 0;
+       } else {
                se->cfs_rq = parent->my_q;
+               se->depth = parent->depth + 1;
+       }
 
        se->my_q = cfs_rq;
        /* guarantee group entities always have weight */
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
new file mode 100644 (file)
index 0000000..b7976a1
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Generic entry point for the idle threads
+ */
+#include <linux/sched.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/tick.h>
+#include <linux/mm.h>
+#include <linux/stackprotector.h>
+
+#include <asm/tlb.h>
+
+#include <trace/events/power.h>
+
+static int __read_mostly cpu_idle_force_poll;
+
+void cpu_idle_poll_ctrl(bool enable)
+{
+       if (enable) {
+               cpu_idle_force_poll++;
+       } else {
+               cpu_idle_force_poll--;
+               WARN_ON_ONCE(cpu_idle_force_poll < 0);
+       }
+}
+
+#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP
+static int __init cpu_idle_poll_setup(char *__unused)
+{
+       cpu_idle_force_poll = 1;
+       return 1;
+}
+__setup("nohlt", cpu_idle_poll_setup);
+
+static int __init cpu_idle_nopoll_setup(char *__unused)
+{
+       cpu_idle_force_poll = 0;
+       return 1;
+}
+__setup("hlt", cpu_idle_nopoll_setup);
+#endif
+
+static inline int cpu_idle_poll(void)
+{
+       rcu_idle_enter();
+       trace_cpu_idle_rcuidle(0, smp_processor_id());
+       local_irq_enable();
+       while (!tif_need_resched())
+               cpu_relax();
+       trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
+       rcu_idle_exit();
+       return 1;
+}
+
+/* Weak implementations for optional arch specific functions */
+void __weak arch_cpu_idle_prepare(void) { }
+void __weak arch_cpu_idle_enter(void) { }
+void __weak arch_cpu_idle_exit(void) { }
+void __weak arch_cpu_idle_dead(void) { }
+void __weak arch_cpu_idle(void)
+{
+       cpu_idle_force_poll = 1;
+       local_irq_enable();
+}
+
+/*
+ * Generic idle loop implementation
+ */
+static void cpu_idle_loop(void)
+{
+       while (1) {
+               tick_nohz_idle_enter();
+
+               while (!need_resched()) {
+                       check_pgt_cache();
+                       rmb();
+
+                       if (cpu_is_offline(smp_processor_id()))
+                               arch_cpu_idle_dead();
+
+                       local_irq_disable();
+                       arch_cpu_idle_enter();
+
+                       /*
+                        * In poll mode we reenable interrupts and spin.
+                        *
+                        * Also if we detected in the wakeup from idle
+                        * path that the tick broadcast device expired
+                        * for us, we don't want to go deep idle as we
+                        * know that the IPI is going to arrive right
+                        * away
+                        */
+                       if (cpu_idle_force_poll || tick_check_broadcast_expired()) {
+                               cpu_idle_poll();
+                       } else {
+                               if (!current_clr_polling_and_test()) {
+                                       stop_critical_timings();
+                                       rcu_idle_enter();
+                                       if (cpuidle_idle_call())
+                                               arch_cpu_idle();
+                                       if (WARN_ON_ONCE(irqs_disabled()))
+                                               local_irq_enable();
+                                       rcu_idle_exit();
+                                       start_critical_timings();
+                               } else {
+                                       local_irq_enable();
+                               }
+                               __current_set_polling();
+                       }
+                       arch_cpu_idle_exit();
+               }
+
+               /*
+                * Since we fell out of the loop above, we know
+                * TIF_NEED_RESCHED must be set, propagate it into
+                * PREEMPT_NEED_RESCHED.
+                *
+                * This is required because for polling idle loops we will
+                * not have had an IPI to fold the state for us.
+                */
+               preempt_set_need_resched();
+               tick_nohz_idle_exit();
+               schedule_preempt_disabled();
+       }
+}
+
+void cpu_startup_entry(enum cpuhp_state state)
+{
+       /*
+        * This #ifdef needs to die, but it's too late in the cycle to
+        * make this generic (arm and sh have never invoked the canary
+        * init for the non boot cpus!). Will be fixed in 3.11
+        */
+#ifdef CONFIG_X86
+       /*
+        * If we're the non-boot CPU, nothing set the stack canary up
+        * for us. The boot CPU already has it initialized but no harm
+        * in doing it again. This is a good place for updating it, as
+        * we wont ever return from this function (so the invalid
+        * canaries already on the stack wont ever trigger).
+        */
+       boot_init_stack_canary();
+#endif
+       __current_set_polling();
+       arch_cpu_idle_prepare();
+       cpu_idle_loop();
+}
index 516c3d9ceea1455cee6c5a7b96db7f92a141f9af..879f2b75266a9933823a2056541af469cdc9c3dd 100644 (file)
@@ -13,18 +13,8 @@ select_task_rq_idle(struct task_struct *p, int cpu, int sd_flag, int flags)
 {
        return task_cpu(p); /* IDLE tasks as never migrated */
 }
-
-static void pre_schedule_idle(struct rq *rq, struct task_struct *prev)
-{
-       idle_exit_fair(rq);
-       rq_last_tick_reset(rq);
-}
-
-static void post_schedule_idle(struct rq *rq)
-{
-       idle_enter_fair(rq);
-}
 #endif /* CONFIG_SMP */
+
 /*
  * Idle tasks are unconditionally rescheduled:
  */
@@ -33,13 +23,12 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl
        resched_task(rq->idle);
 }
 
-static struct task_struct *pick_next_task_idle(struct rq *rq)
+static struct task_struct *
+pick_next_task_idle(struct rq *rq, struct task_struct *prev)
 {
+       put_prev_task(rq, prev);
+
        schedstat_inc(rq, sched_goidle);
-#ifdef CONFIG_SMP
-       /* Trigger the post schedule to do an idle_enter for CFS */
-       rq->post_schedule = 1;
-#endif
        return rq->idle;
 }
 
@@ -58,6 +47,8 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
 
 static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
 {
+       idle_exit_fair(rq);
+       rq_last_tick_reset(rq);
 }
 
 static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued)
@@ -101,8 +92,6 @@ const struct sched_class idle_sched_class = {
 
 #ifdef CONFIG_SMP
        .select_task_rq         = select_task_rq_idle,
-       .pre_schedule           = pre_schedule_idle,
-       .post_schedule          = post_schedule_idle,
 #endif
 
        .set_curr_task          = set_curr_task_idle,
index a2740b775b456ed27c56ad088007c83e1873458b..d8cdf1618551c80143e0f5fd38de556d089eb1f6 100644 (file)
@@ -229,6 +229,14 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
 
 #ifdef CONFIG_SMP
 
+static int pull_rt_task(struct rq *this_rq);
+
+static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
+{
+       /* Try to pull RT tasks here if we lower this rq's prio */
+       return rq->rt.highest_prio.curr > prev->prio;
+}
+
 static inline int rt_overloaded(struct rq *rq)
 {
        return atomic_read(&rq->rd->rto_count);
@@ -315,6 +323,15 @@ static inline int has_pushable_tasks(struct rq *rq)
        return !plist_head_empty(&rq->rt.pushable_tasks);
 }
 
+static inline void set_post_schedule(struct rq *rq)
+{
+       /*
+        * We detect this state here so that we can avoid taking the RQ
+        * lock again later if there is no need to push
+        */
+       rq->post_schedule = has_pushable_tasks(rq);
+}
+
 static void enqueue_pushable_task(struct rq *rq, struct task_struct *p)
 {
        plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks);
@@ -359,6 +376,19 @@ void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 {
 }
 
+static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
+{
+       return false;
+}
+
+static inline int pull_rt_task(struct rq *this_rq)
+{
+       return 0;
+}
+
+static inline void set_post_schedule(struct rq *rq)
+{
+}
 #endif /* CONFIG_SMP */
 
 static inline int on_rt_rq(struct sched_rt_entity *rt_se)
@@ -440,11 +470,6 @@ static void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
                dequeue_rt_entity(rt_se);
 }
 
-static inline int rt_rq_throttled(struct rt_rq *rt_rq)
-{
-       return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted;
-}
-
 static int rt_se_boosted(struct sched_rt_entity *rt_se)
 {
        struct rt_rq *rt_rq = group_rt_rq(rt_se);
@@ -515,11 +540,6 @@ static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
 {
 }
 
-static inline int rt_rq_throttled(struct rt_rq *rt_rq)
-{
-       return rt_rq->rt_throttled;
-}
-
 static inline const struct cpumask *sched_rt_period_mask(void)
 {
        return cpu_online_mask;
@@ -538,6 +558,14 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
 
 #endif /* CONFIG_RT_GROUP_SCHED */
 
+bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
+{
+       struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
+
+       return (hrtimer_active(&rt_b->rt_period_timer) ||
+               rt_rq->rt_time < rt_b->rt_runtime);
+}
+
 #ifdef CONFIG_SMP
 /*
  * We ran out of runtime, see if we can borrow some from our neighbours.
@@ -1310,15 +1338,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
 {
        struct sched_rt_entity *rt_se;
        struct task_struct *p;
-       struct rt_rq *rt_rq;
-
-       rt_rq = &rq->rt;
-
-       if (!rt_rq->rt_nr_running)
-               return NULL;
-
-       if (rt_rq_throttled(rt_rq))
-               return NULL;
+       struct rt_rq *rt_rq  = &rq->rt;
 
        do {
                rt_se = pick_next_rt_entity(rq, rt_rq);
@@ -1332,21 +1352,45 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
        return p;
 }
 
-static struct task_struct *pick_next_task_rt(struct rq *rq)
+static struct task_struct *
+pick_next_task_rt(struct rq *rq, struct task_struct *prev)
 {
-       struct task_struct *p = _pick_next_task_rt(rq);
+       struct task_struct *p;
+       struct rt_rq *rt_rq = &rq->rt;
+
+       if (need_pull_rt_task(rq, prev)) {
+               pull_rt_task(rq);
+               /*
+                * pull_rt_task() can drop (and re-acquire) rq->lock; this
+                * means a dl task can slip in, in which case we need to
+                * re-start task selection.
+                */
+               if (unlikely(rq->dl.dl_nr_running))
+                       return RETRY_TASK;
+       }
+
+       /*
+        * We may dequeue prev's rt_rq in put_prev_task().
+        * So, we update time before rt_nr_running check.
+        */
+       if (prev->sched_class == &rt_sched_class)
+               update_curr_rt(rq);
+
+       if (!rt_rq->rt_nr_running)
+               return NULL;
+
+       if (rt_rq_throttled(rt_rq))
+               return NULL;
+
+       put_prev_task(rq, prev);
+
+       p = _pick_next_task_rt(rq);
 
        /* The running task is never eligible for pushing */
        if (p)
                dequeue_pushable_task(rq, p);
 
-#ifdef CONFIG_SMP
-       /*
-        * We detect this state here so that we can avoid taking the RQ
-        * lock again later if there is no need to push
-        */
-       rq->post_schedule = has_pushable_tasks(rq);
-#endif
+       set_post_schedule(rq);
 
        return p;
 }
@@ -1716,13 +1760,6 @@ skip:
        return ret;
 }
 
-static void pre_schedule_rt(struct rq *rq, struct task_struct *prev)
-{
-       /* Try to pull RT tasks here if we lower this rq's prio */
-       if (rq->rt.highest_prio.curr > prev->prio)
-               pull_rt_task(rq);
-}
-
 static void post_schedule_rt(struct rq *rq)
 {
        push_rt_tasks(rq);
@@ -1825,7 +1862,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p)
                resched_task(rq->curr);
 }
 
-void init_sched_rt_class(void)
+void __init init_sched_rt_class(void)
 {
        unsigned int i;
 
@@ -1999,7 +2036,6 @@ const struct sched_class rt_sched_class = {
        .set_cpus_allowed       = set_cpus_allowed_rt,
        .rq_online              = rq_online_rt,
        .rq_offline             = rq_offline_rt,
-       .pre_schedule           = pre_schedule_rt,
        .post_schedule          = post_schedule_rt,
        .task_woken             = task_woken_rt,
        .switched_from          = switched_from_rt,
index f964add50f3863805f725e8fc13b447806f41022..c9007f28d3a222ca97b5fb98210b2ecc1e756b7a 100644 (file)
@@ -23,24 +23,6 @@ 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 ],
- * and back.
- */
-#define NICE_TO_PRIO(nice)     (MAX_RT_PRIO + (nice) + 20)
-#define PRIO_TO_NICE(prio)     ((prio) - MAX_RT_PRIO - 20)
-#define TASK_NICE(p)           PRIO_TO_NICE((p)->static_prio)
-
-/*
- * 'User priority' is the nice value converted to something we
- * can work with better when scaling various scheduler parameters,
- * it's a [ 0 ... 39 ] range.
- */
-#define USER_PRIO(p)           ((p)-MAX_RT_PRIO)
-#define TASK_USER_PRIO(p)      USER_PRIO((p)->static_prio)
-#define MAX_USER_PRIO          (USER_PRIO(MAX_PRIO))
-
 /*
  * Helpers for converting nanosecond timing to jiffy resolution
  */
@@ -441,6 +423,18 @@ struct rt_rq {
 #endif
 };
 
+#ifdef CONFIG_RT_GROUP_SCHED
+static inline int rt_rq_throttled(struct rt_rq *rt_rq)
+{
+       return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted;
+}
+#else
+static inline int rt_rq_throttled(struct rt_rq *rt_rq)
+{
+       return rt_rq->rt_throttled;
+}
+#endif
+
 /* Deadline class' related fields in a runqueue */
 struct dl_rq {
        /* runqueue is an rbtree, ordered by deadline */
@@ -558,11 +552,9 @@ struct rq {
 #ifdef CONFIG_FAIR_GROUP_SCHED
        /* list of leaf cfs_rq on this cpu: */
        struct list_head leaf_cfs_rq_list;
-#endif /* CONFIG_FAIR_GROUP_SCHED */
 
-#ifdef CONFIG_RT_GROUP_SCHED
-       struct list_head leaf_rt_rq_list;
-#endif
+       struct sched_avg avg;
+#endif /* CONFIG_FAIR_GROUP_SCHED */
 
        /*
         * This is part of a global counter where only the total sum
@@ -651,8 +643,6 @@ struct rq {
 #ifdef CONFIG_SMP
        struct llist_head wake_list;
 #endif
-
-       struct sched_avg avg;
 };
 
 static inline int cpu_of(struct rq *rq)
@@ -1112,6 +1102,8 @@ static const u32 prio_to_wmult[40] = {
 
 #define DEQUEUE_SLEEP          1
 
+#define RETRY_TASK             ((void *)-1UL)
+
 struct sched_class {
        const struct sched_class *next;
 
@@ -1122,14 +1114,22 @@ struct sched_class {
 
        void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
 
-       struct task_struct * (*pick_next_task) (struct rq *rq);
+       /*
+        * It is the responsibility of the pick_next_task() method that will
+        * return the next task to call put_prev_task() on the @prev task or
+        * something equivalent.
+        *
+        * May return RETRY_TASK when it finds a higher prio class has runnable
+        * tasks.
+        */
+       struct task_struct * (*pick_next_task) (struct rq *rq,
+                                               struct task_struct *prev);
        void (*put_prev_task) (struct rq *rq, struct task_struct *p);
 
 #ifdef CONFIG_SMP
        int  (*select_task_rq)(struct task_struct *p, int task_cpu, int sd_flag, int flags);
        void (*migrate_task_rq)(struct task_struct *p, int next_cpu);
 
-       void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
        void (*post_schedule) (struct rq *this_rq);
        void (*task_waking) (struct task_struct *task);
        void (*task_woken) (struct rq *this_rq, struct task_struct *task);
@@ -1159,6 +1159,11 @@ struct sched_class {
 #endif
 };
 
+static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
+{
+       prev->sched_class->put_prev_task(rq, prev);
+}
+
 #define sched_class_highest (&stop_sched_class)
 #define for_each_class(class) \
    for (class = sched_class_highest; class; class = class->next)
@@ -1175,16 +1180,14 @@ extern const struct sched_class idle_sched_class;
 extern void update_group_power(struct sched_domain *sd, int cpu);
 
 extern void trigger_load_balance(struct rq *rq);
-extern void idle_balance(int this_cpu, struct rq *this_rq);
 
 extern void idle_enter_fair(struct rq *this_rq);
 extern void idle_exit_fair(struct rq *this_rq);
 
-#else  /* CONFIG_SMP */
+#else
 
-static inline void idle_balance(int cpu, struct rq *rq)
-{
-}
+static inline void idle_enter_fair(struct rq *rq) { }
+static inline void idle_exit_fair(struct rq *rq) { }
 
 #endif
 
@@ -1213,16 +1216,6 @@ 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)
-{
-       if (unlikely(steal > NSEC_PER_SEC))
-               return div_u64(steal, TICK_NSEC);
-
-       return __iter_div_u64_rem(steal, TICK_NSEC, &steal);
-}
-#endif
-
 static inline void inc_nr_running(struct rq *rq)
 {
        rq->nr_running++;
index fdb6bb0b33561af759e24d8806776dfc0823867c..d6ce65dde5412d4b4b9d8473caf92318ba7fcb24 100644 (file)
@@ -23,16 +23,19 @@ check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
        /* we're never preempted */
 }
 
-static struct task_struct *pick_next_task_stop(struct rq *rq)
+static struct task_struct *
+pick_next_task_stop(struct rq *rq, struct task_struct *prev)
 {
        struct task_struct *stop = rq->stop;
 
-       if (stop && stop->on_rq) {
-               stop->se.exec_start = rq_clock_task(rq);
-               return stop;
-       }
+       if (!stop || !stop->on_rq)
+               return NULL;
 
-       return NULL;
+       put_prev_task(rq, prev);
+
+       stop->se.exec_start = rq_clock_task(rq);
+
+       return stop;
 }
 
 static void
index 490fcbb1dc5b41727408d28e17ae145754c2c051..b50990a5bea0220df9034f0bcc71d92e452edc78 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/smp.h>
 #include <linux/smpboot.h>
 #include <linux/tick.h>
+#include <linux/irq.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/irq.h>
index 84571e09c9079e8887f73a0f24beefe58e00ff77..01fbae5b97b765199feccfbb6f985c1309dc3475 100644 (file)
@@ -293,7 +293,7 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
         */
        smp_call_function_single(min(cpu1, cpu2),
                                 &irq_cpu_stop_queue_work,
-                                &call_args, 0);
+                                &call_args, 1);
        lg_local_unlock(&stop_cpus_lock);
        preempt_enable();
 
index c0a58be780a407a5bf350e852db1c9800c98dd34..adaeab6f7a870ae69537baebf4ca092a161d5013 100644 (file)
@@ -174,10 +174,10 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
 
        /* normalize: avoid signed division (rounding problems) */
        error = -ESRCH;
-       if (niceval < -20)
-               niceval = -20;
-       if (niceval > 19)
-               niceval = 19;
+       if (niceval < MIN_NICE)
+               niceval = MIN_NICE;
+       if (niceval > MAX_NICE)
+               niceval = MAX_NICE;
 
        rcu_read_lock();
        read_lock(&tasklist_lock);
index 49e13e1f8fe6a5e481edb3026ae20360918986c3..7754ff16f3342c42d21509437c4c8f3c110694f6 100644 (file)
@@ -385,13 +385,6 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .procname       = "numa_balancing_migrate_deferred",
-               .data           = &sysctl_numa_balancing_migrate_deferred,
-               .maxlen         = sizeof(unsigned int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-       },
        {
                .procname       = "numa_balancing",
                .data           = NULL, /* filled in by handler */
index 3ce6e8c5f3fca86b436b288194a661cfe7b80829..f448513a45ed6d59ac5e7363fa5e43dafae34820 100644 (file)
@@ -124,7 +124,7 @@ config NO_HZ_FULL
 endchoice
 
 config NO_HZ_FULL_ALL
-       bool "Full dynticks system on all CPUs by default"
+       bool "Full dynticks system on all CPUs by default (except CPU 0)"
        depends on NO_HZ_FULL
        help
          If the user doesn't pass the nohz_full boot option to
index 9250130646f510796fb2811ad7fb11483abc0040..57a413fd0ebf557b947e8fe8b38e3c180f9bfedd 100644 (file)
@@ -3,7 +3,10 @@ obj-y += timeconv.o posix-clock.o alarmtimer.o
 
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)                += clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)              += tick-common.o
-obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += tick-broadcast.o
+ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y)
+ obj-y                                         += tick-broadcast.o
+ obj-$(CONFIG_TICK_ONESHOT)                    += tick-broadcast-hrtimer.o
+endif
 obj-$(CONFIG_GENERIC_SCHED_CLOCK)              += sched_clock.o
 obj-$(CONFIG_TICK_ONESHOT)                     += tick-oneshot.o
 obj-$(CONFIG_TICK_ONESHOT)                     += tick-sched.o
index 086ad6043bcbde85bcb1755e7fa17979d696a46a..ad362c260ef40a7b744bef657aca8f4f5a4609e6 100644 (file)
@@ -439,6 +439,19 @@ void clockevents_config_and_register(struct clock_event_device *dev,
 }
 EXPORT_SYMBOL_GPL(clockevents_config_and_register);
 
+int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
+{
+       clockevents_config(dev, freq);
+
+       if (dev->mode == CLOCK_EVT_MODE_ONESHOT)
+               return clockevents_program_event(dev, dev->next_event, false);
+
+       if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
+               dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev);
+
+       return 0;
+}
+
 /**
  * clockevents_update_freq - Update frequency and reprogram a clock event device.
  * @dev:       device to modify
@@ -446,17 +459,22 @@ EXPORT_SYMBOL_GPL(clockevents_config_and_register);
  *
  * Reconfigure and reprogram a clock event device in oneshot
  * mode. Must be called on the cpu for which the device delivers per
- * cpu timer events with interrupts disabled!  Returns 0 on success,
- * -ETIME when the event is in the past.
+ * cpu timer events. If called for the broadcast device the core takes
+ * care of serialization.
+ *
+ * Returns 0 on success, -ETIME when the event is in the past.
  */
 int clockevents_update_freq(struct clock_event_device *dev, u32 freq)
 {
-       clockevents_config(dev, freq);
-
-       if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
-               return 0;
+       unsigned long flags;
+       int ret;
 
-       return clockevents_program_event(dev, dev->next_event, false);
+       local_irq_save(flags);
+       ret = tick_broadcast_update_freq(dev, freq);
+       if (ret == -ENODEV)
+               ret = __clockevents_update_freq(dev, freq);
+       local_irq_restore(flags);
+       return ret;
 }
 
 /*
@@ -524,12 +542,13 @@ void clockevents_resume(void)
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 /**
  * clockevents_notify - notification about relevant events
+ * Returns 0 on success, any other value on error
  */
-void clockevents_notify(unsigned long reason, void *arg)
+int clockevents_notify(unsigned long reason, void *arg)
 {
        struct clock_event_device *dev, *tmp;
        unsigned long flags;
-       int cpu;
+       int cpu, ret = 0;
 
        raw_spin_lock_irqsave(&clockevents_lock, flags);
 
@@ -542,7 +561,7 @@ void clockevents_notify(unsigned long reason, void *arg)
 
        case CLOCK_EVT_NOTIFY_BROADCAST_ENTER:
        case CLOCK_EVT_NOTIFY_BROADCAST_EXIT:
-               tick_broadcast_oneshot_control(reason);
+               ret = tick_broadcast_oneshot_control(reason);
                break;
 
        case CLOCK_EVT_NOTIFY_CPU_DYING:
@@ -585,6 +604,7 @@ void clockevents_notify(unsigned long reason, void *arg)
                break;
        }
        raw_spin_unlock_irqrestore(&clockevents_lock, flags);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(clockevents_notify);
 
index af8d1d4f3d55156eaae7936b1a34d8cd7141248f..419a52cecd20c4fa2cac2fab666b1be48a4e9f4b 100644 (file)
@@ -514,12 +514,13 @@ static void sync_cmos_clock(struct work_struct *work)
                next.tv_sec++;
                next.tv_nsec -= NSEC_PER_SEC;
        }
-       schedule_delayed_work(&sync_cmos_work, timespec_to_jiffies(&next));
+       queue_delayed_work(system_power_efficient_wq,
+                          &sync_cmos_work, timespec_to_jiffies(&next));
 }
 
 void ntp_notify_cmos_timer(void)
 {
-       schedule_delayed_work(&sync_cmos_work, 0);
+       queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0);
 }
 
 #else
diff --git a/kernel/time/tick-broadcast-hrtimer.c b/kernel/time/tick-broadcast-hrtimer.c
new file mode 100644 (file)
index 0000000..eb682d5
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * linux/kernel/time/tick-broadcast-hrtimer.c
+ * This file emulates a local clock event device
+ * via a pseudo clock device.
+ */
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/profile.h>
+#include <linux/clockchips.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+
+#include "tick-internal.h"
+
+static struct hrtimer bctimer;
+
+static void bc_set_mode(enum clock_event_mode mode,
+                       struct clock_event_device *bc)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /*
+                * Note, we cannot cancel the timer here as we might
+                * run into the following live lock scenario:
+                *
+                * cpu 0                cpu1
+                * lock(broadcast_lock);
+                *                      hrtimer_interrupt()
+                *                      bc_handler()
+                *                         tick_handle_oneshot_broadcast();
+                *                          lock(broadcast_lock);
+                * hrtimer_cancel()
+                *  wait_for_callback()
+                */
+               hrtimer_try_to_cancel(&bctimer);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * This is called from the guts of the broadcast code when the cpu
+ * which is about to enter idle has the earliest broadcast timer event.
+ */
+static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
+{
+       /*
+        * We try to cancel the timer first. If the callback is on
+        * flight on some other cpu then we let it handle it. If we
+        * were able to cancel the timer nothing can rearm it as we
+        * own broadcast_lock.
+        *
+        * However we can also be called from the event handler of
+        * ce_broadcast_hrtimer itself when it expires. We cannot
+        * restart the timer because we are in the callback, but we
+        * can set the expiry time and let the callback return
+        * HRTIMER_RESTART.
+        */
+       if (hrtimer_try_to_cancel(&bctimer) >= 0) {
+               hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED);
+               /* Bind the "device" to the cpu */
+               bc->bound_on = smp_processor_id();
+       } else if (bc->bound_on == smp_processor_id()) {
+               hrtimer_set_expires(&bctimer, expires);
+       }
+       return 0;
+}
+
+static struct clock_event_device ce_broadcast_hrtimer = {
+       .set_mode               = bc_set_mode,
+       .set_next_ktime         = bc_set_next,
+       .features               = CLOCK_EVT_FEAT_ONESHOT |
+                                 CLOCK_EVT_FEAT_KTIME |
+                                 CLOCK_EVT_FEAT_HRTIMER,
+       .rating                 = 0,
+       .bound_on               = -1,
+       .min_delta_ns           = 1,
+       .max_delta_ns           = KTIME_MAX,
+       .min_delta_ticks        = 1,
+       .max_delta_ticks        = ULONG_MAX,
+       .mult                   = 1,
+       .shift                  = 0,
+       .cpumask                = cpu_all_mask,
+};
+
+static enum hrtimer_restart bc_handler(struct hrtimer *t)
+{
+       ce_broadcast_hrtimer.event_handler(&ce_broadcast_hrtimer);
+
+       if (ce_broadcast_hrtimer.next_event.tv64 == KTIME_MAX)
+               return HRTIMER_NORESTART;
+
+       return HRTIMER_RESTART;
+}
+
+void tick_setup_hrtimer_broadcast(void)
+{
+       hrtimer_init(&bctimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       bctimer.function = bc_handler;
+       clockevents_register_device(&ce_broadcast_hrtimer);
+}
index 98977a57ac72d2a221ed78731b62d67a2e1778fb..64c5990fd500b86e86e9d0a92d86fa7b7b45a0b1 100644 (file)
@@ -120,6 +120,19 @@ int tick_is_broadcast_device(struct clock_event_device *dev)
        return (dev && tick_broadcast_device.evtdev == dev);
 }
 
+int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq)
+{
+       int ret = -ENODEV;
+
+       if (tick_is_broadcast_device(dev)) {
+               raw_spin_lock(&tick_broadcast_lock);
+               ret = __clockevents_update_freq(dev, freq);
+               raw_spin_unlock(&tick_broadcast_lock);
+       }
+       return ret;
+}
+
+
 static void err_broadcast(const struct cpumask *mask)
 {
        pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
@@ -272,12 +285,8 @@ static void tick_do_broadcast(struct cpumask *mask)
  */
 static void tick_do_periodic_broadcast(void)
 {
-       raw_spin_lock(&tick_broadcast_lock);
-
        cpumask_and(tmpmask, cpu_online_mask, tick_broadcast_mask);
        tick_do_broadcast(tmpmask);
-
-       raw_spin_unlock(&tick_broadcast_lock);
 }
 
 /*
@@ -287,13 +296,15 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 {
        ktime_t next;
 
+       raw_spin_lock(&tick_broadcast_lock);
+
        tick_do_periodic_broadcast();
 
        /*
         * The device is in periodic mode. No reprogramming necessary:
         */
        if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
-               return;
+               goto unlock;
 
        /*
         * Setup the next period for devices, which do not have
@@ -306,9 +317,11 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
                next = ktime_add(next, tick_period);
 
                if (!clockevents_program_event(dev, next, false))
-                       return;
+                       goto unlock;
                tick_do_periodic_broadcast();
        }
+unlock:
+       raw_spin_unlock(&tick_broadcast_lock);
 }
 
 /*
@@ -630,24 +643,61 @@ again:
        raw_spin_unlock(&tick_broadcast_lock);
 }
 
+static int broadcast_needs_cpu(struct clock_event_device *bc, int cpu)
+{
+       if (!(bc->features & CLOCK_EVT_FEAT_HRTIMER))
+               return 0;
+       if (bc->next_event.tv64 == KTIME_MAX)
+               return 0;
+       return bc->bound_on == cpu ? -EBUSY : 0;
+}
+
+static void broadcast_shutdown_local(struct clock_event_device *bc,
+                                    struct clock_event_device *dev)
+{
+       /*
+        * For hrtimer based broadcasting we cannot shutdown the cpu
+        * local device if our own event is the first one to expire or
+        * if we own the broadcast timer.
+        */
+       if (bc->features & CLOCK_EVT_FEAT_HRTIMER) {
+               if (broadcast_needs_cpu(bc, smp_processor_id()))
+                       return;
+               if (dev->next_event.tv64 < bc->next_event.tv64)
+                       return;
+       }
+       clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+}
+
+static void broadcast_move_bc(int deadcpu)
+{
+       struct clock_event_device *bc = tick_broadcast_device.evtdev;
+
+       if (!bc || !broadcast_needs_cpu(bc, deadcpu))
+               return;
+       /* This moves the broadcast assignment to this cpu */
+       clockevents_program_event(bc, bc->next_event, 1);
+}
+
 /*
  * Powerstate information: The system enters/leaves a state, where
  * affected devices might stop
+ * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
  */
-void tick_broadcast_oneshot_control(unsigned long reason)
+int tick_broadcast_oneshot_control(unsigned long reason)
 {
        struct clock_event_device *bc, *dev;
        struct tick_device *td;
        unsigned long flags;
        ktime_t now;
-       int cpu;
+       int cpu, ret = 0;
 
        /*
         * Periodic mode does not care about the enter/exit of power
         * states
         */
        if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
-               return;
+               return 0;
 
        /*
         * We are called with preemtion disabled from the depth of the
@@ -658,7 +708,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
        dev = td->evtdev;
 
        if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
-               return;
+               return 0;
 
        bc = tick_broadcast_device.evtdev;
 
@@ -666,7 +716,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
        if (reason == CLOCK_EVT_NOTIFY_BROADCAST_ENTER) {
                if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
                        WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
-                       clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+                       broadcast_shutdown_local(bc, dev);
                        /*
                         * We only reprogram the broadcast timer if we
                         * did not mark ourself in the force mask and
@@ -679,6 +729,16 @@ void tick_broadcast_oneshot_control(unsigned long reason)
                            dev->next_event.tv64 < bc->next_event.tv64)
                                tick_broadcast_set_event(bc, cpu, dev->next_event, 1);
                }
+               /*
+                * If the current CPU owns the hrtimer broadcast
+                * mechanism, it cannot go deep idle and we remove the
+                * CPU from the broadcast mask. We don't have to go
+                * through the EXIT path as the local timer is not
+                * shutdown.
+                */
+               ret = broadcast_needs_cpu(bc, cpu);
+               if (ret)
+                       cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
        } else {
                if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
                        clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
@@ -746,6 +806,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
        }
 out:
        raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
+       return ret;
 }
 
 /*
@@ -852,6 +913,8 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
        cpumask_clear_cpu(cpu, tick_broadcast_pending_mask);
        cpumask_clear_cpu(cpu, tick_broadcast_force_mask);
 
+       broadcast_move_bc(cpu);
+
        raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
index 20b2fe37d1053a21b138dbb2a7856e574c2ea9aa..015661279b682fea4fcbc3a393d9e24760bf8b34 100644 (file)
@@ -98,18 +98,19 @@ static void tick_periodic(int cpu)
 void tick_handle_periodic(struct clock_event_device *dev)
 {
        int cpu = smp_processor_id();
-       ktime_t next;
+       ktime_t next = dev->next_event;
 
        tick_periodic(cpu);
 
        if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
                return;
-       /*
-        * Setup the next period for devices, which do not have
-        * periodic mode:
-        */
-       next = ktime_add(dev->next_event, tick_period);
        for (;;) {
+               /*
+                * Setup the next period for devices, which do not have
+                * periodic mode:
+                */
+               next = ktime_add(next, tick_period);
+
                if (!clockevents_program_event(dev, next, false))
                        return;
                /*
@@ -118,12 +119,11 @@ void tick_handle_periodic(struct clock_event_device *dev)
                 * to be sure we're using a real hardware clocksource.
                 * Otherwise we could get trapped in an infinite
                 * loop, as the tick_periodic() increments jiffies,
-                * when then will increment time, posibly causing
+                * which then will increment time, possibly causing
                 * the loop to trigger again and again.
                 */
                if (timekeeping_valid_for_hres())
                        tick_periodic(cpu);
-               next = ktime_add(next, tick_period);
        }
 }
 
index 8329669b51ec3d8a74897f979f8c6270a4db3f37..7ab92b19965a65934f2cd06de6f4fa34be74dce4 100644 (file)
@@ -46,7 +46,7 @@ extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
 extern void tick_resume_oneshot(void);
 # ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
-extern void tick_broadcast_oneshot_control(unsigned long reason);
+extern int tick_broadcast_oneshot_control(unsigned long reason);
 extern void tick_broadcast_switch_to_oneshot(void);
 extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
 extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
@@ -58,7 +58,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
        BUG();
 }
-static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
+static inline int tick_broadcast_oneshot_control(unsigned long reason) { return 0; }
 static inline void tick_broadcast_switch_to_oneshot(void) { }
 static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
 static inline int tick_broadcast_oneshot_active(void) { return 0; }
@@ -87,7 +87,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
        BUG();
 }
-static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
+static inline int tick_broadcast_oneshot_control(unsigned long reason) { return 0; }
 static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
 static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
 {
@@ -111,6 +111,7 @@ extern int tick_resume_broadcast(void);
 extern void tick_broadcast_init(void);
 extern void
 tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
+int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq);
 
 #else /* !BROADCAST */
 
@@ -133,6 +134,8 @@ static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
 static inline void tick_suspend_broadcast(void) { }
 static inline int tick_resume_broadcast(void) { return 0; }
 static inline void tick_broadcast_init(void) { }
+static inline int tick_broadcast_update_freq(struct clock_event_device *dev,
+                                            u32 freq) { return -ENODEV; }
 
 /*
  * Set the periodic handler in non broadcast mode
@@ -152,6 +155,8 @@ static inline int tick_device_is_functional(struct clock_event_device *dev)
        return !(dev->features & CLOCK_EVT_FEAT_DUMMY);
 }
 
+int __clockevents_update_freq(struct clock_event_device *dev, u32 freq);
+
 #endif
 
 extern void do_timer(unsigned long ticks);
index 0aa4ce81bc168e2432f8f76e1e62c0b41512d47b..5b40279ecd711d93074a33b0198dff6201c202e8 100644 (file)
@@ -1435,7 +1435,8 @@ void update_wall_time(void)
 out:
        raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
        if (clock_set)
-               clock_was_set();
+               /* Have to call _delayed version, since in irq context*/
+               clock_was_set_delayed();
 }
 
 /**
index 802433a4f5eb7a6b73fa0442d44bf7f196ad6f9b..4d54f97558df8ca830ed4b4f38e847e6d7a72878 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/seq_file.h>
 #include <linux/time.h>
 
+#include "timekeeping_internal.h"
+
 static unsigned int sleep_time_bin[32] = {0};
 
 static int tk_debug_show_sleep_time(struct seq_file *s, void *data)
index accfd241b9e5d5c67040407dfa4f3d8603851de2..87bd529879c23bb12705fa0144cff354064f91dc 100644 (file)
@@ -52,7 +52,7 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/timer.h>
 
-u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
+__visible u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
 
 EXPORT_SYMBOL(jiffies_64);
 
@@ -81,6 +81,7 @@ struct tvec_base {
        unsigned long timer_jiffies;
        unsigned long next_timer;
        unsigned long active_timers;
+       unsigned long all_timers;
        struct tvec_root tv1;
        struct tvec tv2;
        struct tvec tv3;
@@ -337,6 +338,20 @@ void set_timer_slack(struct timer_list *timer, int slack_hz)
 }
 EXPORT_SYMBOL_GPL(set_timer_slack);
 
+/*
+ * If the list is empty, catch up ->timer_jiffies to the current time.
+ * The caller must hold the tvec_base lock.  Returns true if the list
+ * was empty and therefore ->timer_jiffies was updated.
+ */
+static bool catchup_timer_jiffies(struct tvec_base *base)
+{
+       if (!base->all_timers) {
+               base->timer_jiffies = jiffies;
+               return true;
+       }
+       return false;
+}
+
 static void
 __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
 {
@@ -383,15 +398,17 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
 
 static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
 {
+       (void)catchup_timer_jiffies(base);
        __internal_add_timer(base, timer);
        /*
         * Update base->active_timers and base->next_timer
         */
        if (!tbase_get_deferrable(timer->base)) {
-               if (time_before(timer->expires, base->next_timer))
+               if (!base->active_timers++ ||
+                   time_before(timer->expires, base->next_timer))
                        base->next_timer = timer->expires;
-               base->active_timers++;
        }
+       base->all_timers++;
 }
 
 #ifdef CONFIG_TIMER_STATS
@@ -671,6 +688,8 @@ detach_expired_timer(struct timer_list *timer, struct tvec_base *base)
        detach_timer(timer, true);
        if (!tbase_get_deferrable(timer->base))
                base->active_timers--;
+       base->all_timers--;
+       (void)catchup_timer_jiffies(base);
 }
 
 static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
@@ -685,6 +704,8 @@ static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
                if (timer->expires == base->next_timer)
                        base->next_timer = base->timer_jiffies;
        }
+       base->all_timers--;
+       (void)catchup_timer_jiffies(base);
        return 1;
 }
 
@@ -739,12 +760,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
 
        debug_activate(timer, expires);
 
-       cpu = smp_processor_id();
-
-#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP)
-       if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
-               cpu = get_nohz_timer_target();
-#endif
+       cpu = get_nohz_timer_target(pinned);
        new_base = per_cpu(tvec_bases, cpu);
 
        if (base != new_base) {
@@ -939,8 +955,15 @@ void add_timer_on(struct timer_list *timer, int cpu)
         * with the timer by holding the timer base lock. This also
         * makes sure that a CPU on the way to stop its tick can not
         * evaluate the timer wheel.
+        *
+        * Spare the IPI for deferrable timers on idle targets though.
+        * The next busy ticks will take care of it. Except full dynticks
+        * require special care against races with idle_cpu(), lets deal
+        * with that later.
         */
-       wake_up_nohz_cpu(cpu);
+       if (!tbase_get_deferrable(timer->base) || tick_nohz_full_cpu(cpu))
+               wake_up_nohz_cpu(cpu);
+
        spin_unlock_irqrestore(&base->lock, flags);
 }
 EXPORT_SYMBOL_GPL(add_timer_on);
@@ -1146,6 +1169,10 @@ static inline void __run_timers(struct tvec_base *base)
        struct timer_list *timer;
 
        spin_lock_irq(&base->lock);
+       if (catchup_timer_jiffies(base)) {
+               spin_unlock_irq(&base->lock);
+               return;
+       }
        while (time_after_eq(jiffies, base->timer_jiffies)) {
                struct list_head work_list;
                struct list_head *head = &work_list;
@@ -1160,7 +1187,7 @@ static inline void __run_timers(struct tvec_base *base)
                                        !cascade(base, &base->tv4, INDEX(2)))
                        cascade(base, &base->tv5, INDEX(3));
                ++base->timer_jiffies;
-               list_replace_init(base->tv1.vec + index, &work_list);
+               list_replace_init(base->tv1.vec + index, head);
                while (!list_empty(head)) {
                        void (*fn)(unsigned long);
                        unsigned long data;
@@ -1523,9 +1550,8 @@ static int init_timers_cpu(int cpu)
                        if (!base)
                                return -ENOMEM;
 
-                       /* Make sure that tvec_base is 2 byte aligned */
-                       if (tbase_get_deferrable(base)) {
-                               WARN_ON(1);
+                       /* Make sure tvec_base has TIMER_FLAG_MASK bits free */
+                       if (WARN_ON(base != tbase_get_base(base))) {
                                kfree(base);
                                return -ENOMEM;
                        }
@@ -1559,6 +1585,7 @@ static int init_timers_cpu(int cpu)
        base->timer_jiffies = jiffies;
        base->next_timer = base->timer_jiffies;
        base->active_timers = 0;
+       base->all_timers = 0;
        return 0;
 }
 
@@ -1648,9 +1675,9 @@ void __init init_timers(void)
 
        err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
                               (void *)(long)smp_processor_id());
-       init_timer_stats();
-
        BUG_ON(err != NOTIFY_OK);
+
+       init_timer_stats();
        register_cpu_notifier(&timers_nb);
        open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
 }
diff --git a/kernel/torture.c b/kernel/torture.c
new file mode 100644 (file)
index 0000000..acc9afc
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * Common functions for in-kernel torture tests.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright (C) IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@us.ibm.com>
+ *     Based on kernel/rcu/torture.c.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/trace_clock.h>
+#include <asm/byteorder.h>
+#include <linux/torture.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
+
+static char *torture_type;
+static bool verbose;
+
+/* Mediate rmmod and system shutdown.  Concurrent rmmod & shutdown illegal! */
+#define FULLSTOP_DONTSTOP 0    /* Normal operation. */
+#define FULLSTOP_SHUTDOWN 1    /* System shutdown with torture running. */
+#define FULLSTOP_RMMOD    2    /* Normal rmmod of torture. */
+static int fullstop = FULLSTOP_RMMOD;
+static DEFINE_MUTEX(fullstop_mutex);
+static int *torture_runnable;
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+/*
+ * Variables for online-offline handling.  Only present if CPU hotplug
+ * is enabled, otherwise does nothing.
+ */
+
+static struct task_struct *onoff_task;
+static long onoff_holdoff;
+static long onoff_interval;
+static long n_offline_attempts;
+static long n_offline_successes;
+static unsigned long sum_offline;
+static int min_offline = -1;
+static int max_offline;
+static long n_online_attempts;
+static long n_online_successes;
+static unsigned long sum_online;
+static int min_online = -1;
+static int max_online;
+
+/*
+ * Execute random CPU-hotplug operations at the interval specified
+ * by the onoff_interval.
+ */
+static int
+torture_onoff(void *arg)
+{
+       int cpu;
+       unsigned long delta;
+       int maxcpu = -1;
+       DEFINE_TORTURE_RANDOM(rand);
+       int ret;
+       unsigned long starttime;
+
+       VERBOSE_TOROUT_STRING("torture_onoff task started");
+       for_each_online_cpu(cpu)
+               maxcpu = cpu;
+       WARN_ON(maxcpu < 0);
+       if (onoff_holdoff > 0) {
+               VERBOSE_TOROUT_STRING("torture_onoff begin holdoff");
+               schedule_timeout_interruptible(onoff_holdoff);
+               VERBOSE_TOROUT_STRING("torture_onoff end holdoff");
+       }
+       while (!torture_must_stop()) {
+               cpu = (torture_random(&rand) >> 4) % (maxcpu + 1);
+               if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
+                       if (verbose)
+                               pr_alert("%s" TORTURE_FLAG
+                                        "torture_onoff task: offlining %d\n",
+                                        torture_type, cpu);
+                       starttime = jiffies;
+                       n_offline_attempts++;
+                       ret = cpu_down(cpu);
+                       if (ret) {
+                               if (verbose)
+                                       pr_alert("%s" TORTURE_FLAG
+                                                "torture_onoff task: offline %d failed: errno %d\n",
+                                                torture_type, cpu, ret);
+                       } else {
+                               if (verbose)
+                                       pr_alert("%s" TORTURE_FLAG
+                                                "torture_onoff task: offlined %d\n",
+                                                torture_type, cpu);
+                               n_offline_successes++;
+                               delta = jiffies - starttime;
+                               sum_offline += delta;
+                               if (min_offline < 0) {
+                                       min_offline = delta;
+                                       max_offline = delta;
+                               }
+                               if (min_offline > delta)
+                                       min_offline = delta;
+                               if (max_offline < delta)
+                                       max_offline = delta;
+                       }
+               } else if (cpu_is_hotpluggable(cpu)) {
+                       if (verbose)
+                               pr_alert("%s" TORTURE_FLAG
+                                        "torture_onoff task: onlining %d\n",
+                                        torture_type, cpu);
+                       starttime = jiffies;
+                       n_online_attempts++;
+                       ret = cpu_up(cpu);
+                       if (ret) {
+                               if (verbose)
+                                       pr_alert("%s" TORTURE_FLAG
+                                                "torture_onoff task: online %d failed: errno %d\n",
+                                                torture_type, cpu, ret);
+                       } else {
+                               if (verbose)
+                                       pr_alert("%s" TORTURE_FLAG
+                                                "torture_onoff task: onlined %d\n",
+                                                torture_type, cpu);
+                               n_online_successes++;
+                               delta = jiffies - starttime;
+                               sum_online += delta;
+                               if (min_online < 0) {
+                                       min_online = delta;
+                                       max_online = delta;
+                               }
+                               if (min_online > delta)
+                                       min_online = delta;
+                               if (max_online < delta)
+                                       max_online = delta;
+                       }
+               }
+               schedule_timeout_interruptible(onoff_interval);
+       }
+       torture_kthread_stopping("torture_onoff");
+       return 0;
+}
+
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
+/*
+ * Initiate online-offline handling.
+ */
+int torture_onoff_init(long ooholdoff, long oointerval)
+{
+       int ret = 0;
+
+#ifdef CONFIG_HOTPLUG_CPU
+       onoff_holdoff = ooholdoff;
+       onoff_interval = oointerval;
+       if (onoff_interval <= 0)
+               return 0;
+       ret = torture_create_kthread(torture_onoff, NULL, onoff_task);
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+       return ret;
+}
+EXPORT_SYMBOL_GPL(torture_onoff_init);
+
+/*
+ * Clean up after online/offline testing.
+ */
+static void torture_onoff_cleanup(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       if (onoff_task == NULL)
+               return;
+       VERBOSE_TOROUT_STRING("Stopping torture_onoff task");
+       kthread_stop(onoff_task);
+       onoff_task = NULL;
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+}
+EXPORT_SYMBOL_GPL(torture_onoff_cleanup);
+
+/*
+ * Print online/offline testing statistics.
+ */
+char *torture_onoff_stats(char *page)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       page += sprintf(page,
+                      "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
+                      n_online_successes, n_online_attempts,
+                      n_offline_successes, n_offline_attempts,
+                      min_online, max_online,
+                      min_offline, max_offline,
+                      sum_online, sum_offline, HZ);
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+       return page;
+}
+EXPORT_SYMBOL_GPL(torture_onoff_stats);
+
+/*
+ * Were all the online/offline operations successful?
+ */
+bool torture_onoff_failures(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       return n_online_successes != n_online_attempts ||
+              n_offline_successes != n_offline_attempts;
+#else /* #ifdef CONFIG_HOTPLUG_CPU */
+       return false;
+#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
+}
+EXPORT_SYMBOL_GPL(torture_onoff_failures);
+
+#define TORTURE_RANDOM_MULT    39916801  /* prime */
+#define TORTURE_RANDOM_ADD     479001701 /* prime */
+#define TORTURE_RANDOM_REFRESH 10000
+
+/*
+ * Crude but fast random-number generator.  Uses a linear congruential
+ * generator, with occasional help from cpu_clock().
+ */
+unsigned long
+torture_random(struct torture_random_state *trsp)
+{
+       if (--trsp->trs_count < 0) {
+               trsp->trs_state += (unsigned long)local_clock();
+               trsp->trs_count = TORTURE_RANDOM_REFRESH;
+       }
+       trsp->trs_state = trsp->trs_state * TORTURE_RANDOM_MULT +
+               TORTURE_RANDOM_ADD;
+       return swahw32(trsp->trs_state);
+}
+EXPORT_SYMBOL_GPL(torture_random);
+
+/*
+ * Variables for shuffling.  The idea is to ensure that each CPU stays
+ * idle for an extended period to test interactions with dyntick idle,
+ * as well as interactions with any per-CPU varibles.
+ */
+struct shuffle_task {
+       struct list_head st_l;
+       struct task_struct *st_t;
+};
+
+static long shuffle_interval;  /* In jiffies. */
+static struct task_struct *shuffler_task;
+static cpumask_var_t shuffle_tmp_mask;
+static int shuffle_idle_cpu;   /* Force all torture tasks off this CPU */
+static struct list_head shuffle_task_list = LIST_HEAD_INIT(shuffle_task_list);
+static DEFINE_MUTEX(shuffle_task_mutex);
+
+/*
+ * Register a task to be shuffled.  If there is no memory, just splat
+ * and don't bother registering.
+ */
+void torture_shuffle_task_register(struct task_struct *tp)
+{
+       struct shuffle_task *stp;
+
+       if (WARN_ON_ONCE(tp == NULL))
+               return;
+       stp = kmalloc(sizeof(*stp), GFP_KERNEL);
+       if (WARN_ON_ONCE(stp == NULL))
+               return;
+       stp->st_t = tp;
+       mutex_lock(&shuffle_task_mutex);
+       list_add(&stp->st_l, &shuffle_task_list);
+       mutex_unlock(&shuffle_task_mutex);
+}
+EXPORT_SYMBOL_GPL(torture_shuffle_task_register);
+
+/*
+ * Unregister all tasks, for example, at the end of the torture run.
+ */
+static void torture_shuffle_task_unregister_all(void)
+{
+       struct shuffle_task *stp;
+       struct shuffle_task *p;
+
+       mutex_lock(&shuffle_task_mutex);
+       list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) {
+               list_del(&stp->st_l);
+               kfree(stp);
+       }
+       mutex_unlock(&shuffle_task_mutex);
+}
+
+/* Shuffle tasks such that we allow shuffle_idle_cpu to become idle.
+ * A special case is when shuffle_idle_cpu = -1, in which case we allow
+ * the tasks to run on all CPUs.
+ */
+static void torture_shuffle_tasks(void)
+{
+       struct shuffle_task *stp;
+
+       cpumask_setall(shuffle_tmp_mask);
+       get_online_cpus();
+
+       /* No point in shuffling if there is only one online CPU (ex: UP) */
+       if (num_online_cpus() == 1) {
+               put_online_cpus();
+               return;
+       }
+
+       /* Advance to the next CPU.  Upon overflow, don't idle any CPUs. */
+       shuffle_idle_cpu = cpumask_next(shuffle_idle_cpu, shuffle_tmp_mask);
+       if (shuffle_idle_cpu >= nr_cpu_ids)
+               shuffle_idle_cpu = -1;
+       if (shuffle_idle_cpu != -1) {
+               cpumask_clear_cpu(shuffle_idle_cpu, shuffle_tmp_mask);
+               if (cpumask_empty(shuffle_tmp_mask)) {
+                       put_online_cpus();
+                       return;
+               }
+       }
+
+       mutex_lock(&shuffle_task_mutex);
+       list_for_each_entry(stp, &shuffle_task_list, st_l)
+               set_cpus_allowed_ptr(stp->st_t, shuffle_tmp_mask);
+       mutex_unlock(&shuffle_task_mutex);
+
+       put_online_cpus();
+}
+
+/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
+ * system to become idle at a time and cut off its timer ticks. This is meant
+ * to test the support for such tickless idle CPU in RCU.
+ */
+static int torture_shuffle(void *arg)
+{
+       VERBOSE_TOROUT_STRING("torture_shuffle task started");
+       do {
+               schedule_timeout_interruptible(shuffle_interval);
+               torture_shuffle_tasks();
+               torture_shutdown_absorb("torture_shuffle");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("torture_shuffle");
+       return 0;
+}
+
+/*
+ * Start the shuffler, with shuffint in jiffies.
+ */
+int torture_shuffle_init(long shuffint)
+{
+       shuffle_interval = shuffint;
+
+       shuffle_idle_cpu = -1;
+
+       if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
+               VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask");
+               return -ENOMEM;
+       }
+
+       /* Create the shuffler thread */
+       return torture_create_kthread(torture_shuffle, NULL, shuffler_task);
+}
+EXPORT_SYMBOL_GPL(torture_shuffle_init);
+
+/*
+ * Stop the shuffling.
+ */
+static void torture_shuffle_cleanup(void)
+{
+       torture_shuffle_task_unregister_all();
+       if (shuffler_task) {
+               VERBOSE_TOROUT_STRING("Stopping torture_shuffle task");
+               kthread_stop(shuffler_task);
+               free_cpumask_var(shuffle_tmp_mask);
+       }
+       shuffler_task = NULL;
+}
+EXPORT_SYMBOL_GPL(torture_shuffle_cleanup);
+
+/*
+ * Variables for auto-shutdown.  This allows "lights out" torture runs
+ * to be fully scripted.
+ */
+static int shutdown_secs;              /* desired test duration in seconds. */
+static struct task_struct *shutdown_task;
+static unsigned long shutdown_time;    /* jiffies to system shutdown. */
+static void (*torture_shutdown_hook)(void);
+
+/*
+ * Absorb kthreads into a kernel function that won't return, so that
+ * they won't ever access module text or data again.
+ */
+void torture_shutdown_absorb(const char *title)
+{
+       while (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
+               pr_notice("torture thread %s parking due to system shutdown\n",
+                         title);
+               schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
+       }
+}
+EXPORT_SYMBOL_GPL(torture_shutdown_absorb);
+
+/*
+ * Cause the torture test to shutdown the system after the test has
+ * run for the time specified by the shutdown_secs parameter.
+ */
+static int torture_shutdown(void *arg)
+{
+       long delta;
+       unsigned long jiffies_snap;
+
+       VERBOSE_TOROUT_STRING("torture_shutdown task started");
+       jiffies_snap = jiffies;
+       while (ULONG_CMP_LT(jiffies_snap, shutdown_time) &&
+              !torture_must_stop()) {
+               delta = shutdown_time - jiffies_snap;
+               if (verbose)
+                       pr_alert("%s" TORTURE_FLAG
+                                "torture_shutdown task: %lu jiffies remaining\n",
+                                torture_type, delta);
+               schedule_timeout_interruptible(delta);
+               jiffies_snap = jiffies;
+       }
+       if (torture_must_stop()) {
+               torture_kthread_stopping("torture_shutdown");
+               return 0;
+       }
+
+       /* OK, shut down the system. */
+
+       VERBOSE_TOROUT_STRING("torture_shutdown task shutting down system");
+       shutdown_task = NULL;   /* Avoid self-kill deadlock. */
+       if (torture_shutdown_hook)
+               torture_shutdown_hook();
+       else
+               VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping.");
+       kernel_power_off();     /* Shut down the system. */
+       return 0;
+}
+
+/*
+ * Start up the shutdown task.
+ */
+int torture_shutdown_init(int ssecs, void (*cleanup)(void))
+{
+       int ret = 0;
+
+       shutdown_secs = ssecs;
+       torture_shutdown_hook = cleanup;
+       if (shutdown_secs > 0) {
+               shutdown_time = jiffies + shutdown_secs * HZ;
+               ret = torture_create_kthread(torture_shutdown, NULL,
+                                            shutdown_task);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(torture_shutdown_init);
+
+/*
+ * Detect and respond to a system shutdown.
+ */
+static int torture_shutdown_notify(struct notifier_block *unused1,
+                                  unsigned long unused2, void *unused3)
+{
+       mutex_lock(&fullstop_mutex);
+       if (ACCESS_ONCE(fullstop) == FULLSTOP_DONTSTOP) {
+               VERBOSE_TOROUT_STRING("Unscheduled system shutdown detected");
+               ACCESS_ONCE(fullstop) = FULLSTOP_SHUTDOWN;
+       } else {
+               pr_warn("Concurrent rmmod and shutdown illegal!\n");
+       }
+       mutex_unlock(&fullstop_mutex);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block torture_shutdown_nb = {
+       .notifier_call = torture_shutdown_notify,
+};
+
+/*
+ * Shut down the shutdown task.  Say what???  Heh!  This can happen if
+ * the torture module gets an rmmod before the shutdown time arrives.  ;-)
+ */
+static void torture_shutdown_cleanup(void)
+{
+       unregister_reboot_notifier(&torture_shutdown_nb);
+       if (shutdown_task != NULL) {
+               VERBOSE_TOROUT_STRING("Stopping torture_shutdown task");
+               kthread_stop(shutdown_task);
+       }
+       shutdown_task = NULL;
+}
+
+/*
+ * Variables for stuttering, which means to periodically pause and
+ * restart testing in order to catch bugs that appear when load is
+ * suddenly applied to or removed from the system.
+ */
+static struct task_struct *stutter_task;
+static int stutter_pause_test;
+static int stutter;
+
+/*
+ * Block until the stutter interval ends.  This must be called periodically
+ * by all running kthreads that need to be subject to stuttering.
+ */
+void stutter_wait(const char *title)
+{
+       while (ACCESS_ONCE(stutter_pause_test) ||
+              (torture_runnable && !ACCESS_ONCE(*torture_runnable))) {
+               if (stutter_pause_test)
+                       schedule_timeout_interruptible(1);
+               else
+                       schedule_timeout_interruptible(round_jiffies_relative(HZ));
+               torture_shutdown_absorb(title);
+       }
+}
+EXPORT_SYMBOL_GPL(stutter_wait);
+
+/*
+ * Cause the torture test to "stutter", starting and stopping all
+ * threads periodically.
+ */
+static int torture_stutter(void *arg)
+{
+       VERBOSE_TOROUT_STRING("torture_stutter task started");
+       do {
+               if (!torture_must_stop()) {
+                       schedule_timeout_interruptible(stutter);
+                       ACCESS_ONCE(stutter_pause_test) = 1;
+               }
+               if (!torture_must_stop())
+                       schedule_timeout_interruptible(stutter);
+               ACCESS_ONCE(stutter_pause_test) = 0;
+               torture_shutdown_absorb("torture_stutter");
+       } while (!torture_must_stop());
+       torture_kthread_stopping("torture_stutter");
+       return 0;
+}
+
+/*
+ * Initialize and kick off the torture_stutter kthread.
+ */
+int torture_stutter_init(int s)
+{
+       int ret;
+
+       stutter = s;
+       ret = torture_create_kthread(torture_stutter, NULL, stutter_task);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(torture_stutter_init);
+
+/*
+ * Cleanup after the torture_stutter kthread.
+ */
+static void torture_stutter_cleanup(void)
+{
+       if (!stutter_task)
+               return;
+       VERBOSE_TOROUT_STRING("Stopping torture_stutter task");
+       kthread_stop(stutter_task);
+       stutter_task = NULL;
+}
+
+/*
+ * Initialize torture module.  Please note that this is -not- invoked via
+ * the usual module_init() mechanism, but rather by an explicit call from
+ * the client torture module.  This call must be paired with a later
+ * torture_init_end().
+ *
+ * The runnable parameter points to a flag that controls whether or not
+ * the test is currently runnable.  If there is no such flag, pass in NULL.
+ */
+void __init torture_init_begin(char *ttype, bool v, int *runnable)
+{
+       mutex_lock(&fullstop_mutex);
+       torture_type = ttype;
+       verbose = v;
+       torture_runnable = runnable;
+       fullstop = FULLSTOP_DONTSTOP;
+
+}
+EXPORT_SYMBOL_GPL(torture_init_begin);
+
+/*
+ * Tell the torture module that initialization is complete.
+ */
+void __init torture_init_end(void)
+{
+       mutex_unlock(&fullstop_mutex);
+       register_reboot_notifier(&torture_shutdown_nb);
+}
+EXPORT_SYMBOL_GPL(torture_init_end);
+
+/*
+ * Clean up torture module.  Please note that this is -not- invoked via
+ * the usual module_exit() mechanism, but rather by an explicit call from
+ * the client torture module.  Returns true if a race with system shutdown
+ * is detected, otherwise, all kthreads started by functions in this file
+ * will be shut down.
+ *
+ * This must be called before the caller starts shutting down its own
+ * kthreads.
+ */
+bool torture_cleanup(void)
+{
+       mutex_lock(&fullstop_mutex);
+       if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
+               pr_warn("Concurrent rmmod and shutdown illegal!\n");
+               mutex_unlock(&fullstop_mutex);
+               schedule_timeout_uninterruptible(10);
+               return true;
+       }
+       ACCESS_ONCE(fullstop) = FULLSTOP_RMMOD;
+       mutex_unlock(&fullstop_mutex);
+       torture_shutdown_cleanup();
+       torture_shuffle_cleanup();
+       torture_stutter_cleanup();
+       torture_onoff_cleanup();
+       return false;
+}
+EXPORT_SYMBOL_GPL(torture_cleanup);
+
+/*
+ * Is it time for the current torture test to stop?
+ */
+bool torture_must_stop(void)
+{
+       return torture_must_stop_irq() || kthread_should_stop();
+}
+EXPORT_SYMBOL_GPL(torture_must_stop);
+
+/*
+ * Is it time for the current torture test to stop?  This is the irq-safe
+ * version, hence no check for kthread_should_stop().
+ */
+bool torture_must_stop_irq(void)
+{
+       return ACCESS_ONCE(fullstop) != FULLSTOP_DONTSTOP;
+}
+EXPORT_SYMBOL_GPL(torture_must_stop_irq);
+
+/*
+ * Each kthread must wait for kthread_should_stop() before returning from
+ * its top-level function, otherwise segfaults ensue.  This function
+ * prints a "stopping" message and waits for kthread_should_stop(), and
+ * should be called from all torture kthreads immediately prior to
+ * returning.
+ */
+void torture_kthread_stopping(char *title)
+{
+       if (verbose)
+               VERBOSE_TOROUT_STRING(title);
+       while (!kthread_should_stop()) {
+               torture_shutdown_absorb(title);
+               schedule_timeout_uninterruptible(1);
+       }
+}
+EXPORT_SYMBOL_GPL(torture_kthread_stopping);
+
+/*
+ * Create a generic torture kthread that is immediately runnable.  If you
+ * need the kthread to be stopped so that you can do something to it before
+ * it starts, you will need to open-code your own.
+ */
+int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m,
+                           char *f, struct task_struct **tp)
+{
+       int ret = 0;
+
+       VERBOSE_TOROUT_STRING(m);
+       *tp = kthread_run(fn, arg, s);
+       if (IS_ERR(*tp)) {
+               ret = PTR_ERR(*tp);
+               VERBOSE_TOROUT_ERRSTRING(f);
+               *tp = NULL;
+       }
+       torture_shuffle_task_register(*tp);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(_torture_create_kthread);
+
+/*
+ * Stop a generic kthread, emitting a message.
+ */
+void _torture_stop_kthread(char *m, struct task_struct **tp)
+{
+       if (*tp == NULL)
+               return;
+       VERBOSE_TOROUT_STRING(m);
+       kthread_stop(*tp);
+       *tp = NULL;
+}
+EXPORT_SYMBOL_GPL(_torture_stop_kthread);
index a5457d577b98313b1ca8b1670ad32a2140001498..0434ff1b808e92c539b70828185c8fa1c44c865a 100644 (file)
@@ -40,8 +40,8 @@ static int write_iteration = 50;
 module_param(write_iteration, uint, 0644);
 MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings");
 
-static int producer_nice = 19;
-static int consumer_nice = 19;
+static int producer_nice = MAX_NICE;
+static int consumer_nice = MAX_NICE;
 
 static int producer_fifo = -1;
 static int consumer_fifo = -1;
@@ -308,7 +308,7 @@ static void ring_buffer_producer(void)
 
        /* Let the user know that the test is running at low priority */
        if (producer_fifo < 0 && consumer_fifo < 0 &&
-           producer_nice == 19 && consumer_nice == 19)
+           producer_nice == MAX_NICE && consumer_nice == MAX_NICE)
                trace_printk("WARNING!!! This test is running at lowest priority.\n");
 
        trace_printk("Time:     %lld (usecs)\n", time);
index 815c878f409bd94e08777d1b9f83b1553f4a2e24..24c1f23825579df4f2bf46e2dca98e6af8fb4abd 100644 (file)
@@ -1600,15 +1600,31 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
 
+static struct ring_buffer *temp_buffer;
+
 struct ring_buffer_event *
 trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
                          struct ftrace_event_file *ftrace_file,
                          int type, unsigned long len,
                          unsigned long flags, int pc)
 {
+       struct ring_buffer_event *entry;
+
        *current_rb = ftrace_file->tr->trace_buffer.buffer;
-       return trace_buffer_lock_reserve(*current_rb,
+       entry = trace_buffer_lock_reserve(*current_rb,
                                         type, len, flags, pc);
+       /*
+        * If tracing is off, but we have triggers enabled
+        * we still need to look at the event data. Use the temp_buffer
+        * to store the trace event for the tigger to use. It's recusive
+        * safe and will not be recorded anywhere.
+        */
+       if (!entry && ftrace_file->flags & FTRACE_EVENT_FL_TRIGGER_COND) {
+               *current_rb = temp_buffer;
+               entry = trace_buffer_lock_reserve(*current_rb,
+                                                 type, len, flags, pc);
+       }
+       return entry;
 }
 EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
 
@@ -6494,11 +6510,16 @@ __init static int tracer_alloc_buffers(void)
 
        raw_spin_lock_init(&global_trace.start_lock);
 
+       /* Used for event triggers */
+       temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE);
+       if (!temp_buffer)
+               goto out_free_cpumask;
+
        /* TODO: make the number of buffers hot pluggable with CPUS */
        if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
                printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
                WARN_ON(1);
-               goto out_free_cpumask;
+               goto out_free_temp_buffer;
        }
 
        if (global_trace.buffer_disabled)
@@ -6540,6 +6561,8 @@ __init static int tracer_alloc_buffers(void)
 
        return 0;
 
+out_free_temp_buffer:
+       ring_buffer_free(temp_buffer);
 out_free_cpumask:
        free_percpu(global_trace.trace_buffer.data);
 #ifdef CONFIG_TRACER_MAX_TRACE
index e854f420e033eb65a2bca233bb8df2e42778faf7..c894614de14d8efdbbc145141d19f9a56af9a984 100644 (file)
@@ -31,9 +31,25 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
        }
 
        /* The ftrace function trace is allowed only for root. */
-       if (ftrace_event_is_function(tp_event) &&
-           perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
+       if (ftrace_event_is_function(tp_event)) {
+               if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+
+               /*
+                * We don't allow user space callchains for  function trace
+                * event, due to issues with page faults while tracing page
+                * fault handler and its overall trickiness nature.
+                */
+               if (!p_event->attr.exclude_callchain_user)
+                       return -EINVAL;
+
+               /*
+                * Same reason to disable user stack dump as for user space
+                * callchains above.
+                */
+               if (p_event->attr.sample_type & PERF_SAMPLE_STACK_USER)
+                       return -EINVAL;
+       }
 
        /* No tracing, just counting, so no obvious leak */
        if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
index e71ffd4eccb5b4d7a7b0234dd72e525b1c647550..7b16d40bd64d934d2be40e146bf8baa8e074487d 100644 (file)
 
 DEFINE_MUTEX(event_mutex);
 
-DEFINE_MUTEX(event_storage_mutex);
-EXPORT_SYMBOL_GPL(event_storage_mutex);
-
-char event_storage[EVENT_STORAGE_SIZE];
-EXPORT_SYMBOL_GPL(event_storage);
-
 LIST_HEAD(ftrace_events);
 static LIST_HEAD(ftrace_common_fields);
 
@@ -1777,6 +1771,16 @@ static void trace_module_add_events(struct module *mod)
 {
        struct ftrace_event_call **call, **start, **end;
 
+       if (!mod->num_trace_events)
+               return;
+
+       /* Don't add infrastructure for mods without tracepoints */
+       if (trace_module_has_bad_taint(mod)) {
+               pr_err("%s: module has bad taint, not creating trace events\n",
+                      mod->name);
+               return;
+       }
+
        start = mod->trace_events;
        end = mod->trace_events + mod->num_trace_events;
 
index 7c3e3e72e2b6bd2f0a6bd929ff67526497281b4a..ee0a5098ac43adca42f1631450f6f8330782cd5c 100644 (file)
@@ -95,15 +95,12 @@ static void __always_unused ____ftrace_check_##name(void)           \
 #undef __array
 #define __array(type, item, len)                                       \
        do {                                                            \
+               char *type_str = #type"["__stringify(len)"]";           \
                BUILD_BUG_ON(len > MAX_FILTER_STR_VAL);                 \
-               mutex_lock(&event_storage_mutex);                       \
-               snprintf(event_storage, sizeof(event_storage),          \
-                        "%s[%d]", #type, len);                         \
-               ret = trace_define_field(event_call, event_storage, #item, \
+               ret = trace_define_field(event_call, type_str, #item,   \
                                 offsetof(typeof(field), item),         \
                                 sizeof(field.item),                    \
                                 is_signed_type(type), filter_type);    \
-               mutex_unlock(&event_storage_mutex);                     \
                if (ret)                                                \
                        return ret;                                     \
        } while (0);
index 2aefbee93a6d574a0ea082632788a1d5c7791474..887ef88b0bc70e10463a37da502e1718385e35ca 100644 (file)
@@ -498,14 +498,14 @@ void trace_hardirqs_off(void)
 }
 EXPORT_SYMBOL(trace_hardirqs_off);
 
-void trace_hardirqs_on_caller(unsigned long caller_addr)
+__visible void trace_hardirqs_on_caller(unsigned long caller_addr)
 {
        if (!preempt_trace() && irq_trace())
                stop_critical_timing(CALLER_ADDR0, caller_addr);
 }
 EXPORT_SYMBOL(trace_hardirqs_on_caller);
 
-void trace_hardirqs_off_caller(unsigned long caller_addr)
+__visible void trace_hardirqs_off_caller(unsigned long caller_addr)
 {
        if (!preempt_trace() && irq_trace())
                start_critical_timing(CALLER_ADDR0, caller_addr);
index 29f26540e9c9550fd1c099512e7b20beb21ce234..031cc5655a514d2bcf89f930388dcddda396986f 100644 (file)
@@ -631,6 +631,11 @@ void tracepoint_iter_reset(struct tracepoint_iter *iter)
 EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
 
 #ifdef CONFIG_MODULES
+bool trace_module_has_bad_taint(struct module *mod)
+{
+       return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP));
+}
+
 static int tracepoint_module_coming(struct module *mod)
 {
        struct tp_module *tp_mod, *iter;
@@ -641,7 +646,7 @@ static int tracepoint_module_coming(struct module *mod)
         * module headers (for forced load), to make sure we don't cause a crash.
         * Staging and out-of-tree GPL modules are fine.
         */
-       if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
+       if (trace_module_has_bad_taint(mod))
                return 0;
        mutex_lock(&tracepoints_mutex);
        tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
index 193e977a10eaeb6a7f9ca5927d08f558d68df434..0ee63af30bd14a4ad7f4b8f846d19b100fd596b3 100644 (file)
@@ -516,6 +516,13 @@ void destroy_work_on_stack(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(destroy_work_on_stack);
 
+void destroy_delayed_work_on_stack(struct delayed_work *work)
+{
+       destroy_timer_on_stack(&work->timer);
+       debug_object_free(&work->work, &work_debug_descr);
+}
+EXPORT_SYMBOL_GPL(destroy_delayed_work_on_stack);
+
 #else
 static inline void debug_work_activate(struct work_struct *work) { }
 static inline void debug_work_deactivate(struct work_struct *work) { }
@@ -3225,7 +3232,7 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr,
                return -ENOMEM;
 
        if (sscanf(buf, "%d", &attrs->nice) == 1 &&
-           attrs->nice >= -20 && attrs->nice <= 19)
+           attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
                ret = apply_workqueue_attrs(wq, attrs);
        else
                ret = -EINVAL;
index a48abeac753f39ef520fbe1bc5243cb494c47621..dd7f8858188a6ac92ac19bb7ae032d62786ee612 100644 (file)
@@ -980,6 +980,21 @@ config DEBUG_LOCKING_API_SELFTESTS
          The following locking APIs are covered: spinlocks, rwlocks,
          mutexes and rwsems.
 
+config LOCK_TORTURE_TEST
+       tristate "torture tests for locking"
+       depends on DEBUG_KERNEL
+       select TORTURE_TEST
+       default n
+       help
+         This option provides a kernel module that runs torture tests
+         on kernel locking primitives.  The kernel module may be built
+         after the fact on the running kernel to be tested, if desired.
+
+         Say Y here if you want kernel locking-primitive torture tests
+         to be built into the kernel.
+         Say M if you want these torture tests to build as a module.
+         Say N if you are unsure.
+
 endmenu # lock debugging
 
 config TRACE_IRQFLAGS
@@ -1141,9 +1156,14 @@ config SPARSE_RCU_POINTER
 
         Say N if you are unsure.
 
+config TORTURE_TEST
+       tristate
+       default n
+
 config RCU_TORTURE_TEST
        tristate "torture tests for RCU"
        depends on DEBUG_KERNEL
+       select TORTURE_TEST
        default n
        help
          This option provides a kernel module that runs torture tests
index 2defd1308b045c46389a6232391999914573deb6..98f2d7e91a9114e5e124e42bef00d7935708e521 100644 (file)
@@ -424,111 +424,134 @@ void debug_dma_dump_mappings(struct device *dev)
 EXPORT_SYMBOL(debug_dma_dump_mappings);
 
 /*
- * For each page mapped (initial page in the case of
- * dma_alloc_coherent/dma_map_{single|page}, or each page in a
- * scatterlist) insert into this tree using the pfn as the key. At
+ * For each mapping (initial cacheline in the case of
+ * dma_alloc_coherent/dma_map_page, initial cacheline in each page of a
+ * scatterlist, or the cacheline specified in dma_map_single) insert
+ * into this tree using the cacheline as the key. At
  * dma_unmap_{single|sg|page} or dma_free_coherent delete the entry.  If
- * the pfn already exists at insertion time add a tag as a reference
+ * the entry already exists at insertion time add a tag as a reference
  * count for the overlapping mappings.  For now, the overlap tracking
- * just ensures that 'unmaps' balance 'maps' before marking the pfn
- * idle, but we should also be flagging overlaps as an API violation.
+ * just ensures that 'unmaps' balance 'maps' before marking the
+ * cacheline idle, but we should also be flagging overlaps as an API
+ * violation.
  *
  * Memory usage is mostly constrained by the maximum number of available
  * dma-debug entries in that we need a free dma_debug_entry before
- * inserting into the tree.  In the case of dma_map_{single|page} and
- * dma_alloc_coherent there is only one dma_debug_entry and one pfn to
- * track per event.  dma_map_sg(), on the other hand,
- * consumes a single dma_debug_entry, but inserts 'nents' entries into
- * the tree.
+ * inserting into the tree.  In the case of dma_map_page and
+ * dma_alloc_coherent there is only one dma_debug_entry and one
+ * dma_active_cacheline entry to track per event.  dma_map_sg(), on the
+ * other hand, consumes a single dma_debug_entry, but inserts 'nents'
+ * entries into the tree.
  *
  * At any time debug_dma_assert_idle() can be called to trigger a
- * warning if the given page is in the active set.
+ * warning if any cachelines in the given page are in the active set.
  */
-static RADIX_TREE(dma_active_pfn, GFP_NOWAIT);
+static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT);
 static DEFINE_SPINLOCK(radix_lock);
-#define ACTIVE_PFN_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT)
+#define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT)
 
-static int active_pfn_read_overlap(unsigned long pfn)
+static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry)
+{
+       return (entry->pfn << CACHELINE_PER_PAGE_SHIFT) +
+               (entry->offset >> L1_CACHE_SHIFT);
+}
+
+static int active_cacheline_read_overlap(phys_addr_t cln)
 {
        int overlap = 0, i;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
-               if (radix_tree_tag_get(&dma_active_pfn, pfn, i))
+               if (radix_tree_tag_get(&dma_active_cacheline, cln, i))
                        overlap |= 1 << i;
        return overlap;
 }
 
-static int active_pfn_set_overlap(unsigned long pfn, int overlap)
+static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
 {
        int i;
 
-       if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
+       if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0)
                return overlap;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
                if (overlap & 1 << i)
-                       radix_tree_tag_set(&dma_active_pfn, pfn, i);
+                       radix_tree_tag_set(&dma_active_cacheline, cln, i);
                else
-                       radix_tree_tag_clear(&dma_active_pfn, pfn, i);
+                       radix_tree_tag_clear(&dma_active_cacheline, cln, i);
 
        return overlap;
 }
 
-static void active_pfn_inc_overlap(unsigned long pfn)
+static void active_cacheline_inc_overlap(phys_addr_t cln)
 {
-       int overlap = active_pfn_read_overlap(pfn);
+       int overlap = active_cacheline_read_overlap(cln);
 
-       overlap = active_pfn_set_overlap(pfn, ++overlap);
+       overlap = active_cacheline_set_overlap(cln, ++overlap);
 
        /* If we overflowed the overlap counter then we're potentially
         * leaking dma-mappings.  Otherwise, if maps and unmaps are
         * balanced then this overflow may cause false negatives in
-        * debug_dma_assert_idle() as the pfn may be marked idle
+        * debug_dma_assert_idle() as the cacheline may be marked idle
         * prematurely.
         */
-       WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
-                 "DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
-                 ACTIVE_PFN_MAX_OVERLAP, pfn);
+       WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
+                 "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n",
+                 ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
 }
 
-static int active_pfn_dec_overlap(unsigned long pfn)
+static int active_cacheline_dec_overlap(phys_addr_t cln)
 {
-       int overlap = active_pfn_read_overlap(pfn);
+       int overlap = active_cacheline_read_overlap(cln);
 
-       return active_pfn_set_overlap(pfn, --overlap);
+       return active_cacheline_set_overlap(cln, --overlap);
 }
 
-static int active_pfn_insert(struct dma_debug_entry *entry)
+static int active_cacheline_insert(struct dma_debug_entry *entry)
 {
+       phys_addr_t cln = to_cacheline_number(entry);
        unsigned long flags;
        int rc;
 
+       /* If the device is not writing memory then we don't have any
+        * concerns about the cpu consuming stale data.  This mitigates
+        * legitimate usages of overlapping mappings.
+        */
+       if (entry->direction == DMA_TO_DEVICE)
+               return 0;
+
        spin_lock_irqsave(&radix_lock, flags);
-       rc = radix_tree_insert(&dma_active_pfn, entry->pfn, entry);
+       rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
        if (rc == -EEXIST)
-               active_pfn_inc_overlap(entry->pfn);
+               active_cacheline_inc_overlap(cln);
        spin_unlock_irqrestore(&radix_lock, flags);
 
        return rc;
 }
 
-static void active_pfn_remove(struct dma_debug_entry *entry)
+static void active_cacheline_remove(struct dma_debug_entry *entry)
 {
+       phys_addr_t cln = to_cacheline_number(entry);
        unsigned long flags;
 
+       /* ...mirror the insert case */
+       if (entry->direction == DMA_TO_DEVICE)
+               return;
+
        spin_lock_irqsave(&radix_lock, flags);
        /* since we are counting overlaps the final put of the
-        * entry->pfn will occur when the overlap count is 0.
-        * active_pfn_dec_overlap() returns -1 in that case
+        * cacheline will occur when the overlap count is 0.
+        * active_cacheline_dec_overlap() returns -1 in that case
         */
-       if (active_pfn_dec_overlap(entry->pfn) < 0)
-               radix_tree_delete(&dma_active_pfn, entry->pfn);
+       if (active_cacheline_dec_overlap(cln) < 0)
+               radix_tree_delete(&dma_active_cacheline, cln);
        spin_unlock_irqrestore(&radix_lock, flags);
 }
 
 /**
  * debug_dma_assert_idle() - assert that a page is not undergoing dma
- * @page: page to lookup in the dma_active_pfn tree
+ * @page: page to lookup in the dma_active_cacheline tree
  *
  * Place a call to this routine in cases where the cpu touching the page
  * before the dma completes (page is dma_unmapped) will lead to data
@@ -536,22 +559,38 @@ static void active_pfn_remove(struct dma_debug_entry *entry)
  */
 void debug_dma_assert_idle(struct page *page)
 {
+       static struct dma_debug_entry *ents[CACHELINES_PER_PAGE];
+       struct dma_debug_entry *entry = NULL;
+       void **results = (void **) &ents;
+       unsigned int nents, i;
        unsigned long flags;
-       struct dma_debug_entry *entry;
+       phys_addr_t cln;
 
        if (!page)
                return;
 
+       cln = (phys_addr_t) page_to_pfn(page) << CACHELINE_PER_PAGE_SHIFT;
        spin_lock_irqsave(&radix_lock, flags);
-       entry = radix_tree_lookup(&dma_active_pfn, page_to_pfn(page));
+       nents = radix_tree_gang_lookup(&dma_active_cacheline, results, cln,
+                                      CACHELINES_PER_PAGE);
+       for (i = 0; i < nents; i++) {
+               phys_addr_t ent_cln = to_cacheline_number(ents[i]);
+
+               if (ent_cln == cln) {
+                       entry = ents[i];
+                       break;
+               } else if (ent_cln >= cln + CACHELINES_PER_PAGE)
+                       break;
+       }
        spin_unlock_irqrestore(&radix_lock, flags);
 
        if (!entry)
                return;
 
+       cln = to_cacheline_number(entry);
        err_printk(entry->dev, entry,
-                  "DMA-API: cpu touching an active dma mapped page "
-                  "[pfn=0x%lx]\n", entry->pfn);
+                  "DMA-API: cpu touching an active dma mapped cacheline [cln=%pa]\n",
+                  &cln);
 }
 
 /*
@@ -568,9 +607,9 @@ static void add_dma_entry(struct dma_debug_entry *entry)
        hash_bucket_add(bucket, entry);
        put_hash_bucket(bucket, &flags);
 
-       rc = active_pfn_insert(entry);
+       rc = active_cacheline_insert(entry);
        if (rc == -ENOMEM) {
-               pr_err("DMA-API: pfn tracking ENOMEM, dma-debug disabled\n");
+               pr_err("DMA-API: cacheline tracking ENOMEM, dma-debug disabled\n");
                global_disable = true;
        }
 
@@ -631,7 +670,7 @@ static void dma_entry_free(struct dma_debug_entry *entry)
 {
        unsigned long flags;
 
-       active_pfn_remove(entry);
+       active_cacheline_remove(entry);
 
        /*
         * add to beginning of the list - this way the entries are
index 4dc1b990aa2339b572bd31d18b917dc3a1e161df..34fd931b54b53ac10c64d1320b2f54c299679ff1 100644 (file)
@@ -9,7 +9,7 @@ if FONT_SUPPORT
 
 config FONTS
        bool "Select compiled-in fonts"
-       depends on FRAMEBUFFER_CONSOLE
+       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.
@@ -22,7 +22,7 @@ config FONTS
 
 config FONT_8x8
        bool "VGA 8x8 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
+       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
@@ -45,7 +45,7 @@ config FONT_8x16
 
 config FONT_6x11
        bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        default y if !SPARC && !FONTS && MAC
        help
          Small console font with Macintosh-style high-half glyphs.  Some Mac
index 7811ed3b4e701c2e0d82368a8bae457279ca3246..bd4a8dfdf0b8052cdaedd0b3478eea4138ac100a 100644 (file)
@@ -1253,8 +1253,10 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
 
                node = indirect_to_ptr(node);
                max_index = radix_tree_maxindex(node->height);
-               if (cur_index > max_index)
+               if (cur_index > max_index) {
+                       rcu_read_unlock();
                        break;
+               }
 
                cur_index = __locate(node, item, cur_index, &found_index);
                rcu_read_unlock();
index 1e5b2df442916de82ef497f844c068724f8cd555..61489677870007e273301209438ac4913562b140 100644 (file)
@@ -244,8 +244,19 @@ static void __prandom_reseed(bool late)
        static bool latch = false;
        static DEFINE_SPINLOCK(lock);
 
+       /* Asking for random bytes might result in bytes getting
+        * moved into the nonblocking pool and thus marking it
+        * as initialized. In this case we would double back into
+        * this function and attempt to do a late reseed.
+        * Ignore the pointless attempt to reseed again if we're
+        * already waiting for bytes when the nonblocking pool
+        * got initialized.
+        */
+
        /* only allow initial seeding (late == false) once */
-       spin_lock_irqsave(&lock, flags);
+       if (!spin_trylock_irqsave(&lock, flags))
+               return;
+
        if (latch && !late)
                goto out;
        latch = true;
index e5878de4f1013ddbdd3db07d1fca2bcc3a692a7c..9b1f9062a202fc243bef05853e5b965e91f96182 100644 (file)
@@ -648,7 +648,7 @@ EXPORT_SYMBOL(memmove);
  * @count: The size of the area.
  */
 #undef memcmp
-int memcmp(const void *cs, const void *ct, size_t count)
+__visible int memcmp(const void *cs, const void *ct, size_t count)
 {
        const unsigned char *su1, *su2;
        int res = 0;
index 185b6d300ebcedb86c0214c7007716ac868c17a1..5e2cf6f342f8cac5dad0d91481c0622c36542179 100644 (file)
@@ -719,10 +719,15 @@ char *resource_string(char *buf, char *end, struct resource *res,
                specp = &mem_spec;
                decode = 0;
        }
-       p = number(p, pend, res->start, *specp);
-       if (res->start != res->end) {
-               *p++ = '-';
-               p = number(p, pend, res->end, *specp);
+       if (decode && res->flags & IORESOURCE_UNSET) {
+               p = string(p, pend, "size ", str_spec);
+               p = number(p, pend, resource_size(res), *specp);
+       } else {
+               p = number(p, pend, res->start, *specp);
+               if (res->start != res->end) {
+                       *p++ = '-';
+                       p = number(p, pend, res->end, *specp);
+               }
        }
        if (decode) {
                if (res->flags & IORESOURCE_MEM_64)
index 2d9f1504d75e26d45ddf58fe2db8c048ecbc8d83..2888024e0b0abea6b6f37f4531ad0f8dfec5c7b3 100644 (file)
@@ -575,5 +575,5 @@ config PGTABLE_MAPPING
          then you should select this. This causes zsmalloc to use page table
          mapping rather than copying for object mapping.
 
-         You can check speed with zsmalloc benchmark[1].
-         [1] https://github.com/spartacus06/zsmalloc
+         You can check speed with zsmalloc benchmark:
+         https://github.com/spartacus06/zsmapbench
index b48c5259ea33dfed9e4c08c956d8e30a36480c42..918577595ea8695298cd21ecab7acaca35b1eb92 100644 (file)
@@ -251,7 +251,6 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 {
        int nr_scanned = 0, total_isolated = 0;
        struct page *cursor, *valid_page = NULL;
-       unsigned long nr_strict_required = end_pfn - blockpfn;
        unsigned long flags;
        bool locked = false;
 
@@ -264,11 +263,12 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                nr_scanned++;
                if (!pfn_valid_within(blockpfn))
-                       continue;
+                       goto isolate_fail;
+
                if (!valid_page)
                        valid_page = page;
                if (!PageBuddy(page))
-                       continue;
+                       goto isolate_fail;
 
                /*
                 * The zone lock must be held to isolate freepages.
@@ -289,12 +289,10 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                /* Recheck this is a buddy page under lock */
                if (!PageBuddy(page))
-                       continue;
+                       goto isolate_fail;
 
                /* Found a free page, break it into order-0 pages */
                isolated = split_free_page(page);
-               if (!isolated && strict)
-                       break;
                total_isolated += isolated;
                for (i = 0; i < isolated; i++) {
                        list_add(&page->lru, freelist);
@@ -305,7 +303,15 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                if (isolated) {
                        blockpfn += isolated - 1;
                        cursor += isolated - 1;
+                       continue;
                }
+
+isolate_fail:
+               if (strict)
+                       break;
+               else
+                       continue;
+
        }
 
        trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
@@ -315,7 +321,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
         * pages requested were isolated. If there were any failures, 0 is
         * returned and CMA will fail.
         */
-       if (strict && nr_strict_required > total_isolated)
+       if (strict && blockpfn < end_pfn)
                total_isolated = 0;
 
        if (locked)
index bbc4d660221ac4e514e24d49ce140b25ad5364d2..34feba60a17e6dce30b2cdfa929926ad5a450bee 100644 (file)
 
 #include "internal.h"
 
+static int mm_counter(struct page *page)
+{
+       return PageAnon(page) ? MM_ANONPAGES : MM_FILEPAGES;
+}
+
 static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long addr, pte_t *ptep)
 {
        pte_t pte = *ptep;
+       struct page *page;
+       swp_entry_t entry;
 
        if (pte_present(pte)) {
-               struct page *page;
-
                flush_cache_page(vma, addr, pte_pfn(pte));
                pte = ptep_clear_flush(vma, addr, ptep);
                page = vm_normal_page(vma, addr, pte);
                if (page) {
                        if (pte_dirty(pte))
                                set_page_dirty(page);
+                       update_hiwater_rss(mm);
+                       dec_mm_counter(mm, mm_counter(page));
                        page_remove_rmap(page);
                        page_cache_release(page);
+               }
+       } else {        /* zap_pte() is not called when pte_none() */
+               if (!pte_file(pte)) {
                        update_hiwater_rss(mm);
-                       dec_mm_counter(mm, MM_FILEPAGES);
+                       entry = pte_to_swp_entry(pte);
+                       if (non_swap_entry(entry)) {
+                               if (is_migration_entry(entry)) {
+                                       page = migration_entry_to_page(entry);
+                                       dec_mm_counter(mm, mm_counter(page));
+                               }
+                       } else {
+                               free_swap_and_cache(entry);
+                               dec_mm_counter(mm, MM_SWAPENTS);
+                       }
                }
-       } else {
-               if (!pte_file(pte))
-                       free_swap_and_cache(pte_to_swp_entry(pte));
                pte_clear_not_present_full(mm, addr, ptep, 0);
        }
 }
index 4df39b1bde91ff9c9300db00f9df485733c064db..1546655a2d78afe4dc1c954b5e0ccff77ba3437f 100644 (file)
@@ -1961,7 +1961,7 @@ out:
        return ret;
 }
 
-#define VM_NO_THP (VM_SPECIAL|VM_MIXEDMAP|VM_HUGETLB|VM_SHARED|VM_MAYSHARE)
+#define VM_NO_THP (VM_SPECIAL | VM_HUGETLB | VM_SHARED | VM_MAYSHARE)
 
 int hugepage_madvise(struct vm_area_struct *vma,
                     unsigned long *vm_flags, int advice)
index aa4c7c7250c11a95b9676b70c7cc38f987d88717..68710e80994afed815c58b59a1a3cf421df8101f 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -444,7 +444,7 @@ static void break_cow(struct rmap_item *rmap_item)
 static struct page *page_trans_compound_anon(struct page *page)
 {
        if (PageTransCompound(page)) {
-               struct page *head = compound_trans_head(page);
+               struct page *head = compound_head(page);
                /*
                 * head may actually be splitted and freed from under
                 * us but it's ok here.
index ce7a8cc7b40417556c7e2cffd4f5172ababb57c5..5b6b0039f725032de5d63376aa0388e49bd3192d 100644 (file)
@@ -1127,8 +1127,8 @@ skip_node:
         * skipping css reference should be safe.
         */
        if (next_css) {
-               if ((next_css->flags & CSS_ONLINE) &&
-                               (next_css == &root->css || css_tryget(next_css)))
+               if ((next_css == &root->css) ||
+                   ((next_css->flags & CSS_ONLINE) && css_tryget(next_css)))
                        return mem_cgroup_from_css(next_css);
 
                prev_css = next_css;
@@ -6595,6 +6595,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
        struct mem_cgroup_event *event, *tmp;
+       struct cgroup_subsys_state *iter;
 
        /*
         * Unregister events and notify userspace.
@@ -6611,7 +6612,14 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        kmem_cgroup_css_offline(memcg);
 
        mem_cgroup_invalidate_reclaim_iterators(memcg);
-       mem_cgroup_reparent_charges(memcg);
+
+       /*
+        * This requires that offlining is serialized.  Right now that is
+        * guaranteed because css_killed_work_fn() holds the cgroup_mutex.
+        */
+       css_for_each_descendant_post(iter, css)
+               mem_cgroup_reparent_charges(mem_cgroup_from_css(iter));
+
        mem_cgroup_destroy_all_caches(memcg);
        vmpressure_cleanup(&memcg->vmpressure);
 }
index 2f2f34a4e77de18e47bc815e3fd90ace33967e55..90002ea43638cd0dd669d12092837714ec3113f3 100644 (file)
@@ -1651,7 +1651,7 @@ int soft_offline_page(struct page *page, int flags)
 {
        int ret;
        unsigned long pfn = page_to_pfn(page);
-       struct page *hpage = compound_trans_head(page);
+       struct page *hpage = compound_head(page);
 
        if (PageHWPoison(page)) {
                pr_info("soft offline: %#lx page already poisoned\n", pfn);
index ae3c8f3595d4ff522f0427b05ace2f7e041da8ad..4755c857694246ca6365a382931bcd431af9bda2 100644 (file)
@@ -1556,10 +1556,10 @@ SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
 
 #ifdef CONFIG_COMPAT
 
-asmlinkage long compat_sys_get_mempolicy(int __user *policy,
-                                    compat_ulong_t __user *nmask,
-                                    compat_ulong_t maxnode,
-                                    compat_ulong_t addr, compat_ulong_t flags)
+COMPAT_SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
+                      compat_ulong_t __user *, nmask,
+                      compat_ulong_t, maxnode,
+                      compat_ulong_t, addr, compat_ulong_t, flags)
 {
        long err;
        unsigned long __user *nm = NULL;
@@ -1586,8 +1586,8 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy,
        return err;
 }
 
-asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
-                                    compat_ulong_t maxnode)
+COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode, compat_ulong_t __user *, nmask,
+                      compat_ulong_t, maxnode)
 {
        long err = 0;
        unsigned long __user *nm = NULL;
@@ -1609,9 +1609,9 @@ asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
        return sys_set_mempolicy(mode, nm, nr_bits+1);
 }
 
-asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
-                            compat_ulong_t mode, compat_ulong_t __user *nmask,
-                            compat_ulong_t maxnode, compat_ulong_t flags)
+COMPAT_SYSCALL_DEFINE6(mbind, compat_ulong_t, start, compat_ulong_t, len,
+                      compat_ulong_t, mode, compat_ulong_t __user *, nmask,
+                      compat_ulong_t, maxnode, compat_ulong_t, flags)
 {
        long err = 0;
        unsigned long __user *nm = NULL;
@@ -2301,35 +2301,6 @@ static void sp_free(struct sp_node *n)
        kmem_cache_free(sn_cache, n);
 }
 
-#ifdef CONFIG_NUMA_BALANCING
-static bool numa_migrate_deferred(struct task_struct *p, int last_cpupid)
-{
-       /* Never defer a private fault */
-       if (cpupid_match_pid(p, last_cpupid))
-               return false;
-
-       if (p->numa_migrate_deferred) {
-               p->numa_migrate_deferred--;
-               return true;
-       }
-       return false;
-}
-
-static inline void defer_numa_migrate(struct task_struct *p)
-{
-       p->numa_migrate_deferred = sysctl_numa_balancing_migrate_deferred;
-}
-#else
-static inline bool numa_migrate_deferred(struct task_struct *p, int last_cpupid)
-{
-       return false;
-}
-
-static inline void defer_numa_migrate(struct task_struct *p)
-{
-}
-#endif /* CONFIG_NUMA_BALANCING */
-
 /**
  * mpol_misplaced - check whether current page node is valid in policy
  *
@@ -2403,52 +2374,9 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
 
        /* Migrate the page towards the node whose CPU is referencing it */
        if (pol->flags & MPOL_F_MORON) {
-               int last_cpupid;
-               int this_cpupid;
-
                polnid = thisnid;
-               this_cpupid = cpu_pid_to_cpupid(thiscpu, current->pid);
-
-               /*
-                * Multi-stage node selection is used in conjunction
-                * with a periodic migration fault to build a temporal
-                * task<->page relation. By using a two-stage filter we
-                * remove short/unlikely relations.
-                *
-                * Using P(p) ~ n_p / n_t as per frequentist
-                * probability, we can equate a task's usage of a
-                * particular page (n_p) per total usage of this
-                * page (n_t) (in a given time-span) to a probability.
-                *
-                * Our periodic faults will sample this probability and
-                * getting the same result twice in a row, given these
-                * samples are fully independent, is then given by
-                * P(n)^2, provided our sample period is sufficiently
-                * short compared to the usage pattern.
-                *
-                * This quadric squishes small probabilities, making
-                * it less likely we act on an unlikely task<->page
-                * relation.
-                */
-               last_cpupid = page_cpupid_xchg_last(page, this_cpupid);
-               if (!cpupid_pid_unset(last_cpupid) && cpupid_to_nid(last_cpupid) != thisnid) {
 
-                       /* See sysctl_numa_balancing_migrate_deferred comment */
-                       if (!cpupid_match_pid(current, last_cpupid))
-                               defer_numa_migrate(current);
-
-                       goto out;
-               }
-
-               /*
-                * The quadratic filter above reduces extraneous migration
-                * of shared pages somewhat. This code reduces it even more,
-                * reducing the overhead of page migrations of shared pages.
-                * This makes workloads with shared pages rely more on
-                * "move task near its memory", and less on "move memory
-                * towards its task", which is exactly what we want.
-                */
-               if (numa_migrate_deferred(current, last_cpupid))
+               if (!should_numa_migrate_memory(current, page, curnid, thiscpu))
                        goto out;
        }
 
index 482a33d89134fd83e15d5f6863dae57f5cb05aac..bed48809e5d01c14513a1395a12a3c4098341755 100644 (file)
@@ -177,6 +177,37 @@ out:
        return SWAP_AGAIN;
 }
 
+/*
+ * Congratulations to trinity for discovering this bug.
+ * mm/fremap.c's remap_file_pages() accepts any range within a single vma to
+ * convert that vma to VM_NONLINEAR; and generic_file_remap_pages() will then
+ * replace the specified range by file ptes throughout (maybe populated after).
+ * If page migration finds a page within that range, while it's still located
+ * by vma_interval_tree rather than lost to i_mmap_nonlinear list, no problem:
+ * zap_pte() clears the temporary migration entry before mmap_sem is dropped.
+ * But if the migrating page is in a part of the vma outside the range to be
+ * remapped, then it will not be cleared, and remove_migration_ptes() needs to
+ * deal with it.  Fortunately, this part of the vma is of course still linear,
+ * so we just need to use linear location on the nonlinear list.
+ */
+static int remove_linear_migration_ptes_from_nonlinear(struct page *page,
+               struct address_space *mapping, void *arg)
+{
+       struct vm_area_struct *vma;
+       /* hugetlbfs does not support remap_pages, so no huge pgoff worries */
+       pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+       unsigned long addr;
+
+       list_for_each_entry(vma,
+               &mapping->i_mmap_nonlinear, shared.nonlinear) {
+
+               addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+               if (addr >= vma->vm_start && addr < vma->vm_end)
+                       remove_migration_pte(page, vma, addr, arg);
+       }
+       return SWAP_AGAIN;
+}
+
 /*
  * Get rid of all migration entries and replace them by
  * references to the indicated page.
@@ -186,6 +217,7 @@ static void remove_migration_ptes(struct page *old, struct page *new)
        struct rmap_walk_control rwc = {
                .rmap_one = remove_migration_pte,
                .arg = old,
+               .file_nonlinear = remove_linear_migration_ptes_from_nonlinear,
        };
 
        rmap_walk(new, &rwc);
@@ -1158,7 +1190,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
                                        pm->node);
        else
                return alloc_pages_exact_node(pm->node,
-                               GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
+                               GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
 }
 
 /*
@@ -1544,9 +1576,9 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
        struct page *newpage;
 
        newpage = alloc_pages_exact_node(nid,
-                                        (GFP_HIGHUSER_MOVABLE | GFP_THISNODE |
-                                         __GFP_NOMEMALLOC | __GFP_NORETRY |
-                                         __GFP_NOWARN) &
+                                        (GFP_HIGHUSER_MOVABLE |
+                                         __GFP_THISNODE | __GFP_NOMEMALLOC |
+                                         __GFP_NORETRY | __GFP_NOWARN) &
                                         ~GFP_IOFS, 0);
 
        return newpage;
@@ -1747,7 +1779,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
                goto out_dropref;
 
        new_page = alloc_pages_node(node,
-               (GFP_TRANSHUGE | GFP_THISNODE) & ~__GFP_WAIT, HPAGE_PMD_ORDER);
+               (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_WAIT,
+               HPAGE_PMD_ORDER);
        if (!new_page)
                goto out_fail;
 
index 8a8cd0265e523b54909e456881a00d497fa456d3..f802c2d216a7d28bf76c5c911d83d10d213fd474 100644 (file)
@@ -31,6 +31,9 @@ void use_mm(struct mm_struct *mm)
        tsk->mm = mm;
        switch_mm(active_mm, mm, tsk);
        task_unlock(tsk);
+#ifdef finish_arch_post_lock_switch
+       finish_arch_post_lock_switch();
+#endif
 
        if (active_mm != mm)
                mmdrop(active_mm);
index e3758a09a009747bd17cb75442d0fcae69a74cc4..3bac76ae4b30ec8a62042bdff9644e87ee181d3c 100644 (file)
@@ -369,9 +369,11 @@ void prep_compound_page(struct page *page, unsigned long order)
        __SetPageHead(page);
        for (i = 1; i < nr_pages; i++) {
                struct page *p = page + i;
-               __SetPageTail(p);
                set_page_count(p, 0);
                p->first_page = page;
+               /* Make sure p->first_page is always valid for PageTail() */
+               smp_wmb();
+               __SetPageTail(p);
        }
 }
 
@@ -1236,6 +1238,15 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
        }
        local_irq_restore(flags);
 }
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+       return (gfp_mask & GFP_THISNODE) == GFP_THISNODE;
+}
+#else
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+       return false;
+}
 #endif
 
 /*
@@ -1572,7 +1583,13 @@ again:
                                          get_pageblock_migratetype(page));
        }
 
-       __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+       /*
+        * NOTE: GFP_THISNODE allocations do not partake in the kswapd
+        * aging protocol, so they can't be fair.
+        */
+       if (!gfp_thisnode_allocation(gfp_flags))
+               __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+
        __count_zone_vm_events(PGALLOC, zone, 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
@@ -1944,8 +1961,12 @@ zonelist_scan:
                 * ultimately fall back to remote zones that do not
                 * partake in the fairness round-robin cycle of this
                 * zonelist.
+                *
+                * NOTE: GFP_THISNODE allocations do not partake in
+                * the kswapd aging protocol, so they can't be fair.
                 */
-               if (alloc_flags & ALLOC_WMARK_LOW) {
+               if ((alloc_flags & ALLOC_WMARK_LOW) &&
+                   !gfp_thisnode_allocation(gfp_mask)) {
                        if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
                                continue;
                        if (!zone_local(preferred_zone, zone))
@@ -2501,8 +2522,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
         * allowed per node queues are empty and that nodes are
         * over allocated.
         */
-       if (IS_ENABLED(CONFIG_NUMA) &&
-                       (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
+       if (gfp_thisnode_allocation(gfp_mask))
                goto nopage;
 
 restart:
index 036cfe07050f65eee962f51e6223321f9e01e132..63e24fb4387b6d305960f9e7ba8c0554e6818ca5 100644 (file)
@@ -102,10 +102,11 @@ struct pcpu_chunk {
        int                     free_size;      /* free bytes in the chunk */
        int                     contig_hint;    /* max contiguous size hint */
        void                    *base_addr;     /* base address of this chunk */
-       int                     map_used;       /* # of map entries used */
+       int                     map_used;       /* # of map entries used before the sentry */
        int                     map_alloc;      /* # of map entries allocated */
        int                     *map;           /* allocation map */
        void                    *data;          /* chunk data */
+       int                     first_free;     /* no free below this */
        bool                    immutable;      /* no [de]population allowed */
        unsigned long           populated[];    /* populated bitmap */
 };
@@ -356,11 +357,11 @@ static int pcpu_need_to_extend(struct pcpu_chunk *chunk)
 {
        int new_alloc;
 
-       if (chunk->map_alloc >= chunk->map_used + 2)
+       if (chunk->map_alloc >= chunk->map_used + 3)
                return 0;
 
        new_alloc = PCPU_DFL_MAP_ALLOC;
-       while (new_alloc < chunk->map_used + 2)
+       while (new_alloc < chunk->map_used + 3)
                new_alloc *= 2;
 
        return new_alloc;
@@ -417,48 +418,6 @@ out_unlock:
        return 0;
 }
 
-/**
- * pcpu_split_block - split a map block
- * @chunk: chunk of interest
- * @i: index of map block to split
- * @head: head size in bytes (can be 0)
- * @tail: tail size in bytes (can be 0)
- *
- * Split the @i'th map block into two or three blocks.  If @head is
- * non-zero, @head bytes block is inserted before block @i moving it
- * to @i+1 and reducing its size by @head bytes.
- *
- * If @tail is non-zero, the target block, which can be @i or @i+1
- * depending on @head, is reduced by @tail bytes and @tail byte block
- * is inserted after the target block.
- *
- * @chunk->map must have enough free slots to accommodate the split.
- *
- * CONTEXT:
- * pcpu_lock.
- */
-static void pcpu_split_block(struct pcpu_chunk *chunk, int i,
-                            int head, int tail)
-{
-       int nr_extra = !!head + !!tail;
-
-       BUG_ON(chunk->map_alloc < chunk->map_used + nr_extra);
-
-       /* insert new subblocks */
-       memmove(&chunk->map[i + nr_extra], &chunk->map[i],
-               sizeof(chunk->map[0]) * (chunk->map_used - i));
-       chunk->map_used += nr_extra;
-
-       if (head) {
-               chunk->map[i + 1] = chunk->map[i] - head;
-               chunk->map[i++] = head;
-       }
-       if (tail) {
-               chunk->map[i++] -= tail;
-               chunk->map[i] = tail;
-       }
-}
-
 /**
  * pcpu_alloc_area - allocate area from a pcpu_chunk
  * @chunk: chunk of interest
@@ -483,19 +442,27 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
        int oslot = pcpu_chunk_slot(chunk);
        int max_contig = 0;
        int i, off;
+       bool seen_free = false;
+       int *p;
 
-       for (i = 0, off = 0; i < chunk->map_used; off += abs(chunk->map[i++])) {
-               bool is_last = i + 1 == chunk->map_used;
+       for (i = chunk->first_free, p = chunk->map + i; i < chunk->map_used; i++, p++) {
                int head, tail;
+               int this_size;
+
+               off = *p;
+               if (off & 1)
+                       continue;
 
                /* extra for alignment requirement */
                head = ALIGN(off, align) - off;
-               BUG_ON(i == 0 && head != 0);
 
-               if (chunk->map[i] < 0)
-                       continue;
-               if (chunk->map[i] < head + size) {
-                       max_contig = max(chunk->map[i], max_contig);
+               this_size = (p[1] & ~1) - off;
+               if (this_size < head + size) {
+                       if (!seen_free) {
+                               chunk->first_free = i;
+                               seen_free = true;
+                       }
+                       max_contig = max(this_size, max_contig);
                        continue;
                }
 
@@ -505,44 +472,59 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
                 * than sizeof(int), which is very small but isn't too
                 * uncommon for percpu allocations.
                 */
-               if (head && (head < sizeof(int) || chunk->map[i - 1] > 0)) {
-                       if (chunk->map[i - 1] > 0)
-                               chunk->map[i - 1] += head;
-                       else {
-                               chunk->map[i - 1] -= head;
+               if (head && (head < sizeof(int) || !(p[-1] & 1))) {
+                       *p = off += head;
+                       if (p[-1] & 1)
                                chunk->free_size -= head;
-                       }
-                       chunk->map[i] -= head;
-                       off += head;
+                       else
+                               max_contig = max(*p - p[-1], max_contig);
+                       this_size -= head;
                        head = 0;
                }
 
                /* if tail is small, just keep it around */
-               tail = chunk->map[i] - head - size;
-               if (tail < sizeof(int))
+               tail = this_size - head - size;
+               if (tail < sizeof(int)) {
                        tail = 0;
+                       size = this_size - head;
+               }
 
                /* split if warranted */
                if (head || tail) {
-                       pcpu_split_block(chunk, i, head, tail);
+                       int nr_extra = !!head + !!tail;
+
+                       /* insert new subblocks */
+                       memmove(p + nr_extra + 1, p + 1,
+                               sizeof(chunk->map[0]) * (chunk->map_used - i));
+                       chunk->map_used += nr_extra;
+
                        if (head) {
-                               i++;
-                               off += head;
-                               max_contig = max(chunk->map[i - 1], max_contig);
+                               if (!seen_free) {
+                                       chunk->first_free = i;
+                                       seen_free = true;
+                               }
+                               *++p = off += head;
+                               ++i;
+                               max_contig = max(head, max_contig);
+                       }
+                       if (tail) {
+                               p[1] = off + size;
+                               max_contig = max(tail, max_contig);
                        }
-                       if (tail)
-                               max_contig = max(chunk->map[i + 1], max_contig);
                }
 
+               if (!seen_free)
+                       chunk->first_free = i + 1;
+
                /* update hint and mark allocated */
-               if (is_last)
+               if (i + 1 == chunk->map_used)
                        chunk->contig_hint = max_contig; /* fully scanned */
                else
                        chunk->contig_hint = max(chunk->contig_hint,
                                                 max_contig);
 
-               chunk->free_size -= chunk->map[i];
-               chunk->map[i] = -chunk->map[i];
+               chunk->free_size -= size;
+               *p |= 1;
 
                pcpu_chunk_relocate(chunk, oslot);
                return off;
@@ -570,34 +552,50 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
 static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
 {
        int oslot = pcpu_chunk_slot(chunk);
-       int i, off;
-
-       for (i = 0, off = 0; i < chunk->map_used; off += abs(chunk->map[i++]))
-               if (off == freeme)
-                       break;
+       int off = 0;
+       unsigned i, j;
+       int to_free = 0;
+       int *p;
+
+       freeme |= 1;    /* we are searching for <given offset, in use> pair */
+
+       i = 0;
+       j = chunk->map_used;
+       while (i != j) {
+               unsigned k = (i + j) / 2;
+               off = chunk->map[k];
+               if (off < freeme)
+                       i = k + 1;
+               else if (off > freeme)
+                       j = k;
+               else
+                       i = j = k;
+       }
        BUG_ON(off != freeme);
-       BUG_ON(chunk->map[i] > 0);
 
-       chunk->map[i] = -chunk->map[i];
-       chunk->free_size += chunk->map[i];
+       if (i < chunk->first_free)
+               chunk->first_free = i;
 
+       p = chunk->map + i;
+       *p = off &= ~1;
+       chunk->free_size += (p[1] & ~1) - off;
+
+       /* merge with next? */
+       if (!(p[1] & 1))
+               to_free++;
        /* merge with previous? */
-       if (i > 0 && chunk->map[i - 1] >= 0) {
-               chunk->map[i - 1] += chunk->map[i];
-               chunk->map_used--;
-               memmove(&chunk->map[i], &chunk->map[i + 1],
-                       (chunk->map_used - i) * sizeof(chunk->map[0]));
+       if (i > 0 && !(p[-1] & 1)) {
+               to_free++;
                i--;
+               p--;
        }
-       /* merge with next? */
-       if (i + 1 < chunk->map_used && chunk->map[i + 1] >= 0) {
-               chunk->map[i] += chunk->map[i + 1];
-               chunk->map_used--;
-               memmove(&chunk->map[i + 1], &chunk->map[i + 2],
-                       (chunk->map_used - (i + 1)) * sizeof(chunk->map[0]));
+       if (to_free) {
+               chunk->map_used -= to_free;
+               memmove(p + 1, p + 1 + to_free,
+                       (chunk->map_used - i) * sizeof(chunk->map[0]));
        }
 
-       chunk->contig_hint = max(chunk->map[i], chunk->contig_hint);
+       chunk->contig_hint = max(chunk->map[i + 1] - chunk->map[i] - 1, chunk->contig_hint);
        pcpu_chunk_relocate(chunk, oslot);
 }
 
@@ -617,7 +615,9 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
        }
 
        chunk->map_alloc = PCPU_DFL_MAP_ALLOC;
-       chunk->map[chunk->map_used++] = pcpu_unit_size;
+       chunk->map[0] = 0;
+       chunk->map[1] = pcpu_unit_size | 1;
+       chunk->map_used = 1;
 
        INIT_LIST_HEAD(&chunk->list);
        chunk->free_size = pcpu_unit_size;
@@ -713,6 +713,16 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
        unsigned long flags;
        void __percpu *ptr;
 
+       /*
+        * We want the lowest bit of offset available for in-use/free
+        * indicator, so force >= 16bit alignment and make size even.
+        */
+       if (unlikely(align < 2))
+               align = 2;
+
+       if (unlikely(size & 1))
+               size++;
+
        if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
                WARN(true, "illegal size (%zu) or align (%zu) for "
                     "percpu allocation\n", size, align);
@@ -1343,9 +1353,13 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
        }
        schunk->contig_hint = schunk->free_size;
 
-       schunk->map[schunk->map_used++] = -ai->static_size;
+       schunk->map[0] = 1;
+       schunk->map[1] = ai->static_size;
+       schunk->map_used = 1;
        if (schunk->free_size)
-               schunk->map[schunk->map_used++] = schunk->free_size;
+               schunk->map[++schunk->map_used] = 1 | (ai->static_size + schunk->free_size);
+       else
+               schunk->map[1] |= 1;
 
        /* init dynamic chunk if necessary */
        if (dyn_size) {
@@ -1358,8 +1372,10 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
                bitmap_fill(dchunk->populated, pcpu_unit_pages);
 
                dchunk->contig_hint = dchunk->free_size = dyn_size;
-               dchunk->map[dchunk->map_used++] = -pcpu_reserved_chunk_limit;
-               dchunk->map[dchunk->map_used++] = dchunk->free_size;
+               dchunk->map[0] = 1;
+               dchunk->map[1] = pcpu_reserved_chunk_limit;
+               dchunk->map[2] = (pcpu_reserved_chunk_limit + dchunk->free_size) | 1;
+               dchunk->map_used = 2;
        }
 
        /* link the first chunk in */
index fd26d0433509e2b5885c74249a9eb04828285180..3c5cf68566ec1375ff4d4deedc09db4c540e4b37 100644 (file)
@@ -456,25 +456,23 @@ free_iovecs:
        return rc;
 }
 
-asmlinkage ssize_t
-compat_sys_process_vm_readv(compat_pid_t pid,
-                           const struct compat_iovec __user *lvec,
-                           unsigned long liovcnt,
-                           const struct compat_iovec __user *rvec,
-                           unsigned long riovcnt,
-                           unsigned long flags)
+COMPAT_SYSCALL_DEFINE6(process_vm_readv, compat_pid_t, pid,
+                      const struct compat_iovec __user *, lvec,
+                      compat_ulong_t, liovcnt,
+                      const struct compat_iovec __user *, rvec,
+                      compat_ulong_t, riovcnt,
+                      compat_ulong_t, flags)
 {
        return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
                                    riovcnt, flags, 0);
 }
 
-asmlinkage ssize_t
-compat_sys_process_vm_writev(compat_pid_t pid,
-                            const struct compat_iovec __user *lvec,
-                            unsigned long liovcnt,
-                            const struct compat_iovec __user *rvec,
-                            unsigned long riovcnt,
-                            unsigned long flags)
+COMPAT_SYSCALL_DEFINE6(process_vm_writev, compat_pid_t, pid,
+                      const struct compat_iovec __user *, lvec,
+                      compat_ulong_t, liovcnt,
+                      const struct compat_iovec __user *, rvec,
+                      compat_ulong_t, riovcnt,
+                      compat_ulong_t, flags)
 {
        return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
                                    riovcnt, flags, 1);
index d9d42316a99a917ff6562c7cbc54dd50a085a1f6..11cf322f8133d7048d414c6f0eed227f6b12d3ac 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1165,6 +1165,16 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                }
                set_pte_at(mm, address, pte,
                           swp_entry_to_pte(make_hwpoison_entry(page)));
+       } else if (pte_unused(pteval)) {
+               /*
+                * The guest indicated that the page content is of no
+                * interest anymore. Simply discard the pte, vmscan
+                * will take care of the rest.
+                */
+               if (PageAnon(page))
+                       dec_mm_counter(mm, MM_ANONPAGES);
+               else
+                       dec_mm_counter(mm, MM_FILEPAGES);
        } else if (PageAnon(page)) {
                swp_entry_t entry = { .val = page_private(page) };
                pte_t swp_pte;
@@ -1360,8 +1370,9 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
 }
 
 static int try_to_unmap_nonlinear(struct page *page,
-               struct address_space *mapping, struct vm_area_struct *vma)
+               struct address_space *mapping, void *arg)
 {
+       struct vm_area_struct *vma;
        int ret = SWAP_AGAIN;
        unsigned long cursor;
        unsigned long max_nl_cursor = 0;
@@ -1663,7 +1674,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc)
        if (list_empty(&mapping->i_mmap_nonlinear))
                goto done;
 
-       ret = rwc->file_nonlinear(page, mapping, vma);
+       ret = rwc->file_nonlinear(page, mapping, rwc->arg);
 
 done:
        mutex_unlock(&mapping->i_mmap_mutex);
index b31ba67d440ac997a05de372e831046bf98d9070..0092097b3f4ce5e22844759a9e264ef143d05c7c 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -98,7 +98,7 @@ static void put_compound_page(struct page *page)
        }
 
        /* __split_huge_page_refcount can run under us */
-       page_head = compound_trans_head(page);
+       page_head = compound_head(page);
 
        /*
         * THP can not break up slab pages so avoid taking
@@ -253,7 +253,7 @@ bool __get_page_tail(struct page *page)
         */
        unsigned long flags;
        bool got;
-       struct page *page_head = compound_trans_head(page);
+       struct page *page_head = compound_head(page);
 
        /* Ref to put_compound_page() comment. */
        if (!__compound_tail_refcounted(page_head)) {
index ec9909935fb60850ed3635e1636f568c8c88bbf0..175273f38cb1bd59f5aeb88cb8c815033475dfe8 100644 (file)
@@ -307,9 +307,11 @@ static void vlan_sync_address(struct net_device *dev,
 static void vlan_transfer_features(struct net_device *dev,
                                   struct net_device *vlandev)
 {
+       struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
+
        vlandev->gso_max_size = dev->gso_max_size;
 
-       if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
+       if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto))
                vlandev->hard_header_len = dev->hard_header_len;
        else
                vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;
index de51c48c439382db712761747188dc72061c82b0..27bfe2f8e2de71bee3f873106d88498765d36e93 100644 (file)
@@ -538,6 +538,9 @@ static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev
        struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
        struct net_device *real_dev = vlan->real_dev;
 
+       if (saddr == NULL)
+               saddr = dev->dev_addr;
+
        return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
 }
 
@@ -575,6 +578,9 @@ static int vlan_dev_init(struct net_device *dev)
 
        dev->features |= real_dev->vlan_features | NETIF_F_LLTX;
        dev->gso_max_size = real_dev->gso_max_size;
+       if (dev->features & NETIF_F_VLAN_FEATURES)
+               netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
+
 
        /* ipv6 shared card related stuff */
        dev->dev_id = real_dev->dev_id;
@@ -589,7 +595,8 @@ static int vlan_dev_init(struct net_device *dev)
 #endif
 
        dev->needed_headroom = real_dev->needed_headroom;
-       if (real_dev->features & NETIF_F_HW_VLAN_CTAG_TX) {
+       if (vlan_hw_offload_capable(real_dev->features,
+                                   vlan_dev_priv(dev)->vlan_proto)) {
                dev->header_ops      = &vlan_passthru_header_ops;
                dev->hard_header_len = real_dev->hard_header_len;
        } else {
index 63f0455c0bc3e21fea311a4d14d24a995c606d6f..8fe8b71b487add263a711d39e52f683675708dd6 100644 (file)
@@ -49,14 +49,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        brstats->tx_bytes += skb->len;
        u64_stats_update_end(&brstats->syncp);
 
-       if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
-               goto out;
-
        BR_INPUT_SKB_CB(skb)->brdev = dev;
 
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
 
+       if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
+               goto out;
+
        if (is_broadcast_ether_addr(dest))
                br_flood_deliver(br, skb, false);
        else if (is_multicast_ether_addr(dest)) {
index 28d54462742278f388caf3f4a96e13b212b35688..d0cca3c65f0174ab8c6522b5f54ab2ad33b66dca 100644 (file)
@@ -29,6 +29,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
        struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
        struct net_bridge *br = netdev_priv(brdev);
        struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
+       struct net_port_vlans *pv;
 
        u64_stats_update_begin(&brstats->syncp);
        brstats->rx_packets++;
@@ -39,18 +40,18 @@ static int br_pass_frame_up(struct sk_buff *skb)
         * packet is allowed except in promisc modue when someone
         * may be running packet capture.
         */
+       pv = br_get_vlan_info(br);
        if (!(brdev->flags & IFF_PROMISC) &&
-           !br_allowed_egress(br, br_get_vlan_info(br), skb)) {
+           !br_allowed_egress(br, pv, skb)) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
 
-       skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
-       if (!skb)
-               return NET_RX_DROP;
-
        indev = skb->dev;
        skb->dev = brdev;
+       skb = br_handle_vlan(br, pv, skb);
+       if (!skb)
+               return NET_RX_DROP;
 
        return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
                       netif_receive_skb);
index ef66365b7354da9f2fe2c4d87d2056d9a781f3c8..93067ecdb9a212321c8780bd65153d60e8203907 100644 (file)
@@ -1127,9 +1127,10 @@ static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
                                        struct bridge_mcast_querier *querier,
                                        int saddr,
+                                       bool is_general_query,
                                        unsigned long max_delay)
 {
-       if (saddr)
+       if (saddr && is_general_query)
                br_multicast_update_querier_timer(br, querier, max_delay);
        else if (timer_pending(&querier->timer))
                return;
@@ -1181,8 +1182,16 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
+        * all-systems destination addresses (224.0.0.1) for general queries
+        */
+       if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
-                                   max_delay);
+                                   !group, max_delay);
 
        if (!group)
                goto out;
@@ -1228,6 +1237,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        unsigned long max_delay;
        unsigned long now = jiffies;
        const struct in6_addr *group = NULL;
+       bool is_general_query;
        int err = 0;
 
        spin_lock(&br->multicast_lock);
@@ -1235,6 +1245,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
+       if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1256,8 +1272,19 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);
        }
 
+       is_general_query = group && ipv6_addr_any(group);
+
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer
+        * all-nodes destination address (ff02::1) for general queries
+        */
+       if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        br_multicast_query_received(br, port, &br->ip6_querier,
-                                   !ipv6_addr_any(&ip6h->saddr), max_delay);
+                                   !ipv6_addr_any(&ip6h->saddr),
+                                   is_general_query, max_delay);
 
        if (!group)
                goto out;
index 8249ca764c79c5f2ddab51006ad445752b3ac137..f23c74b3a95327722916405cee92d5d61048c8a2 100644 (file)
@@ -119,22 +119,6 @@ static void __vlan_flush(struct net_port_vlans *v)
        kfree_rcu(v, rcu);
 }
 
-/* Strip the tag from the packet.  Will return skb with tci set 0.  */
-static struct sk_buff *br_vlan_untag(struct sk_buff *skb)
-{
-       if (skb->protocol != htons(ETH_P_8021Q)) {
-               skb->vlan_tci = 0;
-               return skb;
-       }
-
-       skb->vlan_tci = 0;
-       skb = vlan_untag(skb);
-       if (skb)
-               skb->vlan_tci = 0;
-
-       return skb;
-}
-
 struct sk_buff *br_handle_vlan(struct net_bridge *br,
                               const struct net_port_vlans *pv,
                               struct sk_buff *skb)
@@ -144,13 +128,27 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
        if (!br->vlan_enabled)
                goto out;
 
+       /* Vlan filter table must be configured at this point.  The
+        * only exception is the bridge is set in promisc mode and the
+        * packet is destined for the bridge device.  In this case
+        * pass the packet as is.
+        */
+       if (!pv) {
+               if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
+                       goto out;
+               } else {
+                       kfree_skb(skb);
+                       return NULL;
+               }
+       }
+
        /* At this point, we know that the frame was filtered and contains
         * a valid vlan id.  If the vlan id is set in the untagged bitmap,
         * send untagged; otherwise, send tagged.
         */
        br_vlan_get_tag(skb, &vid);
        if (test_bit(vid, pv->untagged_bitmap))
-               skb = br_vlan_untag(skb);
+               skb->vlan_tci = 0;
 
 out:
        return skb;
@@ -174,6 +172,18 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
        if (!v)
                return false;
 
+       /* If vlan tx offload is disabled on bridge device and frame was
+        * sent from vlan device on the bridge device, it does not have
+        * HW accelerated vlan tag.
+        */
+       if (unlikely(!vlan_tx_tag_present(skb) &&
+                    (skb->protocol == htons(ETH_P_8021Q) ||
+                     skb->protocol == htons(ETH_P_8021AD)))) {
+               skb = vlan_untag(skb);
+               if (unlikely(!skb))
+                       return false;
+       }
+
        err = br_vlan_get_tag(skb, vid);
        if (!*vid) {
                u16 pvid = br_get_pvid(v);
index 8be757cca2ec444171982cb8c33ef58ab27310be..081e81fd017fa53f7a6ed3afd341601b43377531 100644 (file)
@@ -121,13 +121,9 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
        if (!ro->recv_own_msgs && oskb->sk == sk)
                return;
 
-       /* do not pass frames with DLC > 8 to a legacy socket */
-       if (!ro->fd_frames) {
-               struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
-
-               if (unlikely(cfd->len > CAN_MAX_DLEN))
-                       return;
-       }
+       /* do not pass non-CAN2.0 frames to a legacy socket */
+       if (!ro->fd_frames && oskb->len != CAN_MTU)
+               return;
 
        /* clone the given skb to be able to enqueue it into the rcv queue */
        skb = skb_clone(oskb, GFP_ATOMIC);
@@ -738,9 +734,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
                       struct msghdr *msg, size_t size, int flags)
 {
        struct sock *sk = sock->sk;
-       struct raw_sock *ro = raw_sk(sk);
        struct sk_buff *skb;
-       int rxmtu;
        int err = 0;
        int noblock;
 
@@ -751,20 +745,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (!skb)
                return err;
 
-       /*
-        * when serving a legacy socket the DLC <= 8 is already checked inside
-        * raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
-        * socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
-        */
-       if (!ro->fd_frames)
-               rxmtu = CAN_MTU;
-       else
-               rxmtu = skb->len;
-
-       if (size < rxmtu)
+       if (size < skb->len)
                msg->msg_flags |= MSG_TRUNC;
        else
-               size = rxmtu;
+               size = skb->len;
 
        err = memcpy_toiovec(msg->msg_iov, skb->data, size);
        if (err < 0) {
index f50161fb812eace2eb659ae78bf12062c608b5b6..9a76eaf63184753d6020eb1f3a9ab51299b1ae02 100644 (file)
@@ -384,8 +384,8 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
        return sock_setsockopt(sock, level, optname, optval, optlen);
 }
 
-asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
-                               char __user *optval, unsigned int optlen)
+COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
+                      char __user *, optval, unsigned int, optlen)
 {
        int err;
        struct socket *sock = sockfd_lookup(fd, &err);
@@ -504,8 +504,8 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
 }
 EXPORT_SYMBOL(compat_sock_get_timestampns);
 
-asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
-                               char __user *optval, int __user *optlen)
+COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
+                      char __user *, optval, int __user *, optlen)
 {
        int err;
        struct socket *sock = sockfd_lookup(fd, &err);
@@ -735,15 +735,15 @@ static unsigned char nas[21] = {
 };
 #undef AL
 
-asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
+COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
        if (flags & MSG_CMSG_COMPAT)
                return -EINVAL;
        return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
-asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
-                                   unsigned int vlen, unsigned int flags)
+COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
+                      unsigned int, vlen, unsigned int, flags)
 {
        if (flags & MSG_CMSG_COMPAT)
                return -EINVAL;
@@ -751,28 +751,28 @@ asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
                              flags | MSG_CMSG_COMPAT);
 }
 
-asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
+COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
 {
        if (flags & MSG_CMSG_COMPAT)
                return -EINVAL;
        return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
-asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
+COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
 {
        return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
 }
 
-asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
-                                   unsigned int flags, struct sockaddr __user *addr,
-                                   int __user *addrlen)
+COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
+                      unsigned int, flags, struct sockaddr __user *, addr,
+                      int __user *, addrlen)
 {
        return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
 }
 
-asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
-                                   unsigned int vlen, unsigned int flags,
-                                   struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
+                      unsigned int, vlen, unsigned int, flags,
+                      struct compat_timespec __user *, timeout)
 {
        int datagrams;
        struct timespec ktspec;
@@ -795,7 +795,7 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
        return datagrams;
 }
 
-asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
+COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
 {
        int ret;
        u32 a[6];
index b1b0c8d4d7df31d34a575ab326dab71f1a315e51..45fa2f11f84dcc7f0efe12711c2d51526360a08d 100644 (file)
@@ -2286,7 +2286,7 @@ out:
 }
 EXPORT_SYMBOL(skb_checksum_help);
 
-__be16 skb_network_protocol(struct sk_buff *skb)
+__be16 skb_network_protocol(struct sk_buff *skb, int *depth)
 {
        __be16 type = skb->protocol;
        int vlan_depth = ETH_HLEN;
@@ -2313,6 +2313,8 @@ __be16 skb_network_protocol(struct sk_buff *skb)
                vlan_depth += VLAN_HLEN;
        }
 
+       *depth = vlan_depth;
+
        return type;
 }
 
@@ -2326,12 +2328,13 @@ struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
 {
        struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
        struct packet_offload *ptype;
-       __be16 type = skb_network_protocol(skb);
+       int vlan_depth = skb->mac_len;
+       __be16 type = skb_network_protocol(skb, &vlan_depth);
 
        if (unlikely(!type))
                return ERR_PTR(-EINVAL);
 
-       __skb_pull(skb, skb->mac_len);
+       __skb_pull(skb, vlan_depth);
 
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, &offload_base, list) {
@@ -2498,8 +2501,10 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
                                            const struct net_device *dev,
                                            netdev_features_t features)
 {
+       int tmp;
+
        if (skb->ip_summed != CHECKSUM_NONE &&
-           !can_checksum_protocol(features, skb_network_protocol(skb))) {
+           !can_checksum_protocol(features, skb_network_protocol(skb, &tmp))) {
                features &= ~NETIF_F_ALL_CSUM;
        } else if (illegal_highdma(dev, skb)) {
                features &= ~NETIF_F_SG;
index b9e9e0d38672a8ca9a17f8d6ec8daf88b8a09a65..e16129019c6658ae7b1ab697692f8e6484c8cd90 100644 (file)
@@ -766,9 +766,6 @@ static void neigh_periodic_work(struct work_struct *work)
        nht = rcu_dereference_protected(tbl->nht,
                                        lockdep_is_held(&tbl->lock));
 
-       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
-               goto out;
-
        /*
         *      periodically recompute ReachableTime from random function
         */
@@ -781,6 +778,9 @@ static void neigh_periodic_work(struct work_struct *work)
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
        }
 
+       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
+               goto out;
+
        for (i = 0 ; i < (1 << nht->hash_shift); i++) {
                np = &nht->hash_buckets[i];
 
@@ -3046,7 +3046,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        if (!t)
                goto err;
 
-       for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
+       for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
                t->neigh_vars[i].data += (long) p;
                t->neigh_vars[i].extra1 = dev;
                t->neigh_vars[i].extra2 = p;
index a664f7829a6d16db4579789ca5b8c40654cc78d7..df9e6b1a975920f47fbd68b540ccb4d7f8511759 100644 (file)
@@ -742,7 +742,7 @@ static bool pkt_is_ns(struct sk_buff *skb)
        struct nd_msg *msg;
        struct ipv6hdr *hdr;
 
-       if (skb->protocol != htons(ETH_P_ARP))
+       if (skb->protocol != htons(ETH_P_IPV6))
                return false;
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
                return false;
index 1a0dac2ef9ada3ac331fdd31ce1b1548898cf310..120eecc0f5a471f0157894f48ee33f1d1f6a9af5 100644 (file)
@@ -2121,12 +2121,13 @@ EXPORT_SYMBOL(rtmsg_ifinfo);
 static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
                                   struct net_device *dev,
                                   u8 *addr, u32 pid, u32 seq,
-                                  int type, unsigned int flags)
+                                  int type, unsigned int flags,
+                                  int nlflags)
 {
        struct nlmsghdr *nlh;
        struct ndmsg *ndm;
 
-       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), nlflags);
        if (!nlh)
                return -EMSGSIZE;
 
@@ -2164,7 +2165,7 @@ static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, int type)
        if (!skb)
                goto errout;
 
-       err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF);
+       err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF, 0);
        if (err < 0) {
                kfree_skb(skb);
                goto errout;
@@ -2389,7 +2390,8 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
 
                err = nlmsg_populate_fdb_fill(skb, dev, ha->addr,
                                              portid, seq,
-                                             RTM_NEWNEIGH, NTF_SELF);
+                                             RTM_NEWNEIGH, NTF_SELF,
+                                             NLM_F_MULTI);
                if (err < 0)
                        return err;
 skip:
index 5976ef0846bdda08db6289bb91f05a63b85e6e3a..90b96a11b974d2697defcc9ccf4b14b65d704c49 100644 (file)
@@ -707,9 +707,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->mark               = old->mark;
        new->skb_iif            = old->skb_iif;
        __nf_copy(new, old);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       new->nf_trace           = old->nf_trace;
-#endif
 #ifdef CONFIG_NET_SCHED
        new->tc_index           = old->tc_index;
 #ifdef CONFIG_NET_CLS_ACT
@@ -2130,25 +2127,31 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
  *
  *     The `hlen` as calculated by skb_zerocopy_headlen() specifies the
  *     headroom in the `to` buffer.
+ *
+ *     Return value:
+ *     0: everything is OK
+ *     -ENOMEM: couldn't orphan frags of @from due to lack of memory
+ *     -EFAULT: skb_copy_bits() found some problem with skb geometry
  */
-void
-skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
+int
+skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
 {
        int i, j = 0;
        int plen = 0; /* length of skb->head fragment */
+       int ret;
        struct page *page;
        unsigned int offset;
 
        BUG_ON(!from->head_frag && !hlen);
 
        /* dont bother with small payloads */
-       if (len <= skb_tailroom(to)) {
-               skb_copy_bits(from, 0, skb_put(to, len), len);
-               return;
-       }
+       if (len <= skb_tailroom(to))
+               return skb_copy_bits(from, 0, skb_put(to, len), len);
 
        if (hlen) {
-               skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+               ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+               if (unlikely(ret))
+                       return ret;
                len -= hlen;
        } else {
                plen = min_t(int, skb_headlen(from), len);
@@ -2166,6 +2169,11 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
        to->len += len + plen;
        to->data_len += len + plen;
 
+       if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
+               skb_tx_error(from);
+               return -ENOMEM;
+       }
+
        for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
                if (!len)
                        break;
@@ -2176,6 +2184,8 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
                j++;
        }
        skb_shinfo(to)->nr_frags = j;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(skb_zerocopy);
 
@@ -2841,81 +2851,85 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
 
 /**
  *     skb_segment - Perform protocol segmentation on skb.
- *     @skb: buffer to segment
+ *     @head_skb: buffer to segment
  *     @features: features for the output path (see dev->features)
  *
  *     This function performs segmentation on the given skb.  It returns
  *     a pointer to the first in a list of new skbs for the segments.
  *     In case of error it returns ERR_PTR(err).
  */
-struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
+struct sk_buff *skb_segment(struct sk_buff *head_skb,
+                           netdev_features_t features)
 {
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
-       struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
-       skb_frag_t *skb_frag = skb_shinfo(skb)->frags;
-       unsigned int mss = skb_shinfo(skb)->gso_size;
-       unsigned int doffset = skb->data - skb_mac_header(skb);
+       struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
+       skb_frag_t *frag = skb_shinfo(head_skb)->frags;
+       unsigned int mss = skb_shinfo(head_skb)->gso_size;
+       unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
+       struct sk_buff *frag_skb = head_skb;
        unsigned int offset = doffset;
-       unsigned int tnl_hlen = skb_tnl_header_len(skb);
+       unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
        unsigned int headroom;
        unsigned int len;
        __be16 proto;
        bool csum;
        int sg = !!(features & NETIF_F_SG);
-       int nfrags = skb_shinfo(skb)->nr_frags;
+       int nfrags = skb_shinfo(head_skb)->nr_frags;
        int err = -ENOMEM;
        int i = 0;
        int pos;
+       int dummy;
 
-       proto = skb_network_protocol(skb);
+       proto = skb_network_protocol(head_skb, &dummy);
        if (unlikely(!proto))
                return ERR_PTR(-EINVAL);
 
        csum = !!can_checksum_protocol(features, proto);
-       __skb_push(skb, doffset);
-       headroom = skb_headroom(skb);
-       pos = skb_headlen(skb);
+       __skb_push(head_skb, doffset);
+       headroom = skb_headroom(head_skb);
+       pos = skb_headlen(head_skb);
 
        do {
                struct sk_buff *nskb;
-               skb_frag_t *frag;
+               skb_frag_t *nskb_frag;
                int hsize;
                int size;
 
-               len = skb->len - offset;
+               len = head_skb->len - offset;
                if (len > mss)
                        len = mss;
 
-               hsize = skb_headlen(skb) - offset;
+               hsize = skb_headlen(head_skb) - offset;
                if (hsize < 0)
                        hsize = 0;
                if (hsize > len || !sg)
                        hsize = len;
 
-               if (!hsize && i >= nfrags && skb_headlen(fskb) &&
-                   (skb_headlen(fskb) == len || sg)) {
-                       BUG_ON(skb_headlen(fskb) > len);
+               if (!hsize && i >= nfrags && skb_headlen(list_skb) &&
+                   (skb_headlen(list_skb) == len || sg)) {
+                       BUG_ON(skb_headlen(list_skb) > len);
 
                        i = 0;
-                       nfrags = skb_shinfo(fskb)->nr_frags;
-                       skb_frag = skb_shinfo(fskb)->frags;
-                       pos += skb_headlen(fskb);
+                       nfrags = skb_shinfo(list_skb)->nr_frags;
+                       frag = skb_shinfo(list_skb)->frags;
+                       frag_skb = list_skb;
+                       pos += skb_headlen(list_skb);
 
                        while (pos < offset + len) {
                                BUG_ON(i >= nfrags);
 
-                               size = skb_frag_size(skb_frag);
+                               size = skb_frag_size(frag);
                                if (pos + size > offset + len)
                                        break;
 
                                i++;
                                pos += size;
-                               skb_frag++;
+                               frag++;
                        }
 
-                       nskb = skb_clone(fskb, GFP_ATOMIC);
-                       fskb = fskb->next;
+                       nskb = skb_clone(list_skb, GFP_ATOMIC);
+                       list_skb = list_skb->next;
 
                        if (unlikely(!nskb))
                                goto err;
@@ -2936,7 +2950,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                        __skb_push(nskb, doffset);
                } else {
                        nskb = __alloc_skb(hsize + doffset + headroom,
-                                          GFP_ATOMIC, skb_alloc_rx_flag(skb),
+                                          GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
                                           NUMA_NO_NODE);
 
                        if (unlikely(!nskb))
@@ -2952,12 +2966,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                        segs = nskb;
                tail = nskb;
 
-               __copy_skb_header(nskb, skb);
-               nskb->mac_len = skb->mac_len;
+               __copy_skb_header(nskb, head_skb);
+               nskb->mac_len = head_skb->mac_len;
 
                skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
 
-               skb_copy_from_linear_data_offset(skb, -tnl_hlen,
+               skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
                                                 nskb->data - tnl_hlen,
                                                 doffset + tnl_hlen);
 
@@ -2966,30 +2980,32 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 
                if (!sg) {
                        nskb->ip_summed = CHECKSUM_NONE;
-                       nskb->csum = skb_copy_and_csum_bits(skb, offset,
+                       nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
                                                            skb_put(nskb, len),
                                                            len, 0);
                        continue;
                }
 
-               frag = skb_shinfo(nskb)->frags;
+               nskb_frag = skb_shinfo(nskb)->frags;
 
-               skb_copy_from_linear_data_offset(skb, offset,
+               skb_copy_from_linear_data_offset(head_skb, offset,
                                                 skb_put(nskb, hsize), hsize);
 
-               skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+               skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
+                       SKBTX_SHARED_FRAG;
 
                while (pos < offset + len) {
                        if (i >= nfrags) {
-                               BUG_ON(skb_headlen(fskb));
+                               BUG_ON(skb_headlen(list_skb));
 
                                i = 0;
-                               nfrags = skb_shinfo(fskb)->nr_frags;
-                               skb_frag = skb_shinfo(fskb)->frags;
+                               nfrags = skb_shinfo(list_skb)->nr_frags;
+                               frag = skb_shinfo(list_skb)->frags;
+                               frag_skb = list_skb;
 
                                BUG_ON(!nfrags);
 
-                               fskb = fskb->next;
+                               list_skb = list_skb->next;
                        }
 
                        if (unlikely(skb_shinfo(nskb)->nr_frags >=
@@ -3000,27 +3016,30 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                                goto err;
                        }
 
-                       *frag = *skb_frag;
-                       __skb_frag_ref(frag);
-                       size = skb_frag_size(frag);
+                       if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
+                               goto err;
+
+                       *nskb_frag = *frag;
+                       __skb_frag_ref(nskb_frag);
+                       size = skb_frag_size(nskb_frag);
 
                        if (pos < offset) {
-                               frag->page_offset += offset - pos;
-                               skb_frag_size_sub(frag, offset - pos);
+                               nskb_frag->page_offset += offset - pos;
+                               skb_frag_size_sub(nskb_frag, offset - pos);
                        }
 
                        skb_shinfo(nskb)->nr_frags++;
 
                        if (pos + size <= offset + len) {
                                i++;
-                               skb_frag++;
+                               frag++;
                                pos += size;
                        } else {
-                               skb_frag_size_sub(frag, pos + size - (offset + len));
+                               skb_frag_size_sub(nskb_frag, pos + size - (offset + len));
                                goto skip_fraglist;
                        }
 
-                       frag++;
+                       nskb_frag++;
                }
 
 skip_fraglist:
@@ -3034,7 +3053,7 @@ perform_csum_check:
                                                  nskb->len - doffset, 0);
                        nskb->ip_summed = CHECKSUM_NONE;
                }
-       } while ((offset += len) < skb->len);
+       } while ((offset += len) < head_skb->len);
 
        return segs;
 
index 5b6a9431b0176142cb1f93392a0294c468d84887..c0fc6bdad1e3629f123244d6d7c77805c9b5f0bd 100644 (file)
@@ -2357,10 +2357,13 @@ void release_sock(struct sock *sk)
        if (sk->sk_backlog.tail)
                __release_sock(sk);
 
+       /* Warning : release_cb() might need to release sk ownership,
+        * ie call sock_release_ownership(sk) before us.
+        */
        if (sk->sk_prot->release_cb)
                sk->sk_prot->release_cb(sk);
 
-       sk->sk_lock.owned = 0;
+       sock_release_ownership(sk);
        if (waitqueue_active(&sk->sk_lock.wq))
                wake_up(&sk->sk_lock.wq);
        spin_unlock_bh(&sk->sk_lock.slock);
index 327060c6c874b337cf6edf9bd37c5b8181c0beee..7ae0d7f6dbd0bff10516e9415050d7aa41a07da0 100644 (file)
@@ -297,7 +297,7 @@ static bool seq_nr_after(u16 a, u16 b)
 
 void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx)
 {
-       if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) {
+       if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) {
                WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx);
                return;
        }
index ecd2c3f245ce2b2e0b79f17417c5e6ad8c70abf6..19ab78aca547fc7fb45e56607e7adafd0036d947 100644 (file)
@@ -1296,8 +1296,11 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 
        segs = ERR_PTR(-EPROTONOSUPPORT);
 
-       /* Note : following gso_segment() might change skb->encapsulation */
-       udpfrag = !skb->encapsulation && proto == IPPROTO_UDP;
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
 
        ops = rcu_dereference(inet_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment))
index 1863422fb7d553340151b1402ee30d4be1fcde29..250be7421ab36c50ce00a25dcd3c659ca1c97f18 100644 (file)
@@ -182,6 +182,14 @@ static int gre_cisco_rcv(struct sk_buff *skb)
        int i;
        bool csum_err = false;
 
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+       if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
+               /* Looped back packet, drop it! */
+               if (rt_is_output_route(skb_rtable(skb)))
+                       goto drop;
+       }
+#endif
+
        if (parse_gre_header(skb, &tpi, &csum_err) < 0)
                goto drop;
 
index bb075fc9a14f25169c175c7fcdcb86d56c709627..3b01959bf4bb0bbc208d8d564c8595c67eedd179 100644 (file)
@@ -208,7 +208,7 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
        }
 
        work = frag_mem_limit(nf) - nf->low_thresh;
-       while (work > 0) {
+       while (work > 0 || force) {
                spin_lock(&nf->lru_lock);
 
                if (list_empty(&nf->lru_list)) {
@@ -278,9 +278,10 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 
        atomic_inc(&qp->refcnt);
        hlist_add_head(&qp->list, &hb->chain);
+       inet_frag_lru_add(nf, qp);
        spin_unlock(&hb->chain_lock);
        read_unlock(&f->lock);
-       inet_frag_lru_add(nf, qp);
+
        return qp;
 }
 
index 8971780aec7c5fadb4223c0391b05aa9c881ba34..73c6b63bba74e57b70589ff548fccf0db79cc9a4 100644 (file)
@@ -422,9 +422,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       to->nf_trace = from->nf_trace;
-#endif
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
        to->ipvs_property = from->ipvs_property;
 #endif
index 50228be5c17bfc2c02d6539eea210a537bcc421b..a82a22d8f77fdca5f496e9d7cb45f40b70d194ca 100644 (file)
@@ -93,13 +93,14 @@ static void tunnel_dst_reset(struct ip_tunnel *t)
        tunnel_dst_set(t, NULL);
 }
 
-static void tunnel_dst_reset_all(struct ip_tunnel *t)
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t)
 {
        int i;
 
        for_each_possible_cpu(i)
                __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
 }
+EXPORT_SYMBOL(ip_tunnel_dst_reset_all);
 
 static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
 {
@@ -119,52 +120,6 @@ static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
        return (struct rtable *)dst;
 }
 
-/* Often modified stats are per cpu, other are shared (netdev->stats) */
-struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
-                                               struct rtnl_link_stats64 *tot)
-{
-       int i;
-
-       for_each_possible_cpu(i) {
-               const struct pcpu_sw_netstats *tstats =
-                                                  per_cpu_ptr(dev->tstats, i);
-               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
-               unsigned int start;
-
-               do {
-                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
-                       rx_packets = tstats->rx_packets;
-                       tx_packets = tstats->tx_packets;
-                       rx_bytes = tstats->rx_bytes;
-                       tx_bytes = tstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
-               tot->rx_packets += rx_packets;
-               tot->tx_packets += tx_packets;
-               tot->rx_bytes   += rx_bytes;
-               tot->tx_bytes   += tx_bytes;
-       }
-
-       tot->multicast = dev->stats.multicast;
-
-       tot->rx_crc_errors = dev->stats.rx_crc_errors;
-       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
-       tot->rx_length_errors = dev->stats.rx_length_errors;
-       tot->rx_frame_errors = dev->stats.rx_frame_errors;
-       tot->rx_errors = dev->stats.rx_errors;
-
-       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
-       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
-       tot->tx_dropped = dev->stats.tx_dropped;
-       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
-       tot->tx_errors = dev->stats.tx_errors;
-
-       tot->collisions  = dev->stats.collisions;
-
-       return tot;
-}
-EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
-
 static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
                                __be16 flags, __be32 key)
 {
@@ -461,9 +416,6 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
 
 #ifdef CONFIG_NET_IPGRE_BROADCAST
        if (ipv4_is_multicast(iph->daddr)) {
-               /* Looped back packet, drop it! */
-               if (rt_is_output_route(skb_rtable(skb)))
-                       goto drop;
                tunnel->dev->stats.multicast++;
                skb->pkt_type = PACKET_BROADCAST;
        }
@@ -759,7 +711,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
                if (set_mtu)
                        dev->mtu = mtu;
        }
-       tunnel_dst_reset_all(t);
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(dev);
 }
 
@@ -1088,7 +1040,7 @@ void ip_tunnel_uninit(struct net_device *dev)
        if (itn->fb_tunnel_dev != dev)
                ip_tunnel_del(netdev_priv(dev));
 
-       tunnel_dst_reset_all(tunnel);
+       ip_tunnel_dst_reset_all(tunnel);
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
 
index 6156f4ef5e919ccdc470f8cdb5a27593dedbe2c3..8d69626f2206900dfbb336063034875743a3936e 100644 (file)
@@ -148,3 +148,49 @@ error:
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(iptunnel_handle_offloads);
+
+/* Often modified stats are per cpu, other are shared (netdev->stats) */
+struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
+                                               struct rtnl_link_stats64 *tot)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               const struct pcpu_sw_netstats *tstats =
+                                                  per_cpu_ptr(dev->tstats, i);
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+               unsigned int start;
+
+               do {
+                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
+                       rx_packets = tstats->rx_packets;
+                       tx_packets = tstats->tx_packets;
+                       rx_bytes = tstats->rx_bytes;
+                       tx_bytes = tstats->tx_bytes;
+               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+               tot->rx_packets += rx_packets;
+               tot->tx_packets += tx_packets;
+               tot->rx_bytes   += rx_bytes;
+               tot->tx_bytes   += tx_bytes;
+       }
+
+       tot->multicast = dev->stats.multicast;
+
+       tot->rx_crc_errors = dev->stats.rx_crc_errors;
+       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+       tot->rx_length_errors = dev->stats.rx_length_errors;
+       tot->rx_frame_errors = dev->stats.rx_frame_errors;
+       tot->rx_errors = dev->stats.rx_errors;
+
+       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+       tot->tx_dropped = dev->stats.tx_dropped;
+       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+       tot->tx_errors = dev->stats.tx_errors;
+
+       tot->collisions  = dev->stats.collisions;
+
+       return tot;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
index b9b3472975ba31a646502dcd8c76046869be4e98..28863570dd60557ca27d8c73c7590b926c7dcf57 100644 (file)
@@ -2255,13 +2255,14 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
 }
 
 static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
-                           u32 portid, u32 seq, struct mfc_cache *c, int cmd)
+                           u32 portid, u32 seq, struct mfc_cache *c, int cmd,
+                           int flags)
 {
        struct nlmsghdr *nlh;
        struct rtmsg *rtm;
        int err;
 
-       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -2329,7 +2330,7 @@ static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
        if (skb == NULL)
                goto errout;
 
-       err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
+       err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
        if (err < 0)
                goto errout;
 
@@ -2368,7 +2369,8 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
                                if (ipmr_fill_mroute(mrt, skb,
                                                     NETLINK_CB(cb->skb).portid,
                                                     cb->nlh->nlmsg_seq,
-                                                    mfc, RTM_NEWROUTE) < 0)
+                                                    mfc, RTM_NEWROUTE,
+                                                    NLM_F_MULTI) < 0)
                                        goto done;
 next_entry:
                                e++;
@@ -2382,7 +2384,8 @@ next_entry:
                        if (ipmr_fill_mroute(mrt, skb,
                                             NETLINK_CB(cb->skb).portid,
                                             cb->nlh->nlmsg_seq,
-                                            mfc, RTM_NEWROUTE) < 0) {
+                                            mfc, RTM_NEWROUTE,
+                                            NLM_F_MULTI) < 0) {
                                spin_unlock_bh(&mfc_unres_lock);
                                goto done;
                        }
index d551e31b416e02e728a433293d25317e9c930dcb..7c676671329d9432eb2392f6b4fc649ebcdae97f 100644 (file)
@@ -1198,8 +1198,8 @@ static int snmp_translate(struct nf_conn *ct,
                map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
        } else {
                /* DNAT replies */
-               map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip);
-               map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
+               map.from = NOCT1(&ct->tuplehash[!dir].tuple.src.u3.ip);
+               map.to = NOCT1(&ct->tuplehash[dir].tuple.dst.u3.ip);
        }
 
        if (map.from == map.to)
index 9f3a2db9109efda9a121135d46406f0beabb8805..97c8f5620c430930c0b9c7958db079a968bd807b 100644 (file)
@@ -1044,7 +1044,8 @@ void tcp_free_fastopen_req(struct tcp_sock *tp)
        }
 }
 
-static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
+static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
+                               int *copied, size_t size)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int err, flags;
@@ -1059,11 +1060,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
        if (unlikely(tp->fastopen_req == NULL))
                return -ENOBUFS;
        tp->fastopen_req->data = msg;
+       tp->fastopen_req->size = size;
 
        flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
        err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
                                    msg->msg_namelen, flags);
-       *size = tp->fastopen_req->copied;
+       *copied = tp->fastopen_req->copied;
        tcp_free_fastopen_req(tp);
        return err;
 }
@@ -1083,7 +1085,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        flags = msg->msg_flags;
        if (flags & MSG_FASTOPEN) {
-               err = tcp_sendmsg_fastopen(sk, msg, &copied_syn);
+               err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
                if (err == -EINPROGRESS && copied_syn > 0)
                        goto out;
                else if (err)
index ad37bf18ae4b95a6870a8019ecc3ca9ff55d7679..2388275adb9bd0fcfb8ea7a97a22ac661b4df745 100644 (file)
@@ -290,8 +290,7 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
        left = tp->snd_cwnd - in_flight;
        if (sk_can_gso(sk) &&
            left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
-           left * tp->mss_cache < sk->sk_gso_max_size &&
-           left < sk->sk_gso_max_segs)
+           left < tp->xmit_size_goal_segs)
                return true;
        return left <= tcp_max_tso_deferred_mss(tp);
 }
index 227cba79fa6b1f490f27a3aaf013070fbf9c8015..eeaac399420de043bb466603fcb03ff83076438a 100644 (file)
@@ -1945,8 +1945,9 @@ void tcp_enter_loss(struct sock *sk, int how)
                if (skb == tcp_send_head(sk))
                        break;
 
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
+               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
                        tp->undo_marker = 0;
+
                TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
                if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
index 3cf9765104978cbf8ed49d184f926f23130cd4fd..1e4eac779f51c81bf5472d13ed446fefb0827753 100644 (file)
@@ -2628,7 +2628,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 {
        __be32 dest, src;
        __u16 destp, srcp;
-       long delta = tw->tw_ttd - jiffies;
+       s32 delta = tw->tw_ttd - inet_tw_time_stamp();
 
        dest  = tw->tw_daddr;
        src   = tw->tw_rcv_saddr;
index 3be16727f058b191d305366f9cf5851f03c7c417..17a11e65e57fea3fa3728ce905df6130c580c48a 100644 (file)
@@ -767,6 +767,17 @@ void tcp_release_cb(struct sock *sk)
        if (flags & (1UL << TCP_TSQ_DEFERRED))
                tcp_tsq_handler(sk);
 
+       /* Here begins the tricky part :
+        * We are called from release_sock() with :
+        * 1) BH disabled
+        * 2) sk_lock.slock spinlock held
+        * 3) socket owned by us (sk->sk_lock.owned == 1)
+        *
+        * But following code is meant to be called from BH handlers,
+        * so we should keep BH disabled, but early release socket ownership
+        */
+       sock_release_ownership(sk);
+
        if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
                tcp_write_timer_handler(sk);
                __sock_put(sk);
@@ -864,8 +875,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 
                if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
                             fclone->fclone == SKB_FCLONE_CLONE))
-                       NET_INC_STATS_BH(sock_net(sk),
-                                        LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
+                       NET_INC_STATS(sock_net(sk),
+                                     LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
 
                if (unlikely(skb_cloned(skb)))
                        skb = pskb_copy(skb, gfp_mask);
@@ -2337,6 +2348,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        unsigned int cur_mss;
+       int err;
 
        /* Inconslusive MTU probe */
        if (icsk->icsk_mtup.probe_size) {
@@ -2400,11 +2412,15 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                     skb_headroom(skb) >= 0xFFFF)) {
                struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
                                                   GFP_ATOMIC);
-               return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
-                             -ENOBUFS;
+               err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
+                            -ENOBUFS;
        } else {
-               return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
+               err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
        }
+
+       if (likely(!err))
+               TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS;
+       return err;
 }
 
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
@@ -2908,7 +2924,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
        space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) -
                MAX_TCP_OPTION_SPACE;
 
-       syn_data = skb_copy_expand(syn, skb_headroom(syn), space,
+       space = min_t(size_t, space, fo->size);
+
+       /* limit to order-0 allocations */
+       space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER));
+
+       syn_data = skb_copy_expand(syn, MAX_TCP_HEADER, space,
                                   sk->sk_allocation);
        if (syn_data == NULL)
                goto fallback;
index d92e5586783e518c1f5db2b1bd3261766ff7a913..438a73aa777cf560f38a87801b03b8ce20a315b1 100644 (file)
@@ -138,6 +138,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
 config IPV6_VTI
 tristate "Virtual (secure) IPv6: tunneling"
        select IPV6_TUNNEL
+       select NET_IP_TUNNEL
        depends on INET6_XFRM_MODE_TUNNEL
        ---help---
        Tunneling means encapsulating data of one protocol type within
index fdbfeca36d6344c22db31886c3661796eb9e8f86..6c7fa0853fc74ef179b00de52d78aecee342e18b 100644 (file)
@@ -133,10 +133,12 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
 static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
 static DEFINE_SPINLOCK(addrconf_hash_lock);
 
-static void addrconf_verify(unsigned long);
+static void addrconf_verify(void);
+static void addrconf_verify_rtnl(void);
+static void addrconf_verify_work(struct work_struct *);
 
-static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0);
-static DEFINE_SPINLOCK(addrconf_verify_lock);
+static struct workqueue_struct *addrconf_wq;
+static DECLARE_DELAYED_WORK(addr_chk_work, addrconf_verify_work);
 
 static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
@@ -151,7 +153,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
                                                  u32 flags, u32 noflags);
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp);
-static void addrconf_dad_timer(unsigned long data);
+static void addrconf_dad_work(struct work_struct *w);
 static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
 static void addrconf_dad_run(struct inet6_dev *idev);
 static void addrconf_rs_timer(unsigned long data);
@@ -247,9 +249,9 @@ static void addrconf_del_rs_timer(struct inet6_dev *idev)
                __in6_dev_put(idev);
 }
 
-static void addrconf_del_dad_timer(struct inet6_ifaddr *ifp)
+static void addrconf_del_dad_work(struct inet6_ifaddr *ifp)
 {
-       if (del_timer(&ifp->dad_timer))
+       if (cancel_delayed_work(&ifp->dad_work))
                __in6_ifa_put(ifp);
 }
 
@@ -261,12 +263,12 @@ static void addrconf_mod_rs_timer(struct inet6_dev *idev,
        mod_timer(&idev->rs_timer, jiffies + when);
 }
 
-static void addrconf_mod_dad_timer(struct inet6_ifaddr *ifp,
-                                  unsigned long when)
+static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp,
+                                  unsigned long delay)
 {
-       if (!timer_pending(&ifp->dad_timer))
+       if (!delayed_work_pending(&ifp->dad_work))
                in6_ifa_hold(ifp);
-       mod_timer(&ifp->dad_timer, jiffies + when);
+       mod_delayed_work(addrconf_wq, &ifp->dad_work, delay);
 }
 
 static int snmp6_alloc_dev(struct inet6_dev *idev)
@@ -751,8 +753,9 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
 
        in6_dev_put(ifp->idev);
 
-       if (del_timer(&ifp->dad_timer))
-               pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
+       if (cancel_delayed_work(&ifp->dad_work))
+               pr_notice("delayed DAD work was pending while freeing ifa=%p\n",
+                         ifp);
 
        if (ifp->state != INET6_IFADDR_STATE_DEAD) {
                pr_warn("Freeing alive inet6 address %p\n", ifp);
@@ -849,8 +852,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
-       setup_timer(&ifa->dad_timer, addrconf_dad_timer,
-                   (unsigned long)ifa);
+       INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work);
        INIT_HLIST_NODE(&ifa->addr_lst);
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
@@ -990,6 +992,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
        enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP;
        unsigned long expires;
 
+       ASSERT_RTNL();
+
        spin_lock_bh(&ifp->state_lock);
        state = ifp->state;
        ifp->state = INET6_IFADDR_STATE_DEAD;
@@ -1021,7 +1025,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 
        write_unlock_bh(&ifp->idev->lock);
 
-       addrconf_del_dad_timer(ifp);
+       addrconf_del_dad_work(ifp);
 
        ipv6_ifa_notify(RTM_DELADDR, ifp);
 
@@ -1103,8 +1107,11 @@ retry:
         * Lifetime is greater than REGEN_ADVANCE time units.  In particular,
         * an implementation must not create a temporary address with a zero
         * Preferred Lifetime.
+        * Use age calculation as in addrconf_verify to avoid unnecessary
+        * temporary addresses being generated.
         */
-       if (tmp_prefered_lft <= regen_advance) {
+       age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+       if (tmp_prefered_lft <= regen_advance + age) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                ret = -1;
@@ -1601,7 +1608,7 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
 {
        if (ifp->flags&IFA_F_PERMANENT) {
                spin_lock_bh(&ifp->lock);
-               addrconf_del_dad_timer(ifp);
+               addrconf_del_dad_work(ifp);
                ifp->flags |= IFA_F_TENTATIVE;
                if (dad_failed)
                        ifp->flags |= IFA_F_DADFAILED;
@@ -1622,20 +1629,21 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
                        spin_unlock_bh(&ifp->lock);
                }
                ipv6_del_addr(ifp);
-       } else
+       } else {
                ipv6_del_addr(ifp);
+       }
 }
 
 static int addrconf_dad_end(struct inet6_ifaddr *ifp)
 {
        int err = -ENOENT;
 
-       spin_lock(&ifp->state_lock);
+       spin_lock_bh(&ifp->state_lock);
        if (ifp->state == INET6_IFADDR_STATE_DAD) {
                ifp->state = INET6_IFADDR_STATE_POSTDAD;
                err = 0;
        }
-       spin_unlock(&ifp->state_lock);
+       spin_unlock_bh(&ifp->state_lock);
 
        return err;
 }
@@ -1668,7 +1676,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
                }
        }
 
-       addrconf_dad_stop(ifp, 1);
+       spin_lock_bh(&ifp->state_lock);
+       /* transition from _POSTDAD to _ERRDAD */
+       ifp->state = INET6_IFADDR_STATE_ERRDAD;
+       spin_unlock_bh(&ifp->state_lock);
+
+       addrconf_mod_dad_work(ifp, 0);
 }
 
 /* Join to solicited addr multicast group. */
@@ -1677,6 +1690,8 @@ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
 {
        struct in6_addr maddr;
 
+       ASSERT_RTNL();
+
        if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))
                return;
 
@@ -1688,6 +1703,8 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
 {
        struct in6_addr maddr;
 
+       ASSERT_RTNL();
+
        if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP))
                return;
 
@@ -1698,6 +1715,9 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
 static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
+
+       ASSERT_RTNL();
+
        if (ifp->prefix_len >= 127) /* RFC 6164 */
                return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -1709,6 +1729,9 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
+
+       ASSERT_RTNL();
+
        if (ifp->prefix_len >= 127) /* RFC 6164 */
                return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -2268,11 +2291,13 @@ ok:
                                return;
                        }
 
-                       ifp->flags |= IFA_F_MANAGETEMPADDR;
                        update_lft = 0;
                        create = 1;
+                       spin_lock_bh(&ifp->lock);
+                       ifp->flags |= IFA_F_MANAGETEMPADDR;
                        ifp->cstamp = jiffies;
                        ifp->tokenized = tokenized;
+                       spin_unlock_bh(&ifp->lock);
                        addrconf_dad_start(ifp);
                }
 
@@ -2323,7 +2348,7 @@ ok:
                                         create, now);
 
                        in6_ifa_put(ifp);
-                       addrconf_verify(0);
+                       addrconf_verify();
                }
        }
        inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo);
@@ -2472,7 +2497,7 @@ static int inet6_addr_add(struct net *net, int ifindex,
                        manage_tempaddrs(idev, ifp, valid_lft, prefered_lft,
                                         true, jiffies);
                in6_ifa_put(ifp);
-               addrconf_verify(0);
+               addrconf_verify_rtnl();
                return 0;
        }
 
@@ -3008,7 +3033,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                hlist_for_each_entry_rcu(ifa, h, addr_lst) {
                        if (ifa->idev == idev) {
                                hlist_del_init_rcu(&ifa->addr_lst);
-                               addrconf_del_dad_timer(ifa);
+                               addrconf_del_dad_work(ifa);
                                goto restart;
                        }
                }
@@ -3046,7 +3071,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
        while (!list_empty(&idev->addr_list)) {
                ifa = list_first_entry(&idev->addr_list,
                                       struct inet6_ifaddr, if_list);
-               addrconf_del_dad_timer(ifa);
+               addrconf_del_dad_work(ifa);
 
                list_del(&ifa->if_list);
 
@@ -3145,10 +3170,10 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
                rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);
 
        ifp->dad_probes = idev->cnf.dad_transmits;
-       addrconf_mod_dad_timer(ifp, rand_num);
+       addrconf_mod_dad_work(ifp, rand_num);
 }
 
-static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
 {
        struct inet6_dev *idev = ifp->idev;
        struct net_device *dev = idev->dev;
@@ -3200,25 +3225,68 @@ out:
        read_unlock_bh(&idev->lock);
 }
 
-static void addrconf_dad_timer(unsigned long data)
+static void addrconf_dad_start(struct inet6_ifaddr *ifp)
 {
-       struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
+       bool begin_dad = false;
+
+       spin_lock_bh(&ifp->state_lock);
+       if (ifp->state != INET6_IFADDR_STATE_DEAD) {
+               ifp->state = INET6_IFADDR_STATE_PREDAD;
+               begin_dad = true;
+       }
+       spin_unlock_bh(&ifp->state_lock);
+
+       if (begin_dad)
+               addrconf_mod_dad_work(ifp, 0);
+}
+
+static void addrconf_dad_work(struct work_struct *w)
+{
+       struct inet6_ifaddr *ifp = container_of(to_delayed_work(w),
+                                               struct inet6_ifaddr,
+                                               dad_work);
        struct inet6_dev *idev = ifp->idev;
        struct in6_addr mcaddr;
 
+       enum {
+               DAD_PROCESS,
+               DAD_BEGIN,
+               DAD_ABORT,
+       } action = DAD_PROCESS;
+
+       rtnl_lock();
+
+       spin_lock_bh(&ifp->state_lock);
+       if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
+               action = DAD_BEGIN;
+               ifp->state = INET6_IFADDR_STATE_DAD;
+       } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) {
+               action = DAD_ABORT;
+               ifp->state = INET6_IFADDR_STATE_POSTDAD;
+       }
+       spin_unlock_bh(&ifp->state_lock);
+
+       if (action == DAD_BEGIN) {
+               addrconf_dad_begin(ifp);
+               goto out;
+       } else if (action == DAD_ABORT) {
+               addrconf_dad_stop(ifp, 1);
+               goto out;
+       }
+
        if (!ifp->dad_probes && addrconf_dad_end(ifp))
                goto out;
 
-       write_lock(&idev->lock);
+       write_lock_bh(&idev->lock);
        if (idev->dead || !(idev->if_flags & IF_READY)) {
-               write_unlock(&idev->lock);
+               write_unlock_bh(&idev->lock);
                goto out;
        }
 
        spin_lock(&ifp->lock);
        if (ifp->state == INET6_IFADDR_STATE_DEAD) {
                spin_unlock(&ifp->lock);
-               write_unlock(&idev->lock);
+               write_unlock_bh(&idev->lock);
                goto out;
        }
 
@@ -3229,7 +3297,7 @@ static void addrconf_dad_timer(unsigned long data)
 
                ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
                spin_unlock(&ifp->lock);
-               write_unlock(&idev->lock);
+               write_unlock_bh(&idev->lock);
 
                addrconf_dad_completed(ifp);
 
@@ -3237,16 +3305,17 @@ static void addrconf_dad_timer(unsigned long data)
        }
 
        ifp->dad_probes--;
-       addrconf_mod_dad_timer(ifp,
-                              NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
+       addrconf_mod_dad_work(ifp,
+                             NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
        spin_unlock(&ifp->lock);
-       write_unlock(&idev->lock);
+       write_unlock_bh(&idev->lock);
 
        /* send a neighbour solicitation for our addr */
        addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
        ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any);
 out:
        in6_ifa_put(ifp);
+       rtnl_unlock();
 }
 
 /* ifp->idev must be at least read locked */
@@ -3273,7 +3342,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
        struct in6_addr lladdr;
        bool send_rs, send_mld;
 
-       addrconf_del_dad_timer(ifp);
+       addrconf_del_dad_work(ifp);
 
        /*
         *      Configure the address for reception. Now it is valid.
@@ -3514,23 +3583,23 @@ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr)
  *     Periodic address status verification
  */
 
-static void addrconf_verify(unsigned long foo)
+static void addrconf_verify_rtnl(void)
 {
        unsigned long now, next, next_sec, next_sched;
        struct inet6_ifaddr *ifp;
        int i;
 
+       ASSERT_RTNL();
+
        rcu_read_lock_bh();
-       spin_lock(&addrconf_verify_lock);
        now = jiffies;
        next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
 
-       del_timer(&addr_chk_timer);
+       cancel_delayed_work(&addr_chk_work);
 
        for (i = 0; i < IN6_ADDR_HSIZE; i++) {
 restart:
-               hlist_for_each_entry_rcu_bh(ifp,
-                                        &inet6_addr_lst[i], addr_lst) {
+               hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[i], addr_lst) {
                        unsigned long age;
 
                        /* When setting preferred_lft to a value not zero or
@@ -3625,13 +3694,22 @@ restart:
 
        ADBG(KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
              now, next, next_sec, next_sched);
-
-       addr_chk_timer.expires = next_sched;
-       add_timer(&addr_chk_timer);
-       spin_unlock(&addrconf_verify_lock);
+       mod_delayed_work(addrconf_wq, &addr_chk_work, next_sched - now);
        rcu_read_unlock_bh();
 }
 
+static void addrconf_verify_work(struct work_struct *w)
+{
+       rtnl_lock();
+       addrconf_verify_rtnl();
+       rtnl_unlock();
+}
+
+static void addrconf_verify(void)
+{
+       mod_delayed_work(addrconf_wq, &addr_chk_work, 0);
+}
+
 static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local,
                                     struct in6_addr **peer_pfx)
 {
@@ -3688,6 +3766,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
        bool was_managetempaddr;
        bool had_prefixroute;
 
+       ASSERT_RTNL();
+
        if (!valid_lft || (prefered_lft > valid_lft))
                return -EINVAL;
 
@@ -3753,7 +3833,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
                                 !was_managetempaddr, jiffies);
        }
 
-       addrconf_verify(0);
+       addrconf_verify_rtnl();
 
        return 0;
 }
@@ -4383,6 +4463,8 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
        bool update_rs = false;
        struct in6_addr ll_addr;
 
+       ASSERT_RTNL();
+
        if (token == NULL)
                return -EINVAL;
        if (ipv6_addr_any(token))
@@ -4431,7 +4513,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
        }
 
        write_unlock_bh(&idev->lock);
-       addrconf_verify(0);
+       addrconf_verify_rtnl();
        return 0;
 }
 
@@ -4633,6 +4715,9 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 {
        struct net *net = dev_net(ifp->idev->dev);
 
+       if (event)
+               ASSERT_RTNL();
+
        inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
 
        switch (event) {
@@ -5241,6 +5326,12 @@ int __init addrconf_init(void)
        if (err < 0)
                goto out_addrlabel;
 
+       addrconf_wq = create_workqueue("ipv6_addrconf");
+       if (!addrconf_wq) {
+               err = -ENOMEM;
+               goto out_nowq;
+       }
+
        /* The addrconf netdev notifier requires that loopback_dev
         * has it's ipv6 private information allocated and setup
         * before it can bring up and give link-local addresses
@@ -5271,7 +5362,7 @@ int __init addrconf_init(void)
 
        register_netdevice_notifier(&ipv6_dev_notf);
 
-       addrconf_verify(0);
+       addrconf_verify();
 
        rtnl_af_register(&inet6_ops);
 
@@ -5299,6 +5390,8 @@ errout:
        rtnl_af_unregister(&inet6_ops);
        unregister_netdevice_notifier(&ipv6_dev_notf);
 errlo:
+       destroy_workqueue(addrconf_wq);
+out_nowq:
        unregister_pernet_subsys(&addrconf_ops);
 out_addrlabel:
        ipv6_addr_label_cleanup();
@@ -5334,7 +5427,8 @@ void addrconf_cleanup(void)
        for (i = 0; i < IN6_ADDR_HSIZE; i++)
                WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
        spin_unlock_bh(&addrconf_hash_lock);
-
-       del_timer(&addr_chk_timer);
+       cancel_delayed_work(&addr_chk_work);
        rtnl_unlock();
+
+       destroy_workqueue(addrconf_wq);
 }
index 140748debc4ade194e5e179636e94264da7e65a1..8af3eb57f4380fd7de7497ff98f40c88f2040e50 100644 (file)
@@ -212,7 +212,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                found = (nexthdr == target);
 
                if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
-                       if (target < 0)
+                       if (target < 0 || found)
                                break;
                        return -ENOENT;
                }
index cf77f3abfd061280f6a211deb4a24bcd247c944a..447a7fbd1bb6f28dc78203ef4f4254705dc68c99 100644 (file)
@@ -25,11 +25,11 @@ int __init ipv6_exthdrs_offload_init(void)
        int ret;
 
        ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
-       if (!ret)
+       if (ret)
                goto out;
 
        ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
-       if (!ret)
+       if (ret)
                goto out_rt;
 
 out:
index 1e8683b135bb7b503d9ab97d5c3c165af2453fa1..59f95affceb0773d052184bdf5fec9f276433d63 100644 (file)
@@ -89,7 +89,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        unsigned int unfrag_ip6hlen;
        u8 *prevhdr;
        int offset = 0;
-       bool tunnel;
+       bool encap, udpfrag;
        int nhoff;
 
        if (unlikely(skb_shinfo(skb)->gso_type &
@@ -110,8 +110,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
                goto out;
 
-       tunnel = SKB_GSO_CB(skb)->encap_level > 0;
-       if (tunnel)
+       encap = SKB_GSO_CB(skb)->encap_level > 0;
+       if (encap)
                features = skb->dev->hw_enc_features & netif_skb_features(skb);
        SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h);
 
@@ -121,6 +121,12 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
 
        proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
 
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
+
        ops = rcu_dereference(inet6_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment)) {
                skb_reset_transport_header(skb);
@@ -133,13 +139,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        for (skb = segs; skb; skb = skb->next) {
                ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff);
                ipv6h->payload_len = htons(skb->len - nhoff - sizeof(*ipv6h));
-               if (tunnel) {
-                       skb_reset_inner_headers(skb);
-                       skb->encapsulation = 1;
-               }
                skb->network_header = (u8 *)ipv6h - skb->head;
 
-               if (!tunnel && proto == IPPROTO_UDP) {
+               if (udpfrag) {
                        unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
                        fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
                        fptr->frag_off = htons(offset);
@@ -148,6 +150,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
                        offset += (ntohs(ipv6h->payload_len) -
                                   sizeof(struct frag_hdr));
                }
+               if (encap)
+                       skb_reset_inner_headers(skb);
        }
 
 out:
index 070a2fae2375cd5f6c4ad8109887dc6236ee5b08..64d6073731d368e54073f9ca97ac6ad0cecdd415 100644 (file)
@@ -530,9 +530,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       to->nf_trace = from->nf_trace;
-#endif
        skb_copy_secmark(to, from);
 }
 
@@ -1104,21 +1101,19 @@ static void ip6_append_data_mtu(unsigned int *mtu,
                                unsigned int fragheaderlen,
                                struct sk_buff *skb,
                                struct rt6_info *rt,
-                               bool pmtuprobe)
+                               unsigned int orig_mtu)
 {
        if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
                if (skb == NULL) {
                        /* first fragment, reserve header_len */
-                       *mtu = *mtu - rt->dst.header_len;
+                       *mtu = orig_mtu - rt->dst.header_len;
 
                } else {
                        /*
                         * this fragment is not first, the headers
                         * space is regarded as data space.
                         */
-                       *mtu = min(*mtu, pmtuprobe ?
-                                  rt->dst.dev->mtu :
-                                  dst_mtu(rt->dst.path));
+                       *mtu = orig_mtu;
                }
                *maxfraglen = ((*mtu - fragheaderlen) & ~7)
                              + fragheaderlen - sizeof(struct frag_hdr);
@@ -1135,7 +1130,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct inet_cork *cork;
        struct sk_buff *skb, *skb_prev = NULL;
-       unsigned int maxfraglen, fragheaderlen, mtu;
+       unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
        int exthdrlen;
        int dst_exthdrlen;
        int hh_len;
@@ -1217,6 +1212,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                dst_exthdrlen = 0;
                mtu = cork->fragsize;
        }
+       orig_mtu = mtu;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
@@ -1314,8 +1310,7 @@ alloc_new_skb:
                        if (skb == NULL || skb_prev == NULL)
                                ip6_append_data_mtu(&mtu, &maxfraglen,
                                                    fragheaderlen, skb, rt,
-                                                   np->pmtudisc >=
-                                                   IPV6_PMTUDISC_PROBE);
+                                                   orig_mtu);
 
                        skb_prev = skb;
 
index 0eb4038a4d63434738e938113b37bfe6611e07c3..8737400af0a095cac6666112cb8dcd4d60518823 100644 (file)
@@ -2349,13 +2349,14 @@ int ip6mr_get_route(struct net *net,
 }
 
 static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
-                            u32 portid, u32 seq, struct mfc6_cache *c, int cmd)
+                            u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
+                            int flags)
 {
        struct nlmsghdr *nlh;
        struct rtmsg *rtm;
        int err;
 
-       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -2423,7 +2424,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
        if (skb == NULL)
                goto errout;
 
-       err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
+       err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
        if (err < 0)
                goto errout;
 
@@ -2462,7 +2463,8 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
                                if (ip6mr_fill_mroute(mrt, skb,
                                                      NETLINK_CB(cb->skb).portid,
                                                      cb->nlh->nlmsg_seq,
-                                                     mfc, RTM_NEWROUTE) < 0)
+                                                     mfc, RTM_NEWROUTE,
+                                                     NLM_F_MULTI) < 0)
                                        goto done;
 next_entry:
                                e++;
@@ -2476,7 +2478,8 @@ next_entry:
                        if (ip6mr_fill_mroute(mrt, skb,
                                              NETLINK_CB(cb->skb).portid,
                                              cb->nlh->nlmsg_seq,
-                                             mfc, RTM_NEWROUTE) < 0) {
+                                             mfc, RTM_NEWROUTE,
+                                             NLM_F_MULTI) < 0) {
                                spin_unlock_bh(&mfc_unres_lock);
                                goto done;
                        }
index fb9beb78f00b23fc307384bf6aef21adf2ab6895..587bbdcb22b4c04c0186932d463bce29ca32b38e 100644 (file)
@@ -135,6 +135,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        fl6.flowi6_proto = IPPROTO_ICMPV6;
        fl6.saddr = np->saddr;
        fl6.daddr = *daddr;
+       fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_icmp_type = user_icmph.icmp6_type;
        fl6.fl6_icmp_code = user_icmph.icmp6_code;
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
index 11dac21e658690cdf01d7eb41c7e653d142ad9d4..fba54a407bb2b7c2aae62ac2d03df806bc1a794a 100644 (file)
@@ -1513,7 +1513,7 @@ int ip6_route_add(struct fib6_config *cfg)
        if (!table)
                goto out;
 
-       rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
+       rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
 
        if (!rt) {
                err = -ENOMEM;
index 3dfbcf1dcb1cbdb38a2a0b17a328bb424b139eb0..b4d74c86586cd1a0256afb59870e32ebbebd56e8 100644 (file)
@@ -475,6 +475,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
                ipip6_tunnel_unlink(sitn, tunnel);
                ipip6_tunnel_del_prl(tunnel, NULL);
        }
+       ip_tunnel_dst_reset_all(tunnel);
        dev_put(dev);
 }
 
@@ -1082,6 +1083,7 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
                t->parms.link = p->link;
                ipip6_tunnel_bind_dev(t->dev);
        }
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(t->dev);
 }
 
@@ -1112,6 +1114,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
        t->ip6rd.relay_prefix = relay_prefix;
        t->ip6rd.prefixlen = ip6rd->prefixlen;
        t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(t->dev);
        return 0;
 }
@@ -1271,6 +1274,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
                        break;
                }
+               ip_tunnel_dst_reset_all(t);
                netdev_state_change(dev);
                break;
 
@@ -1326,6 +1330,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
 
 static void ipip6_dev_free(struct net_device *dev)
 {
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+
+       free_percpu(tunnel->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1375,6 +1382,12 @@ static int ipip6_tunnel_init(struct net_device *dev)
                u64_stats_init(&ipip6_tunnel_stats->syncp);
        }
 
+       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+       if (!tunnel->dst_cache) {
+               free_percpu(dev->tstats);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -1405,6 +1418,12 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
                u64_stats_init(&ipip6_fb_stats->syncp);
        }
 
+       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+       if (!tunnel->dst_cache) {
+               free_percpu(dev->tstats);
+               return -ENOMEM;
+       }
+
        dev_hold(dev);
        rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
        return 0;
index e7359f9eaa8d4dd14b706afc9c7241c85e52d056..b261ee8b83fc87ddabcb447d1235ea8b67429de2 100644 (file)
@@ -113,7 +113,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index 1a04c13293628eb420088717dce841266328b09f..79326978517a6842b8538b6a45b95309b8e37d4f 100644 (file)
@@ -433,12 +433,13 @@ static inline int verify_sec_ctx_len(const void *p)
        return 0;
 }
 
-static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx)
+static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx,
+                                                                    gfp_t gfp)
 {
        struct xfrm_user_sec_ctx *uctx = NULL;
        int ctx_size = sec_ctx->sadb_x_ctx_len;
 
-       uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL);
+       uctx = kmalloc((sizeof(*uctx)+ctx_size), gfp);
 
        if (!uctx)
                return NULL;
@@ -1124,7 +1125,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
 
        sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
        if (sec_ctx != NULL) {
-               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
 
                if (!uctx)
                        goto out;
@@ -2231,14 +2232,14 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_
 
        sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
        if (sec_ctx != NULL) {
-               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
 
                if (!uctx) {
                        err = -ENOBUFS;
                        goto out;
                }
 
-               err = security_xfrm_policy_alloc(&xp->security, uctx);
+               err = security_xfrm_policy_alloc(&xp->security, uctx, GFP_KERNEL);
                kfree(uctx);
 
                if (err)
@@ -2335,12 +2336,12 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
 
        sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
        if (sec_ctx != NULL) {
-               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
 
                if (!uctx)
                        return -ENOMEM;
 
-               err = security_xfrm_policy_alloc(&pol_ctx, uctx);
+               err = security_xfrm_policy_alloc(&pol_ctx, uctx, GFP_KERNEL);
                kfree(uctx);
                if (err)
                        return err;
@@ -3239,8 +3240,8 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
                }
                if ((*dir = verify_sec_ctx_len(p)))
                        goto out;
-               uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
-               *dir = security_xfrm_policy_alloc(&xp->security, uctx);
+               uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_ATOMIC);
+               *dir = security_xfrm_policy_alloc(&xp->security, uctx, GFP_ATOMIC);
                kfree(uctx);
 
                if (*dir)
index 735d0f60c83a126683b599d1e967eb9ca18b0471..c83827e7c3248ad493b576ca565f21b485aa0453 100644 (file)
@@ -112,7 +112,6 @@ struct l2tp_net {
        spinlock_t l2tp_session_hlist_lock;
 };
 
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 
 static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
@@ -1863,7 +1862,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);
 /* We come here whenever a session's send_seq, cookie_len or
  * l2specific_len parameters are set.
  */
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+void l2tp_session_set_header_len(struct l2tp_session *session, int version)
 {
        if (version == L2TP_HDR_VER_2) {
                session->hdr_len = 6;
@@ -1876,6 +1875,7 @@ static void l2tp_session_set_header_len(struct l2tp_session *session, int versio
        }
 
 }
+EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
 
 struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
 {
@@ -2016,7 +2016,7 @@ static int __init l2tp_init(void)
        if (rc)
                goto out;
 
-       l2tp_wq = alloc_workqueue("l2tp", WQ_NON_REENTRANT | WQ_UNBOUND, 0);
+       l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);
        if (!l2tp_wq) {
                pr_err("alloc_workqueue failed\n");
                rc = -ENOMEM;
index 1f01ba3435bcf0889a79e510567f19f248b7eef5..3f93ccd6ba9768fe171f4e35e79d613226c1dbc7 100644 (file)
@@ -263,6 +263,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                      int length, int (*payload_hook)(struct sk_buff *skb));
 int l2tp_session_queue_purge(struct l2tp_session *session);
 int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
+void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 
 int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
                  int hdr_len);
index 4cfd722e91536c1de137ec64f1e33bbc7fc5e1ea..bd7387adea9eff25ce7ffd0683589dcdcc020ad0 100644 (file)
@@ -578,8 +578,10 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
        if (info->attrs[L2TP_ATTR_RECV_SEQ])
                session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
 
-       if (info->attrs[L2TP_ATTR_SEND_SEQ])
+       if (info->attrs[L2TP_ATTR_SEND_SEQ]) {
                session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
+               l2tp_session_set_header_len(session, session->tunnel->version);
+       }
 
        if (info->attrs[L2TP_ATTR_LNS_MODE])
                session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
index be5fadf3473946a3b7ef886eeadcb2d219e867aa..5990919356a5d7c7573d8cbd0f6c899f28eb7f67 100644 (file)
@@ -254,12 +254,14 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
                po = pppox_sk(sk);
                ppp_input(&po->chan, skb);
        } else {
-               l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: socket not bound\n",
-                         session->name);
+               l2tp_dbg(session, PPPOL2TP_MSG_DATA,
+                        "%s: recv %d byte data frame, passing to L2TP socket\n",
+                        session->name, data_len);
 
-               /* Not bound. Nothing we can do, so discard. */
-               atomic_long_inc(&session->stats.rx_errors);
-               kfree_skb(skb);
+               if (sock_queue_rcv_skb(sk, skb) < 0) {
+                       atomic_long_inc(&session->stats.rx_errors);
+                       kfree_skb(skb);
+               }
        }
 
        return;
@@ -1312,6 +1314,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                        po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
                                PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
                }
+               l2tp_session_set_header_len(session, session->tunnel->version);
                l2tp_info(session, PPPOL2TP_MSG_CONTROL,
                          "%s: set send_seq=%d\n",
                          session->name, session->send_seq);
index f43613a97dd664e2daf1856b001d7bdee5708d4f..0c1ecfdf9a128b05f76e545d3e0b95de50123176 100644 (file)
@@ -100,6 +100,12 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
                }
                max_bw = max(max_bw, width);
        }
+
+       /* use the configured bandwidth in case of monitor interface */
+       sdata = rcu_dereference(local->monitor_sdata);
+       if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf)
+               max_bw = max(max_bw, conf->def.width);
+
        rcu_read_unlock();
 
        return max_bw;
index 3701930c66493af53461a4f0c1849ad26450e092..5e44e3179e02aabaea7b6d455ec5ed656e3691b0 100644 (file)
@@ -1692,14 +1692,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
 void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
 void ieee80211_add_pending_skb(struct ieee80211_local *local,
                               struct sk_buff *skb);
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                  struct sk_buff_head *skbs,
-                                  void (*fn)(void *data), void *data);
-static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
-                                             struct sk_buff_head *skbs)
-{
-       ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
-}
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs);
 void ieee80211_flush_queues(struct ieee80211_local *local,
                            struct ieee80211_sub_if_data *sdata);
 
index 2802f9d9279de1527927a88bc731489cc22613c7..ad8b377b4b9f6cfa5d5e222a3c0aff169f4d72d1 100644 (file)
@@ -36,6 +36,7 @@ static struct sk_buff *mps_qos_null_get(struct sta_info *sta)
                                      sdata->vif.addr);
        nullfunc->frame_control = fc;
        nullfunc->duration_id = 0;
+       nullfunc->seq_ctrl = 0;
        /* no address resolution for this frame -> set addr 1 immediately */
        memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
        memset(skb_put(skb, 2), 0, 2); /* append QoS control field */
index fc1d82465b3ce1b1cdcc9edb4f5157618b70e8ce..245dce969b31165078c04fca9a5fc963457e9d68 100644 (file)
@@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        switch (vht_oper->chan_width) {
        case IEEE80211_VHT_CHANWIDTH_USE_HT:
                vht_chandef.width = chandef->width;
+               vht_chandef.center_freq1 = chandef->center_freq1;
                break;
        case IEEE80211_VHT_CHANWIDTH_80MHZ:
                vht_chandef.width = NL80211_CHAN_WIDTH_80;
@@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        ret = 0;
 
 out:
+       /*
+        * When tracking the current AP, don't do any further checks if the
+        * new chandef is identical to the one we're currently using for the
+        * connection. This keeps us from playing ping-pong with regulatory,
+        * without it the following can happen (for example):
+        *  - connect to an AP with 80 MHz, world regdom allows 80 MHz
+        *  - AP advertises regdom US
+        *  - CRDA loads regdom US with 80 MHz prohibited (old database)
+        *  - the code below detects an unsupported channel, downgrades, and
+        *    we disconnect from the AP in the caller
+        *  - disconnect causes CRDA to reload world regdomain and the game
+        *    starts anew.
+        * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881)
+        *
+        * It seems possible that there are still scenarios with CSA or real
+        * bandwidth changes where a this could happen, but those cases are
+        * less common and wouldn't completely prevent using the AP.
+        */
+       if (tracking &&
+           cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
+               return ret;
+
        /* don't print the message below for VHT mismatch if VHT is disabled */
        if (ret & IEEE80211_STA_DISABLE_VHT)
                vht_chandef = *chandef;
@@ -3753,6 +3776,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (WARN_ON(!chanctx_conf)) {
                        rcu_read_unlock();
+                       sta_info_free(local, new_sta);
                        return -EINVAL;
                }
                rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
index c24ca0d0f4697ea7040c813dbf24d1c32f707329..3e57f96c9666daf4b420cfd663864878bef34204 100644 (file)
@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *sta)
               sta->sta.addr, sta->sta.aid);
 
        if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+               /*
+                * Clear the flag only if the other one is still set
+                * so that the TX path won't start TX'ing new frames
+                * directly ... In the case that the driver flag isn't
+                * set ieee80211_sta_ps_deliver_wakeup() will clear it.
+                */
+               clear_sta_flag(sta, WLAN_STA_PS_STA);
                ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
                       sta->sta.addr, sta->sta.aid);
                return;
index decd30c1e29053d9a5e3ea56c7ccb66a7407578d..137a192e64bc3c2aa61cc9c5912a89bd3008cbe3 100644 (file)
@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
        return -ENOENT;
 }
 
-static void cleanup_single_sta(struct sta_info *sta)
+static void __cleanup_single_sta(struct sta_info *sta)
 {
        int ac, i;
        struct tid_ampdu_tx *tid_tx;
@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        struct ps_data *ps;
 
-       if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+       if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+           test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
                if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        ps = &sdata->bss->ps;
@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta)
                        return;
 
                clear_sta_flag(sta, WLAN_STA_PS_STA);
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
 
                atomic_dec(&ps->num_sta_ps);
                sta_info_recalc_tim(sta);
@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta)
                ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
                kfree(tid_tx);
        }
+}
 
+static void cleanup_single_sta(struct sta_info *sta)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       __cleanup_single_sta(sta);
        sta_info_free(local, sta);
 }
 
@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        rcu_read_unlock();
 
        spin_lock_init(&sta->lock);
+       spin_lock_init(&sta->ps_lock);
        INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
        mutex_init(&sta->ampdu_mlme.mtx);
@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
                goto out_err;
        }
 
-       /* notify driver */
-       err = sta_info_insert_drv_state(local, sdata, sta);
-       if (err)
-               goto out_err;
-
        local->num_sta++;
        local->sta_generation++;
        smp_mb();
 
+       /* simplify things and don't accept BA sessions yet */
+       set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+
        /* make the station visible */
        sta_info_hash_add(local, sta);
 
        list_add_rcu(&sta->list, &local->sta_list);
 
+       /* notify driver */
+       err = sta_info_insert_drv_state(local, sdata, sta);
+       if (err)
+               goto out_remove;
+
        set_sta_flag(sta, WLAN_STA_INSERTED);
+       /* accept BA sessions now */
+       clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
 
        ieee80211_recalc_min_chandef(sdata);
        ieee80211_sta_debugfs_add(sta);
@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
                mesh_accept_plinks_update(sdata);
 
        return 0;
+ out_remove:
+       sta_info_hash_del(local, sta);
+       list_del_rcu(&sta->list);
+       local->num_sta--;
+       synchronize_net();
+       __cleanup_single_sta(sta);
  out_err:
        mutex_unlock(&local->sta_mtx);
        rcu_read_lock();
@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
 }
 EXPORT_SYMBOL(ieee80211_find_sta);
 
-static void clear_sta_ps_flags(void *_sta)
+/* powersave support code */
+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 {
-       struct sta_info *sta = _sta;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff_head pending;
+       int filtered = 0, buffered = 0, ac;
+       unsigned long flags;
        struct ps_data *ps;
 
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta)
        else
                return;
 
-       clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-       if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
-               atomic_dec(&ps->num_sta_ps);
-}
-
-/* powersave support code */
-void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
-{
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct ieee80211_local *local = sdata->local;
-       struct sk_buff_head pending;
-       int filtered = 0, buffered = 0, ac;
-       unsigned long flags;
-
        clear_sta_flag(sta, WLAN_STA_SP);
 
        BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
        skb_queue_head_init(&pending);
 
+       /* sync with ieee80211_tx_h_unicast_ps_buf */
+       spin_lock(&sta->ps_lock);
        /* Send all buffered frames to the station */
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                int count = skb_queue_len(&pending), tmp;
@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
                buffered += tmp - count;
        }
 
-       ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+       ieee80211_add_pending_skbs(local, &pending);
+       clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+       clear_sta_flag(sta, WLAN_STA_PS_STA);
+       spin_unlock(&sta->ps_lock);
+
+       atomic_dec(&ps->num_sta_ps);
 
        /* This station just woke up and isn't aware of our SMPS state */
        if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
@@ -1188,6 +1206,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
        memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
        memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+       nullfunc->seq_ctrl = 0;
 
        skb->priority = tid;
        skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
index d77ff70906303855458734a5bfac0526460056eb..d3a6d8208f2f85f7db331238f41c0da2938f0f8d 100644 (file)
@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
  * @drv_unblock_wk: used for driver PS unblocking
  * @listen_interval: listen interval of this station, when we're acting as AP
  * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
  * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
  *     when it leaves power saving state or polls
  * @tx_filtered: buffers (per AC) of frames we already tried to
@@ -356,10 +357,8 @@ struct sta_info {
        /* use the accessors defined below */
        unsigned long _flags;
 
-       /*
-        * STA powersave frame queues, no more than the internal
-        * locking required.
-        */
+       /* STA powersave lock and frame queues */
+       spinlock_t ps_lock;
        struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
        struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
        unsigned long driver_buffered_tids;
index 97a02d3f7d87720795e1518d27fce0bbaed9bc4f..4080c615636fabf3d430ecd898d4349ccd213464 100644 (file)
@@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                       sta->sta.addr, sta->sta.aid, ac);
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                        purge_old_ps_buffers(tx->local);
+
+               /* sync with ieee80211_sta_ps_deliver_wakeup */
+               spin_lock(&sta->ps_lock);
+               /*
+                * STA woke up the meantime and all the frames on ps_tx_buf have
+                * been queued to pending queue. No reordering can happen, go
+                * ahead and Tx the packet.
+                */
+               if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
+                   !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+                       spin_unlock(&sta->ps_lock);
+                       return TX_CONTINUE;
+               }
+
                if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
                        struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
                        ps_dbg(tx->sdata,
@@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
                skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
+               spin_unlock(&sta->ps_lock);
 
                if (!timer_pending(&local->sta_cleanup))
                        mod_timer(&local->sta_cleanup,
index 676dc0967f377f1251a761bf2dff0c35c8e92346..b8700d417a9cf26735a581fe25eb2619cf4a37da 100644 (file)
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
 
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
-                                  struct sk_buff_head *skbs,
-                                  void (*fn)(void *data), void *data)
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                               struct sk_buff_head *skbs)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct sk_buff *skb;
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
                __skb_queue_tail(&local->pending[queue], skb);
        }
 
-       if (fn)
-               fn(data);
-
        for (i = 0; i < hw->queues; i++)
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
@@ -1740,6 +1736,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
+       /*
+        * Reconfigure sched scan if it was interrupted by FW restart or
+        * suspend.
+        */
+       mutex_lock(&local->mtx);
+       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
+                                               lockdep_is_held(&local->mtx));
+       if (sched_scan_sdata && local->sched_scan_req)
+               /*
+                * Sched scan stopped, but we don't want to report it. Instead,
+                * we're trying to reschedule.
+                */
+               if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
+                                                        local->sched_scan_req))
+                       sched_scan_stopped = true;
+       mutex_unlock(&local->mtx);
+
+       if (sched_scan_stopped)
+               cfg80211_sched_scan_stopped(local->hw.wiphy);
+
        /*
         * If this is for hw restart things are still running.
         * We may want to change that later, however.
@@ -1768,26 +1784,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        WARN_ON(1);
 #endif
 
-       /*
-        * Reconfigure sched scan if it was interrupted by FW restart or
-        * suspend.
-        */
-       mutex_lock(&local->mtx);
-       sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
-                                               lockdep_is_held(&local->mtx));
-       if (sched_scan_sdata && local->sched_scan_req)
-               /*
-                * Sched scan stopped, but we don't want to report it. Instead,
-                * we're trying to reschedule.
-                */
-               if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
-                                                        local->sched_scan_req))
-                       sched_scan_stopped = true;
-       mutex_unlock(&local->mtx);
-
-       if (sched_scan_stopped)
-               cfg80211_sched_scan_stopped(local->hw.wiphy);
-
        return 0;
 }
 
index 21211c60ca988992034bfc330977e846c3fc7010..d51422c778dee359bec450c75b77bfb24ca712f4 100644 (file)
@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                return IEEE80211_AC_BE;
        }
 
+       if (skb->protocol == sdata->control_port_protocol) {
+               skb->priority = 7;
+               return ieee80211_downgrade_queue(sdata, skb);
+       }
+
        /* use the data classifier to determine what 802.1d tag the
         * data frame has */
        rcu_read_lock();
index bb322d0beb484f3c66a334a5e0b24651f2a1ffca..b9f0e03743228ec852eee97eb6bb9ef1e0ab73e9 100644 (file)
@@ -1310,27 +1310,22 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
 }
 
 static int
-ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[])
+ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[])
 {
 #ifdef CONFIG_NF_NAT_NEEDED
        int ret;
 
-       if (cda[CTA_NAT_DST]) {
-               ret = ctnetlink_parse_nat_setup(ct,
-                                               NF_NAT_MANIP_DST,
-                                               cda[CTA_NAT_DST]);
-               if (ret < 0)
-                       return ret;
-       }
-       if (cda[CTA_NAT_SRC]) {
-               ret = ctnetlink_parse_nat_setup(ct,
-                                               NF_NAT_MANIP_SRC,
-                                               cda[CTA_NAT_SRC]);
-               if (ret < 0)
-                       return ret;
-       }
-       return 0;
+       ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_DST,
+                                       cda[CTA_NAT_DST]);
+       if (ret < 0)
+               return ret;
+
+       ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC,
+                                       cda[CTA_NAT_SRC]);
+       return ret;
 #else
+       if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
+               return 0;
        return -EOPNOTSUPP;
 #endif
 }
@@ -1659,11 +1654,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
                        goto err2;
        }
 
-       if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
-               err = ctnetlink_change_nat(ct, cda);
-               if (err < 0)
-                       goto err2;
-       }
+       err = ctnetlink_setup_nat(ct, cda);
+       if (err < 0)
+               goto err2;
 
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
index d3f5cd6dd962b195ea85775cd0432cf204e697b2..52ca952b802c5e3ea41c83823b90f74365b8fc76 100644 (file)
@@ -432,15 +432,15 @@ nf_nat_setup_info(struct nf_conn *ct,
 }
 EXPORT_SYMBOL(nf_nat_setup_info);
 
-unsigned int
-nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+static unsigned int
+__nf_nat_alloc_null_binding(struct nf_conn *ct, enum nf_nat_manip_type manip)
 {
        /* Force range to this IP; let proto decide mapping for
         * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
         * Use reply in case it's already been mangled (eg local packet).
         */
        union nf_inet_addr ip =
-               (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
+               (manip == NF_NAT_MANIP_SRC ?
                ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
                ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
        struct nf_nat_range range = {
@@ -448,7 +448,13 @@ nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
                .min_addr       = ip,
                .max_addr       = ip,
        };
-       return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
+       return nf_nat_setup_info(ct, &range, manip);
+}
+
+unsigned int
+nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+{
+       return __nf_nat_alloc_null_binding(ct, HOOK2MANIP(hooknum));
 }
 EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
 
@@ -702,9 +708,9 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
 
 static int
 nfnetlink_parse_nat(const struct nlattr *nat,
-                   const struct nf_conn *ct, struct nf_nat_range *range)
+                   const struct nf_conn *ct, struct nf_nat_range *range,
+                   const struct nf_nat_l3proto *l3proto)
 {
-       const struct nf_nat_l3proto *l3proto;
        struct nlattr *tb[CTA_NAT_MAX+1];
        int err;
 
@@ -714,38 +720,46 @@ nfnetlink_parse_nat(const struct nlattr *nat,
        if (err < 0)
                return err;
 
-       rcu_read_lock();
-       l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
-       if (l3proto == NULL) {
-               err = -EAGAIN;
-               goto out;
-       }
        err = l3proto->nlattr_to_range(tb, range);
        if (err < 0)
-               goto out;
+               return err;
 
        if (!tb[CTA_NAT_PROTO])
-               goto out;
+               return 0;
 
-       err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
-out:
-       rcu_read_unlock();
-       return err;
+       return nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
 }
 
+/* This function is called under rcu_read_lock() */
 static int
 nfnetlink_parse_nat_setup(struct nf_conn *ct,
                          enum nf_nat_manip_type manip,
                          const struct nlattr *attr)
 {
        struct nf_nat_range range;
+       const struct nf_nat_l3proto *l3proto;
        int err;
 
-       err = nfnetlink_parse_nat(attr, ct, &range);
+       /* Should not happen, restricted to creating new conntracks
+        * via ctnetlink.
+        */
+       if (WARN_ON_ONCE(nf_nat_initialized(ct, manip)))
+               return -EEXIST;
+
+       /* Make sure that L3 NAT is there by when we call nf_nat_setup_info to
+        * attach the null binding, otherwise this may oops.
+        */
+       l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
+       if (l3proto == NULL)
+               return -EAGAIN;
+
+       /* No NAT information has been passed, allocate the null-binding */
+       if (attr == NULL)
+               return __nf_nat_alloc_null_binding(ct, manip);
+
+       err = nfnetlink_parse_nat(attr, ct, &range, l3proto);
        if (err < 0)
                return err;
-       if (nf_nat_initialized(ct, manip))
-               return -EEXIST;
 
        return nf_nat_setup_info(ct, &range, manip);
 }
index f072fe803510320f7210c31b1a08ccddea5ae5b6..108120f216b17671351cb492c86cb0ae928504f6 100644 (file)
@@ -354,13 +354,16 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 
        skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
                                  GFP_ATOMIC);
-       if (!skb)
+       if (!skb) {
+               skb_tx_error(entskb);
                return NULL;
+       }
 
        nlh = nlmsg_put(skb, 0, 0,
                        NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
                        sizeof(struct nfgenmsg), 0);
        if (!nlh) {
+               skb_tx_error(entskb);
                kfree_skb(skb);
                return NULL;
        }
@@ -488,13 +491,15 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                nla->nla_type = NFQA_PAYLOAD;
                nla->nla_len = nla_attr_size(data_len);
 
-               skb_zerocopy(skb, entskb, data_len, hlen);
+               if (skb_zerocopy(skb, entskb, data_len, hlen))
+                       goto nla_put_failure;
        }
 
        nlh->nlmsg_len = skb->len;
        return skb;
 
 nla_put_failure:
+       skb_tx_error(entskb);
        kfree_skb(skb);
        net_err_ratelimited("nf_queue: error creating packet message\n");
        return NULL;
index e8254ad2e5a9f37e84694293c8ba4069b5e5f35e..425cf39af8907f1d0618b0904121073ea4dc116a 100644 (file)
@@ -116,7 +116,7 @@ static void nft_meta_get_eval(const struct nft_expr *expr,
                                 skb->sk->sk_socket->file->f_cred->fsgid);
                read_unlock_bh(&skb->sk->sk_callback_lock);
                break;
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
        case NFT_META_RTCLASSID: {
                const struct dst_entry *dst = skb_dst(skb);
 
@@ -199,7 +199,7 @@ static int nft_meta_init_validate_get(uint32_t key)
        case NFT_META_OIFTYPE:
        case NFT_META_SKUID:
        case NFT_META_SKGID:
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
        case NFT_META_RTCLASSID:
 #endif
 #ifdef CONFIG_NETWORK_SECMARK
index a2aeb318678f9e0e577801f6e42bda4df66ea805..85daa84bfdfee3d65296fb62c723a78e180c4497 100644 (file)
@@ -135,7 +135,8 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
        if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
                return ERR_PTR(-EINVAL);
 
-       if (len <= 4 && IS_ALIGNED(offset, len) && base != NFT_PAYLOAD_LL_HEADER)
+       if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
+           base != NFT_PAYLOAD_LL_HEADER)
                return &nft_payload_fast_ops;
        else
                return &nft_payload_ops;
index 8a310f239c93ed769f0eeadc1ce30c97fcd63de8..b718a52a46544036ba81a4105da149d8261d30c3 100644 (file)
@@ -21,9 +21,9 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
 {
        switch (pkt->ops->pf) {
        case NFPROTO_IPV4:
-               nft_reject_ipv4_eval(expr, data, pkt);
+               return nft_reject_ipv4_eval(expr, data, pkt);
        case NFPROTO_IPV6:
-               nft_reject_ipv6_eval(expr, data, pkt);
+               return nft_reject_ipv6_eval(expr, data, pkt);
        }
 }
 
index fdf51353cf78ac80958cadfa0e58e159970aa8bf..04748ab649c25bbb2d2d7cee6fbc192fb267dfbc 100644 (file)
@@ -1489,8 +1489,8 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family != AF_NETLINK)
                return -EINVAL;
 
-       /* Only superuser is allowed to send multicasts */
-       if (nladdr->nl_groups && !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
+       if ((nladdr->nl_groups || nladdr->nl_pid) &&
+           !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
                return -EPERM;
 
        if (!nlk->portid)
index 46bda010bf11740c1a2fcd9002a193a7ab70801a..56db888b1cd56785e23f0e0272d4ae3af87e32e6 100644 (file)
@@ -301,7 +301,7 @@ static int nci_open_device(struct nci_dev *ndev)
        rc = __nci_request(ndev, nci_reset_req, 0,
                           msecs_to_jiffies(NCI_RESET_TIMEOUT));
 
-       if (ndev->ops->setup(ndev))
+       if (ndev->ops->setup)
                ndev->ops->setup(ndev);
 
        if (!rc) {
index e9a48baf85510f92a5d29aceed7d27acce24035a..270b77dfac304afea375d4a5999b88cca863da90 100644 (file)
@@ -464,7 +464,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        }
        nla->nla_len = nla_attr_size(skb->len);
 
-       skb_zerocopy(user_skb, skb, skb->len, hlen);
+       err = skb_zerocopy(user_skb, skb, skb->len, hlen);
+       if (err)
+               goto out;
 
        /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
        if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
@@ -478,6 +480,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 
        err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
 out:
+       if (err)
+               skb_tx_error(skb);
        kfree_skb(nskb);
        return err;
 }
@@ -1174,7 +1178,7 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *in
        struct datapath *dp;
 
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
-       if (!dp)
+       if (IS_ERR(dp))
                return;
 
        WARN(dp->user_features, "Dropping previously announced user features\n");
@@ -1762,11 +1766,12 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        int bucket = cb->args[0], skip = cb->args[1];
        int i, j = 0;
 
+       rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
-       if (!dp)
+       if (!dp) {
+               rcu_read_unlock();
                return -ENODEV;
-
-       rcu_read_lock();
+       }
        for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
                struct vport *vport;
 
index 16f4b46161d4fe2b806a46e895aa46922e2ce038..2998989e76db0a7ccb8e25ef11aa393180956593 100644 (file)
@@ -73,6 +73,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
 
        if ((flow->key.eth.type == htons(ETH_P_IP) ||
             flow->key.eth.type == htons(ETH_P_IPV6)) &&
+           flow->key.ip.frag != OVS_FRAG_TYPE_LATER &&
            flow->key.ip.proto == IPPROTO_TCP &&
            likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) {
                tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb));
@@ -91,7 +92,7 @@ static void stats_read(struct flow_stats *stats,
                       unsigned long *used, __be16 *tcp_flags)
 {
        spin_lock(&stats->lock);
-       if (time_after(stats->used, *used))
+       if (!*used || time_after(stats->used, *used))
                *used = stats->used;
        *tcp_flags |= stats->tcp_flags;
        ovs_stats->n_packets += stats->packet_count;
@@ -102,30 +103,24 @@ static void stats_read(struct flow_stats *stats,
 void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
                        unsigned long *used, __be16 *tcp_flags)
 {
-       int cpu, cur_cpu;
+       int cpu;
 
        *used = 0;
        *tcp_flags = 0;
        memset(ovs_stats, 0, sizeof(*ovs_stats));
 
+       local_bh_disable();
        if (!flow->stats.is_percpu) {
                stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
        } else {
-               cur_cpu = get_cpu();
                for_each_possible_cpu(cpu) {
                        struct flow_stats *stats;
 
-                       if (cpu == cur_cpu)
-                               local_bh_disable();
-
                        stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
                        stats_read(stats, ovs_stats, used, tcp_flags);
-
-                       if (cpu == cur_cpu)
-                               local_bh_enable();
                }
-               put_cpu();
        }
+       local_bh_enable();
 }
 
 static void stats_reset(struct flow_stats *stats)
@@ -140,25 +135,17 @@ static void stats_reset(struct flow_stats *stats)
 
 void ovs_flow_stats_clear(struct sw_flow *flow)
 {
-       int cpu, cur_cpu;
+       int cpu;
 
+       local_bh_disable();
        if (!flow->stats.is_percpu) {
                stats_reset(flow->stats.stat);
        } else {
-               cur_cpu = get_cpu();
-
                for_each_possible_cpu(cpu) {
-
-                       if (cpu == cur_cpu)
-                               local_bh_disable();
-
                        stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
-
-                       if (cpu == cur_cpu)
-                               local_bh_enable();
                }
-               put_cpu();
        }
+       local_bh_enable();
 }
 
 static int check_header(struct sk_buff *skb, int len)
index 1313145e3b8650853514552a0ddb371b4000b788..a07d55e75698cf52068ebd54fb651a45d264817a 100644 (file)
@@ -273,11 +273,12 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
 
 void qdisc_list_add(struct Qdisc *q)
 {
-       struct Qdisc *root = qdisc_dev(q)->qdisc;
+       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+               struct Qdisc *root = qdisc_dev(q)->qdisc;
 
-       WARN_ON_ONCE(root == &noop_qdisc);
-       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
+               WARN_ON_ONCE(root == &noop_qdisc);
                list_add_tail(&q->list, &root->list);
+       }
 }
 EXPORT_SYMBOL(qdisc_list_add);
 
index 08ef7a42c0e411657e789cb140fad522aef97ed1..21e251766eb1a099c8f603c1f7bb5d33ec5b04a2 100644 (file)
@@ -601,6 +601,7 @@ static int fq_resize(struct Qdisc *sch, u32 log)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
        struct rb_root *array;
+       void *old_fq_root;
        u32 idx;
 
        if (q->fq_root && log == q->fq_trees_log)
@@ -615,13 +616,19 @@ static int fq_resize(struct Qdisc *sch, u32 log)
        for (idx = 0; idx < (1U << log); idx++)
                array[idx] = RB_ROOT;
 
-       if (q->fq_root) {
-               fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
-               fq_free(q->fq_root);
-       }
+       sch_tree_lock(sch);
+
+       old_fq_root = q->fq_root;
+       if (old_fq_root)
+               fq_rehash(q, old_fq_root, q->fq_trees_log, array, log);
+
        q->fq_root = array;
        q->fq_trees_log = log;
 
+       sch_tree_unlock(sch);
+
+       fq_free(old_fq_root);
+
        return 0;
 }
 
@@ -697,9 +704,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
                q->flow_refill_delay = usecs_to_jiffies(usecs_delay);
        }
 
-       if (!err)
+       if (!err) {
+               sch_tree_unlock(sch);
                err = fq_resize(sch, fq_log);
-
+               sch_tree_lock(sch);
+       }
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_dequeue(sch);
 
index 1cb413fead89522a64931a4e2472b39c4d6a720d..4f505a006896578ebdac1392af1dc064500665c9 100644 (file)
@@ -334,18 +334,6 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                        qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate,
                                                      tb[TCA_TBF_PTAB]));
 
-       if (q->qdisc != &noop_qdisc) {
-               err = fifo_set_limit(q->qdisc, qopt->limit);
-               if (err)
-                       goto done;
-       } else if (qopt->limit > 0) {
-               child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
-               if (IS_ERR(child)) {
-                       err = PTR_ERR(child);
-                       goto done;
-               }
-       }
-
        buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U);
        mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U);
 
@@ -390,6 +378,18 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                goto done;
        }
 
+       if (q->qdisc != &noop_qdisc) {
+               err = fifo_set_limit(q->qdisc, qopt->limit);
+               if (err)
+                       goto done;
+       } else if (qopt->limit > 0) {
+               child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
+               if (IS_ERR(child)) {
+                       err = PTR_ERR(child);
+                       goto done;
+               }
+       }
+
        sch_tree_lock(sch);
        if (child) {
                qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
index f558433537b8f829a3f6147256abb7c5d23e4b47..ee13d28d39d10702096f733ee8d88aa862459952 100644 (file)
@@ -1239,78 +1239,107 @@ void sctp_assoc_update(struct sctp_association *asoc,
 }
 
 /* Update the retran path for sending a retransmitted packet.
- * Round-robin through the active transports, else round-robin
- * through the inactive transports as this is the next best thing
- * we can try.
+ * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints:
+ *
+ *   When there is outbound data to send and the primary path
+ *   becomes inactive (e.g., due to failures), or where the
+ *   SCTP user explicitly requests to send data to an
+ *   inactive destination transport address, before reporting
+ *   an error to its ULP, the SCTP endpoint should try to send
+ *   the data to an alternate active destination transport
+ *   address if one exists.
+ *
+ *   When retransmitting data that timed out, if the endpoint
+ *   is multihomed, it should consider each source-destination
+ *   address pair in its retransmission selection policy.
+ *   When retransmitting timed-out data, the endpoint should
+ *   attempt to pick the most divergent source-destination
+ *   pair from the original source-destination pair to which
+ *   the packet was transmitted.
+ *
+ *   Note: Rules for picking the most divergent source-destination
+ *   pair are an implementation decision and are not specified
+ *   within this document.
+ *
+ * Our basic strategy is to round-robin transports in priorities
+ * according to sctp_state_prio_map[] e.g., if no such
+ * transport with state SCTP_ACTIVE exists, round-robin through
+ * SCTP_UNKNOWN, etc. You get the picture.
  */
-void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+static const u8 sctp_trans_state_to_prio_map[] = {
+       [SCTP_ACTIVE]   = 3,    /* best case */
+       [SCTP_UNKNOWN]  = 2,
+       [SCTP_PF]       = 1,
+       [SCTP_INACTIVE] = 0,    /* worst case */
+};
+
+static u8 sctp_trans_score(const struct sctp_transport *trans)
 {
-       struct sctp_transport *t, *next;
-       struct list_head *head = &asoc->peer.transport_addr_list;
-       struct list_head *pos;
+       return sctp_trans_state_to_prio_map[trans->state];
+}
 
-       if (asoc->peer.transport_count == 1)
-               return;
+static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
+                                                   struct sctp_transport *best)
+{
+       if (best == NULL)
+               return curr;
 
-       /* Find the next transport in a round-robin fashion. */
-       t = asoc->peer.retran_path;
-       pos = &t->transports;
-       next = NULL;
+       return sctp_trans_score(curr) > sctp_trans_score(best) ? curr : best;
+}
 
-       while (1) {
-               /* Skip the head. */
-               if (pos->next == head)
-                       pos = head->next;
-               else
-                       pos = pos->next;
+void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+{
+       struct sctp_transport *trans = asoc->peer.retran_path;
+       struct sctp_transport *trans_next = NULL;
 
-               t = list_entry(pos, struct sctp_transport, transports);
+       /* We're done as we only have the one and only path. */
+       if (asoc->peer.transport_count == 1)
+               return;
+       /* If active_path and retran_path are the same and active,
+        * then this is the only active path. Use it.
+        */
+       if (asoc->peer.active_path == asoc->peer.retran_path &&
+           asoc->peer.active_path->state == SCTP_ACTIVE)
+               return;
 
-               /* We have exhausted the list, but didn't find any
-                * other active transports.  If so, use the next
-                * transport.
-                */
-               if (t == asoc->peer.retran_path) {
-                       t = next;
+       /* Iterate from retran_path's successor back to retran_path. */
+       for (trans = list_next_entry(trans, transports); 1;
+            trans = list_next_entry(trans, transports)) {
+               /* Manually skip the head element. */
+               if (&trans->transports == &asoc->peer.transport_addr_list)
+                       continue;
+               if (trans->state == SCTP_UNCONFIRMED)
+                       continue;
+               trans_next = sctp_trans_elect_best(trans, trans_next);
+               /* Active is good enough for immediate return. */
+               if (trans_next->state == SCTP_ACTIVE)
                        break;
-               }
-
-               /* Try to find an active transport. */
-
-               if ((t->state == SCTP_ACTIVE) ||
-                   (t->state == SCTP_UNKNOWN)) {
+               /* We've reached the end, time to update path. */
+               if (trans == asoc->peer.retran_path)
                        break;
-               } else {
-                       /* Keep track of the next transport in case
-                        * we don't find any active transport.
-                        */
-                       if (t->state != SCTP_UNCONFIRMED && !next)
-                               next = t;
-               }
        }
 
-       if (t)
-               asoc->peer.retran_path = t;
-       else
-               t = asoc->peer.retran_path;
+       if (trans_next != NULL)
+               asoc->peer.retran_path = trans_next;
 
-       pr_debug("%s: association:%p addr:%pISpc\n", __func__, asoc,
-                &t->ipaddr.sa);
+       pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
+                __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
 }
 
-/* Choose the transport for sending retransmit packet.  */
-struct sctp_transport *sctp_assoc_choose_alter_transport(
-       struct sctp_association *asoc, struct sctp_transport *last_sent_to)
+struct sctp_transport *
+sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
+                                 struct sctp_transport *last_sent_to)
 {
        /* If this is the first time packet is sent, use the active path,
         * else use the retran path. If the last packet was sent over the
         * retran path, update the retran path and use it.
         */
-       if (!last_sent_to)
+       if (last_sent_to == NULL) {
                return asoc->peer.active_path;
-       else {
+       else {
                if (last_sent_to == asoc->peer.retran_path)
                        sctp_assoc_update_retran_path(asoc);
+
                return asoc->peer.retran_path;
        }
 }
index 632090b961c331b78efa79664392c7626451926d..3a1767ef3201a6a1870f641ef29e3683ea6dcff7 100644 (file)
@@ -1421,8 +1421,8 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
        BUG_ON(!list_empty(&chunk->list));
        list_del_init(&chunk->transmitted_list);
 
-       /* Free the chunk skb data and the SCTP_chunk stub itself. */
-       dev_kfree_skb(chunk->skb);
+       consume_skb(chunk->skb);
+       consume_skb(chunk->auth_chunk);
 
        SCTP_DBG_OBJCNT_DEC(chunk);
        kmem_cache_free(sctp_chunk_cachep, chunk);
index bd859154000e47cccdae4f9f5e4353ba3cb83fd0..5d6883ff00c3b7056639f06254caffcb14349e27 100644 (file)
@@ -495,11 +495,12 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
        }
 
        /* If the transport error count is greater than the pf_retrans
-        * threshold, and less than pathmaxrtx, then mark this transport
-        * as Partially Failed, ee SCTP Quick Failover Draft, secon 5.1,
-        * point 1
+        * threshold, and less than pathmaxrtx, and if the current state
+        * is not SCTP_UNCONFIRMED, then mark this transport as Partially
+        * Failed, see SCTP Quick Failover Draft, section 5.1
         */
        if ((transport->state != SCTP_PF) &&
+          (transport->state != SCTP_UNCONFIRMED) &&
           (asoc->pf_retrans < transport->pathmaxrxt) &&
           (transport->error_count > asoc->pf_retrans)) {
 
index 591b44d3b7de6bb39faa994cddc72851422ec08f..01e002430c858c293cdda11bd2962c3340043fb9 100644 (file)
@@ -758,6 +758,12 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                struct sctp_chunk auth;
                sctp_ierror_t ret;
 
+               /* Make sure that we and the peer are AUTH capable */
+               if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
+                       sctp_association_free(new_asoc);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+               }
+
                /* set-up our fake chunk so that we can process it */
                auth.skb = chunk->auth_chunk;
                auth.asoc = chunk->asoc;
@@ -768,10 +774,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                auth.transport = chunk->transport;
 
                ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-
-               /* We can now safely free the auth_chunk clone */
-               kfree_skb(chunk->auth_chunk);
-
                if (ret != SCTP_IERROR_NO_ERROR) {
                        sctp_association_free(new_asoc);
                        return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
index 879933aaed4c07ecd9cdad1809939ff729a588a7..a19ae1968d379d70ad36e51039d79469cfe30d18 100644 (file)
@@ -450,16 +450,17 @@ EXPORT_SYMBOL(sockfd_lookup);
 
 static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
 {
-       struct file *file;
+       struct fd f = fdget(fd);
        struct socket *sock;
 
        *err = -EBADF;
-       file = fget_light(fd, fput_needed);
-       if (file) {
-               sock = sock_from_file(file, err);
-               if (sock)
+       if (f.file) {
+               sock = sock_from_file(f.file, err);
+               if (likely(sock)) {
+                       *fput_needed = f.flags;
                        return sock;
-               fput_light(file, *fput_needed);
+               }
+               fdput(f);
        }
        return NULL;
 }
@@ -1985,6 +1986,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
 {
        if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
                return -EFAULT;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        return 0;
index a38c89969c686128df1a556598b248a70eec665f..574b86193b15a8251dc85555cc03a8e5f9af1768 100644 (file)
@@ -610,8 +610,13 @@ static struct notifier_block notifier = {
 
 int tipc_bearer_setup(void)
 {
+       int err;
+
+       err = register_netdevice_notifier(&notifier);
+       if (err)
+               return err;
        dev_add_pack(&tipc_packet_type);
-       return register_netdevice_notifier(&notifier);
+       return 0;
 }
 
 void tipc_bearer_cleanup(void)
index c301a9a592d82d570050116df07e54a4551da537..e6d721692ae016bbc900ac909406ca0a645848b0 100644 (file)
@@ -181,7 +181,7 @@ static struct sk_buff *cfg_set_own_addr(void)
        if (tipc_own_addr)
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (cannot change node address once assigned)");
-       tipc_core_start_net(addr);
+       tipc_net_start(addr);
        return tipc_cfg_reply_none();
 }
 
@@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
        struct tipc_cfg_msg_hdr *req_hdr;
        struct tipc_cfg_msg_hdr *rep_hdr;
        struct sk_buff *rep_buf;
-       int ret;
 
        /* Validate configuration message header (ignore invalid message) */
        req_hdr = (struct tipc_cfg_msg_hdr *)buf;
@@ -398,12 +397,8 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
                memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
                rep_hdr->tcm_len = htonl(rep_buf->len);
                rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
-
-               ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
-                                       rep_buf->len);
-               if (ret < 0)
-                       pr_err("Sending cfg reply message failed, no memory\n");
-
+               tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
+                                 rep_buf->len);
                kfree_skb(rep_buf);
        }
 }
index f9e88d8b04ca182b2e8c217e579647fbf9581e4e..80c20647b3d29fd75d2ebb8c760c2aa75214c515 100644 (file)
@@ -76,38 +76,14 @@ struct sk_buff *tipc_buf_acquire(u32 size)
        return skb;
 }
 
-/**
- * tipc_core_stop_net - shut down TIPC networking sub-systems
- */
-static void tipc_core_stop_net(void)
-{
-       tipc_net_stop();
-       tipc_bearer_cleanup();
-}
-
-/**
- * start_net - start TIPC networking sub-systems
- */
-int tipc_core_start_net(unsigned long addr)
-{
-       int res;
-
-       tipc_net_start(addr);
-       res = tipc_bearer_setup();
-       if (res < 0)
-               goto err;
-       return res;
-
-err:
-       tipc_core_stop_net();
-       return res;
-}
-
 /**
  * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
  */
 static void tipc_core_stop(void)
 {
+       tipc_handler_stop();
+       tipc_net_stop();
+       tipc_bearer_cleanup();
        tipc_netlink_stop();
        tipc_cfg_stop();
        tipc_subscr_stop();
@@ -122,30 +98,65 @@ static void tipc_core_stop(void)
  */
 static int tipc_core_start(void)
 {
-       int res;
+       int err;
 
        get_random_bytes(&tipc_random, sizeof(tipc_random));
 
-       res = tipc_handler_start();
-       if (!res)
-               res = tipc_ref_table_init(tipc_max_ports, tipc_random);
-       if (!res)
-               res = tipc_nametbl_init();
-       if (!res)
-               res = tipc_netlink_start();
-       if (!res)
-               res = tipc_socket_init();
-       if (!res)
-               res = tipc_register_sysctl();
-       if (!res)
-               res = tipc_subscr_start();
-       if (!res)
-               res = tipc_cfg_init();
-       if (res) {
-               tipc_handler_stop();
-               tipc_core_stop();
-       }
-       return res;
+       err = tipc_handler_start();
+       if (err)
+               goto out_handler;
+
+       err = tipc_ref_table_init(tipc_max_ports, tipc_random);
+       if (err)
+               goto out_reftbl;
+
+       err = tipc_nametbl_init();
+       if (err)
+               goto out_nametbl;
+
+       err = tipc_netlink_start();
+       if (err)
+               goto out_netlink;
+
+       err = tipc_socket_init();
+       if (err)
+               goto out_socket;
+
+       err = tipc_register_sysctl();
+       if (err)
+               goto out_sysctl;
+
+       err = tipc_subscr_start();
+       if (err)
+               goto out_subscr;
+
+       err = tipc_cfg_init();
+       if (err)
+               goto out_cfg;
+
+       err = tipc_bearer_setup();
+       if (err)
+               goto out_bearer;
+
+       return 0;
+out_bearer:
+       tipc_cfg_stop();
+out_cfg:
+       tipc_subscr_stop();
+out_subscr:
+       tipc_unregister_sysctl();
+out_sysctl:
+       tipc_socket_stop();
+out_socket:
+       tipc_netlink_stop();
+out_netlink:
+       tipc_nametbl_stop();
+out_nametbl:
+       tipc_ref_table_stop();
+out_reftbl:
+       tipc_handler_stop();
+out_handler:
+       return err;
 }
 
 static int __init tipc_init(void)
@@ -174,8 +185,6 @@ static int __init tipc_init(void)
 
 static void __exit tipc_exit(void)
 {
-       tipc_handler_stop();
-       tipc_core_stop_net();
        tipc_core_stop();
        pr_info("Deactivated\n");
 }
index 5569d96b4da3f3652bd418656a2f7e81822feda4..4dfe137587bbd35a519b87a107f4e665a625bdaa 100644 (file)
@@ -90,7 +90,6 @@ extern int tipc_random __read_mostly;
 /*
  * Routines available to privileged subsystems
  */
-int tipc_core_start_net(unsigned long);
 int tipc_handler_start(void);
 void tipc_handler_stop(void);
 int tipc_netlink_start(void);
index e4bc8a2967447fbde1f39d0d19146f2c7848ac99..1fabf160501f4f7b8127ef8d8a7583076e9b2eb4 100644 (file)
@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument)
 
        spin_lock_bh(&qitem_lock);
        if (!handler_enabled) {
-               pr_err("Signal request ignored by handler\n");
                spin_unlock_bh(&qitem_lock);
                return -ENOPROTOOPT;
        }
index 92a1533af4e0a689f93f30c5b560368f1a548e37..042e8e3cabc09f84aa5dce626c57a30faf3ca32d 100644 (file)
@@ -941,20 +941,48 @@ int tipc_nametbl_init(void)
        return 0;
 }
 
-void tipc_nametbl_stop(void)
+/**
+ * tipc_purge_publications - remove all publications for a given type
+ *
+ * tipc_nametbl_lock must be held when calling this function
+ */
+static void tipc_purge_publications(struct name_seq *seq)
 {
-       u32 i;
+       struct publication *publ, *safe;
+       struct sub_seq *sseq;
+       struct name_info *info;
 
-       if (!table.types)
+       if (!seq->sseqs) {
+               nameseq_delete_empty(seq);
                return;
+       }
+       sseq = seq->sseqs;
+       info = sseq->info;
+       list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
+               tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
+                                        publ->ref, publ->key);
+       }
+}
+
+void tipc_nametbl_stop(void)
+{
+       u32 i;
+       struct name_seq *seq;
+       struct hlist_head *seq_head;
+       struct hlist_node *safe;
 
-       /* Verify name table is empty, then release it */
+       /* Verify name table is empty and purge any lingering
+        * publications, then release the name table
+        */
        write_lock_bh(&tipc_nametbl_lock);
        for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
                if (hlist_empty(&table.types[i]))
                        continue;
-               pr_err("nametbl_stop(): orphaned hash chain detected\n");
-               break;
+               seq_head = &table.types[i];
+               hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
+                       tipc_purge_publications(seq);
+               }
+               continue;
        }
        kfree(table.types);
        table.types = NULL;
index 9f72a6376362e613cb87185acbb3581174c45592..3aaf73de9e2d017e96b3cc1124d5c9420d827abd 100644 (file)
@@ -83,8 +83,6 @@ static struct genl_ops tipc_genl_ops[] = {
        },
 };
 
-static int tipc_genl_family_registered;
-
 int tipc_netlink_start(void)
 {
        int res;
@@ -94,16 +92,10 @@ int tipc_netlink_start(void)
                pr_err("Failed to register netlink interface\n");
                return res;
        }
-
-       tipc_genl_family_registered = 1;
        return 0;
 }
 
 void tipc_netlink_stop(void)
 {
-       if (!tipc_genl_family_registered)
-               return;
-
        genl_unregister_family(&tipc_genl_family);
-       tipc_genl_family_registered = 0;
 }
index 2a2a938dc22cb3c14def50169afffa37ea5bec86..de3d593e2fee08c384ca2970d7a0fc695ff4d5fc 100644 (file)
@@ -126,9 +126,6 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
  */
 void tipc_ref_table_stop(void)
 {
-       if (!tipc_ref_table.entries)
-               return;
-
        vfree(tipc_ref_table.entries);
        tipc_ref_table.entries = NULL;
 }
index b635ca347a870dc55187c221b3df1f2dc295a333..646a930eefbf8fa9a86cfe7011848143aafa49b8 100644 (file)
@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
 static void tipc_conn_kref_release(struct kref *kref)
 {
        struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
-       struct tipc_server *s = con->server;
 
        if (con->sock) {
                tipc_sock_release_local(con->sock);
@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref)
        }
 
        tipc_clean_outqueues(con);
-
-       if (con->conid)
-               s->tipc_conn_shutdown(con->conid, con->usr_data);
-
        kfree(con);
 }
 
@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con)
        struct tipc_server *s = con->server;
 
        if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
+               if (con->conid)
+                       s->tipc_conn_shutdown(con->conid, con->usr_data);
+
                spin_lock_bh(&s->idr_lock);
                idr_remove(&s->conn_idr, con->conid);
                s->idr_in_use--;
@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid,
        list_add_tail(&e->list, &con->outqueue);
        spin_unlock_bh(&con->outqueue_lock);
 
-       if (test_bit(CF_CONNECTED, &con->flags))
+       if (test_bit(CF_CONNECTED, &con->flags)) {
                if (!queue_work(s->send_wq, &con->swork))
                        conn_put(con);
-
+       } else {
+               conn_put(con);
+       }
        return 0;
 }
 
@@ -573,7 +573,6 @@ int tipc_server_start(struct tipc_server *s)
                kmem_cache_destroy(s->rcvbuf_cache);
                return ret;
        }
-       s->enabled = 1;
        return ret;
 }
 
@@ -583,10 +582,6 @@ void tipc_server_stop(struct tipc_server *s)
        int total = 0;
        int id;
 
-       if (!s->enabled)
-               return;
-
-       s->enabled = 0;
        spin_lock_bh(&s->idr_lock);
        for (id = 0; total < s->idr_in_use; id++) {
                con = idr_find(&s->conn_idr, id);
index 98b23f20bc0f5cbb1631111177bd0d88adfcaa68..be817b0b547e87148a103284adc5285a66147c28 100644 (file)
@@ -56,7 +56,6 @@
  * @name: server name
  * @imp: message importance
  * @type: socket type
- * @enabled: identify whether server is launched or not
  */
 struct tipc_server {
        struct idr conn_idr;
@@ -74,7 +73,6 @@ struct tipc_server {
        const char name[TIPC_SERVER_NAME_LEN];
        int imp;
        int type;
-       int enabled;
 };
 
 int tipc_conn_sendmsg(struct tipc_server *s, int conid,
index aab4948f0affa995adc2603bd09db4b5d354b266..0ed0eaa62f29e7148052907892ff90ebd20d2fed 100644 (file)
@@ -70,8 +70,6 @@ static const struct proto_ops msg_ops;
 static struct proto tipc_proto;
 static struct proto tipc_proto_kern;
 
-static int sockets_enabled;
-
 /*
  * Revised TIPC socket locking policy:
  *
@@ -999,7 +997,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
 
        for (;;) {
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
+               if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
                        if (sock->state == SS_DISCONNECTING) {
                                err = -ENOTCONN;
                                break;
@@ -1625,7 +1623,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
        for (;;) {
                prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                          TASK_INTERRUPTIBLE);
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
+               if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
                        release_sock(sk);
                        timeo = schedule_timeout(timeo);
                        lock_sock(sk);
@@ -2027,8 +2025,6 @@ int tipc_socket_init(void)
                proto_unregister(&tipc_proto);
                goto out;
        }
-
-       sockets_enabled = 1;
  out:
        return res;
 }
@@ -2038,10 +2034,6 @@ int tipc_socket_init(void)
  */
 void tipc_socket_stop(void)
 {
-       if (!sockets_enabled)
-               return;
-
-       sockets_enabled = 0;
        sock_unregister(tipc_family_ops.family);
        proto_unregister(&tipc_proto);
 }
index 7cb0bd5b1176872dcd09ca830a8a01c5b1ec37c6..642437231ad5d2da2e7c9de5bd4494b082f3472e 100644 (file)
@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
 {
        struct tipc_subscriber *subscriber = sub->subscriber;
        struct kvec msg_sect;
-       int ret;
 
        msg_sect.iov_base = (void *)&sub->evt;
        msg_sect.iov_len = sizeof(struct tipc_event);
-
        sub->evt.event = htohl(event, sub->swap);
        sub->evt.found_lower = htohl(found_lower, sub->swap);
        sub->evt.found_upper = htohl(found_upper, sub->swap);
        sub->evt.port.ref = htohl(port_ref, sub->swap);
        sub->evt.port.node = htohl(node, sub->swap);
-       ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL,
-                               msg_sect.iov_base, msg_sect.iov_len);
-       if (ret < 0)
-               pr_err("Sending subscription event failed, no memory\n");
+       tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
+                         msg_sect.iov_len);
 }
 
 /**
@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub)
        /* The spin lock per subscriber is used to protect its members */
        spin_lock_bh(&subscriber->lock);
 
-       /* Validate if the connection related to the subscriber is
-        * closed (in case subscriber is terminating)
-        */
-       if (subscriber->conid == 0) {
-               spin_unlock_bh(&subscriber->lock);
-               return;
-       }
-
        /* Validate timeout (in case subscription is being cancelled) */
        if (sub->timeout == TIPC_WAIT_FOREVER) {
                spin_unlock_bh(&subscriber->lock);
@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber)
 
        spin_lock_bh(&subscriber->lock);
 
-       /* Invalidate subscriber reference */
-       subscriber->conid = 0;
-
        /* Destroy any existing subscriptions for subscriber */
        list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
                                 subscription_list) {
@@ -278,9 +263,9 @@ static void subscr_cancel(struct tipc_subscr *s,
  *
  * Called with subscriber lock held.
  */
-static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
-                                            struct tipc_subscriber *subscriber)
-{
+static int subscr_subscribe(struct tipc_subscr *s,
+                           struct tipc_subscriber *subscriber,
+                           struct tipc_subscription **sub_p) {
        struct tipc_subscription *sub;
        int swap;
 
@@ -291,23 +276,21 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
        if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
                s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
                subscr_cancel(s, subscriber);
-               return NULL;
+               return 0;
        }
 
        /* Refuse subscription if global limit exceeded */
        if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
                pr_warn("Subscription rejected, limit reached (%u)\n",
                        TIPC_MAX_SUBSCRIPTIONS);
-               subscr_terminate(subscriber);
-               return NULL;
+               return -EINVAL;
        }
 
        /* Allocate subscription object */
        sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
        if (!sub) {
                pr_warn("Subscription rejected, no memory\n");
-               subscr_terminate(subscriber);
-               return NULL;
+               return -ENOMEM;
        }
 
        /* Initialize subscription object */
@@ -321,8 +304,7 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
            (sub->seq.lower > sub->seq.upper)) {
                pr_warn("Subscription rejected, illegal request\n");
                kfree(sub);
-               subscr_terminate(subscriber);
-               return NULL;
+               return -EINVAL;
        }
        INIT_LIST_HEAD(&sub->nameseq_list);
        list_add(&sub->subscription_list, &subscriber->subscription_list);
@@ -335,8 +317,8 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
                             (Handler)subscr_timeout, (unsigned long)sub);
                k_start_timer(&sub->timer, sub->timeout);
        }
-
-       return sub;
+       *sub_p = sub;
+       return 0;
 }
 
 /* Handle one termination request for the subscriber */
@@ -350,10 +332,14 @@ static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
                                  void *usr_data, void *buf, size_t len)
 {
        struct tipc_subscriber *subscriber = usr_data;
-       struct tipc_subscription *sub;
+       struct tipc_subscription *sub = NULL;
 
        spin_lock_bh(&subscriber->lock);
-       sub = subscr_subscribe((struct tipc_subscr *)buf, subscriber);
+       if (subscr_subscribe((struct tipc_subscr *)buf, subscriber, &sub) < 0) {
+               spin_unlock_bh(&subscriber->lock);
+               subscr_terminate(subscriber);
+               return;
+       }
        if (sub)
                tipc_nametbl_subscribe(sub);
        spin_unlock_bh(&subscriber->lock);
index 29fc8bee97022f456f8b64b8ff6ff54a977962dd..94404f19f9deebbb7c55b7a1660dd011510ba3fd 100644 (file)
@@ -163,9 +163,8 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 
 static inline unsigned int unix_hash_fold(__wsum n)
 {
-       unsigned int hash = (__force unsigned int)n;
+       unsigned int hash = (__force unsigned int)csum_fold(n);
 
-       hash ^= hash>>16;
        hash ^= hash>>8;
        return hash&(UNIX_HASH_SIZE-1);
 }
@@ -1788,8 +1787,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
 
        err = mutex_lock_interruptible(&u->readlock);
-       if (err) {
-               err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
+       if (unlikely(err)) {
+               /* recvmsg() in non blocking mode is supposed to return -EAGAIN
+                * sk_rcvtimeo is not honored by mutex_lock_interruptible()
+                */
+               err = noblock ? -EAGAIN : -ERESTARTSYS;
                goto out;
        }
 
@@ -1914,6 +1916,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct unix_sock *u = unix_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name);
        int copied = 0;
+       int noblock = flags & MSG_DONTWAIT;
        int check_creds = 0;
        int target;
        int err = 0;
@@ -1929,7 +1932,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
 
        target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
-       timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
+       timeo = sock_rcvtimeo(sk, noblock);
 
        /* Lock the socket to prevent queue disordering
         * while sleeps in memcpy_tomsg
@@ -1941,8 +1944,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
        }
 
        err = mutex_lock_interruptible(&u->readlock);
-       if (err) {
-               err = sock_intr_errno(timeo);
+       if (unlikely(err)) {
+               /* recvmsg() in non blocking mode is supposed to return -EAGAIN
+                * sk_rcvtimeo is not honored by mutex_lock_interruptible()
+                */
+               err = noblock ? -EAGAIN : -ERESTARTSYS;
                goto out;
        }
 
index 010892b81a06642a3886c7df9b74f0af9ecb1d3c..a3bf18d116095f14f4238bc792d22e5f51f2dd26 100644 (file)
@@ -788,8 +788,6 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
        default:
                break;
        }
-
-       wdev->beacon_interval = 0;
 }
 
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
index 9b897fca7487dd4fe8d8364368e8516ab8f369c0..f0541370e68eb9071caa429772a0a55d952c27d4 100644 (file)
@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
                return;
        case NL80211_REGDOM_SET_BY_USER:
                treatment = reg_process_hint_user(reg_request);
-               if (treatment == REG_REQ_OK ||
+               if (treatment == REG_REQ_IGNORE ||
                    treatment == REG_REQ_ALREADY_SET)
                        return;
                schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
@@ -2373,6 +2373,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
        struct regulatory_request *lr;
+       bool user_reset = false;
        int r;
 
        if (!reg_is_valid_request(rd->alpha2)) {
@@ -2389,6 +2390,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
                break;
        case NL80211_REGDOM_SET_BY_USER:
                r = reg_set_rd_user(rd, lr);
+               user_reset = true;
                break;
        case NL80211_REGDOM_SET_BY_DRIVER:
                r = reg_set_rd_driver(rd, lr);
@@ -2402,8 +2404,14 @@ int set_regdom(const struct ieee80211_regdomain *rd)
        }
 
        if (r) {
-               if (r == -EALREADY)
+               switch (r) {
+               case -EALREADY:
                        reg_set_request_processed();
+                       break;
+               default:
+                       /* Back to world regulatory in case of errors */
+                       restore_regulatory_settings(user_reset);
+               }
 
                kfree(rd);
                return r;
index 4b98b25793c5c23fa1799463b45ad71a030fceb9..1d5c7bf29938231fa06428dc6236e36c1719860e 100644 (file)
@@ -1158,7 +1158,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
        if (hlist_unhashed(&pol->bydst))
                return NULL;
 
-       hlist_del(&pol->bydst);
+       hlist_del_init(&pol->bydst);
        hlist_del(&pol->byidx);
        list_del(&pol->walk.all);
        net->xfrm.policy_count[dir]--;
index a26b7aa794755f970756cadb3c817bfc500956d2..40f1b3e92e7812e83127064237db07f18048b0a5 100644 (file)
@@ -1159,6 +1159,11 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
        }
        x->props.aalgo = orig->props.aalgo;
 
+       if (orig->aead) {
+               x->aead = xfrm_algo_aead_clone(orig->aead);
+               if (!x->aead)
+                       goto error;
+       }
        if (orig->ealg) {
                x->ealg = xfrm_algo_clone(orig->ealg);
                if (!x->ealg)
@@ -1201,6 +1206,9 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
        x->props.flags = orig->props.flags;
        x->props.extra_flags = orig->props.extra_flags;
 
+       x->tfcpad = orig->tfcpad;
+       x->replay_maxdiff = orig->replay_maxdiff;
+       x->replay_maxage = orig->replay_maxage;
        x->curlft.add_time = orig->curlft.add_time;
        x->km.state = orig->km.state;
        x->km.seq = orig->km.seq;
@@ -1215,11 +1223,12 @@ out:
        return NULL;
 }
 
-/* net->xfrm.xfrm_state_lock is held */
 struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
 {
        unsigned int h;
-       struct xfrm_state *x;
+       struct xfrm_state *x = NULL;
+
+       spin_lock_bh(&net->xfrm.xfrm_state_lock);
 
        if (m->reqid) {
                h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1236,7 +1245,7 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                             m->old_family))
                                continue;
                        xfrm_state_hold(x);
-                       return x;
+                       break;
                }
        } else {
                h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1251,11 +1260,13 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                             m->old_family))
                                continue;
                        xfrm_state_hold(x);
-                       return x;
+                       break;
                }
        }
 
-       return NULL;
+       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+
+       return x;
 }
 EXPORT_SYMBOL(xfrm_migrate_state_find);
 
@@ -1451,7 +1462,7 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
 {
        int err = 0;
        struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
-       struct net *net = xs_net(*dst);
+       struct net *net = xs_net(*src);
 
        if (!afinfo)
                return -EAFNOSUPPORT;
index 1ae3ec7c18b0de977b1b781c8fee72d8357543bc..2f7ddc3a59b42db13c1df648b188a8dc312c5f8b 100644 (file)
 #include <linux/in6.h>
 #endif
 
-static inline int aead_len(struct xfrm_algo_aead *alg)
-{
-       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
-}
-
 static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
 {
        struct nlattr *rt = attrs[type];
@@ -1226,7 +1221,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs
                return 0;
 
        uctx = nla_data(rt);
-       return security_xfrm_policy_alloc(&pol->security, uctx);
+       return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL);
 }
 
 static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
@@ -1631,7 +1626,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
                if (rt) {
                        struct xfrm_user_sec_ctx *uctx = nla_data(rt);
 
-                       err = security_xfrm_policy_alloc(&ctx, uctx);
+                       err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
                        if (err)
                                return err;
                }
@@ -1933,7 +1928,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
                if (rt) {
                        struct xfrm_user_sec_ctx *uctx = nla_data(rt);
 
-                       err = security_xfrm_policy_alloc(&ctx, uctx);
+                       err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
                        if (err)
                                return err;
                }
index 547e15daf03dc86dbfa72818122bc4c61929edb0..93a0da26582b863c64efd5ff226a8386bfb58064 100644 (file)
@@ -155,6 +155,15 @@ ld-option = $(call try-run,\
 # Important: no spaces around options
 ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
 
+# ld-version
+# Usage: $(call ld-version)
+# Note this is mainly for HJ Lu's 3 number binutil versions
+ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh)
+
+# ld-ifversion
+# Usage:  $(call ld-ifversion, -ge, 22252, y)
+ld-ifversion = $(shell [ $(call ld-version) $(1) $(2) ] && echo $(3))
+
 ######
 
 ###
index d5d859c8072964014971b9b1401b96f83a183e5d..9f0ee22b914f3c8e83ea58ab71278e98b8c03e89 100644 (file)
@@ -198,7 +198,7 @@ $(multi-objs-y:.o=.s)   : modname = $(modname-multi)
 $(multi-objs-y:.o=.lst) : modname = $(modname-multi)
 
 quiet_cmd_cc_s_c = CC $(quiet_modtag)  $@
-cmd_cc_s_c       = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<
+cmd_cc_s_c       = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $<
 
 $(obj)/%.s: $(src)/%.c FORCE
        $(call if_changed_dep,cc_s_c)
diff --git a/scripts/gcc-ld b/scripts/gcc-ld
new file mode 100644 (file)
index 0000000..cadab9a
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+# run gcc with ld options
+# used as a wrapper to execute link time optimizations
+# yes virginia, this is not pretty
+
+ARGS="-nostdlib"
+
+while [ "$1" != "" ] ; do
+       case "$1" in
+       -save-temps|-m32|-m64) N="$1" ;;
+       -r) N="$1" ;;
+       -[Wg]*) N="$1" ;;
+       -[olv]|-[Ofd]*|-nostdlib) N="$1" ;;
+       --end-group|--start-group)
+                N="-Wl,$1" ;;
+       -[RTFGhIezcbyYu]*|\
+--script|--defsym|-init|-Map|--oformat|-rpath|\
+-rpath-link|--sort-section|--section-start|-Tbss|-Tdata|-Ttext|\
+--version-script|--dynamic-list|--version-exports-symbol|--wrap|-m)
+               A="$1" ; shift ; N="-Wl,$A,$1" ;;
+       -[m]*) N="$1" ;;
+       -*) N="-Wl,$1" ;;
+       *)  N="$1" ;;
+       esac
+       ARGS="$ARGS $N"
+       shift
+done
+
+exec $CC $ARGS
index ef474098d9f1d1e2609221d3d3571c1f29d1b599..17fa901418ae6a491ba61f3814a1143e2a62bfde 100644 (file)
@@ -257,7 +257,7 @@ case "$arg" in
                 && compr="lzop -9 -f"
                echo "$output_file" | grep -q "\.lz4$" \
                 && [ -x "`which lz4 2> /dev/null`" ] \
-                && compr="lz4 -9 -f"
+                && compr="lz4 -l -9 -f"
                echo "$output_file" | grep -q "\.cpio$" && compr="cat"
                shift
                ;;
diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh
new file mode 100755 (executable)
index 0000000..198580d
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/awk -f
+# extract linker version number from stdin and turn into single number
+       {
+       gsub(".*)", "");
+       split($1,a, ".");
+       print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5];
+       exit
+       }
index 40610984a1b54b06c579f953dabeb5ddb1304525..066355673930342a1b5e839950cbd1186ed6c24b 100644 (file)
@@ -623,7 +623,10 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
 
        switch (sym->st_shndx) {
        case SHN_COMMON:
-               warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+               if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) {
+                       /* Should warn here, but modpost runs before the linker */
+               } else
+                       warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
                break;
        case SHN_UNDEF:
                /* undefined symbol */
@@ -849,6 +852,7 @@ static const char *section_white_list[] =
        ".xt.lit",         /* xtensa */
        ".arcextmap*",                  /* arc */
        ".gnu.linkonce.arcext*",        /* arc : modules */
+       ".gnu.lto*",
        NULL
 };
 
@@ -1455,6 +1459,10 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
                to = find_elf_symbol(elf, r->r_addend, sym);
                tosym = sym_name(elf, to);
 
+               if (!strncmp(fromsym, "reference___initcall",
+                               sizeof("reference___initcall")-1))
+                       return;
+
                /* check whitelist - we may ignore it */
                if (secref_whitelist(mismatch,
                                        fromsec, fromsym, tosec, tosym)) {
@@ -1502,6 +1510,16 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 #define R_ARM_JUMP24   29
 #endif
 
+#ifndef        R_ARM_THM_CALL
+#define        R_ARM_THM_CALL          10
+#endif
+#ifndef        R_ARM_THM_JUMP24
+#define        R_ARM_THM_JUMP24        30
+#endif
+#ifndef        R_ARM_THM_JUMP19
+#define        R_ARM_THM_JUMP19        51
+#endif
+
 static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 {
        unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1515,6 +1533,9 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
        case R_ARM_PC24:
        case R_ARM_CALL:
        case R_ARM_JUMP24:
+       case R_ARM_THM_CALL:
+       case R_ARM_THM_JUMP24:
+       case R_ARM_THM_JUMP19:
                /* From ARM ABI: ((S + A) | T) - P */
                r->r_addend = (int)(long)(elf->hdr +
                              sechdr->sh_offset +
@@ -1680,6 +1701,19 @@ static void check_sec_ref(struct module *mod, const char *modname,
        }
 }
 
+static char *remove_dot(char *s)
+{
+       char *end;
+       int n = strcspn(s, ".");
+
+       if (n > 0 && s[n] != 0) {
+               strtoul(s + n + 1, &end, 10);
+               if  (end > s + n + 1 && (*end == '.' || *end == 0))
+                       s[n] = 0;
+       }
+       return s;
+}
+
 static void read_symbols(char *modname)
 {
        const char *symname;
@@ -1718,7 +1752,7 @@ static void read_symbols(char *modname)
        }
 
        for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
-               symname = info.strtab + sym->st_name;
+               symname = remove_dot(info.strtab + sym->st_name);
 
                handle_modversions(mod, &info, sym, symname);
                handle_moddevtable(mod, &info, sym, symname);
index 51207e4d5f8bcae0add675e31cf579f28763d1d4..168b43dc0a59b6be4edea0fc5768fb2d63cfa440 100644 (file)
@@ -127,7 +127,7 @@ struct elf_info {
        Elf_Section  export_gpl_sec;
        Elf_Section  export_unused_gpl_sec;
        Elf_Section  export_gpl_future_sec;
-       const char   *strtab;
+       char         *strtab;
        char         *modinfo;
        unsigned int modinfo_len;
 
index 8b4f24ae43381de05af67271edd9a8ddd57c651f..21e2b9cae685f01536ed159443707d5046c8c34c 100644 (file)
@@ -757,7 +757,8 @@ static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
-                                         struct xfrm_user_sec_ctx *sec_ctx)
+                                         struct xfrm_user_sec_ctx *sec_ctx,
+                                         gfp_t gfp)
 {
        return 0;
 }
index bbd32c729dbb4e019d1461116b84c25107e35ab8..347896548ad3159a152186a4c1a27cdf92f1f4ad 100644 (file)
@@ -65,8 +65,8 @@ no_payload:
  * taking a 32-bit syscall are zero.  If you can, you should call sys_keyctl()
  * directly.
  */
-asmlinkage long compat_sys_keyctl(u32 option,
-                                 u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
+                      u32, arg2, u32, arg3, u32, arg4, u32, arg5)
 {
        switch (option) {
        case KEYCTL_GET_KEYRING_ID:
index d46cbc5e335e9c330ccd74a08fcbf78aeafe8c96..2fb2576dc6448b3c1020dc311e0d81bfe77fb768 100644 (file)
@@ -1000,7 +1000,11 @@ static int keyring_detect_cycle_iterator(const void *object,
 
        kenter("{%d}", key->serial);
 
-       BUG_ON(key != ctx->match_data);
+       /* We might get a keyring with matching index-key that is nonetheless a
+        * different keyring. */
+       if (key != ctx->match_data)
+               return 0;
+
        ctx->result = ERR_PTR(-EDEADLK);
        return 1;
 }
index 15b6928592ef68aac565e3fc94daf4737b6adc54..919cad93ac82fa2fa7c017b5c85353ca8ac6818e 100644 (file)
@@ -1317,9 +1317,11 @@ void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 
-int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                              struct xfrm_user_sec_ctx *sec_ctx,
+                              gfp_t gfp)
 {
-       return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx);
+       return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx, gfp);
 }
 EXPORT_SYMBOL(security_xfrm_policy_alloc);
 
index 4b34847208cc9690284e9e7c7b6f9a960cfbead3..b332e2cc0954becf1fa365f9690fef63d52ba97c 100644 (file)
@@ -668,7 +668,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                if (flags[i] == SBLABEL_MNT)
                        continue;
                rc = security_context_to_sid(mount_options[i],
-                                            strlen(mount_options[i]), &sid);
+                                            strlen(mount_options[i]), &sid, GFP_KERNEL);
                if (rc) {
                        printk(KERN_WARNING "SELinux: security_context_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2489,7 +2489,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
                if (flags[i] == SBLABEL_MNT)
                        continue;
                len = strlen(mount_options[i]);
-               rc = security_context_to_sid(mount_options[i], len, &sid);
+               rc = security_context_to_sid(mount_options[i], len, &sid,
+                                            GFP_KERNEL);
                if (rc) {
                        printk(KERN_WARNING "SELinux: security_context_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2893,7 +2894,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (rc)
                return rc;
 
-       rc = security_context_to_sid(value, size, &newsid);
+       rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
        if (rc == -EINVAL) {
                if (!capable(CAP_MAC_ADMIN)) {
                        struct audit_buffer *ab;
@@ -3050,7 +3051,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        if (!value || !size)
                return -EACCES;
 
-       rc = security_context_to_sid((void *)value, size, &newsid);
+       rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
        if (rc)
                return rc;
 
@@ -5529,7 +5530,7 @@ static int selinux_setprocattr(struct task_struct *p,
                        str[size-1] = 0;
                        size--;
                }
-               error = security_context_to_sid(value, size, &sid);
+               error = security_context_to_sid(value, size, &sid, GFP_KERNEL);
                if (error == -EINVAL && !strcmp(name, "fscreate")) {
                        if (!capable(CAP_MAC_ADMIN)) {
                                struct audit_buffer *ab;
@@ -5638,7 +5639,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 
 static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
-       return security_context_to_sid(secdata, seclen, secid);
+       return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
 }
 
 static void selinux_release_secctx(char *secdata, u32 seclen)
index 8ed8daf7f1eed9df82f963294e89e849b0da4b1d..ce7852cf526b8e564f69a20c005da00a19a941ca 100644 (file)
@@ -134,7 +134,7 @@ int security_sid_to_context(u32 sid, char **scontext,
 int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
 
 int security_context_to_sid(const char *scontext, u32 scontext_len,
-       u32 *out_sid);
+                           u32 *out_sid, gfp_t gfp);
 
 int security_context_to_sid_default(const char *scontext, u32 scontext_len,
                                    u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
index 48c3cc94c1681718a78e6793c7e961e2d404f3fb..9f0584710c858a8281d51f2c287dc3b43b30d77f 100644 (file)
@@ -10,7 +10,8 @@
 #include <net/flow.h>
 
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
-                             struct xfrm_user_sec_ctx *uctx);
+                             struct xfrm_user_sec_ctx *uctx,
+                             gfp_t gfp);
 int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
                              struct xfrm_sec_ctx **new_ctxp);
 void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
index 5122affe06a8840e193150d62bd9b2f996fe67fe..d60c0ee66387d8078055414992ad36d7a2d31fa8 100644 (file)
@@ -576,7 +576,7 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
        if (length)
                goto out;
 
-       length = security_context_to_sid(buf, size, &sid);
+       length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -731,11 +731,13 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
@@ -817,11 +819,13 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
                objname = namebuf;
        }
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
@@ -878,11 +882,13 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
@@ -934,7 +940,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s", con, user) != 2)
                goto out;
 
-       length = security_context_to_sid(con, strlen(con) + 1, &sid);
+       length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -994,11 +1000,13 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
index 5d0144ee8ed6d58e1f75043edcd7995cf1ca3a0e..4bca49414a40e5a40c4369415f5c5b0aecba6347 100644 (file)
@@ -1289,16 +1289,18 @@ out:
  * @scontext: security context
  * @scontext_len: length in bytes
  * @sid: security identifier, SID
+ * @gfp: context for the allocation
  *
  * Obtains a SID associated with the security context that
  * has the string representation specified by @scontext.
  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
  * memory is available, or 0 on success.
  */
-int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
+int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
+                           gfp_t gfp)
 {
        return security_context_to_sid_core(scontext, scontext_len,
-                                           sid, SECSID_NULL, GFP_KERNEL, 0);
+                                           sid, SECSID_NULL, gfp, 0);
 }
 
 /**
index 0462cb3ff0a741a36b279dcef37ee784e8520c5c..98b042630a9eafcfa982a469461ee5fd4da362b7 100644 (file)
@@ -78,7 +78,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
  * xfrm_user_sec_ctx context.
  */
 static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
-                                  struct xfrm_user_sec_ctx *uctx)
+                                  struct xfrm_user_sec_ctx *uctx,
+                                  gfp_t gfp)
 {
        int rc;
        const struct task_security_struct *tsec = current_security();
@@ -94,7 +95,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
        if (str_len >= PAGE_SIZE)
                return -ENOMEM;
 
-       ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
+       ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
        if (!ctx)
                return -ENOMEM;
 
@@ -103,7 +104,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
        ctx->ctx_len = str_len;
        memcpy(ctx->ctx_str, &uctx[1], str_len);
        ctx->ctx_str[str_len] = '\0';
-       rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid);
+       rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp);
        if (rc)
                goto err;
 
@@ -282,9 +283,10 @@ int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
  * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
  */
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
-                             struct xfrm_user_sec_ctx *uctx)
+                             struct xfrm_user_sec_ctx *uctx,
+                             gfp_t gfp)
 {
-       return selinux_xfrm_alloc_user(ctxp, uctx);
+       return selinux_xfrm_alloc_user(ctxp, uctx, gfp);
 }
 
 /*
@@ -332,7 +334,7 @@ int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
 int selinux_xfrm_state_alloc(struct xfrm_state *x,
                             struct xfrm_user_sec_ctx *uctx)
 {
-       return selinux_xfrm_alloc_user(&x->security, uctx);
+       return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
 }
 
 /*
index e08789484e3001e08e53acd481d97dcc37a7f88f..34c668f2779882f10b278a5e92654511eec90ec6 100644 (file)
@@ -116,7 +116,7 @@ struct aoa_card {
        struct snd_card *alsa_card;
 };
         
-extern int aoa_snd_device_new(snd_device_type_t type,
+extern int aoa_snd_device_new(enum snd_device_type type,
        void * device_data, struct snd_device_ops * ops);
 extern struct snd_card *aoa_get_card(void);
 extern int aoa_snd_ctl_add(struct snd_kcontrol* control);
index 4cedc6950d72ffb79c329612fd91dc0fed465668..f01bffb702bc3d84544b0a29e12a158eb38805d1 100644 (file)
@@ -889,7 +889,7 @@ static int onyx_init_codec(struct aoa_codec *codec)
                return -ENODEV;
        }
 
-       if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) {
+       if (aoa_snd_device_new(SNDRV_DEV_CODEC, onyx, &ops)) {
                printk(KERN_ERR PFX "failed to create onyx snd device!\n");
                return -ENODEV;
        }
index c491ae0f749ca42578c8fd8faf4f4b43f0fcaf55..cf3c6303b7e3ca8e3dba43f00fb3ce934620ab50 100644 (file)
@@ -826,7 +826,7 @@ static int tas_init_codec(struct aoa_codec *codec)
                return -ENODEV;
        }
 
-       if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) {
+       if (aoa_snd_device_new(SNDRV_DEV_CODEC, tas, &ops)) {
                printk(KERN_ERR PFX "failed to create tas snd device!\n");
                return -ENODEV;
        }
index 69d2cb601f2a4daa7d32d6abda14c5095b56de01..7e8c3417cd853999246f3292dd16e395f6e70e6b 100644 (file)
@@ -92,7 +92,7 @@ static int toonie_init_codec(struct aoa_codec *codec)
        if (toonie->codec.connected != 1)
                return -ENOTCONN;
 
-       if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) {
+       if (aoa_snd_device_new(SNDRV_DEV_CODEC, toonie, &ops)) {
                printk(KERN_ERR PFX "failed to create toonie snd device!\n");
                return -ENODEV;
        }
index 0fa3855b4790e30753b7b8ea4fb29644a6e8cd1f..4a7e4e6b746fd3712cc596781346259814c2b6d4 100644 (file)
@@ -23,13 +23,12 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
                /* cannot be EEXIST due to usage in aoa_fabric_register */
                return -EBUSY;
 
-       err = snd_card_create(index, name, mod, sizeof(struct aoa_card),
-                             &alsa_card);
+       err = snd_card_new(dev, index, name, mod, sizeof(struct aoa_card),
+                          &alsa_card);
        if (err < 0)
                return err;
        aoa_card = alsa_card->private_data;
        aoa_card->alsa_card = alsa_card;
-       alsa_card->dev = dev;
        strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
        strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
        strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
@@ -60,7 +59,7 @@ void aoa_alsa_cleanup(void)
        }
 }
 
-int aoa_snd_device_new(snd_device_type_t type,
+int aoa_snd_device_new(enum snd_device_type type,
                       void * device_data, struct snd_device_ops * ops)
 {
        struct snd_card *card = aoa_get_card();
index c421fdb3c7a12bf76a2584c21831913e57455ce9..0e83a73efb16e18dc4a5dc5982e86976dc9e2f2c 100644 (file)
@@ -899,8 +899,8 @@ static struct aaci *aaci_init_card(struct amba_device *dev)
        struct snd_card *card;
        int err;
 
-       err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                             THIS_MODULE, sizeof(struct aaci), &card);
+       err = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                          THIS_MODULE, sizeof(struct aaci), &card);
        if (err < 0)
                return NULL;
 
@@ -1055,8 +1055,6 @@ static int aaci_probe(struct amba_device *dev,
        if (ret)
                goto out;
 
-       snd_card_set_dev(aaci->card, &dev->dev);
-
        ret = snd_card_register(aaci->card);
        if (ret == 0) {
                dev_info(&dev->dev, "%s\n", aaci->card->longname);
index 9a2ac1e0f77addbe779e919c83cf61ad22368111..3a10df6688ee4d310d474c5babbbc6f89f9359c0 100644 (file)
@@ -179,12 +179,11 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
                goto err_dev;
        }
 
-       ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                             THIS_MODULE, 0, &card);
+       ret = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                          THIS_MODULE, 0, &card);
        if (ret < 0)
                goto err;
 
-       card->dev = &dev->dev;
        strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
 
        ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
@@ -210,7 +209,6 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
 
        if (pdata && pdata->codec_pdata[0])
                snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]);
-       snd_card_set_dev(card, &dev->dev);
        ret = snd_card_register(card);
        if (ret == 0) {
                platform_set_drvdata(dev, card);
index 3519518e25a09612c71f1888bc097e9f088ca6ee..edf2ca72d518a3cef2058ffd7b66930bec154b01 100644 (file)
@@ -429,8 +429,9 @@ static int atmel_abdac_probe(struct platform_device *pdev)
        }
        clk_enable(pclk);
 
-       retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                       THIS_MODULE, sizeof(struct atmel_abdac), &card);
+       retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
+                             SNDRV_DEFAULT_STR1, THIS_MODULE,
+                             sizeof(struct atmel_abdac), &card);
        if (retval) {
                dev_dbg(&pdev->dev, "could not create sound card device\n");
                goto out_put_sample_clk;
@@ -467,8 +468,6 @@ static int atmel_abdac_probe(struct platform_device *pdev)
                goto out_unmap_regs;
        }
 
-       snd_card_set_dev(card, &pdev->dev);
-
        if (pdata->dws.dma_dev) {
                dma_cap_mask_t mask;
 
@@ -492,7 +491,7 @@ static int atmel_abdac_probe(struct platform_device *pdev)
        if (!pdata->dws.dma_dev || !dac->dma.chan) {
                dev_dbg(&pdev->dev, "DMA not available\n");
                retval = -ENODEV;
-               goto out_unset_card_dev;
+               goto out_unmap_regs;
        }
 
        strcpy(card->driver, "Atmel ABDAC");
@@ -521,9 +520,6 @@ static int atmel_abdac_probe(struct platform_device *pdev)
 out_release_dma:
        dma_release_channel(dac->dma.chan);
        dac->dma.chan = NULL;
-out_unset_card_dev:
-       snd_card_set_dev(card, NULL);
-       free_irq(irq, dac);
 out_unmap_regs:
        iounmap(dac->regs);
 out_free_card:
@@ -579,7 +575,6 @@ static int atmel_abdac_remove(struct platform_device *pdev)
 
        dma_release_channel(dac->dma.chan);
        dac->dma.chan = NULL;
-       snd_card_set_dev(card, NULL);
        iounmap(dac->regs);
        free_irq(dac->irq, dac);
        snd_card_free(card);
index c5f0ddd729b35a5ea0292b3c7a9347cb8aa04271..05ec049c9faf1edf799fd77f1ef606d18ee40c63 100644 (file)
@@ -945,8 +945,9 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
        }
        clk_enable(pclk);
 
-       retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                       THIS_MODULE, sizeof(struct atmel_ac97c), &card);
+       retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
+                             SNDRV_DEFAULT_STR1, THIS_MODULE,
+                             sizeof(struct atmel_ac97c), &card);
        if (retval) {
                dev_dbg(&pdev->dev, "could not create sound card device\n");
                goto err_snd_card_new;
@@ -990,8 +991,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
                chip->reset_pin = -EINVAL;
        }
 
-       snd_card_set_dev(card, &pdev->dev);
-
        atmel_ac97c_reset(chip);
 
        /* Enable overrun interrupt from codec channel */
@@ -1113,8 +1112,6 @@ err_dma:
                chip->dma.tx_chan = NULL;
        }
 err_ac97_bus:
-       snd_card_set_dev(card, NULL);
-
        if (gpio_is_valid(chip->reset_pin))
                gpio_free(chip->reset_pin);
 
@@ -1195,7 +1192,6 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
                chip->dma.tx_chan = NULL;
        }
 
-       snd_card_set_dev(card, NULL);
        snd_card_free(card);
 
        return 0;
index 7a20897d33dbc1147b381ca6884f87dc88eb7ff1..7403f348ed1425733ce77735c8dff37d1610ad4d 100644 (file)
@@ -133,7 +133,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
                kfree(data);
        }
        snd_card_unref(compr->card);
-       return 0;
+       return ret;
 }
 
 static int snd_compr_free(struct inode *inode, struct file *f)
index d8aa206e8bdece19a337175ee1e4a9f83b8e8569..f038f5afafe2bfb596af4e4c7f4abec306dba443 100644 (file)
@@ -151,7 +151,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
        if (snd_BUG_ON(!card || !id))
                return;
        read_lock(&card->ctl_files_rwlock);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
        card->mixer_oss_change_count++;
 #endif
        list_for_each_entry(ctl, &card->ctl_files, list) {
@@ -170,7 +170,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
                        ev->mask = mask;
                        list_add_tail(&ev->list, &ctl->events);
                } else {
-                       snd_printk(KERN_ERR "No memory available to allocate event\n");
+                       dev_err(card->dev, "No memory available to allocate event\n");
                }
        _found:
                wake_up(&ctl->change_sleep);
@@ -206,7 +206,7 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
 
        kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
        if (kctl == NULL) {
-               snd_printk(KERN_ERR "Cannot allocate control instance\n");
+               pr_err("ALSA: Cannot allocate control instance\n");
                return NULL;
        }
        *kctl = *control;
@@ -241,9 +241,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
        if (ncontrol->name) {
                strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
                if (strcmp(ncontrol->name, kctl.id.name) != 0)
-                       snd_printk(KERN_WARNING
-                                  "Control name '%s' truncated to '%s'\n",
-                                  ncontrol->name, kctl.id.name);
+                       pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
+                               ncontrol->name, kctl.id.name);
        }
        kctl.id.index = ncontrol->index;
        kctl.count = ncontrol->count ? ncontrol->count : 1;
@@ -306,7 +305,7 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
        while (snd_ctl_remove_numid_conflict(card, count)) {
                if (--iter == 0) {
                        /* this situation is very unlikely */
-                       snd_printk(KERN_ERR "unable to allocate new control numid\n");
+                       dev_err(card->dev, "unable to allocate new control numid\n");
                        return -ENOMEM;
                }
        }
@@ -341,7 +340,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
        down_write(&card->controls_rwsem);
        if (snd_ctl_find_id(card, &id)) {
                up_write(&card->controls_rwsem);
-               snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
+               dev_err(card->dev, "control %i:%i:%i:%s:%i is already present\n",
                                        id.iface,
                                        id.device,
                                        id.subdevice,
@@ -1406,7 +1405,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
                }
        }
        up_read(&snd_ioctl_rwsem);
-       snd_printdd("unknown ioctl = 0x%x\n", cmd);
+       dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
        return -ENOTTY;
 }
 
index 2bb95a7a8809fed3a042e8796b5431ce2afbee46..b9c0910fb8c4ead97559c7f9c1737e76b2d5cf7f 100644 (file)
@@ -247,7 +247,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
        } else {
                size = get_elem_size(type, count);
                if (size < 0) {
-                       printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
+                       dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
                        return -EINVAL;
                }
                if (copy_from_user(data->value.bytes.data,
index df88defed176a5592642ad6a91876add70c5f22a..41bec3075ae5b829c6f032520da7062c6214f662 100644 (file)
  *
  * Return: Zero if successful, or a negative error code on failure.
  */
-int snd_device_new(struct snd_card *card, snd_device_type_t type,
+int snd_device_new(struct snd_card *card, enum snd_device_type type,
                   void *device_data, struct snd_device_ops *ops)
 {
        struct snd_device *dev;
+       struct list_head *p;
 
        if (snd_BUG_ON(!card || !device_data || !ops))
                return -ENXIO;
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
-               snd_printk(KERN_ERR "Cannot allocate device\n");
+               dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
                return -ENOMEM;
        }
+       INIT_LIST_HEAD(&dev->list);
        dev->card = card;
        dev->type = type;
        dev->state = SNDRV_DEV_BUILD;
        dev->device_data = device_data;
        dev->ops = ops;
-       list_add(&dev->list, &card->devices);   /* add to the head of list */
+
+       /* insert the entry in an incrementally sorted list */
+       list_for_each_prev(p, &card->devices) {
+               struct snd_device *pdev = list_entry(p, struct snd_device, list);
+               if ((unsigned int)pdev->type <= (unsigned int)type)
+                       break;
+       }
+
+       list_add(&dev->list, p);
        return 0;
 }
-
 EXPORT_SYMBOL(snd_device_new);
 
+static int __snd_device_disconnect(struct snd_device *dev)
+{
+       if (dev->state == SNDRV_DEV_REGISTERED) {
+               if (dev->ops->dev_disconnect &&
+                   dev->ops->dev_disconnect(dev))
+                       dev_err(dev->card->dev, "device disconnect failure\n");
+               dev->state = SNDRV_DEV_DISCONNECTED;
+       }
+       return 0;
+}
+
+static void __snd_device_free(struct snd_device *dev)
+{
+       /* unlink */
+       list_del(&dev->list);
+
+       __snd_device_disconnect(dev);
+       if (dev->ops->dev_free) {
+               if (dev->ops->dev_free(dev))
+                       dev_err(dev->card->dev, "device free failure\n");
+       }
+       kfree(dev);
+}
+
+static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
+{
+       struct snd_device *dev;
+
+       list_for_each_entry(dev, &card->devices, list)
+               if (dev->device_data == device_data)
+                       return dev;
+
+       return NULL;
+}
+
 /**
  * snd_device_free - release the device from the card
  * @card: the card instance
@@ -72,73 +116,33 @@ EXPORT_SYMBOL(snd_device_new);
  * Removes the device from the list on the card and invokes the
  * callbacks, dev_disconnect and dev_free, corresponding to the state.
  * Then release the device.
- *
- * Return: Zero if successful, or a negative error code on failure or if the
- * device not found.
  */
-int snd_device_free(struct snd_card *card, void *device_data)
+void snd_device_free(struct snd_card *card, void *device_data)
 {
        struct snd_device *dev;
        
        if (snd_BUG_ON(!card || !device_data))
-               return -ENXIO;
-       list_for_each_entry(dev, &card->devices, list) {
-               if (dev->device_data != device_data)
-                       continue;
-               /* unlink */
-               list_del(&dev->list);
-               if (dev->state == SNDRV_DEV_REGISTERED &&
-                   dev->ops->dev_disconnect)
-                       if (dev->ops->dev_disconnect(dev))
-                               snd_printk(KERN_ERR
-                                          "device disconnect failure\n");
-               if (dev->ops->dev_free) {
-                       if (dev->ops->dev_free(dev))
-                               snd_printk(KERN_ERR "device free failure\n");
-               }
-               kfree(dev);
-               return 0;
-       }
-       snd_printd("device free %p (from %pF), not found\n", device_data,
-                  __builtin_return_address(0));
-       return -ENXIO;
+               return;
+       dev = look_for_dev(card, device_data);
+       if (dev)
+               __snd_device_free(dev);
+       else
+               dev_dbg(card->dev, "device free %p (from %pF), not found\n",
+                       device_data, __builtin_return_address(0));
 }
-
 EXPORT_SYMBOL(snd_device_free);
 
-/**
- * snd_device_disconnect - disconnect the device
- * @card: the card instance
- * @device_data: the data pointer to disconnect
- *
- * Turns the device into the disconnection state, invoking
- * dev_disconnect callback, if the device was already registered.
- *
- * Usually called from snd_card_disconnect().
- *
- * Return: Zero if successful, or a negative error code on failure or if the
- * device not found.
- */
-int snd_device_disconnect(struct snd_card *card, void *device_data)
+static int __snd_device_register(struct snd_device *dev)
 {
-       struct snd_device *dev;
-
-       if (snd_BUG_ON(!card || !device_data))
-               return -ENXIO;
-       list_for_each_entry(dev, &card->devices, list) {
-               if (dev->device_data != device_data)
-                       continue;
-               if (dev->state == SNDRV_DEV_REGISTERED &&
-                   dev->ops->dev_disconnect) {
-                       if (dev->ops->dev_disconnect(dev))
-                               snd_printk(KERN_ERR "device disconnect failure\n");
-                       dev->state = SNDRV_DEV_DISCONNECTED;
+       if (dev->state == SNDRV_DEV_BUILD) {
+               if (dev->ops->dev_register) {
+                       int err = dev->ops->dev_register(dev);
+                       if (err < 0)
+                               return err;
                }
-               return 0;
+               dev->state = SNDRV_DEV_REGISTERED;
        }
-       snd_printd("device disconnect %p (from %pF), not found\n", device_data,
-                  __builtin_return_address(0));
-       return -ENXIO;
+       return 0;
 }
 
 /**
@@ -157,26 +161,15 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
 int snd_device_register(struct snd_card *card, void *device_data)
 {
        struct snd_device *dev;
-       int err;
 
        if (snd_BUG_ON(!card || !device_data))
                return -ENXIO;
-       list_for_each_entry(dev, &card->devices, list) {
-               if (dev->device_data != device_data)
-                       continue;
-               if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
-                       if ((err = dev->ops->dev_register(dev)) < 0)
-                               return err;
-                       dev->state = SNDRV_DEV_REGISTERED;
-                       return 0;
-               }
-               snd_printd("snd_device_register busy\n");
-               return -EBUSY;
-       }
+       dev = look_for_dev(card, device_data);
+       if (dev)
+               return __snd_device_register(dev);
        snd_BUG();
        return -ENXIO;
 }
-
 EXPORT_SYMBOL(snd_device_register);
 
 /*
@@ -191,11 +184,9 @@ int snd_device_register_all(struct snd_card *card)
        if (snd_BUG_ON(!card))
                return -ENXIO;
        list_for_each_entry(dev, &card->devices, list) {
-               if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
-                       if ((err = dev->ops->dev_register(dev)) < 0)
-                               return err;
-                       dev->state = SNDRV_DEV_REGISTERED;
-               }
+               err = __snd_device_register(dev);
+               if (err < 0)
+                       return err;
        }
        return 0;
 }
@@ -211,8 +202,8 @@ int snd_device_disconnect_all(struct snd_card *card)
 
        if (snd_BUG_ON(!card))
                return -ENXIO;
-       list_for_each_entry(dev, &card->devices, list) {
-               if (snd_device_disconnect(card, dev->device_data) < 0)
+       list_for_each_entry_reverse(dev, &card->devices, list) {
+               if (__snd_device_disconnect(dev) < 0)
                        err = -ENXIO;
        }
        return err;
@@ -222,24 +213,12 @@ int snd_device_disconnect_all(struct snd_card *card)
  * release all the devices on the card.
  * called from init.c
  */
-int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
+void snd_device_free_all(struct snd_card *card)
 {
-       struct snd_device *dev;
-       int err;
-       unsigned int range_low, range_high, type;
+       struct snd_device *dev, *next;
 
        if (snd_BUG_ON(!card))
-               return -ENXIO;
-       range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
-       range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
-      __again:
-       list_for_each_entry(dev, &card->devices, list) {
-               type = (__force unsigned int)dev->type;
-               if (type >= range_low && type <= range_high) {
-                       if ((err = snd_device_free(card, dev->device_data)) < 0)
-                               return err;
-                       goto __again;
-               }
-       }
-       return 0;
+               return;
+       list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
+               __snd_device_free(dev);
 }
index b8b31c433d640279b9f4e13a9b46ca90d9a6452d..886be7da989d1ab52d647105ef3648a8045facbe 100644 (file)
@@ -126,8 +126,7 @@ static int __init snd_hrtimer_init(void)
 
        hrtimer_get_res(CLOCK_MONOTONIC, &tp);
        if (tp.tv_sec > 0 || !tp.tv_nsec) {
-               snd_printk(KERN_ERR
-                          "snd-hrtimer: Invalid resolution %u.%09u",
+               pr_err("snd-hrtimer: Invalid resolution %u.%09u",
                           (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
                return -EINVAL;
        }
index d105073298cb536148214fd04edb318220825e13..69459e5f712e9e50c51f5d3aedb360616afe5c1b 100644 (file)
@@ -375,7 +375,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
                *rhwdep = NULL;
        hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
        if (hwdep == NULL) {
-               snd_printk(KERN_ERR "hwdep: cannot allocate\n");
+               dev_err(card->dev, "hwdep: cannot allocate\n");
                return -ENOMEM;
        }
        hwdep->card = card;
@@ -395,6 +395,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
                *rhwdep = hwdep;
        return 0;
 }
+EXPORT_SYMBOL(snd_hwdep_new);
 
 static int snd_hwdep_free(struct snd_hwdep *hwdep)
 {
@@ -415,37 +416,61 @@ static int snd_hwdep_dev_free(struct snd_device *device)
 static int snd_hwdep_dev_register(struct snd_device *device)
 {
        struct snd_hwdep *hwdep = device->device_data;
+       struct snd_card *card = hwdep->card;
+       struct device *dev;
        int err;
        char name[32];
 
        mutex_lock(&register_mutex);
-       if (snd_hwdep_search(hwdep->card, hwdep->device)) {
+       if (snd_hwdep_search(card, hwdep->device)) {
                mutex_unlock(&register_mutex);
                return -EBUSY;
        }
        list_add_tail(&hwdep->list, &snd_hwdep_devices);
        sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
-       if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
-                                      hwdep->card, hwdep->device,
-                                      &snd_hwdep_f_ops, hwdep, name)) < 0) {
-               snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n",
-                          hwdep->card->number, hwdep->device);
+       dev = hwdep->dev;
+       if (!dev)
+               dev = snd_card_get_device_link(hwdep->card);
+       err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP,
+                                         hwdep->card, hwdep->device,
+                                         &snd_hwdep_f_ops, hwdep, name, dev);
+       if (err < 0) {
+               dev_err(dev,
+                       "unable to register hardware dependent device %i:%i\n",
+                       card->number, hwdep->device);
                list_del(&hwdep->list);
                mutex_unlock(&register_mutex);
                return err;
        }
+
+       if (hwdep->groups) {
+               struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP,
+                                                 hwdep->card, hwdep->device);
+               if (d) {
+                       if (hwdep->private_data)
+                               dev_set_drvdata(d, hwdep->private_data);
+                       err = sysfs_create_groups(&d->kobj, hwdep->groups);
+                       if (err < 0)
+                               dev_warn(dev,
+                                        "hwdep %d:%d: cannot create sysfs groups\n",
+                                        card->number, hwdep->device);
+                       put_device(d);
+               }
+       }
+
 #ifdef CONFIG_SND_OSSEMUL
        hwdep->ossreg = 0;
        if (hwdep->oss_type >= 0) {
                if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
-                       snd_printk (KERN_WARNING "only hwdep device 0 can be registered as OSS direct FM device!\n");
+                       dev_warn(dev,
+                                "only hwdep device 0 can be registered as OSS direct FM device!\n");
                } else {
                        if (snd_register_oss_device(hwdep->oss_type,
-                                                   hwdep->card, hwdep->device,
-                                                   &snd_hwdep_f_ops, hwdep,
-                                                   hwdep->oss_dev) < 0) {
-                               snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n",
-                                          hwdep->card->number, hwdep->device);
+                                                   card, hwdep->device,
+                                                   &snd_hwdep_f_ops, hwdep) < 0) {
+                               dev_err(dev,
+                                       "unable to register OSS compatibility device %i:%i\n",
+                                       card->number, hwdep->device);
                        } else
                                hwdep->ossreg = 1;
                }
@@ -543,5 +568,3 @@ static void __exit alsa_hwdep_exit(void)
 
 module_init(alsa_hwdep_init)
 module_exit(alsa_hwdep_exit)
-
-EXPORT_SYMBOL(snd_hwdep_new);
index e79baa11b60eb15526ba3679537720b2f29d0de6..051d55b05521216d31a1d011d58560744e930672 100644 (file)
@@ -418,9 +418,14 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
                        if (entry->c.text.write) {
                                entry->c.text.write(entry, data->wbuffer);
                                if (data->wbuffer->error) {
-                                       snd_printk(KERN_WARNING "data write error to %s (%i)\n",
-                                               entry->name,
-                                               data->wbuffer->error);
+                                       if (entry->card)
+                                               dev_warn(entry->card->dev, "info: data write error to %s (%i)\n",
+                                                        entry->name,
+                                                        data->wbuffer->error);
+                                       else
+                                               pr_warn("ALSA: info: data write error to %s (%i)\n",
+                                                       entry->name,
+                                                       data->wbuffer->error);
                                }
                        }
                        kfree(data->wbuffer->buffer);
@@ -540,7 +545,7 @@ int __init snd_info_init(void)
                snd_oss_root = entry;
        }
 #endif
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
        {
                struct snd_info_entry *entry;
                if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL)
@@ -567,7 +572,7 @@ int __exit snd_info_done(void)
        snd_minor_info_done();
        snd_info_version_done();
        if (snd_proc_root) {
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
                snd_info_free_entry(snd_seq_root);
 #endif
 #ifdef CONFIG_SND_OSSEMUL
index 0d42fcda0de2805235ea7fd3a685633050132f23..5ee83845c5de578aa2f9fc70684f95061679197a 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/time.h>
 #include <linux/ctype.h>
 #include <linux/pm.h>
+#include <linux/completion.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -94,7 +95,7 @@ static int module_slot_match(struct module *module, int idx)
        return match;
 }
 
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
 int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
 EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
 #endif
@@ -112,11 +113,11 @@ static inline int init_info_for_card(struct snd_card *card)
        struct snd_info_entry *entry;
 
        if ((err = snd_info_card_register(card)) < 0) {
-               snd_printd("unable to create card info\n");
+               dev_dbg(card->dev, "unable to create card info\n");
                return err;
        }
        if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
-               snd_printd("unable to create card entry\n");
+               dev_dbg(card->dev, "unable to create card entry\n");
                return err;
        }
        entry->c.text.read = snd_card_id_read;
@@ -156,8 +157,17 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
        return mask; /* unchanged */
 }
 
+static int snd_card_do_free(struct snd_card *card);
+static const struct attribute_group *card_dev_attr_groups[];
+
+static void release_card_device(struct device *dev)
+{
+       snd_card_do_free(dev_to_snd_card(dev));
+}
+
 /**
- *  snd_card_create - create and initialize a soundcard structure
+ *  snd_card_new - create and initialize a soundcard structure
+ *  @parent: the parent device object
  *  @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
  *  @xid: card identification (ASCII string)
  *  @module: top level module for locking
@@ -172,7 +182,7 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
  *
  *  Return: Zero if successful or a negative error code.
  */
-int snd_card_create(int idx, const char *xid,
+int snd_card_new(struct device *parent, int idx, const char *xid,
                    struct module *module, int extra_size,
                    struct snd_card **card_ret)
 {
@@ -188,6 +198,8 @@ int snd_card_create(int idx, const char *xid,
        card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
        if (!card)
                return -ENOMEM;
+       if (extra_size > 0)
+               card->private_data = (char *)card + sizeof(struct snd_card);
        if (xid)
                strlcpy(card->id, xid, sizeof(card->id));
        err = 0;
@@ -205,14 +217,16 @@ int snd_card_create(int idx, const char *xid,
                err = -ENODEV;
        if (err < 0) {
                mutex_unlock(&snd_card_mutex);
-               snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
+               dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
                         idx, snd_ecards_limit - 1, err);
-               goto __error;
+               kfree(card);
+               return err;
        }
        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);
+       card->dev = parent;
        card->number = idx;
        card->module = module;
        INIT_LIST_HEAD(&card->devices);
@@ -222,36 +236,42 @@ int snd_card_create(int idx, const char *xid,
        INIT_LIST_HEAD(&card->ctl_files);
        spin_lock_init(&card->files_lock);
        INIT_LIST_HEAD(&card->files_list);
-       init_waitqueue_head(&card->shutdown_sleep);
-       atomic_set(&card->refcount, 0);
 #ifdef CONFIG_PM
        mutex_init(&card->power_lock);
        init_waitqueue_head(&card->power_sleep);
 #endif
+
+       device_initialize(&card->card_dev);
+       card->card_dev.parent = parent;
+       card->card_dev.class = sound_class;
+       card->card_dev.release = release_card_device;
+       card->card_dev.groups = card_dev_attr_groups;
+       err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
+       if (err < 0)
+               goto __error;
+
        /* the control interface cannot be accessed from the user space until */
        /* snd_cards_bitmask and snd_cards are set with snd_card_register */
        err = snd_ctl_create(card);
        if (err < 0) {
-               snd_printk(KERN_ERR "unable to register control minors\n");
+               dev_err(parent, "unable to register control minors\n");
                goto __error;
        }
        err = snd_info_card_create(card);
        if (err < 0) {
-               snd_printk(KERN_ERR "unable to create card info\n");
+               dev_err(parent, "unable to create card info\n");
                goto __error_ctl;
        }
-       if (extra_size > 0)
-               card->private_data = (char *)card + sizeof(struct snd_card);
        *card_ret = card;
        return 0;
 
       __error_ctl:
-       snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
+       snd_device_free_all(card);
       __error:
-       kfree(card);
+       put_device(&card->card_dev);
        return err;
 }
-EXPORT_SYMBOL(snd_card_create);
+EXPORT_SYMBOL(snd_card_new);
 
 /* return non-zero if a card is already locked */
 int snd_card_locked(int card)
@@ -394,7 +414,7 @@ int snd_card_disconnect(struct snd_card *card)
        /* phase 3: notify all connected devices about disconnection */
        /* at this point, they cannot respond to any calls except release() */
 
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
        if (snd_mixer_oss_notify_callback)
                snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
 #endif
@@ -402,12 +422,12 @@ int snd_card_disconnect(struct snd_card *card)
        /* notify all devices that we are disconnected */
        err = snd_device_disconnect_all(card);
        if (err < 0)
-               snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
+               dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
 
        snd_info_card_disconnect(card);
-       if (card->card_dev) {
-               device_unregister(card->card_dev);
-               card->card_dev = NULL;
+       if (card->registered) {
+               device_del(&card->card_dev);
+               card->registered = false;
        }
 #ifdef CONFIG_PM
        wake_up(&card->power_sleep);
@@ -430,81 +450,48 @@ EXPORT_SYMBOL(snd_card_disconnect);
  */
 static int snd_card_do_free(struct snd_card *card)
 {
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
        if (snd_mixer_oss_notify_callback)
                snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
 #endif
-       if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
-               snd_printk(KERN_ERR "unable to free all devices (pre)\n");
-               /* Fatal, but this situation should never occur */
-       }
-       if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
-               snd_printk(KERN_ERR "unable to free all devices (normal)\n");
-               /* Fatal, but this situation should never occur */
-       }
-       if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
-               snd_printk(KERN_ERR "unable to free all devices (post)\n");
-               /* Fatal, but this situation should never occur */
-       }
+       snd_device_free_all(card);
        if (card->private_free)
                card->private_free(card);
        snd_info_free_entry(card->proc_id);
        if (snd_info_card_free(card) < 0) {
-               snd_printk(KERN_WARNING "unable to free card info\n");
+               dev_warn(card->dev, "unable to free card info\n");
                /* Not fatal error */
        }
+       if (card->release_completion)
+               complete(card->release_completion);
        kfree(card);
        return 0;
 }
 
-/**
- * snd_card_unref - release the reference counter
- * @card: the card instance
- *
- * Decrements the reference counter.  When it reaches to zero, wake up
- * the sleeper and call the destructor if needed.
- */
-void snd_card_unref(struct snd_card *card)
-{
-       if (atomic_dec_and_test(&card->refcount)) {
-               wake_up(&card->shutdown_sleep);
-               if (card->free_on_last_close)
-                       snd_card_do_free(card);
-       }
-}
-EXPORT_SYMBOL(snd_card_unref);
-
 int snd_card_free_when_closed(struct snd_card *card)
 {
-       int ret;
-
-       atomic_inc(&card->refcount);
-       ret = snd_card_disconnect(card);
-       if (ret) {
-               atomic_dec(&card->refcount);
+       int ret = snd_card_disconnect(card);
+       if (ret)
                return ret;
-       }
-
-       card->free_on_last_close = 1;
-       if (atomic_dec_and_test(&card->refcount))
-               snd_card_do_free(card);
+       put_device(&card->card_dev);
        return 0;
 }
-
 EXPORT_SYMBOL(snd_card_free_when_closed);
 
 int snd_card_free(struct snd_card *card)
 {
-       int ret = snd_card_disconnect(card);
+       struct completion released;
+       int ret;
+
+       init_completion(&released);
+       card->release_completion = &released;
+       ret = snd_card_free_when_closed(card);
        if (ret)
                return ret;
-
        /* wait, until all devices are ready for the free operation */
-       wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
-       snd_card_do_free(card);
+       wait_for_completion(&released);
        return 0;
 }
-
 EXPORT_SYMBOL(snd_card_free);
 
 /* retrieve the last word of shortname or longname */
@@ -598,7 +585,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
                goto again;
        }
        /* last resort... */
-       snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
+       dev_err(card->dev, "unable to set card id (%s)\n", id);
        if (card->proc_root->name)
                strlcpy(card->id, card->proc_root->name, sizeof(card->id));
 }
@@ -626,15 +613,15 @@ static ssize_t
 card_id_show_attr(struct device *dev,
                  struct device_attribute *attr, char *buf)
 {
-       struct snd_card *card = dev_get_drvdata(dev);
-       return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)");
+       struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+       return snprintf(buf, PAGE_SIZE, "%s\n", card->id);
 }
 
 static ssize_t
 card_id_store_attr(struct device *dev, struct device_attribute *attr,
                   const char *buf, size_t count)
 {
-       struct snd_card *card = dev_get_drvdata(dev);
+       struct snd_card *card = container_of(dev, struct snd_card, card_dev);
        char buf1[sizeof(card->id)];
        size_t copy = count > sizeof(card->id) - 1 ?
                                        sizeof(card->id) - 1 : count;
@@ -660,19 +647,32 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static struct device_attribute card_id_attrs =
-       __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
+static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
 
 static ssize_t
 card_number_show_attr(struct device *dev,
                     struct device_attribute *attr, char *buf)
 {
-       struct snd_card *card = dev_get_drvdata(dev);
-       return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1);
+       struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+       return snprintf(buf, PAGE_SIZE, "%i\n", card->number);
 }
 
-static struct device_attribute card_number_attrs =
-       __ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+
+static struct attribute *card_dev_attrs[] = {
+       &dev_attr_id.attr,
+       &dev_attr_number.attr,
+       NULL
+};
+
+static struct attribute_group card_dev_attr_group = {
+       .attrs  = card_dev_attrs,
+};
+
+static const struct attribute_group *card_dev_attr_groups[] = {
+       &card_dev_attr_group,
+       NULL
+};
 
 /**
  *  snd_card_register - register the soundcard
@@ -692,12 +692,11 @@ int snd_card_register(struct snd_card *card)
        if (snd_BUG_ON(!card))
                return -EINVAL;
 
-       if (!card->card_dev) {
-               card->card_dev = device_create(sound_class, card->dev,
-                                              MKDEV(0, 0), card,
-                                              "card%i", card->number);
-               if (IS_ERR(card->card_dev))
-                       card->card_dev = NULL;
+       if (!card->registered) {
+               err = device_add(&card->card_dev);
+               if (err < 0)
+                       return err;
+               card->registered = true;
        }
 
        if ((err = snd_device_register_all(card)) < 0)
@@ -723,19 +722,10 @@ int snd_card_register(struct snd_card *card)
        snd_cards[card->number] = card;
        mutex_unlock(&snd_card_mutex);
        init_info_for_card(card);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
        if (snd_mixer_oss_notify_callback)
                snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
 #endif
-       if (card->card_dev) {
-               err = device_create_file(card->card_dev, &card_id_attrs);
-               if (err < 0)
-                       return err;
-               err = device_create_file(card->card_dev, &card_number_attrs);
-               if (err < 0)
-                       return err;
-       }
-
        return 0;
 }
 
@@ -908,7 +898,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
                return -ENODEV;
        }
        list_add(&mfile->list, &card->files_list);
-       atomic_inc(&card->refcount);
+       get_device(&card->card_dev);
        spin_unlock(&card->files_lock);
        return 0;
 }
@@ -947,11 +937,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
        }
        spin_unlock(&card->files_lock);
        if (!found) {
-               snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
+               dev_err(card->dev, "card file remove problem (%p)\n", file);
                return -ENOENT;
        }
        kfree(found);
-       snd_card_unref(card);
+       put_device(&card->card_dev);
        return 0;
 }
 
index e2b386156a4c300ed0f78b50fa1bebc71d54689a..31e8544d7f2d760320d9db504cafa398d70bda49 100644 (file)
@@ -106,7 +106,7 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
                result = result1;
 #ifdef CONFIG_SND_DEBUG
        if (result > size)
-               snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
+               pr_err("ALSA: pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
 #endif
        if (result >= size || result == 0)
                return 0;
index 4595f93d151e0e5fb82073a788ebe6a725826296..082509eb805d5395ed356ef0e9378432f891b96e 100644 (file)
@@ -207,7 +207,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                break;
 #endif
        default:
-               printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
+               pr_err("snd-malloc: invalid device type %d\n", type);
                dmab->area = NULL;
                dmab->addr = 0;
                return -ENXIO;
@@ -284,7 +284,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
                break;
 #endif
        default:
-               printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
+               pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);
        }
 }
 
index e8a1d18774b2073f997746f6d6f16881a1ecc4bc..5e6349f00ecd770a3c572ef950454ec04f13e1c8 100644 (file)
@@ -1187,7 +1187,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                        if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
                                break;
                if (ch >= SNDRV_OSS_MAX_MIXERS) {
-                       snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
+                       pr_err("ALSA: mixer_oss: invalid OSS volume '%s'\n",
+                              str);
                        continue;
                }
                cptr = snd_info_get_str(str, cptr, sizeof(str));
@@ -1201,7 +1202,7 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                snd_info_get_str(idxstr, cptr, sizeof(idxstr));
                idx = simple_strtoul(idxstr, NULL, 10);
                if (idx >= 0x4000) { /* too big */
-                       snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
+                       pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
                        continue;
                }
                mutex_lock(&mixer->reg_mutex);
@@ -1212,7 +1213,7 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                        goto __unlock;
                tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
                if (! tbl) {
-                       snd_printk(KERN_ERR "mixer_oss: no memory\n");
+                       pr_err("ALSA: mixer_oss: no memory\n");
                        goto __unlock;
                }
                tbl->oss_id = ch;
@@ -1343,20 +1344,18 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
        struct snd_mixer_oss *mixer;
 
        if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
-               char name[128];
                int idx, err;
 
                mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
                if (mixer == NULL)
                        return -ENOMEM;
                mutex_init(&mixer->reg_mutex);
-               sprintf(name, "mixer%i%i", card->number, 0);
                if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
                                                   card, 0,
-                                                  &snd_mixer_oss_f_ops, card,
-                                                  name)) < 0) {
-                       snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
-                                  card->number, 0);
+                                                  &snd_mixer_oss_f_ops, card)) < 0) {
+                       dev_err(card->dev,
+                               "unable to register OSS mixer device %i:%i\n",
+                               card->number, 0);
                        kfree(mixer);
                        return err;
                }
@@ -1365,7 +1364,8 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
                if (*card->mixername)
                        strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
                else
-                       strlcpy(mixer->name, name, sizeof(mixer->name));
+                       snprintf(mixer->name, sizeof(mixer->name),
+                                "mixer%i", card->number);
 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
                snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
                                      card->number,
index 4c1cc51772e6f18e9ab03671069c738471ca8c04..ada69d7a8d70a077c18abfa2aa7bf26ee8125b27 100644 (file)
@@ -854,7 +854,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        params = kmalloc(sizeof(*params), GFP_KERNEL);
        sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
        if (!sw_params || !params || !sparams) {
-               snd_printd("No memory\n");
+               pcm_dbg(substream->pcm, "No memory\n");
                err = -ENOMEM;
                goto failure;
        }
@@ -877,7 +877,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        }
        err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
        if (err < 0) {
-               snd_printd("No usable accesses\n");
+               pcm_dbg(substream->pcm, "No usable accesses\n");
                err = -EINVAL;
                goto failure;
        }
@@ -902,7 +902,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                                break;
                }
                if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) {
-                       snd_printd("Cannot find a format!!!\n");
+                       pcm_dbg(substream->pcm, "Cannot find a format!!!\n");
                        err = -EINVAL;
                        goto failure;
                }
@@ -942,14 +942,16 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                if ((err = snd_pcm_plug_format_plugins(substream,
                                                       params, 
                                                       sparams)) < 0) {
-                       snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
+                       pcm_dbg(substream->pcm,
+                               "snd_pcm_plug_format_plugins failed: %i\n", err);
                        snd_pcm_oss_plugin_clear(substream);
                        goto failure;
                }
                if (runtime->oss.plugin_first) {
                        struct snd_pcm_plugin *plugin;
                        if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
-                               snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);
+                               pcm_dbg(substream->pcm,
+                                       "snd_pcm_plugin_build_io failed: %i\n", err);
                                snd_pcm_oss_plugin_clear(substream);
                                goto failure;
                        }
@@ -983,7 +985,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
 
        if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {
-               snd_printd("HW_PARAMS failed: %i\n", err);
+               pcm_dbg(substream->pcm, "HW_PARAMS failed: %i\n", err);
                goto failure;
        }
 
@@ -1016,7 +1018,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        }
 
        if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
-               snd_printd("SW_PARAMS failed: %i\n", err);
+               pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
                goto failure;
        }
 
@@ -1110,7 +1112,8 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
 
        err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
        if (err < 0) {
-               snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
+               pcm_dbg(substream->pcm,
+                       "snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
                return err;
        }
        runtime->oss.prepare = 0;
@@ -1175,12 +1178,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
-                       if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk(KERN_DEBUG "pcm_oss: write: "
-                                      "recovering from XRUN\n");
-                       else
-                               printk(KERN_DEBUG "pcm_oss: write: "
-                                      "recovering from SUSPEND\n");
+                       pcm_dbg(substream->pcm,
+                               "pcm_oss: write: recovering from %s\n",
+                               runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+                               "XRUN" : "SUSPEND");
 #endif
                        ret = snd_pcm_oss_prepare(substream);
                        if (ret < 0)
@@ -1213,12 +1214,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
-                       if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk(KERN_DEBUG "pcm_oss: read: "
-                                      "recovering from XRUN\n");
-                       else
-                               printk(KERN_DEBUG "pcm_oss: read: "
-                                      "recovering from SUSPEND\n");
+                       pcm_dbg(substream->pcm,
+                               "pcm_oss: read: recovering from %s\n",
+                               runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+                               "XRUN" : "SUSPEND");
 #endif
                        ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
                        if (ret < 0)
@@ -1261,12 +1260,10 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
-                       if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk(KERN_DEBUG "pcm_oss: writev: "
-                                      "recovering from XRUN\n");
-                       else
-                               printk(KERN_DEBUG "pcm_oss: writev: "
-                                      "recovering from SUSPEND\n");
+                       pcm_dbg(substream->pcm,
+                               "pcm_oss: writev: recovering from %s\n",
+                               runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+                               "XRUN" : "SUSPEND");
 #endif
                        ret = snd_pcm_oss_prepare(substream);
                        if (ret < 0)
@@ -1299,12 +1296,10 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
 #ifdef OSS_DEBUG
-                       if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
-                               printk(KERN_DEBUG "pcm_oss: readv: "
-                                      "recovering from XRUN\n");
-                       else
-                               printk(KERN_DEBUG "pcm_oss: readv: "
-                                      "recovering from SUSPEND\n");
+                       pcm_dbg(substream->pcm,
+                               "pcm_oss: readv: recovering from %s\n",
+                               runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+                               "XRUN" : "SUSPEND");
 #endif
                        ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
                        if (ret < 0)
@@ -1561,7 +1556,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&runtime->sleep, &wait);
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "sync1: size = %li\n", size);
+       pcm_dbg(substream->pcm, "sync1: size = %li\n", size);
 #endif
        while (1) {
                result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
@@ -1587,7 +1582,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
                        break;
                }
                if (res == 0) {
-                       snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
+                       pcm_err(substream->pcm,
+                               "OSS sync error - DMA timeout\n");
                        result = -EIO;
                        break;
                }
@@ -1618,7 +1614,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                mutex_lock(&runtime->oss.params_lock);
                if (runtime->oss.buffer_used > 0) {
 #ifdef OSS_DEBUG
-                       printk(KERN_DEBUG "sync: buffer_used\n");
+                       pcm_dbg(substream->pcm, "sync: buffer_used\n");
 #endif
                        size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
                        snd_pcm_format_set_silence(format,
@@ -1631,7 +1627,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                        }
                } else if (runtime->oss.period_ptr > 0) {
 #ifdef OSS_DEBUG
-                       printk(KERN_DEBUG "sync: period_ptr\n");
+                       pcm_dbg(substream->pcm, "sync: period_ptr\n");
 #endif
                        size = runtime->oss.period_bytes - runtime->oss.period_ptr;
                        snd_pcm_format_set_silence(format,
@@ -1983,7 +1979,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
        int err, cmd;
 
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger);
+       pcm_dbg(substream->pcm, "pcm_oss: trigger = 0x%x\n", trigger);
 #endif
        
        psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -2203,9 +2199,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
        }
 
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, "
-              "fragstotal = %i, fragsize = %i\n",
-              info.bytes, info.fragments, info.fragstotal, info.fragsize);
+       pcm_dbg(substream->pcm,
+               "pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n",
+               info.bytes, info.fragments, info.fragstotal, info.fragsize);
 #endif
        if (copy_to_user(_info, &info, sizeof(info)))
                return -EFAULT;
@@ -2215,7 +2211,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
 static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
 {
        // it won't be probably implemented
-       // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n");
+       // pr_debug("TODO: snd_pcm_oss_get_mapbuf\n");
        return -EINVAL;
 }
 
@@ -2519,7 +2515,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
        if (((cmd >> 8) & 0xff) != 'P')
                return -EINVAL;
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd);
+       pr_debug("pcm_oss: ioctl = 0x%x\n", cmd);
 #endif
        switch (cmd) {
        case SNDCTL_DSP_RESET:
@@ -2646,7 +2642,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
        case SNDCTL_DSP_PROFILE:
                return 0;       /* silently ignore */
        default:
-               snd_printd("pcm_oss: unknown command = 0x%x\n", cmd);
+               pr_debug("pcm_oss: unknown command = 0x%x\n", cmd);
        }
        return -EINVAL;
 }
@@ -2673,8 +2669,9 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
 #else
        {
                ssize_t res = snd_pcm_oss_read1(substream, buf, count);
-               printk(KERN_DEBUG "pcm_oss: read %li bytes "
-                      "(returned %li bytes)\n", (long)count, (long)res);
+               pcm_dbg(substream->pcm,
+                       "pcm_oss: read %li bytes (returned %li bytes)\n",
+                       (long)count, (long)res);
                return res;
        }
 #endif
@@ -2693,7 +2690,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
        substream->f_flags = file->f_flags & O_NONBLOCK;
        result = snd_pcm_oss_write1(substream, buf, count);
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n",
+       pcm_dbg(substream->pcm, "pcm_oss: write %li bytes (wrote %li bytes)\n",
               (long)count, (long)result);
 #endif
        return result;
@@ -2772,7 +2769,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
        int err;
 
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "pcm_oss: mmap begin\n");
+       pr_debug("pcm_oss: mmap begin\n");
 #endif
        pcm_oss_file = file->private_data;
        switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
@@ -2822,7 +2819,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
        runtime->silence_threshold = 0;
        runtime->silence_size = 0;
 #ifdef OSS_DEBUG
-       printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n",
+       pr_debug("pcm_oss: mmap ok, bytes = 0x%x\n",
               runtime->oss.mmap_bytes);
 #endif
        /* In mmap mode we never stop */
@@ -3007,12 +3004,10 @@ static const struct file_operations snd_pcm_oss_f_reg =
 
 static void register_oss_dsp(struct snd_pcm *pcm, int index)
 {
-       char name[128];
-       sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
        if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
                                    pcm->card, index, &snd_pcm_oss_f_reg,
-                                   pcm, name) < 0) {
-               snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n",
+                                   pcm) < 0) {
+               pcm_err(pcm, "unable to register OSS PCM device %i:%i\n",
                           pcm->card->number, pcm->device);
        }
 }
@@ -3093,12 +3088,12 @@ static int __init alsa_pcm_oss_init(void)
        /* check device map table */
        for (i = 0; i < SNDRV_CARDS; i++) {
                if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
-                       snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n",
+                       pr_err("ALSA: pcm_oss: invalid dsp_map[%d] = %d\n",
                                   i, dsp_map[i]);
                        dsp_map[i] = 0;
                }
                if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
-                       snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n",
+                       pr_err("ALSA: pcm_oss: invalid adsp_map[%d] = %d\n",
                                   i, adsp_map[i]);
                        adsp_map[i] = 1;
                }
index e1e9e0c999fefa854a507e623b821371ebf00b78..43932e8dce669a57a0908ffbd57585a858d1616b 100644 (file)
@@ -295,7 +295,7 @@ static const char *snd_pcm_state_name(snd_pcm_state_t state)
        return snd_pcm_state_names[(__force int)state];
 }
 
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 #include <linux/soundcard.h>
 
 static const char *snd_pcm_oss_format_name(int format)
@@ -338,7 +338,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (! info) {
-               printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc\n");
+               pcm_dbg(substream->pcm,
+                       "snd_pcm_proc_info_read: cannot malloc\n");
                return;
        }
 
@@ -398,7 +399,7 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); 
        snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);        
        snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);        
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        if (substream->oss.oss) {
                snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
                snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);       
@@ -651,7 +652,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
        struct snd_pcm_str *pstr = &pcm->streams[stream];
        struct snd_pcm_substream *substream, *prev;
 
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        mutex_init(&pstr->oss.setup_mutex);
 #endif
        pstr->stream = stream;
@@ -660,7 +661,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
        if (substream_count > 0 && !pcm->internal) {
                err = snd_pcm_stream_proc_init(pstr);
                if (err < 0) {
-                       snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+                       pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
                        return err;
                }
        }
@@ -668,7 +669,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
        for (idx = 0, prev = NULL; idx < substream_count; idx++) {
                substream = kzalloc(sizeof(*substream), GFP_KERNEL);
                if (substream == NULL) {
-                       snd_printk(KERN_ERR "Cannot allocate PCM substream\n");
+                       pcm_err(pcm, "Cannot allocate PCM substream\n");
                        return -ENOMEM;
                }
                substream->pcm = pcm;
@@ -685,7 +686,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
                if (!pcm->internal) {
                        err = snd_pcm_substream_proc_init(substream);
                        if (err < 0) {
-                               snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+                               pcm_err(pcm,
+                                       "Error in snd_pcm_stream_proc_init\n");
                                if (prev == NULL)
                                        pstr->substream = NULL;
                                else
@@ -724,7 +726,7 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
                *rpcm = NULL;
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
        if (pcm == NULL) {
-               snd_printk(KERN_ERR "Cannot allocate PCM\n");
+               dev_err(card->dev, "Cannot allocate PCM\n");
                return -ENOMEM;
        }
        pcm->card = card;
@@ -807,7 +809,7 @@ EXPORT_SYMBOL(snd_pcm_new_internal);
 static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
 {
        struct snd_pcm_substream *substream, *substream_next;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        struct snd_pcm_oss_setup *setup, *setupn;
 #endif
        substream = pstr->substream;
@@ -819,7 +821,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
                substream = substream_next;
        }
        snd_pcm_stream_proc_done(pstr);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        for (setup = pstr->oss.setup_list; setup; setup = setupn) {
                setupn = setup->next;
                kfree(setup->task_name);
@@ -1016,8 +1018,20 @@ static ssize_t show_pcm_class(struct device *dev,
         return snprintf(buf, PAGE_SIZE, "%s\n", str);
 }
 
-static struct device_attribute pcm_attrs =
-       __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+static DEVICE_ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+static struct attribute *pcm_dev_attrs[] = {
+       &dev_attr_pcm_class.attr,
+       NULL
+};
+
+static struct attribute_group pcm_dev_attr_group = {
+       .attrs  = pcm_dev_attrs,
+};
+
+static const struct attribute_group *pcm_dev_attr_groups[] = {
+       &pcm_dev_attr_group,
+       NULL
+};
 
 static int snd_pcm_dev_register(struct snd_device *device)
 {
@@ -1067,8 +1081,18 @@ static int snd_pcm_dev_register(struct snd_device *device)
                        mutex_unlock(&register_mutex);
                        return err;
                }
-               snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
-                                         &pcm_attrs);
+
+               dev = snd_get_device(devtype, pcm->card, pcm->device);
+               if (dev) {
+                       err = sysfs_create_groups(&dev->kobj,
+                                                 pcm_dev_attr_groups);
+                       if (err < 0)
+                               dev_warn(dev,
+                                        "pcm %d:%d: cannot create sysfs groups\n",
+                                        pcm->card->number, pcm->device);
+                       put_device(dev);
+               }
+
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
                        snd_pcm_timer_init(substream);
        }
index a2104671f51d38df6eec99b3e0aa8ac570ea8988..ce83def9f43bf9d30755e48f1129d25af81792a9 100644 (file)
@@ -174,7 +174,7 @@ static void xrun(struct snd_pcm_substream *substream)
        if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
                char name[16];
                snd_pcm_debug_name(substream, name, sizeof(name));
-               snd_printd(KERN_DEBUG "XRUN: %s\n", name);
+               pcm_warn(substream->pcm, "XRUN: %s\n", name);
                dump_stack_on_xrun(substream);
        }
 }
@@ -184,9 +184,7 @@ static void xrun(struct snd_pcm_substream *substream)
        do {                                                            \
                if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {          \
                        xrun_log_show(substream);                       \
-                       if (snd_printd_ratelimit()) {                   \
-                               snd_printd("PCM: " fmt, ##args);        \
-                       }                                               \
+                       pr_err_ratelimited("ALSA: PCM: " fmt, ##args);  \
                        dump_stack_on_xrun(substream);                  \
                }                                                       \
        } while (0)
@@ -253,7 +251,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
                entry = &log->entries[idx];
                if (entry->period_size == 0)
                        break;
-               snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
+               pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
                           "hwptr=%ld/%ld\n",
                           name, entry->in_interrupt ? "[Q] " : "",
                           entry->jiffies,
@@ -342,14 +340,14 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                return -EPIPE;
        }
        if (pos >= runtime->buffer_size) {
-               if (snd_printd_ratelimit()) {
+               if (printk_ratelimit()) {
                        char name[16];
                        snd_pcm_debug_name(substream, name, sizeof(name));
                        xrun_log_show(substream);
-                       snd_printd(KERN_ERR  "BUG: %s, pos = %ld, "
-                                  "buffer size = %ld, period size = %ld\n",
-                                  name, pos, runtime->buffer_size,
-                                  runtime->period_size);
+                       pcm_err(substream->pcm,
+                               "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+                               name, pos, runtime->buffer_size,
+                               runtime->period_size);
                }
                pos = 0;
        }
@@ -394,8 +392,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                        XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
                char name[16];
                snd_pcm_debug_name(substream, name, sizeof(name));
-               snd_printd("%s_update: %s: pos=%u/%u/%u, "
-                          "hwptr=%ld/%ld/%ld/%ld\n",
+               pcm_dbg(substream->pcm,
+                       "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n",
                           in_interrupt ? "period" : "hwptr",
                           name,
                           (unsigned int)pos,
@@ -1242,6 +1240,7 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
                return -EINVAL;
        return 0;
 }
+EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64);
 
 /**
  * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval
@@ -1941,8 +1940,9 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
                        continue;
                }
                if (!tout) {
-                       snd_printd("%s write error (DMA or IRQ trouble?)\n",
-                                  is_playback ? "playback" : "capture");
+                       pcm_dbg(substream->pcm,
+                               "%s write error (DMA or IRQ trouble?)\n",
+                               is_playback ? "playback" : "capture");
                        err = -EIO;
                        break;
                }
index 01a5e05ede95cddbbcaa6be3ddb4bcf13e3786ce..b653ab001fbac0778547b933815dff289240f7cf 100644 (file)
@@ -190,12 +190,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                if (!(params->rmask & (1 << k)))
                        continue;
 #ifdef RULES_DEBUG
-               printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
-               printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+               pr_debug("%s = ", snd_pcm_hw_param_names[k]);
+               pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
 #endif
                changed = snd_mask_refine(m, constrs_mask(constrs, k));
 #ifdef RULES_DEBUG
-               printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+               pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
 #endif
                if (changed)
                        params->cmask |= 1 << k;
@@ -210,21 +210,21 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                if (!(params->rmask & (1 << k)))
                        continue;
 #ifdef RULES_DEBUG
-               printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
+               pr_debug("%s = ", snd_pcm_hw_param_names[k]);
                if (i->empty)
-                       printk("empty");
+                       pr_cont("empty");
                else
-                       printk("%c%u %u%c", 
+                       pr_cont("%c%u %u%c",
                               i->openmin ? '(' : '[', i->min,
                               i->max, i->openmax ? ')' : ']');
-               printk(" -> ");
+               pr_cont(" -> ");
 #endif
                changed = snd_interval_refine(i, constrs_interval(constrs, k));
 #ifdef RULES_DEBUG
                if (i->empty)
-                       printk("empty\n");
+                       pr_cont("empty\n");
                else 
-                       printk("%c%u %u%c\n", 
+                       pr_cont("%c%u %u%c\n",
                               i->openmin ? '(' : '[', i->min,
                               i->max, i->openmax ? ')' : ']');
 #endif
@@ -255,18 +255,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                        if (!doit)
                                continue;
 #ifdef RULES_DEBUG
-                       printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
+                       pr_debug("Rule %d [%p]: ", k, r->func);
                        if (r->var >= 0) {
-                               printk("%s = ", snd_pcm_hw_param_names[r->var]);
+                               pr_cont("%s = ", snd_pcm_hw_param_names[r->var]);
                                if (hw_is_mask(r->var)) {
                                        m = hw_param_mask(params, r->var);
-                                       printk("%x", *m->bits);
+                                       pr_cont("%x", *m->bits);
                                } else {
                                        i = hw_param_interval(params, r->var);
                                        if (i->empty)
-                                               printk("empty");
+                                               pr_cont("empty");
                                        else
-                                               printk("%c%u %u%c", 
+                                               pr_cont("%c%u %u%c",
                                                       i->openmin ? '(' : '[', i->min,
                                                       i->max, i->openmax ? ')' : ']');
                                }
@@ -275,19 +275,19 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                        changed = r->func(params, r);
 #ifdef RULES_DEBUG
                        if (r->var >= 0) {
-                               printk(" -> ");
+                               pr_cont(" -> ");
                                if (hw_is_mask(r->var))
-                                       printk("%x", *m->bits);
+                                       pr_cont("%x", *m->bits);
                                else {
                                        if (i->empty)
-                                               printk("empty");
+                                               pr_cont("empty");
                                        else
-                                               printk("%c%u %u%c", 
+                                               pr_cont("%c%u %u%c",
                                                       i->openmin ? '(' : '[', i->min,
                                                       i->max, i->openmax ? ')' : ']');
                                }
                        }
-                       printk("\n");
+                       pr_cont("\n");
 #endif
                        rstamps[k] = stamp;
                        if (changed && r->var >= 0) {
@@ -399,7 +399,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                return -EBADFD;
        }
        snd_pcm_stream_unlock_irq(substream);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        if (!substream->oss.oss)
 #endif
                if (atomic_read(&substream->mmap_count))
@@ -954,7 +954,7 @@ static struct action_ops snd_pcm_action_stop = {
  *
  * The state of each stream is then changed to the given state unconditionally.
  *
- * Return: Zero if succesful, or a negative error code.
+ * Return: Zero if successful, or a negative error code.
  */
 int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
 {
@@ -1541,7 +1541,8 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
                        if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
                                result = -ESTRPIPE;
                        else {
-                               snd_printd("playback drain error (DMA or IRQ trouble?)\n");
+                               dev_dbg(substream->pcm->card->dev,
+                                       "playback drain error (DMA or IRQ trouble?)\n");
                                snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
                                result = -EIO;
                        }
@@ -2066,7 +2067,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
 
        err = snd_pcm_hw_constraints_init(substream);
        if (err < 0) {
-               snd_printd("snd_pcm_hw_constraints_init failed\n");
+               pcm_dbg(pcm, "snd_pcm_hw_constraints_init failed\n");
                goto error;
        }
 
@@ -2077,7 +2078,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
 
        err = snd_pcm_hw_constraints_complete(substream);
        if (err < 0) {
-               snd_printd("snd_pcm_hw_constraints_complete failed\n");
+               pcm_dbg(pcm, "snd_pcm_hw_constraints_complete failed\n");
                goto error;
        }
 
@@ -2609,7 +2610,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
                return res;
        }
        }
-       snd_printd("unknown ioctl = 0x%x\n", cmd);
+       pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
        return -ENOTTY;
 }
 
index b01d9481d632c4245d3403a445e6e641b9b2e2aa..20ecd8f180808cf62b0b129902e3f89f7a59e5ff 100644 (file)
@@ -53,7 +53,9 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
                post *= 2;
        }
        if (rate == 0) {
-               snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
+               pcm_err(substream->pcm,
+                       "pcm timer resolution out of range (rate = %u, period_size = %lu)\n",
+                       runtime->rate, runtime->period_size);
                runtime->timer_resolution = -1;
                return;
        }
index 7b596b5751dbcea07a075685017cef6c7e0cb364..6fc71a4c8a5177c63094333093de18a70b3159ac 100644 (file)
@@ -56,6 +56,13 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device);
 static LIST_HEAD(snd_rawmidi_devices);
 static DEFINE_MUTEX(register_mutex);
 
+#define rmidi_err(rmidi, fmt, args...) \
+       dev_err((rmidi)->card->dev, fmt, ##args)
+#define rmidi_warn(rmidi, fmt, args...) \
+       dev_warn((rmidi)->card->dev, fmt, ##args)
+#define rmidi_dbg(rmidi, fmt, args...) \
+       dev_dbg((rmidi)->card->dev, fmt, ##args)
+
 static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
 {
        struct snd_rawmidi *rawmidi;
@@ -165,6 +172,7 @@ int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
        spin_unlock_irqrestore(&runtime->lock, flags);
        return 0;
 }
+EXPORT_SYMBOL(snd_rawmidi_drop_output);
 
 int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
 {
@@ -180,7 +188,9 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
        if (signal_pending(current))
                err = -ERESTARTSYS;
        if (runtime->avail < runtime->buffer_size && !timeout) {
-               snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
+               rmidi_warn(substream->rmidi,
+                          "rawmidi drain error (avail = %li, buffer_size = %li)\n",
+                          (long)runtime->avail, (long)runtime->buffer_size);
                err = -EIO;
        }
        runtime->drain = 0;
@@ -194,6 +204,7 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
        }
        return err;
 }
+EXPORT_SYMBOL(snd_rawmidi_drain_output);
 
 int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
 {
@@ -208,6 +219,7 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
        spin_unlock_irqrestore(&runtime->lock, flags);
        return 0;
 }
+EXPORT_SYMBOL(snd_rawmidi_drain_input);
 
 /* look for an available substream for the given stream direction;
  * if a specific subdevice is given, try to assign it
@@ -345,6 +357,7 @@ int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
                module_put(rmidi->card->module);
        return err;
 }
+EXPORT_SYMBOL(snd_rawmidi_kernel_open);
 
 static int snd_rawmidi_open(struct inode *inode, struct file *file)
 {
@@ -523,6 +536,7 @@ int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
        module_put(rmidi->card->module);
        return 0;
 }
+EXPORT_SYMBOL(snd_rawmidi_kernel_release);
 
 static int snd_rawmidi_release(struct inode *inode, struct file *file)
 {
@@ -599,6 +613,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
        }
        return -ENXIO;
 }
+EXPORT_SYMBOL(snd_rawmidi_info_select);
 
 static int snd_rawmidi_info_select_user(struct snd_card *card,
                                        struct snd_rawmidi_info __user *_info)
@@ -646,6 +661,7 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
        substream->active_sensing = !params->no_active_sensing;
        return 0;
 }
+EXPORT_SYMBOL(snd_rawmidi_output_params);
 
 int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
                             struct snd_rawmidi_params * params)
@@ -671,6 +687,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
        runtime->avail_min = params->avail_min;
        return 0;
 }
+EXPORT_SYMBOL(snd_rawmidi_input_params);
 
 static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
                                     struct snd_rawmidi_status * status)
@@ -802,10 +819,9 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
                        return -EINVAL;
                }
        }
-#ifdef CONFIG_SND_DEBUG
        default:
-               snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd);
-#endif
+               rmidi_dbg(rfile->rmidi,
+                         "rawmidi: unknown command = 0x%x\n", cmd);
        }
        return -ENOTTY;
 }
@@ -875,7 +891,8 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
        if (!substream->opened)
                return -EBADFD;
        if (runtime->buffer == NULL) {
-               snd_printd("snd_rawmidi_receive: input is not active!!!\n");
+               rmidi_dbg(substream->rmidi,
+                         "snd_rawmidi_receive: input is not active!!!\n");
                return -EINVAL;
        }
        spin_lock_irqsave(&runtime->lock, flags);
@@ -926,6 +943,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
        spin_unlock_irqrestore(&runtime->lock, flags);
        return result;
 }
+EXPORT_SYMBOL(snd_rawmidi_receive);
 
 static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
                                     unsigned char __user *userbuf,
@@ -968,6 +986,7 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
        snd_rawmidi_input_trigger(substream, 1);
        return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count);
 }
+EXPORT_SYMBOL(snd_rawmidi_kernel_read);
 
 static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count,
                                loff_t *offset)
@@ -1034,7 +1053,8 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
        unsigned long flags;
 
        if (runtime->buffer == NULL) {
-               snd_printd("snd_rawmidi_transmit_empty: output is not active!!!\n");
+               rmidi_dbg(substream->rmidi,
+                         "snd_rawmidi_transmit_empty: output is not active!!!\n");
                return 1;
        }
        spin_lock_irqsave(&runtime->lock, flags);
@@ -1042,6 +1062,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
        spin_unlock_irqrestore(&runtime->lock, flags);
        return result;          
 }
+EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
 
 /**
  * snd_rawmidi_transmit_peek - copy data from the internal buffer
@@ -1065,7 +1086,8 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
        if (runtime->buffer == NULL) {
-               snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n");
+               rmidi_dbg(substream->rmidi,
+                         "snd_rawmidi_transmit_peek: output is not active!!!\n");
                return -EINVAL;
        }
        result = 0;
@@ -1097,11 +1119,12 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
        spin_unlock_irqrestore(&runtime->lock, flags);
        return result;
 }
+EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
 
 /**
  * snd_rawmidi_transmit_ack - acknowledge the transmission
  * @substream: the rawmidi substream
- * @count: the tranferred count
+ * @count: the transferred count
  *
  * Advances the hardware pointer for the internal output buffer with
  * the given size and updates the condition.
@@ -1115,7 +1138,8 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
        if (runtime->buffer == NULL) {
-               snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n");
+               rmidi_dbg(substream->rmidi,
+                         "snd_rawmidi_transmit_ack: output is not active!!!\n");
                return -EINVAL;
        }
        spin_lock_irqsave(&runtime->lock, flags);
@@ -1131,6 +1155,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
        spin_unlock_irqrestore(&runtime->lock, flags);
        return count;
 }
+EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
 
 /**
  * snd_rawmidi_transmit - copy from the buffer to the device
@@ -1152,6 +1177,7 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                return count;
        return snd_rawmidi_transmit_ack(substream, count);
 }
+EXPORT_SYMBOL(snd_rawmidi_transmit);
 
 static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                                      const unsigned char __user *userbuf,
@@ -1213,6 +1239,7 @@ long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
 {
        return snd_rawmidi_kernel_write1(substream, NULL, buf, count);
 }
+EXPORT_SYMBOL(snd_rawmidi_kernel_write);
 
 static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
                                 size_t count, loff_t *offset)
@@ -1413,7 +1440,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
        for (idx = 0; idx < count; idx++) {
                substream = kzalloc(sizeof(*substream), GFP_KERNEL);
                if (substream == NULL) {
-                       snd_printk(KERN_ERR "rawmidi: cannot allocate substream\n");
+                       rmidi_err(rmidi, "rawmidi: cannot allocate substream\n");
                        return -ENOMEM;
                }
                substream->stream = direction;
@@ -1458,7 +1485,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
                *rrawmidi = NULL;
        rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
        if (rmidi == NULL) {
-               snd_printk(KERN_ERR "rawmidi: cannot allocate\n");
+               dev_err(card->dev, "rawmidi: cannot allocate\n");
                return -ENOMEM;
        }
        rmidi->card = card;
@@ -1492,6 +1519,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
                *rrawmidi = rmidi;
        return 0;
 }
+EXPORT_SYMBOL(snd_rawmidi_new);
 
 static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
 {
@@ -1557,7 +1585,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
        if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
                                       rmidi->card, rmidi->device,
                                       &snd_rawmidi_f_ops, rmidi, name)) < 0) {
-               snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device);
+               rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n",
+                         rmidi->card->number, rmidi->device);
                list_del(&rmidi->list);
                mutex_unlock(&register_mutex);
                return err;
@@ -1574,8 +1603,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
        if ((int)rmidi->device == midi_map[rmidi->card->number]) {
                if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
                                            rmidi->card, 0, &snd_rawmidi_f_ops,
-                                           rmidi, name) < 0) {
-                       snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0);
+                                           rmidi) < 0) {
+                       rmidi_err(rmidi,
+                                 "unable to register OSS rawmidi device %i:%i\n",
+                                 rmidi->card->number, 0);
                } else {
                        rmidi->ossreg++;
 #ifdef SNDRV_OSS_INFO_DEV_MIDI
@@ -1586,8 +1617,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
        if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
                if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
                                            rmidi->card, 1, &snd_rawmidi_f_ops,
-                                           rmidi, name) < 0) {
-                       snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1);
+                                           rmidi) < 0) {
+                       rmidi_err(rmidi,
+                                 "unable to register OSS rawmidi device %i:%i\n",
+                                 rmidi->card->number, 1);
                } else {
                        rmidi->ossreg++;
                }
@@ -1670,6 +1703,7 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
        list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
                substream->ops = ops;
 }
+EXPORT_SYMBOL(snd_rawmidi_set_ops);
 
 /*
  *  ENTRY functions
@@ -1685,11 +1719,13 @@ static int __init alsa_rawmidi_init(void)
        /* check device map table */
        for (i = 0; i < SNDRV_CARDS; i++) {
                if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
-                       snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, midi_map[i]);
+                       pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
+                              i, midi_map[i]);
                        midi_map[i] = 0;
                }
                if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
-                       snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, amidi_map[i]);
+                       pr_err("ALSA: rawmidi: invalid amidi_map[%d] = %d\n",
+                              i, amidi_map[i]);
                        amidi_map[i] = 1;
                }
        }
@@ -1706,21 +1742,3 @@ static void __exit alsa_rawmidi_exit(void)
 
 module_init(alsa_rawmidi_init)
 module_exit(alsa_rawmidi_exit)
-
-EXPORT_SYMBOL(snd_rawmidi_output_params);
-EXPORT_SYMBOL(snd_rawmidi_input_params);
-EXPORT_SYMBOL(snd_rawmidi_drop_output);
-EXPORT_SYMBOL(snd_rawmidi_drain_output);
-EXPORT_SYMBOL(snd_rawmidi_drain_input);
-EXPORT_SYMBOL(snd_rawmidi_receive);
-EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
-EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
-EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
-EXPORT_SYMBOL(snd_rawmidi_transmit);
-EXPORT_SYMBOL(snd_rawmidi_new);
-EXPORT_SYMBOL(snd_rawmidi_set_ops);
-EXPORT_SYMBOL(snd_rawmidi_info_select);
-EXPORT_SYMBOL(snd_rawmidi_kernel_open);
-EXPORT_SYMBOL(snd_rawmidi_kernel_release);
-EXPORT_SYMBOL(snd_rawmidi_kernel_read);
-EXPORT_SYMBOL(snd_rawmidi_kernel_write);
index e85e72baff9e8535c9cbd7a56ba0e4d65ddd1ac1..f3420d11a12fea53547caba81d0e7b8775ce1878 100644 (file)
@@ -27,7 +27,7 @@
 #include <sound/core.h>
 #include <sound/timer.h>
 
-#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
+#if IS_ENABLED(CONFIG_RTC)
 
 #include <linux/mc146818rtc.h>
 
@@ -132,8 +132,7 @@ static int __init rtctimer_init(void)
 
        if (rtctimer_freq < 2 || rtctimer_freq > 8192 ||
            !is_power_of_2(rtctimer_freq)) {
-               snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n",
-                          rtctimer_freq);
+               pr_err("ALSA: rtctimer: invalid frequency %d\n", rtctimer_freq);
                return -EINVAL;
        }
 
@@ -185,4 +184,4 @@ MODULE_LICENSE("GPL");
 
 MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC));
 
-#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
+#endif /* IS_ENABLED(CONFIG_RTC) */
index 8d4d5e853efec94716cf5585a94321c097144eb9..16d42679e43fc29e380612274e9f597f9899dc91 100644 (file)
@@ -39,12 +39,6 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
 
-#ifdef SNDRV_SEQ_OSS_DEBUG
-module_param(seq_oss_debug, int, 0644);
-MODULE_PARM_DESC(seq_oss_debug, "debug option");
-int seq_oss_debug = 0;
-#endif
-
 
 /*
  * prototypes
@@ -231,22 +225,19 @@ register_device(void)
        mutex_lock(&register_mutex);
        if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
                                          NULL, 0,
-                                         &seq_oss_f_ops, NULL,
-                                         SNDRV_SEQ_OSS_DEVNAME)) < 0) {
-               snd_printk(KERN_ERR "can't register device seq\n");
+                                         &seq_oss_f_ops, NULL)) < 0) {
+               pr_err("ALSA: seq_oss: can't register device seq\n");
                mutex_unlock(&register_mutex);
                return rc;
        }
        if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
                                          NULL, 0,
-                                         &seq_oss_f_ops, NULL,
-                                         SNDRV_SEQ_OSS_DEVNAME)) < 0) {
-               snd_printk(KERN_ERR "can't register device music\n");
+                                         &seq_oss_f_ops, NULL)) < 0) {
+               pr_err("ALSA: seq_oss: can't register device music\n");
                snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
                mutex_unlock(&register_mutex);
                return rc;
        }
-       debug_printk(("device registered\n"));
        mutex_unlock(&register_mutex);
        return 0;
 }
@@ -255,11 +246,10 @@ static void
 unregister_device(void)
 {
        mutex_lock(&register_mutex);
-       debug_printk(("device unregistered\n"));
        if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)                
-               snd_printk(KERN_ERR "error unregister device music\n");
+               pr_err("ALSA: seq_oss: error unregister device music\n");
        if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
-               snd_printk(KERN_ERR "error unregister device seq\n");
+               pr_err("ALSA: seq_oss: error unregister device seq\n");
        mutex_unlock(&register_mutex);
 }
 
index c0154a959d55373969c0e4eb608099f1e71098a7..b43924325249c01b0cdd11fc1164572a50369f98 100644 (file)
@@ -31,9 +31,6 @@
 #include <sound/seq_kernel.h>
 #include <sound/info.h>
 
-/* enable debug print */
-#define SNDRV_SEQ_OSS_DEBUG
-
 /* max. applications */
 #define SNDRV_SEQ_OSS_MAX_CLIENTS      16
 #define SNDRV_SEQ_OSS_MAX_SYNTH_DEVS   16
@@ -46,7 +43,6 @@
 #define SNDRV_SEQ_OSS_VERSION_STR      "0.1.8"
 
 /* device and proc interface name */
-#define SNDRV_SEQ_OSS_DEVNAME          "seq_oss"
 #define SNDRV_SEQ_OSS_PROCNAME         "oss"
 
 
@@ -177,13 +173,4 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
 /* misc. functions for proc interface */
 char *enabled_str(int bool);
 
-
-/* for debug */
-#ifdef SNDRV_SEQ_OSS_DEBUG
-extern int seq_oss_debug;
-#define debug_printk(x)        do { if (seq_oss_debug > 0) snd_printd x; } while (0)
-#else
-#define debug_printk(x)        /**/
-#endif
-
 #endif /* __SEQ_OSS_DEVICE_H */
index b3f39b5ed74234ff92d31162fc3af067a523c1ba..b9184d20c39ffb05057b5f74755fa49b37b088ba 100644 (file)
@@ -92,7 +92,6 @@ snd_seq_oss_create_client(void)
                goto __error;
 
        system_client = rc;
-       debug_printk(("new client = %d\n", rc));
 
        /* create annoucement receiver port */
        memset(port, 0, sizeof(*port));
@@ -190,10 +189,9 @@ snd_seq_oss_open(struct file *file, int level)
 
        dp = kzalloc(sizeof(*dp), GFP_KERNEL);
        if (!dp) {
-               snd_printk(KERN_ERR "can't malloc device info\n");
+               pr_err("ALSA: seq_oss: can't malloc device info\n");
                return -ENOMEM;
        }
-       debug_printk(("oss_open: dp = %p\n", dp));
 
        dp->cseq = system_client;
        dp->port = -1;
@@ -206,7 +204,7 @@ snd_seq_oss_open(struct file *file, int level)
 
        dp->index = i;
        if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
-               snd_printk(KERN_ERR "too many applications\n");
+               pr_err("ALSA: seq_oss: too many applications\n");
                rc = -ENOMEM;
                goto _error;
        }
@@ -216,21 +214,19 @@ snd_seq_oss_open(struct file *file, int level)
        snd_seq_oss_midi_setup(dp);
 
        if (dp->synth_opened == 0 && dp->max_mididev == 0) {
-               /* snd_printk(KERN_ERR "no device found\n"); */
+               /* pr_err("ALSA: seq_oss: no device found\n"); */
                rc = -ENODEV;
                goto _error;
        }
 
        /* create port */
-       debug_printk(("create new port\n"));
        rc = create_port(dp);
        if (rc < 0) {
-               snd_printk(KERN_ERR "can't create port\n");
+               pr_err("ALSA: seq_oss: can't create port\n");
                goto _error;
        }
 
        /* allocate queue */
-       debug_printk(("allocate queue\n"));
        rc = alloc_seq_queue(dp);
        if (rc < 0)
                goto _error;
@@ -247,7 +243,6 @@ snd_seq_oss_open(struct file *file, int level)
        dp->file_mode = translate_mode(file);
 
        /* initialize read queue */
-       debug_printk(("initialize read queue\n"));
        if (is_read_mode(dp->file_mode)) {
                dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
                if (!dp->readq) {
@@ -257,7 +252,6 @@ snd_seq_oss_open(struct file *file, int level)
        }
 
        /* initialize write queue */
-       debug_printk(("initialize write queue\n"));
        if (is_write_mode(dp->file_mode)) {
                dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
                if (!dp->writeq) {
@@ -267,14 +261,12 @@ snd_seq_oss_open(struct file *file, int level)
        }
 
        /* initialize timer */
-       debug_printk(("initialize timer\n"));
        dp->timer = snd_seq_oss_timer_new(dp);
        if (!dp->timer) {
-               snd_printk(KERN_ERR "can't alloc timer\n");
+               pr_err("ALSA: seq_oss: can't alloc timer\n");
                rc = -ENOMEM;
                goto _error;
        }
-       debug_printk(("timer initialized\n"));
 
        /* set private data pointer */
        file->private_data = dp;
@@ -288,7 +280,6 @@ snd_seq_oss_open(struct file *file, int level)
        client_table[dp->index] = dp;
        num_clients++;
 
-       debug_printk(("open done\n"));
        return 0;
 
  _error:
@@ -347,7 +338,6 @@ create_port(struct seq_oss_devinfo *dp)
                return rc;
 
        dp->port = port.addr.port;
-       debug_printk(("new port = %d\n", port.addr.port));
 
        return 0;
 }
@@ -363,7 +353,6 @@ delete_port(struct seq_oss_devinfo *dp)
                return 0;
        }
 
-       debug_printk(("delete_port %i\n", dp->port));
        return snd_seq_event_port_detach(dp->cseq, dp->port);
 }
 
@@ -401,7 +390,7 @@ delete_seq_queue(int queue)
        qinfo.queue = queue;
        rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
        if (rc < 0)
-               printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc);
+               pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
        return rc;
 }
 
@@ -438,21 +427,16 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp)
        client_table[dp->index] = NULL;
        num_clients--;
 
-       debug_printk(("resetting..\n"));
        snd_seq_oss_reset(dp);
 
-       debug_printk(("cleaning up..\n"));
        snd_seq_oss_synth_cleanup(dp);
        snd_seq_oss_midi_cleanup(dp);
 
        /* clear slot */
-       debug_printk(("releasing resource..\n"));
        queue = dp->queue;
        if (dp->port >= 0)
                delete_port(dp);
        delete_seq_queue(queue);
-
-       debug_printk(("release done\n"));
 }
 
 
@@ -466,7 +450,6 @@ snd_seq_oss_drain_write(struct seq_oss_devinfo *dp)
                return;
        if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
            dp->writeq) {
-               debug_printk(("syncing..\n"));
                while (snd_seq_oss_writeq_sync(dp->writeq))
                        ;
        }
index 5ac701c903c1f394f99776b9ff987c11f374c8ef..5b8520177b0ec9a67a848ccff39a8f9a80d73ee6 100644 (file)
@@ -90,12 +90,10 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
                return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
 
        case SNDCTL_SEQ_PANIC:
-               debug_printk(("panic\n"));
                snd_seq_oss_reset(dp);
                return -EINVAL;
 
        case SNDCTL_SEQ_SYNC:
-               debug_printk(("sync\n"));
                if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
                        return 0;
                while (snd_seq_oss_writeq_sync(dp->writeq))
@@ -105,55 +103,45 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
                return 0;
 
        case SNDCTL_SEQ_RESET:
-               debug_printk(("reset\n"));
                snd_seq_oss_reset(dp);
                return 0;
 
        case SNDCTL_SEQ_TESTMIDI:
-               debug_printk(("test midi\n"));
                if (get_user(dev, p))
                        return -EFAULT;
                return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
 
        case SNDCTL_SEQ_GETINCOUNT:
-               debug_printk(("get in count\n"));
                if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
                        return 0;
                return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
 
        case SNDCTL_SEQ_GETOUTCOUNT:
-               debug_printk(("get out count\n"));
                if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
                        return 0;
                return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
 
        case SNDCTL_SEQ_GETTIME:
-               debug_printk(("get time\n"));
                return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
 
        case SNDCTL_SEQ_RESETSAMPLES:
-               debug_printk(("reset samples\n"));
                if (get_user(dev, p))
                        return -EFAULT;
                return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
 
        case SNDCTL_SEQ_NRSYNTHS:
-               debug_printk(("nr synths\n"));
                return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
 
        case SNDCTL_SEQ_NRMIDIS:
-               debug_printk(("nr midis\n"));
                return put_user(dp->max_mididev, p) ? -EFAULT : 0;
 
        case SNDCTL_SYNTH_MEMAVL:
-               debug_printk(("mem avail\n"));
                if (get_user(dev, p))
                        return -EFAULT;
                val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
                return put_user(val, p) ? -EFAULT : 0;
 
        case SNDCTL_FM_4OP_ENABLE:
-               debug_printk(("4op\n"));
                if (get_user(dev, p))
                        return -EFAULT;
                snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
@@ -161,19 +149,15 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
 
        case SNDCTL_SYNTH_INFO:
        case SNDCTL_SYNTH_ID:
-               debug_printk(("synth info\n"));
                return snd_seq_oss_synth_info_user(dp, arg);
 
        case SNDCTL_SEQ_OUTOFBAND:
-               debug_printk(("out of band\n"));
                return snd_seq_oss_oob_user(dp, arg);
 
        case SNDCTL_MIDI_INFO:
-               debug_printk(("midi info\n"));
                return snd_seq_oss_midi_info_user(dp, arg);
 
        case SNDCTL_SEQ_THRESHOLD:
-               debug_printk(("threshold\n"));
                if (! is_write_mode(dp->file_mode))
                        return 0;
                if (get_user(val, p))
@@ -186,7 +170,6 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
                return 0;
 
        case SNDCTL_MIDI_PRETIME:
-               debug_printk(("pretime\n"));
                if (dp->readq == NULL || !is_read_mode(dp->file_mode))
                        return 0;
                if (get_user(val, p))
@@ -199,7 +182,6 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
                return put_user(val, p) ? -EFAULT : 0;
 
        default:
-               debug_printk(("others\n"));
                if (! is_write_mode(dp->file_mode))
                        return -EIO;
                return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
index 862d84893ee871c0467f5baf4667d769d6f7203e..3a4569669efa4b561b2751d9d1170e69ee2f4b47 100644 (file)
@@ -153,7 +153,6 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
        struct seq_oss_midi *mdev;
        unsigned long flags;
 
-       debug_printk(("check for MIDI client %d port %d\n", pinfo->addr.client, pinfo->addr.port));
        /* the port must include generic midi */
        if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
                return 0;
@@ -175,7 +174,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
         * allocate midi info record
         */
        if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
-               snd_printk(KERN_ERR "can't malloc midi info\n");
+               pr_err("ALSA: seq_oss: can't malloc midi info\n");
                return -ENOMEM;
        }
 
@@ -191,7 +190,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
 
        /* create MIDI coder */
        if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
-               snd_printk(KERN_ERR "can't malloc midi coder\n");
+               pr_err("ALSA: seq_oss: can't malloc midi coder\n");
                kfree(mdev);
                return -ENOMEM;
        }
@@ -406,7 +405,6 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
                return 0;
        }
 
-       debug_printk(("closing client %d port %d mode %d\n", mdev->client, mdev->port, mdev->opened));
        memset(&subs, 0, sizeof(subs));
        if (mdev->opened & PERM_WRITE) {
                subs.sender = dp->addr;
@@ -470,7 +468,6 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
                struct snd_seq_event ev;
                int c;
 
-               debug_printk(("resetting client %d port %d\n", mdev->client, mdev->port));
                memset(&ev, 0, sizeof(ev));
                ev.dest.client = mdev->client;
                ev.dest.port = mdev->port;
index 73661c4ab82aabefc2f26382db55854c704c8534..654d17a5023c8a23e2ec5f799298d91dc0c7f457 100644 (file)
@@ -48,12 +48,12 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
        struct seq_oss_readq *q;
 
        if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) {
-               snd_printk(KERN_ERR "can't malloc read queue\n");
+               pr_err("ALSA: seq_oss: can't malloc read queue\n");
                return NULL;
        }
 
        if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) {
-               snd_printk(KERN_ERR "can't malloc read queue buffer\n");
+               pr_err("ALSA: seq_oss: can't malloc read queue buffer\n");
                kfree(q);
                return NULL;
        }
index c5b773a1eea9324ec7a1c70a0a7dc926031f87a3..701feb71b700c7e223633b07827e954a804e5825 100644 (file)
@@ -106,7 +106,7 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
        unsigned long flags;
 
        if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) {
-               snd_printk(KERN_ERR "can't malloc synth info\n");
+               pr_err("ALSA: seq_oss: can't malloc synth info\n");
                return -ENOMEM;
        }
        rec->seq_device = -1;
@@ -130,7 +130,7 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
        if (i >= max_synth_devs) {
                if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
                        spin_unlock_irqrestore(&register_lock, flags);
-                       snd_printk(KERN_ERR "no more synth slot\n");
+                       pr_err("ALSA: seq_oss: no more synth slot\n");
                        kfree(rec);
                        return -ENOMEM;
                }
@@ -138,7 +138,6 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
        }
        rec->seq_device = i;
        synth_devs[i] = rec;
-       debug_printk(("synth %s registered %d\n", rec->name, i));
        spin_unlock_irqrestore(&register_lock, flags);
        dev->driver_data = rec;
 #ifdef SNDRV_OSS_INFO_DEV_SYNTH
@@ -163,7 +162,7 @@ snd_seq_oss_synth_unregister(struct snd_seq_device *dev)
        }
        if (index >= max_synth_devs) {
                spin_unlock_irqrestore(&register_lock, flags);
-               snd_printk(KERN_ERR "can't unregister synth\n");
+               pr_err("ALSA: seq_oss: can't unregister synth\n");
                return -EINVAL;
        }
        synth_devs[index] = NULL;
@@ -248,7 +247,7 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
                if (info->nr_voices > 0) {
                        info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
                        if (!info->ch) {
-                               snd_printk(KERN_ERR "Cannot malloc\n");
+                               pr_err("ALSA: seq_oss: Cannot malloc voices\n");
                                rec->oper.close(&info->arg);
                                module_put(rec->oper.owner);
                                snd_use_lock_free(&rec->use_lock);
@@ -256,7 +255,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
                        }
                        reset_channels(info);
                }
-               debug_printk(("synth %d assigned\n", i));
                info->opened++;
                rec->opened++;
                dp->synth_opened++;
@@ -326,7 +324,6 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
                        if (rec == NULL)
                                continue;
                        if (rec->opened > 0) {
-                               debug_printk(("synth %d closed\n", i));
                                rec->oper.close(&info->arg);
                                module_put(rec->oper.owner);
                                rec->opened = 0;
index ab59cbfbcaf20b4263faebb55d092ef93c2a4923..4f24ea9fad935ace703f61cd8ce084d0510ba3b7 100644 (file)
@@ -233,7 +233,6 @@ snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __use
        int value;
 
        if (cmd == SNDCTL_SEQ_CTRLRATE) {
-               debug_printk(("ctrl rate\n"));
                /* if *arg == 0, just return the current rate */
                if (get_user(value, arg))
                        return -EFAULT;
@@ -248,21 +247,16 @@ snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __use
 
        switch (cmd) {
        case SNDCTL_TMR_START:
-               debug_printk(("timer start\n"));
                return snd_seq_oss_timer_start(timer);
        case SNDCTL_TMR_STOP:
-               debug_printk(("timer stop\n"));
                return snd_seq_oss_timer_stop(timer);
        case SNDCTL_TMR_CONTINUE:
-               debug_printk(("timer continue\n"));
                return snd_seq_oss_timer_continue(timer);
        case SNDCTL_TMR_TEMPO:
-               debug_printk(("timer tempo\n"));
                if (get_user(value, arg))
                        return -EFAULT;
                return snd_seq_oss_timer_tempo(timer, value);
        case SNDCTL_TMR_TIMEBASE:
-               debug_printk(("timer timebase\n"));
                if (get_user(value, arg))
                        return -EFAULT;
                if (value < MIN_OSS_TIMEBASE)
@@ -276,7 +270,6 @@ snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __use
        case SNDCTL_TMR_METRONOME:
        case SNDCTL_TMR_SELECT:
        case SNDCTL_TMR_SOURCE:
-               debug_printk(("timer XXX\n"));
                /* not supported */
                return 0;
        }
index 4dc6bae80e15b92a005325f845f0cc16fcd67ce0..9ca5e647e54bf80a7a68552b0ade15ae4f5599cb 100644 (file)
@@ -123,7 +123,7 @@ static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
 static struct snd_seq_client *clientptr(int clientid)
 {
        if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
-               snd_printd("Seq: oops. Trying to get pointer to client %d\n",
+               pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
                           clientid);
                return NULL;
        }
@@ -136,7 +136,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
        struct snd_seq_client *client;
 
        if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
-               snd_printd("Seq: oops. Trying to get pointer to client %d\n",
+               pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
                           clientid);
                return NULL;
        }
@@ -291,8 +291,8 @@ static void seq_free_client(struct snd_seq_client * client)
        mutex_lock(&register_mutex);
        switch (client->type) {
        case NO_CLIENT:
-               snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n",
-                          client->number);
+               pr_warn("ALSA: seq: Trying to free unused client %d\n",
+                       client->number);
                break;
        case USER_CLIENT:
        case KERNEL_CLIENT:
@@ -301,7 +301,7 @@ static void seq_free_client(struct snd_seq_client * client)
                break;
 
        default:
-               snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n",
+               pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n",
                           client->number, client->type);
        }
        mutex_unlock(&register_mutex);
@@ -773,7 +773,7 @@ static int broadcast_event(struct snd_seq_client *client,
 static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event,
                           int atomic, int hop)
 {
-       snd_printd("seq: multicast not supported yet.\n");
+       pr_debug("ALSA: seq: multicast not supported yet.\n");
        return 0; /* ignored */
 }
 #endif /* SUPPORT_BROADCAST */
@@ -794,7 +794,7 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
 
        hop++;
        if (hop >= SNDRV_SEQ_MAX_HOPS) {
-               snd_printd("too long delivery path (%d:%d->%d:%d)\n",
+               pr_debug("ALSA: seq: too long delivery path (%d:%d->%d:%d)\n",
                           event->source.client, event->source.port,
                           event->dest.client, event->dest.port);
                return -EMLINK;
@@ -2196,7 +2196,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
                if (p->cmd == cmd)
                        return p->func(client, arg);
        }
-       snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
+       pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
                   cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
        return -ENOTTY;
 }
index 040c60e1da28f346aa049737802a43ce853940d3..91a786a783e1e7cd563f516df09b9c94e64214eb 100644 (file)
@@ -168,7 +168,7 @@ void snd_seq_device_load_drivers(void)
 
 /*
  * register a sequencer device
- * card = card info (NULL allowed)
+ * card = card info
  * device = device number (if any)
  * id = id of driver
  * result = return pointer (NULL allowed if unnecessary)
@@ -325,7 +325,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
                return -ENOMEM;
        }
        if (ops->driver & DRIVER_LOADED) {
-               snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);
+               pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
                unlock_driver(ops);
                snd_seq_autoload_unlock();
                return -EBUSY;
@@ -398,7 +398,7 @@ int snd_seq_device_unregister_driver(char *id)
                return -ENXIO;
        if (! (ops->driver & DRIVER_LOADED) ||
            (ops->driver & DRIVER_LOCKED)) {
-               snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n",
+               pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
                           id, ops->driver);
                unlock_driver(ops);
                return -EBUSY;
@@ -413,7 +413,7 @@ int snd_seq_device_unregister_driver(char *id)
 
        ops->driver = 0;
        if (ops->num_init_devices > 0)
-               snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n",
+               pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
                           ops->num_init_devices);
        mutex_unlock(&ops->reg_mutex);
 
@@ -459,7 +459,7 @@ static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
        if (dev->status != SNDRV_SEQ_DEVICE_FREE)
                return 0; /* already initialized */
        if (ops->argsize != dev->argsize) {
-               snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",
+               pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
                           dev->name, ops->id, ops->argsize, dev->argsize);
                return -EINVAL;
        }
@@ -467,7 +467,7 @@ static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
                dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
                ops->num_init_devices++;
        } else {
-               snd_printk(KERN_ERR "init_device failed: %s: %s\n",
+               pr_err("ALSA: seq: init_device failed: %s: %s\n",
                           dev->name, dev->id);
        }
 
@@ -486,7 +486,7 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
        if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
                return 0; /* not registered */
        if (ops->argsize != dev->argsize) {
-               snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",
+               pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
                           dev->name, ops->id, ops->argsize, dev->argsize);
                return -EINVAL;
        }
@@ -495,7 +495,7 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
                dev->driver_data = NULL;
                ops->num_init_devices--;
        } else {
-               snd_printk(KERN_ERR "free_device failed: %s: %s\n",
+               pr_err("ALSA: seq: free_device failed: %s: %s\n",
                           dev->name, dev->id);
        }
 
@@ -559,7 +559,7 @@ static void __exit alsa_seq_device_exit(void)
        snd_info_free_entry(info_entry);
 #endif
        if (num_ops)
-               snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
+               pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
 }
 
 module_init(alsa_seq_device_init)
index dbc55071679081568e6e3e89e256d78eccc74b55..ec667f158f192c4467e020164ecd4adf30a5ce04 100644 (file)
@@ -198,7 +198,7 @@ register_client(void)
        int i;
 
        if (ports < 1) {
-               snd_printk(KERN_ERR "invalid number of ports %d\n", ports);
+               pr_err("ALSA: seq_dummy: invalid number of ports %d\n", ports);
                return -EINVAL;
        }
 
index 0d75afa786bc6ffebe8ffd8dc5bde065397c00a8..559989992bef6ba7f35f7c63731bb6d40b5bd463 100644 (file)
@@ -34,7 +34,7 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize)
 
        f = kzalloc(sizeof(*f), GFP_KERNEL);
        if (f == NULL) {
-               snd_printd("malloc failed for snd_seq_fifo_new() \n");
+               pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n");
                return NULL;
        }
 
index 2cfe50c71a9d3d62b580f5132a8faf154689b30d..3b693e924db745c0ec8be74171bb189f17dfc53d 100644 (file)
@@ -31,12 +31,12 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
        int max_count = 5 * HZ;
 
        if (atomic_read(lockp) < 0) {
-               printk(KERN_WARNING "seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
+               pr_warn("ALSA: seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
                return;
        }
        while (atomic_read(lockp) > 0) {
                if (max_count == 0) {
-                       snd_printk(KERN_WARNING "seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
+                       pr_warn("ALSA: seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
                        break;
                }
                schedule_timeout_uninterruptible(1);
index f478f770bf5213f11663bad4041ad256664e6fe6..1e206de0c2dd1f904b8b6f402e8d03733b6ed81a 100644 (file)
@@ -236,7 +236,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
        init_waitqueue_entry(&wait, current);
        spin_lock_irqsave(&pool->lock, flags);
        if (pool->ptr == NULL) {        /* not initialized */
-               snd_printd("seq: pool is not initialized\n");
+               pr_debug("ALSA: seq: pool is not initialized\n");
                err = -EINVAL;
                goto __error;
        }
@@ -388,7 +388,7 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
 
        pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
        if (pool->ptr == NULL) {
-               snd_printd("seq: malloc for sequencer events failed\n");
+               pr_debug("ALSA: seq: malloc for sequencer events failed\n");
                return -ENOMEM;
        }
 
@@ -431,7 +431,7 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
 
        while (atomic_read(&pool->counter) > 0) {
                if (max_count == 0) {
-                       snd_printk(KERN_WARNING "snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
+                       pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
                        break;
                }
                schedule_timeout_uninterruptible(1);
@@ -464,7 +464,7 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize)
        /* create pool block */
        pool = kzalloc(sizeof(*pool), GFP_KERNEL);
        if (pool == NULL) {
-               snd_printd("seq: malloc failed for pool\n");
+               pr_debug("ALSA: seq: malloc failed for pool\n");
                return NULL;
        }
        spin_lock_init(&pool->lock);
index 64069dbf89ca383bfb8500cedf90ed9959f29fa4..3e05c55a28801a423411cc5c61b7d9d57096ce29 100644 (file)
@@ -121,7 +121,7 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
        runtime = substream->runtime;
        if ((tmp = runtime->avail) < count) {
                if (printk_ratelimit())
-                       snd_printk(KERN_ERR "MIDI output buffer overrun\n");
+                       pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
                return -ENOMEM;
        }
        if (snd_rawmidi_kernel_write(substream, buf, count) < count)
@@ -145,7 +145,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
        if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {        /* special case, to save space */
                if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
                        /* invalid event */
-                       snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
+                       pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
                        return 0;
                }
                snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
@@ -189,7 +189,7 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
                                           msynth->subdevice,
                                           SNDRV_RAWMIDI_LFLG_INPUT,
                                           &msynth->input_rfile)) < 0) {
-               snd_printd("midi input open failed!!!\n");
+               pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
                return err;
        }
        runtime = msynth->input_rfile.input->runtime;
@@ -231,7 +231,7 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
                                           msynth->subdevice,
                                           SNDRV_RAWMIDI_LFLG_OUTPUT,
                                           &msynth->output_rfile)) < 0) {
-               snd_printd("midi output open failed!!!\n");
+               pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
                return err;
        }
        memset(&params, 0, sizeof(params));
index 6f64471ddde3df24811e3c1d1b5998780843bbbe..9b6470cdcf246f6e89ecf428d84dee0a25ad361e 100644 (file)
@@ -89,7 +89,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
        int dest_channel = 0;
 
        if (ev == NULL || chanset == NULL) {
-               snd_printd("ev or chanbase NULL (snd_midi_process_event)\n");
+               pr_debug("ALSA: seq_midi_emul: ev or chanbase NULL (snd_midi_process_event)\n");
                return;
        }
        if (chanset->channels == NULL)
@@ -98,7 +98,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
        if (snd_seq_ev_is_channel_type(ev)) {
                dest_channel = ev->data.note.channel;
                if (dest_channel >= chanset->max_channels) {
-                       snd_printd("dest channel is %d, max is %d\n",
+                       pr_debug("ALSA: seq_midi_emul: dest channel is %d, max is %d\n",
                                   dest_channel, chanset->max_channels);
                        return;
                }
@@ -232,7 +232,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
        case SNDRV_SEQ_EVENT_ECHO:
        not_yet:
        default:
-               /*snd_printd("Unimplemented event %d\n", ev->type);*/
+               /*pr_debug("ALSA: seq_midi_emul: Unimplemented event %d\n", ev->type);*/
                break;
        }
 }
index 9516e5ce3aadd8cb50e857a187a469284cb91550..794a341bf0e560d7d5b69d37dc665fd9e571b294 100644 (file)
@@ -135,14 +135,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
                return NULL;
 
        if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
-               snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);
+               pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
                return NULL;
        }
 
        /* create a new port */
        new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
        if (! new_port) {
-               snd_printd("malloc failed for registering client port\n");
+               pr_debug("ALSA: seq: malloc failed for registering client port\n");
                return NULL;    /* failure, out of memory */
        }
        /* init port data */
index 29896ab23403a219283920ab0dd204e545047440..021b02bc9330f5770fa2ef0072ed844de25b677a 100644 (file)
@@ -60,7 +60,7 @@ struct snd_seq_prioq *snd_seq_prioq_new(void)
 
        f = kzalloc(sizeof(*f), GFP_KERNEL);
        if (f == NULL) {
-               snd_printd("oops: malloc failed for snd_seq_prioq_new()\n");
+               pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n");
                return NULL;
        }
        
@@ -79,7 +79,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
        *fifo = NULL;
 
        if (f == NULL) {
-               snd_printd("oops: snd_seq_prioq_delete() called with NULL prioq\n");
+               pr_debug("ALSA: seq: snd_seq_prioq_delete() called with NULL prioq\n");
                return;
        }
 
@@ -197,7 +197,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
                cur = cur->next;
                if (! --count) {
                        spin_unlock_irqrestore(&f->lock, flags);
-                       snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n");
+                       pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
                        return -EINVAL;
                }
        }
@@ -223,7 +223,7 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
        unsigned long flags;
 
        if (f == NULL) {
-               snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+               pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
                return NULL;
        }
        spin_lock_irqsave(&f->lock, flags);
@@ -248,7 +248,7 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
 int snd_seq_prioq_avail(struct snd_seq_prioq * f)
 {
        if (f == NULL) {
-               snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+               pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
                return 0;
        }
        return f->cells;
@@ -259,7 +259,7 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
 struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
 {
        if (f == NULL) {
-               snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+               pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
                return NULL;
        }
        return f->head;
@@ -321,7 +321,7 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
                        freeprev = cell;
                } else {
 #if 0
-                       printk(KERN_DEBUG "type = %i, source = %i, dest = %i, "
+                       pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
                               "client = %i\n",
                                cell->event.type,
                                cell->event.source.client,
index f9077361c119d1a4a5eed6135a3d2e4042c812e5..aad4878cee5579f2556524db0f61a069cc07fef5 100644 (file)
@@ -112,7 +112,7 @@ static struct snd_seq_queue *queue_new(int owner, int locked)
 
        q = kzalloc(sizeof(*q), GFP_KERNEL);
        if (q == NULL) {
-               snd_printd("malloc failed for snd_seq_queue_new()\n");
+               pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n");
                return NULL;
        }
 
index 24d44b2f61acda72453e5be78958aae15b8afccf..e73605393eee5351bed9d4472150fd0b63335e5d 100644 (file)
@@ -57,7 +57,7 @@ struct snd_seq_timer *snd_seq_timer_new(void)
        
        tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
        if (tmr == NULL) {
-               snd_printd("malloc failed for snd_seq_timer_new() \n");
+               pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n");
                return NULL;
        }
        spin_lock_init(&tmr->lock);
@@ -78,7 +78,7 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
        *tmr = NULL;
 
        if (t == NULL) {
-               snd_printd("oops: snd_seq_timer_delete() called with NULL timer\n");
+               pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
                return;
        }
        t->running = 0;
@@ -199,7 +199,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
                /* refuse to change ppq on running timers */
                /* because it will upset the song position (ticks) */
                spin_unlock_irqrestore(&tmr->lock, flags);
-               snd_printd("seq: cannot change ppq of a running timer\n");
+               pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
                return -EBUSY;
        }
 
@@ -252,7 +252,7 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
 
        /* FIXME */
        if (base != SKEW_BASE) {
-               snd_printd("invalid skew base 0x%x\n", base);
+               pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
                return -EINVAL;
        }
        spin_lock_irqsave(&tmr->lock, flags);
@@ -292,7 +292,7 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
                }
        }
        if (err < 0) {
-               snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err);
+               pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
                return err;
        }
        t->callback = snd_seq_timer_interrupt;
index 4b50e604276d8dec6adb47bee6b870a1fe52f8c0..56e0f4cd3f8299837053961747a64b8a736b3867 100644 (file)
@@ -446,7 +446,7 @@ static int snd_virmidi_dev_register(struct snd_rawmidi *rmidi)
                /* should check presence of port more strictly.. */
                break;
        default:
-               snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode);
+               pr_err("ALSA: seq_virmidi: seq_mode is not set: %d\n", rdev->seq_mode);
                return -EINVAL;
        }
        return 0;
index 437c25ea640363b5d38d8214e873cb236f1aec43..38ad1a0dd3f70fc68435309dd75b1d4c45bf3c42 100644 (file)
@@ -118,7 +118,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
        if (mreg && mreg->type == type) {
                private_data = mreg->private_data;
                if (private_data && mreg->card_ptr)
-                       atomic_inc(&mreg->card_ptr->refcount);
+                       get_device(&mreg->card_ptr->card_dev);
        } else
                private_data = NULL;
        mutex_unlock(&sound_mutex);
@@ -355,22 +355,25 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
 
 EXPORT_SYMBOL(snd_unregister_device);
 
-int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
-                             struct device_attribute *attr)
+/* get the assigned device to the given type and device number;
+ * the caller needs to release it via put_device() after using it
+ */
+struct device *snd_get_device(int type, struct snd_card *card, int dev)
 {
-       int minor, ret = -EINVAL;
-       struct device *d;
+       int minor;
+       struct device *d = NULL;
 
        mutex_lock(&sound_mutex);
        minor = find_snd_minor(type, card, dev);
-       if (minor >= 0 && (d = snd_minors[minor]->dev) != NULL)
-               ret = device_create_file(d, attr);
+       if (minor >= 0) {
+               d = snd_minors[minor]->dev;
+               if (d)
+                       get_device(d);
+       }
        mutex_unlock(&sound_mutex);
-       return ret;
-
+       return d;
 }
-
-EXPORT_SYMBOL(snd_add_device_sysfs_file);
+EXPORT_SYMBOL(snd_get_device);
 
 #ifdef CONFIG_PROC_FS
 /*
@@ -458,7 +461,7 @@ static int __init alsa_sound_init(void)
        snd_major = major;
        snd_ecards_limit = cards_limit;
        if (register_chrdev(major, "alsa", &snd_fops)) {
-               snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
+               pr_err("ALSA core: unable to register native major device number %d\n", major);
                return -EIO;
        }
        if (snd_info_init() < 0) {
@@ -467,7 +470,7 @@ static int __init alsa_sound_init(void)
        }
        snd_info_minor_register();
 #ifndef MODULE
-       printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");
+       pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
 #endif
        return 0;
 }
index 726a49ac97253d50634313265abc5699480c7e71..573a65eb2b796961ed72b2999dc4b63fb05326ef 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifdef CONFIG_SND_OSSEMUL
 
-#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
+#if !IS_ENABLED(CONFIG_SOUND)
 #error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
 #endif
 
@@ -55,7 +55,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
        if (mreg && mreg->type == type) {
                private_data = mreg->private_data;
                if (private_data && mreg->card_ptr)
-                       atomic_inc(&mreg->card_ptr->refcount);
+                       get_device(&mreg->card_ptr->card_dev);
        } else
                private_data = NULL;
        mutex_unlock(&sound_oss_mutex);
@@ -105,8 +105,7 @@ static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
 }
 
 int snd_register_oss_device(int type, struct snd_card *card, int dev,
-                           const struct file_operations *f_ops, void *private_data,
-                           const char *name)
+                           const struct file_operations *f_ops, void *private_data)
 {
        int minor = snd_oss_kernel_minor(type, card, dev);
        int minor_unit;
index 6ddcf06f52f9a0c710cfbd65157915e5d90b14a4..cfd455a8ac1af366fb1ed63ae05497035b528b29 100644 (file)
@@ -35,9 +35,9 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 
-#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE)
+#if IS_ENABLED(CONFIG_SND_HRTIMER)
 #define DEFAULT_TIMER_LIMIT 4
-#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
+#elif IS_ENABLED(CONFIG_SND_RTCTIMER)
 #define DEFAULT_TIMER_LIMIT 2
 #else
 #define DEFAULT_TIMER_LIMIT 1
@@ -240,7 +240,8 @@ int snd_timer_open(struct snd_timer_instance **ti,
                /* open a slave instance */
                if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
                    tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
-                       snd_printd("invalid slave class %i\n", tid->dev_sclass);
+                       pr_debug("ALSA: timer: invalid slave class %i\n",
+                                tid->dev_sclass);
                        return -EINVAL;
                }
                mutex_lock(&register_mutex);
@@ -774,7 +775,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
                *rtimer = NULL;
        timer = kzalloc(sizeof(*timer), GFP_KERNEL);
        if (timer == NULL) {
-               snd_printk(KERN_ERR "timer: cannot allocate\n");
+               pr_err("ALSA: timer: cannot allocate\n");
                return -ENOMEM;
        }
        timer->tmr_class = tid->dev_class;
@@ -813,7 +814,7 @@ static int snd_timer_free(struct snd_timer *timer)
        if (! list_empty(&timer->open_list_head)) {
                struct list_head *p, *n;
                struct snd_timer_instance *ti;
-               snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
+               pr_warn("ALSA: timer %p is busy?\n", timer);
                list_for_each_safe(p, n, &timer->open_list_head) {
                        list_del_init(p);
                        ti = list_entry(p, struct snd_timer_instance, open_list);
@@ -1955,12 +1956,10 @@ static int __init alsa_timer_init(void)
 #endif
 
        if ((err = snd_timer_register_system()) < 0)
-               snd_printk(KERN_ERR "unable to register system timer (%i)\n",
-                          err);
+               pr_err("ALSA: unable to register system timer (%i)\n", err);
        if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
                                       &snd_timer_f_ops, NULL, "timer")) < 0)
-               snd_printk(KERN_ERR "unable to register timer device (%i)\n",
-                          err);
+               pr_err("ALSA: unable to register timer device (%i)\n", err);
        snd_timer_proc_init();
        return 0;
 }
index 842a97d5fc3a1ec104fcd691597e07095c3fa76d..6c58e6f73a013bd33e47cc9a7ea8c1b46b7f17df 100644 (file)
@@ -101,7 +101,7 @@ static int slave_init(struct link_slave *slave)
        if (slave->info.count > 2  ||
            (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
             slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
-               snd_printk(KERN_ERR "invalid slave element\n");
+               pr_err("ALSA: vmaster: invalid slave element\n");
                kfree(uinfo);
                return -EINVAL;
        }
index f7589923effa08f25094b87423e559414e7f8aaf..2a16c86a60b3c8bac7dbf3697c17f4bcfa013ee3 100644 (file)
@@ -1142,8 +1142,8 @@ static int loopback_probe(struct platform_device *devptr)
        int dev = devptr->id;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct loopback), &card);
+       err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct loopback), &card);
        if (err < 0)
                return err;
        loopback = card->private_data;
index 915b4d7fbb23fe8c1309e05c17ff525a6d7e7d78..fab90bd2bd5151ae1fcf44f8a7f9b444e1e323fe 100644 (file)
@@ -1054,8 +1054,8 @@ static int snd_dummy_probe(struct platform_device *devptr)
        int idx, err;
        int dev = devptr->id;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_dummy), &card);
+       err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_dummy), &card);
        if (err < 0)
                return err;
        dummy = card->private_data;
@@ -1114,8 +1114,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
 
        dummy_proc_init(dummy);
 
-       snd_card_set_dev(card, &devptr->dev);
-
        err = snd_card_register(card);
        if (err == 0) {
                platform_set_drvdata(devptr, card);
index 95ea4a153ea43afb916de2ad86ffd2990650d355..33ed76530d0bc31402dae0c77405934ff1209b66 100644 (file)
@@ -1280,7 +1280,8 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
        if (!enable[dev])
                return -ENOENT;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pfdev->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
@@ -1310,8 +1311,6 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
                (unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq,
                ml403_ac97cr->capture_irq, dev + 1);
 
-       snd_card_set_dev(card, &pfdev->dev);
-
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
index 90a3a7b38a2a01eee908c7975f1dedce783a2948..83014b83a44e32d1979413bc226a78b6ef14f466 100644 (file)
@@ -64,7 +64,8 @@ static struct platform_device *platform_devices[SNDRV_CARDS];
 static int pnp_registered;
 static unsigned int snd_mpu401_devices;
 
-static int snd_mpu401_create(int dev, struct snd_card **rcard)
+static int snd_mpu401_create(struct device *devptr, int dev,
+                            struct snd_card **rcard)
 {
        struct snd_card *card;
        int err;
@@ -73,7 +74,8 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard)
                snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
 
        *rcard = NULL;
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        strcpy(card->driver, "MPU-401 UART");
@@ -114,10 +116,9 @@ static int snd_mpu401_probe(struct platform_device *devptr)
                snd_printk(KERN_ERR "specify or disable IRQ\n");
                return -EINVAL;
        }
-       err = snd_mpu401_create(dev, &card);
+       err = snd_mpu401_create(&devptr->dev, dev, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, &devptr->dev);
        if ((err = snd_card_register(card)) < 0) {
                snd_card_free(card);
                return err;
@@ -194,14 +195,13 @@ static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
                err = snd_mpu401_pnp(dev, pnp_dev, id);
                if (err < 0)
                        return err;
-               err = snd_mpu401_create(dev, &card);
+               err = snd_mpu401_create(&pnp_dev->dev, dev, &card);
                if (err < 0)
                        return err;
                if ((err = snd_card_register(card)) < 0) {
                        snd_card_free(card);
                        return err;
                }
-               snd_card_set_dev(card, &pnp_dev->dev);
                pnp_set_drvdata(pnp_dev, card);
                snd_mpu401_devices++;
                ++dev;
index e5ec7eb27dec5f873c36b6c6f5e3e79a44fdddfe..4b66c7f22af797332059e2a1ef57ae7c0e6a9f06 100644 (file)
@@ -697,7 +697,8 @@ static int snd_mtpav_probe(struct platform_device *dev)
        int err;
        struct mtpav *mtp_card;
 
-       err = snd_card_create(index, id, THIS_MODULE, sizeof(*mtp_card), &card);
+       err = snd_card_new(&dev->dev, index, id, THIS_MODULE,
+                          sizeof(*mtp_card), &card);
        if (err < 0)
                return err;
 
@@ -732,7 +733,6 @@ static int snd_mtpav_probe(struct platform_device *dev)
 
        snd_mtpav_portscan(mtp_card);
 
-       snd_card_set_dev(card, &dev->dev);
        err = snd_card_register(mtp_card->card);
        if (err < 0)
                goto __error;
index 4e0dd22ba08eddbd7aa744c12069d4417d4f7307..f5fd448dbc5700b96f061c1800ea369e8bcbf9f1 100644 (file)
@@ -959,7 +959,8 @@ static int snd_mts64_probe(struct platform_device *pdev)
        if ((err = snd_mts64_probe_port(p)) < 0)
                return err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
                snd_printd("Cannot create card\n");
                return err;
@@ -1009,8 +1010,6 @@ static int snd_mts64_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, card);
 
-       snd_card_set_dev(card, &pdev->dev);
-
        /* At this point card will be usable */
        if ((err = snd_card_register(card)) < 0) {
                snd_printd("Cannot register card\n");
index 33d9a857a2625e443808df63e0d0092632871562..f66af5884c4066cadcad107378e8ca30b32f0f69 100644 (file)
@@ -501,10 +501,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
        hw->private_data = opl3;
        hw->exclusive = 1;
 #ifdef CONFIG_SND_OSSEMUL
-       if (device == 0) {
+       if (device == 0)
                hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;
-               sprintf(hw->oss_dev, "dmfm%i", card->number);
-       }
 #endif
        strcpy(hw->name, hw->id);
        switch (opl3->hardware & OPL3_HW_MASK) {
index 742a4b642fd9ea19adfcd195244c8fbc9bfa5fb1..ddcc1a325a618124b9206a9f0c0c9a23774938ed 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/opl3.h>
 #include <sound/asound_fm.h>
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 #define OPL3_SUPPORT_SYNTH
 #endif
 
index 328bd29264ce555e048da881af2dcc7e60e289d6..36808cdab06f23b8869a0bcf52336539e737a3cd 100644 (file)
@@ -105,7 +105,7 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev)
        hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pcsp_chip.timer.function = pcsp_do_timer;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -127,8 +127,6 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev)
                return err;
        }
 
-       snd_card_set_dev(pcsp_chip.card, dev);
-
        strcpy(card->driver, "PC-Speaker");
        strcpy(card->shortname, "pcsp");
        sprintf(card->longname, "Internal PC-Speaker at port 0x%x",
index b874b0ad99cd2ba7cd8fea316c53ad225a2220d1..0ecf8a453e0112cb56a76ec2035ad2c196fec87f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/input.h>
 #include <asm/io.h>
 #include "pcsp.h"
+#include "pcsp_input.h"
 
 static void pcspkr_do_sound(unsigned int count)
 {
index 991018df7131d957341ed11e2c5bde91ea34d8cd..78ccfa4555272fa9e1fdd3a266b1ab6c7a7db425 100644 (file)
@@ -748,7 +748,8 @@ static int snd_portman_probe(struct platform_device *pdev)
        if ((err = snd_portman_probe_port(p)) < 0)
                return err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
                snd_printd("Cannot create card\n");
                return err;
@@ -798,8 +799,6 @@ static int snd_portman_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, card);
 
-       snd_card_set_dev(card, &pdev->dev);
-
        /* At this point card will be usable */
        if ((err = snd_card_register(card)) < 0) {
                snd_printd("Cannot register card\n");
index e0bf5e77b43ae757d1f607b5c86a3636a4e371df..9ad4414fa25cf06b89abc1399584b134bb9a4970 100644 (file)
@@ -942,7 +942,8 @@ static int snd_serial_probe(struct platform_device *devptr)
                return -ENODEV;
        }
 
-       err  = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err  = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+                           0, &card);
        if (err < 0)
                return err;
 
@@ -969,8 +970,6 @@ static int snd_serial_probe(struct platform_device *devptr)
                uart->base,
                uart->irq);
 
-       snd_card_set_dev(card, &devptr->dev);
-
        if ((err = snd_card_register(card)) < 0)
                goto _err;
 
index ace3879e8d9649fb95a8d65a4c3481e0ce0e49a4..b178724295f37f4a29d0a0a51494af6e763589c8 100644 (file)
@@ -90,8 +90,8 @@ static int snd_virmidi_probe(struct platform_device *devptr)
        int idx, err;
        int dev = devptr->id;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_card_virmidi), &card);
+       err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_card_virmidi), &card);
        if (err < 0)
                return err;
        vmidi = card->private_data;
@@ -118,8 +118,6 @@ static int snd_virmidi_probe(struct platform_device *devptr)
        strcpy(card->shortname, "VirMIDI");
        sprintf(card->longname, "Virtual MIDI Card %i", dev + 1);
 
-       snd_card_set_dev(card, &devptr->dev);
-
        if ((err = snd_card_register(card)) == 0) {
                platform_set_drvdata(devptr, card);
                return 0;
index c0aa64941cee0bd927450a6b69314d14f2f02bce..0c3948630cf7ec2d5e4b5829f089e422121f93f8 100644 (file)
@@ -1326,10 +1326,10 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
        if (err < 0)
                return err;
 
-       err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card);
+       err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+                          sizeof(*dice), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, &unit->device);
 
        dice = card->private_data;
        dice->card = card;
index fd42e6b315e69d90e39deda16d553fc0baf97395..7ac94439e7584d8e973796dbc07a7032909f64c9 100644 (file)
@@ -631,10 +631,10 @@ static int isight_probe(struct fw_unit *unit,
        struct isight *isight;
        int err;
 
-       err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
+       err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+                          sizeof(*isight), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, &unit->device);
 
        isight = card->private_data;
        isight->card = card;
index 858023cf4298c0cbf6022e16824ab26f085f2b59..2dba848a781fd19f1fb2ca8c25bf2ff56fb0eabd 100644 (file)
@@ -391,10 +391,10 @@ static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
        struct scs *scs;
        int err;
 
-       err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card);
+       err = snd_card_new(&unit->device, -16, NULL, THIS_MODULE,
+                          sizeof(*scs), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, &unit->device);
 
        scs = card->private_data;
        scs->card = card;
index cc8bc3a51bc147ab7a13c0a38ec84134b55f9da3..9f7ef219b109d52037c89672a608df990bab0c5c 100644 (file)
@@ -668,10 +668,10 @@ static int fwspk_probe(struct fw_unit *unit,
        u32 firmware;
        int err;
 
-       err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card);
+       err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+                          sizeof(*fwspk), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, &unit->device);
 
        fwspk = card->private_data;
        fwspk->card = card;
index e04e750a77ed4bac80875bf05e979bbd946f2219..1a3a6fa27158b0096de715c8e322ec0cddeb62ec 100644 (file)
@@ -98,7 +98,7 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
                        AK4113_CINT | AK4113_STC);
        chip->rcs1 = reg_read(chip, AK4113_REG_RCS1);
        chip->rcs2 = reg_read(chip, AK4113_REG_RCS2);
-       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops);
        if (err < 0)
                goto __fail;
 
index 15ae0250eacec065d90c4093127f4604bec84a99..c7f56339415d31052812e1c3d6066c275298411e 100644 (file)
@@ -111,7 +111,7 @@ int snd_ak4114_create(struct snd_card *card,
        chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
        chip->rcs1 = reg_read(chip, AK4114_REG_RCS1);
 
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
+       if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0)
                goto __fail;
 
        if (r_ak4114)
index 40e33c9f2b095f1eb7488729afe20f1f991d994f..88452e899bd94124ddffe1ad3485d7b9896aeddf 100644 (file)
@@ -62,7 +62,7 @@ static void reg_dump(struct ak4117 *ak4117)
 
 static void snd_ak4117_free(struct ak4117 *chip)
 {
-       del_timer(&chip->timer);
+       del_timer_sync(&chip->timer);
        kfree(chip);
 }
 
index 26ce26a5884d7254e6b61ca0f6fd1df2acba545c..f481a41e027eb132a2acfd1632f8351fe4daa8b6 100644 (file)
@@ -144,8 +144,9 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
        struct snd_opl3 *opl3;
        struct snd_timer *timer;
 
-       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                               sizeof(struct snd_ad1816a), &card);
+       error = snd_card_new(&pcard->card->dev,
+                            index[dev], id[dev], THIS_MODULE,
+                            sizeof(struct snd_ad1816a), &card);
        if (error < 0)
                return error;
        chip = card->private_data;
@@ -154,7 +155,6 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
                snd_card_free(card);
                return error;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
 
        if ((error = snd_ad1816a_create(card, port[dev],
                                        irq[dev],
index e3f455bd85cd55c12ac8d561ef0793ba96ab8c4f..093f22a464d7494e373bf6e64c5842613ea8f971 100644 (file)
@@ -91,7 +91,7 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
        struct snd_pcm *pcm;
        int error;
 
-       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
        if (error < 0)
                return error;
 
@@ -119,8 +119,6 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
        if (thinkpad[n])
                strcat(card->longname, " [Thinkpad]");
 
-       snd_card_set_dev(card, dev);
-
        error = snd_card_register(card);
        if (error < 0)
                goto out;
index 35659218710f93f1d738b327f4f43c650b8043cc..120c524bb2a05bd01d4704ccf443f20285bf5fe0 100644 (file)
@@ -53,7 +53,7 @@ static int snd_adlib_probe(struct device *dev, unsigned int n)
        struct snd_opl3 *opl3;
        int error;
 
-       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
        if (error < 0) {
                dev_err(dev, "could not create card\n");
                return error;
@@ -83,8 +83,6 @@ static int snd_adlib_probe(struct device *dev, unsigned int n)
                goto out;
        }
 
-       snd_card_set_dev(card, dev);
-
        error = snd_card_register(card);
        if (error < 0) {
                dev_err(dev, "could not register card\n");
index 10f08a18fe3ba7b9bd7789a343f40575a4a4cf43..32d01525211d34432229c1ca2f90bacc9ccf5665 100644 (file)
@@ -193,8 +193,9 @@ static int snd_card_als100_probe(int dev,
        struct snd_card_als100 *acard;
        struct snd_opl3 *opl3;
 
-       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                               sizeof(struct snd_card_als100), &card);
+       error = snd_card_new(&pcard->card->dev,
+                            index[dev], id[dev], THIS_MODULE,
+                            sizeof(struct snd_card_als100), &card);
        if (error < 0)
                return error;
        acard = card->private_data;
@@ -203,7 +204,6 @@ static int snd_card_als100_probe(int dev,
                snd_card_free(card);
                return error;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
 
        if (pid->driver_data == SB_HW_DT019X)
                dma16[dev] = -1;
index db301ff94ec2ec43611beb6a86c495fc6e475fa6..0ea75fc620725599b817736482dfef306f5de285 100644 (file)
@@ -184,8 +184,9 @@ static int snd_card_azt2320_probe(int dev,
        struct snd_wss *chip;
        struct snd_opl3 *opl3;
 
-       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                               sizeof(struct snd_card_azt2320), &card);
+       error = snd_card_new(&pcard->card->dev,
+                            index[dev], id[dev], THIS_MODULE,
+                            sizeof(struct snd_card_azt2320), &card);
        if (error < 0)
                return error;
        acard = card->private_data;
@@ -194,7 +195,6 @@ static int snd_card_azt2320_probe(int dev,
                snd_card_free(card);
                return error;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
 
        if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
                snd_card_free(card);
index ab6b2dc043f1e399d3205ba802448433f61f357e..4778852a1201388645d15c54f4f67cbd2abd3142 100644 (file)
@@ -293,15 +293,14 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
        }
        outb(val, port);
 
-       err = snd_card_create(index[ndev], id[ndev], THIS_MODULE,
-                               sizeof(struct snd_cmi8328), &card);
+       err = snd_card_new(pdev, index[ndev], id[ndev], THIS_MODULE,
+                          sizeof(struct snd_cmi8328), &card);
        if (err < 0)
                return err;
        cmi = card->private_data;
        cmi->card = card;
        cmi->port = port;
        cmi->wss_cfg = val;
-       snd_card_set_dev(card, pdev);
 
        err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev],
                        dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss);
index 270b9659ef7f703790a65531fc0205ddfead3c3a..dfedfd85f205460095ad09b1f0086c8f25925ea9 100644 (file)
@@ -514,14 +514,15 @@ static int snd_cmi8330_resume(struct snd_card *card)
 
 #define PFX    "cmi8330: "
 
-static int snd_cmi8330_card_new(int dev, struct snd_card **cardp)
+static int snd_cmi8330_card_new(struct device *pdev, int dev,
+                               struct snd_card **cardp)
 {
        struct snd_card *card;
        struct snd_cmi8330 *acard;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_cmi8330), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_cmi8330), &card);
        if (err < 0) {
                snd_printk(KERN_ERR PFX "could not get a new card\n");
                return err;
@@ -635,10 +636,9 @@ static int snd_cmi8330_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       err = snd_cmi8330_card_new(dev, &card);
+       err = snd_cmi8330_card_new(pdev, dev, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, pdev);
        if ((err = snd_cmi8330_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -698,7 +698,7 @@ static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
                               
-       res = snd_cmi8330_card_new(dev, &card);
+       res = snd_cmi8330_card_new(&pcard->card->dev, dev, &card);
        if (res < 0)
                return res;
        if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) {
@@ -706,7 +706,6 @@ static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
                snd_card_free(card);
                return res;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
        if ((res = snd_cmi8330_probe(card, dev)) < 0) {
                snd_card_free(card);
                return res;
index ba9a74eff3e0dda98644dbe13df9cdb505e3043f..7dba07a4343aecfbebbb2c97c43e47b87936e768 100644 (file)
@@ -95,7 +95,7 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
        struct snd_pcm *pcm;
        int error;
 
-       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
        if (error < 0)
                return error;
 
@@ -135,8 +135,6 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
                        dev_warn(dev, "MPU401 not detected\n");
        }
 
-       snd_card_set_dev(card, dev);
-
        error = snd_card_register(card);
        if (error < 0)
                goto out;
index 69614acb20520678ea0c58c5dbfb5a4a74563772..750f51c904fcb446b0726109516f04c1bd348bac 100644 (file)
@@ -364,13 +364,14 @@ static void snd_card_cs4236_free(struct snd_card *card)
        release_and_free_resource(acard->res_sb_port);
 }
 
-static int snd_cs423x_card_new(int dev, struct snd_card **cardp)
+static int snd_cs423x_card_new(struct device *pdev, int dev,
+                              struct snd_card **cardp)
 {
        struct snd_card *card;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_card_cs4236), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_card_cs4236), &card);
        if (err < 0)
                return err;
        card->private_free = snd_card_cs4236_free;
@@ -487,10 +488,9 @@ static int snd_cs423x_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       err = snd_cs423x_card_new(dev, &card);
+       err = snd_cs423x_card_new(pdev, dev, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, pdev);
        if ((err = snd_cs423x_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -577,7 +577,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
                if (!strcmp(cdev->id[0].id, cid))
                        break;
        }
-       err = snd_cs423x_card_new(dev, &card);
+       err = snd_cs423x_card_new(&pdev->dev, dev, &card);
        if (err < 0)
                return err;
        err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
@@ -586,7 +586,6 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
                snd_card_free(card);
                return err;
        }
-       snd_card_set_dev(card, &pdev->dev);
        if ((err = snd_cs423x_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -638,7 +637,7 @@ static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       res = snd_cs423x_card_new(dev, &card);
+       res = snd_cs423x_card_new(&pcard->card->dev, dev, &card);
        if (res < 0)
                return res;
        if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
@@ -647,7 +646,6 @@ static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
                snd_card_free(card);
                return res;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
        if ((res = snd_cs423x_probe(card, dev)) < 0) {
                snd_card_free(card);
                return res;
index cdcfb57f1f0a94226d2f131d1005117c33766627..76001fe0579da1942620ae97f1c0e8bed4aa67fa 100644 (file)
@@ -187,8 +187,8 @@ static int snd_es1688_isa_probe(struct device *dev, unsigned int n)
        struct snd_card *card;
        int error;
 
-       error = snd_card_create(index[n], id[n], THIS_MODULE,
-                               sizeof(struct snd_es1688), &card);
+       error = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+                            sizeof(struct snd_es1688), &card);
        if (error < 0)
                return error;
 
@@ -196,8 +196,6 @@ static int snd_es1688_isa_probe(struct device *dev, unsigned int n)
        if (error < 0)
                goto out;
 
-       snd_card_set_dev(card, dev);
-
        error = snd_es1688_probe(card, n);
        if (error < 0)
                goto out;
@@ -274,8 +272,9 @@ static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
        if (dev == SNDRV_CARDS)
                return -ENODEV;
 
-       error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                               sizeof(struct snd_es1688), &card);
+       error = snd_card_new(&pcard->card->dev,
+                            index[dev], id[dev], THIS_MODULE,
+                            sizeof(struct snd_es1688), &card);
        if (error < 0)
                return error;
        chip = card->private_data;
@@ -285,7 +284,6 @@ static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
                snd_card_free(card);
                return error;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
        error = snd_es1688_probe(card, dev);
        if (error < 0)
                return error;
index 12978b864c3ab52b8cc1388d24d15ead0fd4f690..1c16830af3d8cf73bfd3ff4042d070f556e53d25 100644 (file)
@@ -2105,10 +2105,11 @@ static int snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
 #define is_isapnp_selected(dev)                0
 #endif
 
-static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
+static int snd_es18xx_card_new(struct device *pdev, int dev,
+                              struct snd_card **cardp)
 {
-       return snd_card_create(index[dev], id[dev], THIS_MODULE,
-                              sizeof(struct snd_es18xx), cardp);
+       return snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                           sizeof(struct snd_es18xx), cardp);
 }
 
 static int snd_audiodrive_probe(struct snd_card *card, int dev)
@@ -2179,10 +2180,9 @@ static int snd_es18xx_isa_probe1(int dev, struct device *devptr)
        struct snd_card *card;
        int err;
 
-       err = snd_es18xx_card_new(dev, &card);
+       err = snd_es18xx_card_new(devptr, dev, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, devptr);
        if ((err = snd_audiodrive_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -2284,14 +2284,13 @@ static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       err = snd_es18xx_card_new(dev, &card);
+       err = snd_es18xx_card_new(&pdev->dev, dev, &card);
        if (err < 0)
                return err;
        if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
                snd_card_free(card);
                return err;
        }
-       snd_card_set_dev(card, &pdev->dev);
        if ((err = snd_audiodrive_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -2342,7 +2341,7 @@ static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       res = snd_es18xx_card_new(dev, &card);
+       res = snd_es18xx_card_new(&pcard->card->dev, dev, &card);
        if (res < 0)
                return res;
 
@@ -2350,7 +2349,6 @@ static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
                snd_card_free(card);
                return res;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
        if ((res = snd_audiodrive_probe(card, dev)) < 0) {
                snd_card_free(card);
                return res;
index 81244e7cea5be0d32d00cf14fe2a461432cd1082..1eb2b1ec0fd93c8a288a521f8e35f184ee7ebd69 100644 (file)
@@ -506,13 +506,11 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
        u8 type;
        int err;
 
-       err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
-                             &card);
+       err = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+                          sizeof(*galaxy), &card);
        if (err < 0)
                return err;
 
-       snd_card_set_dev(card, dev);
-
        card->private_free = snd_galaxy_free;
        galaxy = card->private_data;
 
index 1adc1b924f39f4e3d3dc7a4d4414568a3cb10b7c..7ce29ffa1af9b476ef264cc874591a0d8829415d 100644 (file)
@@ -149,7 +149,7 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n)
        struct snd_gus_card *gus;
        int error;
 
-       error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+       error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
        if (error < 0)
                return error;
 
@@ -199,8 +199,6 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n)
                sprintf(card->longname + strlen(card->longname),
                        "&%d", gus->gf1.dma2);
 
-       snd_card_set_dev(card, dev);
-
        error = snd_card_register(card);
        if (error < 0)
                goto out;
index 38e1e3260c2453be6c07d0dfecdb48d5869bba78..28a16936a397b71207b88504cd6ee1fc0e8ad82a 100644 (file)
@@ -242,8 +242,8 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
        struct snd_opl3 *opl3;
        int error;
 
-       error = snd_card_create(index[n], id[n], THIS_MODULE,
-                               sizeof(struct snd_es1688), &card);
+       error = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+                            sizeof(struct snd_es1688), &card);
        if (error < 0)
                return error;
 
@@ -328,8 +328,6 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
                "irq %i&%i, dma %i&%i", es1688->port,
                gus->gf1.irq, es1688->irq, gus->gf1.dma1, es1688->dma8);
 
-       snd_card_set_dev(card, dev);
-
        error = snd_card_register(card);
        if (error < 0)
                goto out;
index 652d5d834620daa453caf9390b618e1fcc46afa6..39df36ca3acbe7438d2dc3bd6e0644683c1f0f53 100644 (file)
@@ -214,8 +214,8 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
        struct snd_wss *wss;
        struct snd_gusmax *maxcard;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_gusmax), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_gusmax), &card);
        if (err < 0)
                return err;
        card->private_free = snd_gusmax_free;
@@ -337,8 +337,6 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
        if (xdma2 >= 0)
                sprintf(card->longname + strlen(card->longname), "&%i", xdma2);
 
-       snd_card_set_dev(card, pdev);
-
        err = snd_card_register(card);
        if (err < 0)
                goto _err;
index afef0d738078f27935d844f5d002db1b7bbe2609..5abbbe477d16c529f839b34f5cf21abe885a1fe9 100644 (file)
@@ -625,14 +625,15 @@ static void snd_interwave_free(struct snd_card *card)
                free_irq(iwcard->irq, (void *)iwcard);
 }
 
-static int snd_interwave_card_new(int dev, struct snd_card **cardp)
+static int snd_interwave_card_new(struct device *pdev, int dev,
+                                 struct snd_card **cardp)
 {
        struct snd_card *card;
        struct snd_interwave *iwcard;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_interwave), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_interwave), &card);
        if (err < 0)
                return err;
        iwcard = card->private_data;
@@ -779,11 +780,10 @@ static int snd_interwave_isa_probe1(int dev, struct device *devptr)
        struct snd_card *card;
        int err;
 
-       err = snd_interwave_card_new(dev, &card);
+       err = snd_interwave_card_new(devptr, dev, &card);
        if (err < 0)
                return err;
 
-       snd_card_set_dev(card, devptr);
        if ((err = snd_interwave_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -876,7 +876,7 @@ static int snd_interwave_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
                                
-       res = snd_interwave_card_new(dev, &card);
+       res = snd_interwave_card_new(&pcard->card->dev, dev, &card);
        if (res < 0)
                return res;
 
@@ -884,7 +884,6 @@ static int snd_interwave_pnp_detect(struct pnp_card_link *pcard,
                snd_card_free(card);
                return res;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
        if ((res = snd_interwave_probe(card, dev)) < 0) {
                snd_card_free(card);
                return res;
index 0a90bd6ae2325d296f12f8d01a730e6d98fb0606..5016bf957f51d69778b2ff57b5ad4d7abe5acb97 100644 (file)
@@ -905,12 +905,11 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
                return -ENODEV;
        }
 
-       err = snd_card_create(index[idx], id[idx], THIS_MODULE,
-                             sizeof(struct snd_msnd), &card);
+       err = snd_card_new(pdev, index[idx], id[idx], THIS_MODULE,
+                          sizeof(struct snd_msnd), &card);
        if (err < 0)
                return err;
 
-       snd_card_set_dev(card, pdev);
        chip = card->private_data;
        chip->card = card;
 
@@ -1122,14 +1121,14 @@ static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
         * Create a new ALSA sound card entry, in anticipation
         * of detecting our hardware ...
         */
-       ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
-                             sizeof(struct snd_msnd), &card);
+       ret = snd_card_new(&pcard->card->dev,
+                          index[idx], id[idx], THIS_MODULE,
+                          sizeof(struct snd_msnd), &card);
        if (ret < 0)
                return ret;
 
        chip = card->private_data;
        chip->card = card;
-       snd_card_set_dev(card, &pcard->card->dev);
 
        /*
         * Read the correct parameters off the ISA PnP bus ...
index cc01c419b7e91931a1b61d0170d101256d9446fe..a219bc37816b30228d5fefd6b984deab70307585 100644 (file)
@@ -627,14 +627,15 @@ static void snd_opl3sa2_free(struct snd_card *card)
        release_and_free_resource(chip->res_port);
 }
 
-static int snd_opl3sa2_card_new(int dev, struct snd_card **cardp)
+static int snd_opl3sa2_card_new(struct device *pdev, int dev,
+                               struct snd_card **cardp)
 {
        struct snd_card *card;
        struct snd_opl3sa2 *chip;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_opl3sa2), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_opl3sa2), &card);
        if (err < 0)
                return err;
        strcpy(card->driver, "OPL3SA2");
@@ -737,14 +738,13 @@ static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       err = snd_opl3sa2_card_new(dev, &card);
+       err = snd_opl3sa2_card_new(&pdev->dev, dev, &card);
        if (err < 0)
                return err;
        if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
                snd_card_free(card);
                return err;
        }
-       snd_card_set_dev(card, &pdev->dev);
        if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -802,14 +802,13 @@ static int snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       err = snd_opl3sa2_card_new(dev, &card);
+       err = snd_opl3sa2_card_new(&pdev->dev, dev, &card);
        if (err < 0)
                return err;
        if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
                snd_card_free(card);
                return err;
        }
-       snd_card_set_dev(card, &pdev->dev);
        if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -883,10 +882,9 @@ static int snd_opl3sa2_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       err = snd_opl3sa2_card_new(dev, &card);
+       err = snd_opl3sa2_card_new(pdev, dev, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, pdev);
        if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
index 619753d96ca5e1cfbc51d4fd146cba5e9b520cfe..c2ca681ac51ba7516cf93834df76cf613a6eff2f 100644 (file)
@@ -1411,8 +1411,8 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
        struct snd_miro *miro;
        struct snd_card *card;
 
-       error = snd_card_create(index, id, THIS_MODULE,
-                               sizeof(struct snd_miro), &card);
+       error = snd_card_new(devptr, index, id, THIS_MODULE,
+                            sizeof(struct snd_miro), &card);
        if (error < 0)
                return error;
 
@@ -1479,8 +1479,6 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
                }
        }
 
-       snd_card_set_dev(card, devptr);
-
        error = snd_miro_probe(card);
        if (error < 0) {
                snd_card_free(card);
@@ -1584,8 +1582,8 @@ static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
                return -EBUSY;
        if (!isapnp)
                return -ENODEV;
-       err = snd_card_create(index, id, THIS_MODULE,
-                               sizeof(struct snd_miro), &card);
+       err = snd_card_new(&pcard->card->dev, index, id, THIS_MODULE,
+                          sizeof(struct snd_miro), &card);
        if (err < 0)
                return err;
 
@@ -1612,7 +1610,6 @@ static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
                return err;
        }
 
-       snd_card_set_dev(card, &pcard->card->dev);
        err = snd_miro_probe(card);
        if (err < 0) {
                snd_card_free(card);
index 6effe99bbb9cd80797a149abebec80ce9bc6162e..c9b5828486037b187c5ec64252c19fefb681f54d 100644 (file)
@@ -934,13 +934,13 @@ static int snd_opti9xx_probe(struct snd_card *card)
        return snd_card_register(card);
 }
 
-static int snd_opti9xx_card_new(struct snd_card **cardp)
+static int snd_opti9xx_card_new(struct device *pdev, struct snd_card **cardp)
 {
        struct snd_card *card;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE,
-                             sizeof(struct snd_opti9xx), &card);
+       err = snd_card_new(pdev, index, id, THIS_MODULE,
+                          sizeof(struct snd_opti9xx), &card);
        if (err < 0)
                return err;
        card->private_free = snd_card_opti9xx_free;
@@ -1010,7 +1010,7 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
        }
 #endif
 
-       error = snd_opti9xx_card_new(&card);
+       error = snd_opti9xx_card_new(devptr, &card);
        if (error < 0)
                return error;
 
@@ -1018,7 +1018,6 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
                snd_card_free(card);
                return error;
        }
-       snd_card_set_dev(card, devptr);
        if ((error = snd_opti9xx_probe(card)) < 0) {
                snd_card_free(card);
                return error;
@@ -1100,7 +1099,7 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
                return -EBUSY;
        if (! isapnp)
                return -ENODEV;
-       error = snd_opti9xx_card_new(&card);
+       error = snd_opti9xx_card_new(&pcard->card->dev, &card);
        if (error < 0)
                return error;
        chip = card->private_data;
@@ -1131,7 +1130,6 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
                snd_card_free(card);
                return error;
        }
-       snd_card_set_dev(card, &pcard->card->dev);
        if ((error = snd_opti9xx_probe(card)) < 0) {
                snd_card_free(card);
                return error;
index 356a6308392f29a19fabd4e670cafdac35cc3486..90d2eba549e90d51fde8c71834dfb6f2cd52e895 100644 (file)
@@ -229,8 +229,8 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
        static int possible_dmas16[] = {5, 7, -1};
        int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_card_jazz16), &card);
+       err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_card_jazz16), &card);
        if (err < 0)
                return err;
 
@@ -327,8 +327,6 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
                                        mpu_port[dev]);
        }
 
-       snd_card_set_dev(card, devptr);
-
        err = snd_card_register(card);
        if (err < 0)
                goto err_free;
index a4130993955f39d0781983c7f12060ba518c0770..3f694543a7ea7774f3719647adc0cc3a399c0809 100644 (file)
@@ -323,13 +323,14 @@ static void snd_sb16_free(struct snd_card *card)
 #define is_isapnp_selected(dev)                0
 #endif
 
-static int snd_sb16_card_new(int dev, struct snd_card **cardp)
+static int snd_sb16_card_new(struct device *devptr, int dev,
+                            struct snd_card **cardp)
 {
        struct snd_card *card;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_card_sb16), &card);
+       err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_card_sb16), &card);
        if (err < 0)
                return err;
        card->private_free = snd_sb16_free;
@@ -493,7 +494,7 @@ static int snd_sb16_isa_probe1(int dev, struct device *pdev)
        struct snd_card *card;
        int err;
 
-       err = snd_sb16_card_new(dev, &card);
+       err = snd_sb16_card_new(pdev, dev, &card);
        if (err < 0)
                return err;
 
@@ -507,7 +508,6 @@ static int snd_sb16_isa_probe1(int dev, struct device *pdev)
        awe_port[dev] = port[dev] + 0x400;
 #endif
 
-       snd_card_set_dev(card, pdev);
        if ((err = snd_sb16_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -613,10 +613,9 @@ static int snd_sb16_pnp_detect(struct pnp_card_link *pcard,
        for ( ; dev < SNDRV_CARDS; dev++) {
                if (!enable[dev] || !isapnp[dev])
                        continue;
-               res = snd_sb16_card_new(dev, &card);
+               res = snd_sb16_card_new(&pcard->card->dev, dev, &card);
                if (res < 0)
                        return res;
-               snd_card_set_dev(card, &pcard->card->dev);
                if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 ||
                    (res = snd_sb16_probe(card, dev)) < 0) {
                        snd_card_free(card);
index a806ae90a9449246cd9b8a43ae6924f7439def21..6c32b3aa34af169b3c409768ce5d82e4cb86539b 100644 (file)
@@ -102,8 +102,8 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
        struct snd_opl3 *opl3;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_sb8), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_sb8), &card);
        if (err < 0)
                return err;
        acard = card->private_data;
@@ -192,8 +192,6 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
                chip->port,
                irq[dev], dma8[dev]);
 
-       snd_card_set_dev(card, pdev);
-
        if ((err = snd_card_register(card)) < 0)
                goto _err;
 
index 09d481b3ba7fae52346ccdb273403e32c76e4862..15a152eaa2e89ee2cd8c7d10fc3c670b1c6ff3c8 100644 (file)
@@ -559,8 +559,8 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
        char __iomem *vmss_port;
 
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport),
-                               &card);
+       err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+                          sizeof(vport), &card);
        if (err < 0)
                return err;
 
@@ -668,8 +668,6 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
        sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d",
                mss_port[dev], xirq, xdma);
 
-       snd_card_set_dev(card, devptr);
-
        err = snd_card_register(card);
        if (err < 0)
                goto err_unmap2;
index 57b338973ede0c99ff9b2b291761bc2d1dfa62c3..44405df7d4becffcf82db3b5e9a1152f65eed304 100644 (file)
@@ -1169,8 +1169,8 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
        struct soundscape *sscape;
        int ret;
 
-       ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct soundscape), &card);
+       ret = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct soundscape), &card);
        if (ret < 0)
                return ret;
 
@@ -1178,7 +1178,6 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
        sscape->type = SSCAPE;
 
        dma[dev] &= 0x03;
-       snd_card_set_dev(card, pdev);
 
        ret = create_sscape(dev, card);
        if (ret < 0)
@@ -1259,8 +1258,9 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
         * Create a new ALSA sound card entry, in anticipation
         * of detecting our hardware ...
         */
-       ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
-                             sizeof(struct soundscape), &card);
+       ret = snd_card_new(&pcard->card->dev,
+                          index[idx], id[idx], THIS_MODULE,
+                          sizeof(struct soundscape), &card);
        if (ret < 0)
                return ret;
 
@@ -1288,7 +1288,6 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
                wss_port[idx] = pnp_port_start(dev, 1);
                dma2[idx] = pnp_dma(dev, 1);
        }
-       snd_card_set_dev(card, &pcard->card->dev);
 
        ret = create_sscape(idx, card);
        if (ret < 0)
index 82dd76939fa040b639f32cb33d072fecafd22239..bfbf38cf984175966e2cdfca4a83647f56c99192 100644 (file)
@@ -334,14 +334,15 @@ snd_wavefront_free(struct snd_card *card)
        }
 }
 
-static int snd_wavefront_card_new(int dev, struct snd_card **cardp)
+static int snd_wavefront_card_new(struct device *pdev, int dev,
+                                 struct snd_card **cardp)
 {
        struct snd_card *card;
        snd_wavefront_card_t *acard;
        int err;
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(snd_wavefront_card_t), &card);
+       err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(snd_wavefront_card_t), &card);
        if (err < 0)
                return err;
 
@@ -564,10 +565,9 @@ static int snd_wavefront_isa_probe(struct device *pdev,
        struct snd_card *card;
        int err;
 
-       err = snd_wavefront_card_new(dev, &card);
+       err = snd_wavefront_card_new(pdev, dev, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, pdev);
        if ((err = snd_wavefront_probe(card, dev)) < 0) {
                snd_card_free(card);
                return err;
@@ -612,7 +612,7 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       res = snd_wavefront_card_new(dev, &card);
+       res = snd_wavefront_card_new(&pcard->card->dev, dev, &card);
        if (res < 0)
                return res;
 
@@ -623,7 +623,6 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
                        return -ENODEV;
                }
        }
-       snd_card_set_dev(card, &pcard->card->dev);
 
        if ((res = snd_wavefront_probe(card, dev)) < 0)
                return res;
index 224f54be15a61002ef17630acff78a191a501039..a7cc49e960685d97f223accb9916f478a1e22e43 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <sound/core.h>
@@ -98,6 +99,7 @@ struct snd_au1000 {
 
        struct snd_pcm *pcm;
        struct audio_stream *stream[2]; /* playback & capture */
+       int dmaid[2];           /* tx(0)/rx(1) DMA ids */
 };
 
 /*--------------------------- Local Functions --------------------------------*/
@@ -465,15 +467,17 @@ snd_au1000_pcm_new(struct snd_au1000 *au1000)
        spin_lock_init(&au1000->stream[CAPTURE]->dma_lock);
 
        flags = claim_dma_lock();
-       if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX,
+       au1000->stream[PLAYBACK]->dma = request_au1000_dma(au1000->dmaid[0],
                        "AC97 TX", au1000_dma_interrupt, 0,
-                       au1000->stream[PLAYBACK])) < 0) {
+                       au1000->stream[PLAYBACK]);
+       if (au1000->stream[PLAYBACK]->dma < 0) {
                release_dma_lock(flags);
                return -EBUSY;
        }
-       if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX,
+       au1000->stream[CAPTURE]->dma = request_au1000_dma(au1000->dmaid[1],
                        "AC97 RX", au1000_dma_interrupt, 0,
-                       au1000->stream[CAPTURE])) < 0){
+                       au1000->stream[CAPTURE]);
+       if (au1000->stream[CAPTURE]->dma < 0){
                release_dma_lock(flags);
                return -EBUSY;
        }
@@ -552,69 +556,12 @@ get the interrupt driven case to work efficiently */
        spin_unlock(&au1000->ac97_lock);
 }
 
-static int
-snd_au1000_ac97_new(struct snd_au1000 *au1000)
-{
-       int err;
-       struct snd_ac97_bus *pbus;
-       struct snd_ac97_template ac97;
-       static struct snd_ac97_bus_ops ops = {
-               .write = snd_au1000_ac97_write,
-               .read = snd_au1000_ac97_read,
-       };
-
-       if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG),
-                       0x100000, "Au1x00 AC97")) == NULL) {
-               snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n");
-               return -EBUSY;
-       }
-       au1000->ac97_ioport = (struct au1000_ac97_reg *)
-               KSEG1ADDR(au1000->ac97_res_port->start);
-
-       spin_lock_init(&au1000->ac97_lock);
-
-       /* configure pins for AC'97
-       TODO: move to board_setup.c */
-       au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
-
-       /* Initialise Au1000's AC'97 Control Block */
-       au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
-       udelay(10);
-       au1000->ac97_ioport->cntrl = AC97C_CE;
-       udelay(10);
-
-       /* Initialise External CODEC -- cold reset */
-       au1000->ac97_ioport->config = AC97C_RESET;
-       udelay(10);
-       au1000->ac97_ioport->config = 0x0;
-       mdelay(5);
-
-       /* Initialise AC97 middle-layer */
-       if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0)
-               return err;
-
-       memset(&ac97, 0, sizeof(ac97));
-       ac97.private_data = au1000;
-       if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0)
-               return err;
-
-       return 0;
-}
-
 /*------------------------------ Setup / Destroy ----------------------------*/
 
-void
-snd_au1000_free(struct snd_card *card)
+static void snd_au1000_free(struct snd_card *card)
 {
        struct snd_au1000 *au1000 = card->private_data;
 
-       if (au1000->ac97_res_port) {
-               /* put internal AC97 block into reset */
-               au1000->ac97_ioport->cntrl = AC97C_RS;
-               au1000->ac97_ioport = NULL;
-               release_and_free_resource(au1000->ac97_res_port);
-       }
-
        if (au1000->stream[PLAYBACK]) {
                if (au1000->stream[PLAYBACK]->dma >= 0)
                        free_au1000_dma(au1000->stream[PLAYBACK]->dma);
@@ -626,71 +573,167 @@ snd_au1000_free(struct snd_card *card)
                        free_au1000_dma(au1000->stream[CAPTURE]->dma);
                kfree(au1000->stream[CAPTURE]);
        }
-}
 
+       if (au1000->ac97_res_port) {
+               /* put internal AC97 block into reset */
+               if (au1000->ac97_ioport) {
+                       au1000->ac97_ioport->cntrl = AC97C_RS;
+                       iounmap(au1000->ac97_ioport);
+                       au1000->ac97_ioport = NULL;
+               }
+               release_and_free_resource(au1000->ac97_res_port);
+               au1000->ac97_res_port = NULL;
+       }
+}
 
-static struct snd_card *au1000_card;
+static struct snd_ac97_bus_ops ops = {
+       .write  = snd_au1000_ac97_write,
+       .read   = snd_au1000_ac97_read,
+};
 
-static int __init
-au1000_init(void)
+static int au1000_ac97_probe(struct platform_device *pdev)
 {
        int err;
+       void __iomem *io;
+       struct resource *r;
        struct snd_card *card;
        struct snd_au1000 *au1000;
+       struct snd_ac97_bus *pbus;
+       struct snd_ac97_template ac97;
 
-       err = snd_card_create(-1, "AC97", THIS_MODULE,
-                             sizeof(struct snd_au1000), &card);
+       err = snd_card_new(&pdev->dev, -1, "AC97", THIS_MODULE,
+                          sizeof(struct snd_au1000), &card);
        if (err < 0)
                return err;
 
-       card->private_free = snd_au1000_free;
        au1000 = card->private_data;
        au1000->card = card;
+       spin_lock_init(&au1000->ac97_lock);
 
-       au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
-       au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
-       /* so that snd_au1000_free will work as intended */
-       au1000->ac97_res_port = NULL;
-       if (au1000->stream[PLAYBACK])
-               au1000->stream[PLAYBACK]->dma = -1;
-       if (au1000->stream[CAPTURE ])
-               au1000->stream[CAPTURE ]->dma = -1;
-
-       if (au1000->stream[PLAYBACK] == NULL ||
-           au1000->stream[CAPTURE ] == NULL) {
-               snd_card_free(card);
-               return -ENOMEM;
-       }
+       /* from here on let ALSA call the special freeing function */
+       card->private_free = snd_au1000_free;
 
-       if ((err = snd_au1000_ac97_new(au1000)) < 0 ) {
-               snd_card_free(card);
-               return err;
+       /* TX DMA ID */
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!r) {
+               err = -ENODEV;
+               snd_printk(KERN_INFO "no TX DMA platform resource!\n");
+               goto out;
        }
-
-       if ((err = snd_au1000_pcm_new(au1000)) < 0) {
-               snd_card_free(card);
-               return err;
+       au1000->dmaid[0] = r->start;
+
+       /* RX DMA ID */
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!r) {
+               err = -ENODEV;
+               snd_printk(KERN_INFO "no RX DMA platform resource!\n");
+               goto out;
+       }
+       au1000->dmaid[1] = r->start;
+
+       au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream),
+                                          GFP_KERNEL);
+       if (!au1000->stream[PLAYBACK])
+               goto out;
+       au1000->stream[PLAYBACK]->dma = -1;
+
+       au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream),
+                                         GFP_KERNEL);
+       if (!au1000->stream[CAPTURE])
+               goto out;
+       au1000->stream[CAPTURE]->dma = -1;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               goto out;
+
+       err = -EBUSY;
+       au1000->ac97_res_port = request_mem_region(r->start,
+                                       r->end - r->start + 1, pdev->name);
+       if (!au1000->ac97_res_port) {
+               snd_printk(KERN_ERR "ALSA AC97: can't grab AC97 port\n");
+               goto out;
        }
 
+       io = ioremap(r->start, r->end - r->start + 1);
+       if (!io)
+               goto out;
+
+       au1000->ac97_ioport = (struct au1000_ac97_reg *)io;
+
+       /* configure pins for AC'97
+       TODO: move to board_setup.c */
+       au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
+
+       /* Initialise Au1000's AC'97 Control Block */
+       au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
+       udelay(10);
+       au1000->ac97_ioport->cntrl = AC97C_CE;
+       udelay(10);
+
+       /* Initialise External CODEC -- cold reset */
+       au1000->ac97_ioport->config = AC97C_RESET;
+       udelay(10);
+       au1000->ac97_ioport->config = 0x0;
+       mdelay(5);
+
+       /* Initialise AC97 middle-layer */
+       err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus);
+       if (err < 0)
+               goto out;
+
+       memset(&ac97, 0, sizeof(ac97));
+       ac97.private_data = au1000;
+       err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97);
+       if (err < 0)
+               goto out;
+
+       err = snd_au1000_pcm_new(au1000);
+       if (err < 0)
+               goto out;
+
        strcpy(card->driver, "Au1000-AC97");
        strcpy(card->shortname, "AMD Au1000-AC97");
        sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver");
 
-       if ((err = snd_card_register(card)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
+       err = snd_card_register(card);
+       if (err < 0)
+               goto out;
 
        printk(KERN_INFO "ALSA AC97: Driver Initialized\n");
-       au1000_card = card;
+
+       platform_set_drvdata(pdev, card);
+
        return 0;
+
+ out:
+       snd_card_free(card);
+       return err;
+}
+
+static int au1000_ac97_remove(struct platform_device *pdev)
+{
+       return snd_card_free(platform_get_drvdata(pdev));
 }
 
-static void __exit au1000_exit(void)
+struct platform_driver au1000_ac97c_driver = {
+       .driver = {
+               .name   = "au1000-ac97c",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = au1000_ac97_probe,
+       .remove         = au1000_ac97_remove,
+};
+
+static int __init au1000_ac97_load(void)
 {
-       snd_card_free(au1000_card);
+       return platform_driver_register(&au1000_ac97c_driver);
 }
 
-module_init(au1000_init);
-module_exit(au1000_exit);
+static void __exit au1000_ac97_unload(void)
+{
+       platform_driver_unregister(&au1000_ac97c_driver);
+}
 
+module_init(au1000_ac97_load);
+module_exit(au1000_ac97_unload);
index 2b7f6e8bdd24343bd41ce854bb93383815386d6b..23441b9e6148b6ded73a89c01eb3ac93e65a4895 100644 (file)
@@ -880,7 +880,7 @@ static int hal2_probe(struct platform_device *pdev)
        struct snd_hal2 *chip;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -889,7 +889,6 @@ static int hal2_probe(struct platform_device *pdev)
                snd_card_free(card);
                return err;
        }
-       snd_card_set_dev(card, &pdev->dev);
 
        err = hal2_pcm_create(chip);
        if (err < 0) {
index cfe99ae149fed9f55d70dc10f23e12e59fa4ee34..04bb06c03ec80bf2673644f616cbfb39579f6ba3 100644 (file)
@@ -920,7 +920,7 @@ static int snd_sgio2audio_probe(struct platform_device *pdev)
        struct snd_sgio2audio *chip;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -929,7 +929,6 @@ static int snd_sgio2audio_probe(struct platform_device *pdev)
                snd_card_free(card);
                return err;
        }
-       snd_card_set_dev(card, &pdev->dev);
 
        err = snd_sgio2audio_new_pcm(chip);
        if (err < 0) {
index fa12c55f560e05992872018b25bd7b75e6267952..d19f757dbd79676ab48d1667c8ed38d7a98434b1 100644 (file)
@@ -15,3 +15,6 @@ int pas_init_mixer(void);
 /*     From pas_midi.c */
 void pas_midi_init(void);
 void pas_midi_interrupt(void);
+
+/*     From pas2_mixer.c*/
+void mix_write(unsigned char data, int ioaddr);
index 7004e24d209f167c196e231ffc1f883033eb8d54..b07954a7953679b077b12b190343492a3271510f 100644 (file)
@@ -74,8 +74,6 @@ static char    *pas_model_names[] = {
  * to support other than the default base address
  */
 
-extern void     mix_write(unsigned char data, int ioaddr);
-
 unsigned char pas_read(int ioaddr)
 {
        return inb(ioaddr + pas_translate_code);
index 67f56a2cee6aec83bd4710f645a82cdca9e39847..4b20be79c1ddbb58b2712a03db08227afd5a12ef 100644 (file)
@@ -959,8 +959,6 @@ snd_harmony_create(struct snd_card *card,
                 goto free_and_ret;
         }
 
-       snd_card_set_dev(card, &padev->dev);
-
        *rchip = h;
 
        return 0;
@@ -977,7 +975,7 @@ snd_harmony_probe(struct parisc_device *padev)
        struct snd_card *card;
        struct snd_harmony *h;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&padev->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index 8756c8e329224f1e2fb81862d6e60be4954a85cd..0b0c0cf13f748e0e231a6d068351c6827a57d128 100644 (file)
@@ -276,7 +276,7 @@ config SND_CS46XX_NEW_DSP
 
 config SND_CS5530
        tristate "CS5530 Audio"
-       depends on ISA_DMA_API
+       depends on ISA_DMA_API && (X86_32 || COMPILE_TEST)
        select SND_SB16_DSP
        help
          Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
@@ -286,6 +286,7 @@ config SND_CS5530
 
 config SND_CS5535AUDIO
        tristate "CS5535/CS5536 Audio"
+       depends on X86_32 || MIPS || COMPILE_TEST
        select SND_PCM
        select SND_AC97_CODEC
        help
@@ -578,8 +579,6 @@ config SND_FM801_TEA575X_BOOL
          FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
          SF64-PCR) into the snd-fm801 driver.
 
-source "sound/pci/hda/Kconfig"
-
 config SND_HDSP
        tristate "RME Hammerfall DSP Audio"
        select FW_LOADER
@@ -796,7 +795,7 @@ config SND_RME9652
 
 config SND_SIS7019
        tristate "SiS 7019 Audio Accelerator"
-       depends on X86 && !X86_64
+       depends on X86_32
        select SND_AC97_CODEC
        select ZONE_DMA
        help
@@ -889,3 +888,5 @@ config SND_YMFPCI
          will be called snd-ymfpci.
 
 endif  # SND_PCI
+
+source "sound/pci/hda/Kconfig"
index bf578ba2677e72566187619e1e0515afe93fdfd6..14ad54b7928cf326732f3967a2fc24faadeef60e 100644 (file)
@@ -214,6 +214,12 @@ static void update_power_regs(struct snd_ac97 *ac97);
 #define ac97_is_power_save_mode(ac97) 0
 #endif
 
+#define ac97_err(ac97, fmt, args...)   \
+       dev_err((ac97)->bus->card->dev, fmt, ##args)
+#define ac97_warn(ac97, fmt, args...)  \
+       dev_warn((ac97)->bus->card->dev, fmt, ##args)
+#define ac97_dbg(ac97, fmt, args...)   \
+       dev_dbg((ac97)->bus->card->dev, fmt, ##args)
 
 /*
  *  I/O routines
@@ -1673,7 +1679,7 @@ static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97)
        int err, idx;
 
        /*
-       printk(KERN_DEBUG "AC97_GPIO_CFG = %x\n",
+       ac97_dbg(ac97, "AC97_GPIO_CFG = %x\n",
               snd_ac97_read(ac97,AC97_GPIO_CFG));
        */
        snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));
@@ -1963,7 +1969,7 @@ static int snd_ac97_dev_register(struct snd_device *device)
                     ac97->bus->card->number, ac97->num,
                     snd_ac97_get_short_name(ac97));
        if ((err = device_register(&ac97->dev)) < 0) {
-               snd_printk(KERN_ERR "Can't register ac97 bus\n");
+               ac97_err(ac97, "Can't register ac97 bus\n");
                ac97->dev.bus = NULL;
                return err;
        }
@@ -2089,7 +2095,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
                                                      msecs_to_jiffies(500), 1);
                }
                if (err < 0) {
-                       snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num);
+                       ac97_warn(ac97, "AC'97 %d does not respond - RESET\n",
+                                ac97->num);
                        /* proceed anyway - it's often non-critical */
                }
        }
@@ -2098,7 +2105,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
        ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
        if (! (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) &&
            (ac97->id == 0x00000000 || ac97->id == 0xffffffff)) {
-               snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id);
+               ac97_err(ac97,
+                        "AC'97 %d access is not valid [0x%x], removing mixer.\n",
+                        ac97->num, ac97->id);
                snd_ac97_free(ac97);
                return -EIO;
        }
@@ -2131,7 +2140,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
 
        if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) {
                if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM)))
-                       snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num);
+                       ac97_err(ac97,
+                                "AC'97 %d access error (not audio or modem codec)\n",
+                                ac97->num);
                snd_ac97_free(ac97);
                return -EACCES;
        }
@@ -2156,7 +2167,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
                                goto __ready_ok;
                        schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
-               snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num);
+               ac97_warn(ac97,
+                         "AC'97 %d analog subsections not ready\n", ac97->num);
        }
 
        /* FIXME: add powerdown control */
@@ -2188,7 +2200,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
                                goto __ready_ok;
                        schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
-               snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
+               ac97_warn(ac97,
+                         "MC'97 %d converters and GPIO not ready (0x%x)\n",
+                         ac97->num,
+                         snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
        }
        
       __ready_ok:
@@ -2723,7 +2738,7 @@ static int tune_ad_sharing(struct snd_ac97 *ac97)
 {
        unsigned short scfg;
        if ((ac97->id & 0xffffff00) != 0x41445300) {
-               snd_printk(KERN_ERR "ac97_quirk AD_SHARING is only for AD codecs\n");
+               ac97_err(ac97, "ac97_quirk AD_SHARING is only for AD codecs\n");
                return -EINVAL;
        }
        /* Turn on OMS bit to route microphone to back panel */
@@ -2739,7 +2754,8 @@ AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0);
 static int tune_alc_jack(struct snd_ac97 *ac97)
 {
        if ((ac97->id & 0xffffff00) != 0x414c4700) {
-               snd_printk(KERN_ERR "ac97_quirk ALC_JACK is only for Realtek codecs\n");
+               ac97_err(ac97,
+                        "ac97_quirk ALC_JACK is only for Realtek codecs\n");
                return -EINVAL;
        }
        snd_ac97_update_bits(ac97, 0x7a, 0x20, 0x20); /* select jack detect function */
@@ -2899,7 +2915,8 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons
        if (override && strcmp(override, "-1") && strcmp(override, "default")) {
                result = apply_quirk_str(ac97, override);
                if (result < 0)
-                       snd_printk(KERN_ERR "applying quirk type %s failed (%d)\n", override, result);
+                       ac97_err(ac97, "applying quirk type %s failed (%d)\n",
+                                override, result);
                return result;
        }
 
@@ -2913,10 +2930,14 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons
                    quirk->subdevice == (quirk->mask & ac97->subsystem_device)) {
                        if (quirk->codec_id && quirk->codec_id != ac97->id)
                                continue;
-                       snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device);
+                       ac97_dbg(ac97, "ac97 quirk for %s (%04x:%04x)\n",
+                                quirk->name, ac97->subsystem_vendor,
+                                ac97->subsystem_device);
                        result = apply_quirk(ac97, quirk->type);
                        if (result < 0)
-                               snd_printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result);
+                               ac97_err(ac97,
+                                        "applying quirk type %d for %s failed (%d)\n",
+                                        quirk->type, quirk->name, result);
                        return result;
                }
        }
index 66a3bc95fb844c3f1b311b227622aacbb680a50c..99176221541782c3cd7c8a9f257ed1d708904c98 100644 (file)
@@ -3477,7 +3477,8 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
 
                sctl = snd_ac97_find_mixer_ctl(ac97, *s);
                if (!sctl) {
-                       snd_printdd("Cannot find slave %s, skipped\n", *s);
+                       dev_dbg(ac97->bus->card->dev,
+                               "Cannot find slave %s, skipped\n", *s);
                        continue;
                }
                err = snd_ctl_add_slave(kctl, sctl);
index eab0fc9ff2e0c7aacb08ffdf69a3be7fdb4b5c2c..d15297a68801c8925d3cd3d7c8be70ef99ef4a1e 100644 (file)
@@ -604,7 +604,9 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
                }
                if (!ok_flag) {
                        spin_unlock_irq(&pcm->bus->bus_lock);
-                       snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i);
+                       dev_err(bus->card->dev,
+                               "cannot find configuration for AC97 slot %i\n",
+                               i);
                        err = -EAGAIN;
                        goto error;
                }
@@ -618,15 +620,20 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
                        if (pcm->r[r].rslots[cidx] & (1 << i)) {
                                reg = get_slot_reg(pcm, cidx, i, r);
                                if (reg == 0xff) {
-                                       snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i);
+                                       dev_err(bus->card->dev,
+                                               "invalid AC97 slot %i?\n", i);
                                        continue;
                                }
                                if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE)))
                                        continue;
-                               //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate);
+                               dev_dbg(bus->card->dev,
+                                       "setting ac97 reg 0x%x to rate %d\n",
+                                       reg, rate);
                                err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate);
                                if (err < 0)
-                                       snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err);
+                                       dev_err(bus->card->dev,
+                                               "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n",
+                                               cidx, reg, rate, err);
                                else
                                        reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE));
                        }
index b680d03e24192e0079e733ec0079d7e6b3ef4904..488f966adde31db86444fd1b03272b3d80b19a8b 100644 (file)
@@ -77,9 +77,6 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 #define DEVNAME "ad1889"
 #define PFX    DEVNAME ": "
 
-/* let's use the global sound debug interfaces */
-#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
-
 /* keep track of some hw registers */
 struct ad1889_register_state {
        u16 reg;        /* reg setup */
@@ -264,11 +261,11 @@ snd_ad1889_ac97_ready(struct snd_ad1889 *chip)
                        && --retry)
                mdelay(1);
        if (!retry) {
-               snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n",
-                      __func__);
+               dev_err(chip->card->dev, "[%s] Link is not ready.\n",
+                       __func__);
                return -EIO;
        }
-       ad1889_debug("[%s] ready after %d ms\n", __func__, 400 - retry);
+       dev_dbg(chip->card->dev, "[%s] ready after %d ms\n", __func__, 400 - retry);
 
        return 0;
 }
@@ -405,9 +402,9 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss)
        
        spin_unlock_irq(&chip->lock);
        
-       ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
-                       "size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-                       count, size, reg, rt->rate);
+       dev_dbg(chip->card->dev,
+               "prepare playback: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n",
+               chip->wave.addr, count, size, reg, rt->rate);
        return 0;
 }
 
@@ -452,9 +449,9 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss)
        
        spin_unlock_irq(&chip->lock);
        
-       ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
-                       "size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-                       count, size, reg, rt->rate);
+       dev_dbg(chip->card->dev,
+               "prepare capture: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n",
+               chip->ramc.addr, count, size, reg, rt->rate);
        return 0;
 }
 
@@ -614,7 +611,8 @@ snd_ad1889_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
 
        if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
-               ad1889_debug("Unexpected master or target abort interrupt!\n");
+               dev_dbg(chip->card->dev,
+                       "Unexpected master or target abort interrupt!\n");
 
        if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
                snd_pcm_period_elapsed(chip->psubs);
@@ -656,7 +654,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
                                                BUFFER_BYTES_MAX);
 
        if (err < 0) {
-               snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);
+               dev_err(chip->card->dev, "buffer allocation error: %d\n", err);
                return err;
        }
        
@@ -912,7 +910,7 @@ snd_ad1889_create(struct snd_card *card,
        /* check PCI availability (32bit DMA) */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-               printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n");
+               dev_err(card->dev, "error setting 32-bit DMA mask.\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -935,7 +933,7 @@ snd_ad1889_create(struct snd_card *card,
        chip->bar = pci_resource_start(pci, 0);
        chip->iobase = pci_ioremap_bar(pci, 0);
        if (chip->iobase == NULL) {
-               printk(KERN_ERR PFX "unable to reserve region.\n");
+               dev_err(card->dev, "unable to reserve region.\n");
                err = -EBUSY;
                goto free_and_ret;
        }
@@ -946,7 +944,7 @@ snd_ad1889_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_ad1889_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
+               dev_err(card->dev, "cannot obtain IRQ %d\n", pci->irq);
                snd_ad1889_free(chip);
                return -EBUSY;
        }
@@ -965,8 +963,6 @@ snd_ad1889_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
 
        return 0;
@@ -996,7 +992,8 @@ snd_ad1889_probe(struct pci_dev *pci,
        }
 
        /* (2) */
-       err = snd_card_create(index[devno], id[devno], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,
+                          0, &card);
        /* XXX REVISIT: we can probably allocate chip in this call */
        if (err < 0)
                return err;
index c6835a3d64fb016df4cc865df0469a37a7181411..feb29c24cab132581be6922fe530ef50f137447d 100644 (file)
@@ -64,18 +64,6 @@ static bool enable;
 module_param(enable, bool, 0444);
 
 
-/*
- *  Debug part definitions
- */
-
-/* #define ALI_DEBUG */
-
-#ifdef ALI_DEBUG
-#define snd_ali_printk(format, args...) printk(KERN_DEBUG format, ##args);
-#else
-#define snd_ali_printk(format, args...)
-#endif
-
 /*
  *  Constants definition
  */
@@ -321,7 +309,7 @@ static int snd_ali_codec_ready(struct snd_ali *codec,
        }
 
        snd_ali_5451_poke(codec, port, res & ~0x8000);
-       snd_printdd("ali_codec_ready: codec is not ready.\n ");
+       dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n ");
        return -EIO;
 }
 
@@ -342,7 +330,7 @@ static int snd_ali_stimer_ready(struct snd_ali *codec)
                schedule_timeout_uninterruptible(1);
        }
 
-       snd_printk(KERN_ERR "ali_stimer_read: stimer is not ready.\n");
+       dev_err(codec->card->dev, "ali_stimer_read: stimer is not ready.\n");
        return -EIO;
 }
 
@@ -354,7 +342,8 @@ static void snd_ali_codec_poke(struct snd_ali *codec,int secondary,
        unsigned int port;
 
        if (reg >= 0x80) {
-               snd_printk(KERN_ERR "ali_codec_poke: reg(%xh) invalid.\n", reg);
+               dev_err(codec->card->dev,
+                       "ali_codec_poke: reg(%xh) invalid.\n", reg);
                return;
        }
 
@@ -385,7 +374,8 @@ static unsigned short snd_ali_codec_peek(struct snd_ali *codec,
        unsigned int port;
 
        if (reg >= 0x80) {
-               snd_printk(KERN_ERR "ali_codec_peek: reg(%xh) invalid.\n", reg);
+               dev_err(codec->card->dev,
+                       "ali_codec_peek: reg(%xh) invalid.\n", reg);
                return ~0;
        }
 
@@ -417,7 +407,7 @@ static void snd_ali_codec_write(struct snd_ac97 *ac97,
 {
        struct snd_ali *codec = ac97->private_data;
 
-       snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val);
+       dev_dbg(codec->card->dev, "codec_write: reg=%xh data=%xh.\n", reg, val);
        if (reg == AC97_GPIO_STATUS) {
                outl((val << ALI_AC97_GPIO_DATA_SHIFT) | ALI_AC97_GPIO_ENABLE,
                     ALI_REG(codec, ALI_AC97_GPIO));
@@ -433,7 +423,7 @@ static unsigned short snd_ali_codec_read(struct snd_ac97 *ac97,
 {
        struct snd_ali *codec = ac97->private_data;
 
-       snd_ali_printk("codec_read reg=%xh.\n", reg);
+       dev_dbg(codec->card->dev, "codec_read reg=%xh.\n", reg);
        return snd_ali_codec_peek(codec, ac97->num, reg);
 }
 
@@ -474,7 +464,7 @@ static int snd_ali_reset_5451(struct snd_ali *codec)
        }
 
        /* non-fatal if you have a non PM capable codec */
-       /* snd_printk(KERN_WARNING "ali5451: reset time out\n"); */
+       /* dev_warn(codec->card->dev, "ali5451: reset time out\n"); */
        return 0;
 }
 
@@ -528,7 +518,7 @@ static void snd_ali_disable_voice_irq(struct snd_ali *codec,
        unsigned int mask;
        struct snd_ali_channel_control *pchregs = &(codec->chregs);
 
-       snd_ali_printk("disable_voice_irq channel=%d\n",channel);
+       dev_dbg(codec->card->dev, "disable_voice_irq channel=%d\n", channel);
 
        mask = 1 << (channel & 0x1f);
        pchregs->data.ainten  = inl(ALI_REG(codec, pchregs->regs.ainten));
@@ -541,7 +531,7 @@ static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel)
        unsigned int idx =  channel & 0x1f;
 
        if (codec->synth.chcnt >= ALI_CHANNELS){
-               snd_printk(KERN_ERR
+               dev_err(codec->card->dev,
                           "ali_alloc_pcm_channel: no free channels.\n");
                return -1;
        }
@@ -549,7 +539,7 @@ static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel)
        if (!(codec->synth.chmap & (1 << idx))) {
                codec->synth.chmap |= 1 << idx;
                codec->synth.chcnt++;
-               snd_ali_printk("alloc_pcm_channel no. %d.\n",idx);
+               dev_dbg(codec->card->dev, "alloc_pcm_channel no. %d.\n", idx);
                return idx;
        }
        return -1;
@@ -560,7 +550,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
        int idx;
        int result = -1;
 
-       snd_ali_printk("find_free_channel: for %s\n",rec ? "rec" : "pcm");
+       dev_dbg(codec->card->dev,
+               "find_free_channel: for %s\n", rec ? "rec" : "pcm");
 
        /* recording */
        if (rec) {
@@ -575,8 +566,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
                if (result >= 0)
                        return result;
                else {
-                       snd_printk(KERN_ERR "ali_find_free_channel: "
-                                  "record channel is busy now.\n");
+                       dev_err(codec->card->dev,
+                               "ali_find_free_channel: record channel is busy now.\n");
                        return -1;
                }
        }
@@ -590,8 +581,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
                if (result >= 0)
                        return result;
                else
-                       snd_printk(KERN_ERR "ali_find_free_channel: "
-                                  "S/PDIF out channel is in busy now.\n");
+                       dev_err(codec->card->dev,
+                               "ali_find_free_channel: S/PDIF out channel is in busy now.\n");
        }
 
        for (idx = 0; idx < ALI_CHANNELS; idx++) {
@@ -599,7 +590,7 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
                if (result >= 0)
                        return result;
        }
-       snd_printk(KERN_ERR "ali_find_free_channel: no free channels.\n");
+       dev_err(codec->card->dev, "ali_find_free_channel: no free channels.\n");
        return -1;
 }
 
@@ -607,14 +598,15 @@ static void snd_ali_free_channel_pcm(struct snd_ali *codec, int channel)
 {
        unsigned int idx = channel & 0x0000001f;
 
-       snd_ali_printk("free_channel_pcm channel=%d\n",channel);
+       dev_dbg(codec->card->dev, "free_channel_pcm channel=%d\n", channel);
 
        if (channel < 0 || channel >= ALI_CHANNELS)
                return;
 
        if (!(codec->synth.chmap & (1 << idx))) {
-               snd_printk(KERN_ERR "ali_free_channel_pcm: "
-                          "channel %d is not in use.\n", channel);
+               dev_err(codec->card->dev,
+                       "ali_free_channel_pcm: channel %d is not in use.\n",
+                       channel);
                return;
        } else {
                codec->synth.chmap &= ~(1 << idx);
@@ -626,7 +618,7 @@ static void snd_ali_stop_voice(struct snd_ali *codec, unsigned int channel)
 {
        unsigned int mask = 1 << (channel & 0x1f);
 
-       snd_ali_printk("stop_voice: channel=%d\n",channel);
+       dev_dbg(codec->card->dev, "stop_voice: channel=%d\n", channel);
        outl(mask, ALI_REG(codec, codec->chregs.regs.stop));
 }
 
@@ -667,7 +659,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
        }
 
        if (count > 50000) {
-               snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n");
+               dev_err(codec->card->dev, "ali_detect_spdif_rate: timeout!\n");
                return;
        }
 
@@ -682,7 +674,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
        }
 
        if (count > 50000) {
-               snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n");
+               dev_err(codec->card->dev, "ali_detect_spdif_rate: timeout!\n");
                return;
        }
 
@@ -857,9 +849,6 @@ static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
        struct snd_ali_voice *pvoice;
        struct snd_ali_channel_control *pchregs;
        unsigned int old, mask;
-#ifdef ALI_DEBUG
-       unsigned int temp, cspf;
-#endif
 
        pchregs = &(codec->chregs);
 
@@ -877,14 +866,11 @@ static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
 
        if (pvoice->pcm && pvoice->substream) {
                /* pcm interrupt */
-#ifdef ALI_DEBUG
-               outb((u8)(pvoice->number), ALI_REG(codec, ALI_GC_CIR));
-               temp = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
-               cspf = (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask;
-#endif
                if (pvoice->running) {
-                       snd_ali_printk("update_ptr: cso=%4.4x cspf=%d.\n",
-                                      (u16)temp, cspf);
+                       dev_dbg(codec->card->dev,
+                               "update_ptr: cso=%4.4x cspf=%d.\n",
+                               inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)),
+                               (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask);
                        spin_unlock(&codec->reg_lock);
                        snd_pcm_period_elapsed(pvoice->substream);
                        spin_lock(&codec->reg_lock);
@@ -940,14 +926,14 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec,
        struct snd_ali_voice *pvoice;
        int idx;
 
-       snd_ali_printk("alloc_voice: type=%d rec=%d\n", type, rec);
+       dev_dbg(codec->card->dev, "alloc_voice: type=%d rec=%d\n", type, rec);
 
        spin_lock_irq(&codec->voice_alloc);
        if (type == SNDRV_ALI_VOICE_TYPE_PCM) {
                idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) :
                        snd_ali_find_free_channel(codec,rec);
                if (idx < 0) {
-                       snd_printk(KERN_ERR "ali_alloc_voice: err.\n");
+                       dev_err(codec->card->dev, "ali_alloc_voice: err.\n");
                        spin_unlock_irq(&codec->voice_alloc);
                        return NULL;
                }
@@ -970,7 +956,7 @@ static void snd_ali_free_voice(struct snd_ali * codec,
        void (*private_free)(void *);
        void *private_data;
 
-       snd_ali_printk("free_voice: channel=%d\n",pvoice->number);
+       dev_dbg(codec->card->dev, "free_voice: channel=%d\n", pvoice->number);
        if (!pvoice->use)
                return;
        snd_ali_clear_voices(codec, pvoice->number, pvoice->number);
@@ -1153,7 +1139,7 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream,
        outl(val, ALI_REG(codec, ALI_AINTEN));
        if (do_start)
                outl(what, ALI_REG(codec, ALI_START));
-       snd_ali_printk("trigger: what=%xh whati=%xh\n", what, whati);
+       dev_dbg(codec->card->dev, "trigger: what=%xh whati=%xh\n", what, whati);
        spin_unlock(&codec->reg_lock);
 
        return 0;
@@ -1239,7 +1225,7 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
        unsigned int VOL;
        unsigned int EC;
        
-       snd_ali_printk("playback_prepare ...\n");
+       dev_dbg(codec->card->dev, "playback_prepare ...\n");
 
        spin_lock_irq(&codec->reg_lock);        
        
@@ -1266,7 +1252,7 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
        /* set target ESO for channel */
        pvoice->eso = runtime->buffer_size; 
 
-       snd_ali_printk("playback_prepare: eso=%xh count=%xh\n",
+       dev_dbg(codec->card->dev, "playback_prepare: eso=%xh count=%xh\n",
                       pvoice->eso, pvoice->count);
 
        /* set ESO to capture first MIDLP interrupt */
@@ -1278,8 +1264,9 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
        PAN = 0;
        VOL = 0;
        EC = 0;
-       snd_ali_printk("playback_prepare:\n");
-       snd_ali_printk("ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n",
+       dev_dbg(codec->card->dev, "playback_prepare:\n");
+       dev_dbg(codec->card->dev,
+               "ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n",
                       pvoice->number,runtime->rate,Delta,GVSEL,PAN,CTRL);
        snd_ali_write_voice_regs(codec,
                                 pvoice->number,
@@ -1332,7 +1319,7 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream)
 
        spin_lock_irq(&codec->reg_lock);
 
-       snd_ali_printk("ali_prepare...\n");
+       dev_dbg(codec->card->dev, "ali_prepare...\n");
 
        snd_ali_enable_special_channel(codec,pvoice->number);
 
@@ -1351,15 +1338,16 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream)
 
                rate = snd_ali_get_spdif_in_rate(codec);
                if (rate == 0) {
-                       snd_printk(KERN_WARNING "ali_capture_preapre: "
-                                  "spdif rate detect err!\n");
+                       dev_warn(codec->card->dev,
+                                "ali_capture_preapre: spdif rate detect err!\n");
                        rate = 48000;
                }
                spin_lock_irq(&codec->reg_lock);
                bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL));
                if (bValue & 0x10) {
                        outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL));
-                       printk(KERN_WARNING "clear SPDIF parity error flag.\n");
+                       dev_warn(codec->card->dev,
+                                "clear SPDIF parity error flag.\n");
                }
 
                if (rate != 48000)
@@ -1418,7 +1406,7 @@ snd_ali_playback_pointer(struct snd_pcm_substream *substream)
        outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
        cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
        spin_unlock(&codec->reg_lock);
-       snd_ali_printk("playback pointer returned cso=%xh.\n", cso);
+       dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso);
 
        return cso;
 }
@@ -1685,7 +1673,8 @@ static int snd_ali_pcm(struct snd_ali *codec, int device,
        err = snd_pcm_new(codec->card, desc->name, device,
                          desc->playback_num, desc->capture_num, &pcm);
        if (err < 0) {
-               snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.\n");
+               dev_err(codec->card->dev,
+                       "snd_ali_pcm: err called snd_pcm_new.\n");
                return err;
        }
        pcm->private_data = codec;
@@ -1861,7 +1850,7 @@ static int snd_ali_mixer(struct snd_ali *codec)
                ac97.num = i;
                err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i]);
                if (err < 0) {
-                       snd_printk(KERN_ERR
+                       dev_err(codec->card->dev,
                                   "ali mixer %d creating error.\n", i);
                        if (i == 0)
                                return err;
@@ -1947,8 +1936,7 @@ static int ali_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "ali5451: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2013,10 +2001,10 @@ static int snd_ali_chip_init(struct snd_ali *codec)
        unsigned char temp;
        struct pci_dev *pci_dev;
 
-       snd_ali_printk("chip initializing ... \n");
+       dev_dbg(codec->card->dev, "chip initializing ...\n");
 
        if (snd_ali_reset_5451(codec)) {
-               snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.\n");
+               dev_err(codec->card->dev, "ali_chip_init: reset 5451 error.\n");
                return -1;
        }
 
@@ -2062,7 +2050,7 @@ static int snd_ali_chip_init(struct snd_ali *codec)
                     ALI_REG(codec, ALI_SCTRL));
        }
 
-       snd_ali_printk("chip initialize succeed.\n");
+       dev_dbg(codec->card->dev, "chip initialize succeed.\n");
        return 0;
 
 }
@@ -2088,7 +2076,7 @@ static int snd_ali_resources(struct snd_ali *codec)
 {
        int err;
 
-       snd_ali_printk("resources allocation ...\n");
+       dev_dbg(codec->card->dev, "resources allocation ...\n");
        err = pci_request_regions(codec->pci, "ALI 5451");
        if (err < 0)
                return err;
@@ -2096,11 +2084,11 @@ static int snd_ali_resources(struct snd_ali *codec)
 
        if (request_irq(codec->pci->irq, snd_ali_card_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, codec)) {
-               snd_printk(KERN_ERR "Unable to request irq.\n");
+               dev_err(codec->card->dev, "Unable to request irq.\n");
                return -EBUSY;
        }
        codec->irq = codec->pci->irq;
-       snd_ali_printk("resources allocated.\n");
+       dev_dbg(codec->card->dev, "resources allocated.\n");
        return 0;
 }
 static int snd_ali_dev_free(struct snd_device *device)
@@ -2125,7 +2113,7 @@ static int snd_ali_create(struct snd_card *card,
 
        *r_ali = NULL;
 
-       snd_ali_printk("creating ...\n");
+       dev_dbg(card->dev, "creating ...\n");
 
        /* enable PCI device */
        err = pci_enable_device(pci);
@@ -2134,8 +2122,8 @@ static int snd_ali_create(struct snd_card *card,
        /* check, if we can restrict PCI DMA transfers to 31 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(31)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(31)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support "
-                          "31bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 31bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -2199,48 +2187,46 @@ static int snd_ali_create(struct snd_card *card,
        /* M1533: southbridge */
        codec->pci_m1533 = pci_get_device(0x10b9, 0x1533, NULL);
        if (!codec->pci_m1533) {
-               snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n");
+               dev_err(card->dev, "cannot find ALi 1533 chip.\n");
                snd_ali_free(codec);
                return -ENODEV;
        }
        /* M7101: power management */
        codec->pci_m7101 = pci_get_device(0x10b9, 0x7101, NULL);
        if (!codec->pci_m7101 && codec->revision == ALI_5451_V02) {
-               snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n");
+               dev_err(card->dev, "cannot find ALi 7101 chip.\n");
                snd_ali_free(codec);
                return -ENODEV;
        }
 
-       snd_ali_printk("snd_device_new is called.\n");
+       dev_dbg(card->dev, "snd_device_new is called.\n");
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops);
        if (err < 0) {
                snd_ali_free(codec);
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        /* initialise synth voices*/
        for (i = 0; i < ALI_CHANNELS; i++)
                codec->synth.voices[i].number = i;
 
        err = snd_ali_chip_init(codec);
        if (err < 0) {
-               snd_printk(KERN_ERR "ali create: chip init error.\n");
+               dev_err(card->dev, "ali create: chip init error.\n");
                return err;
        }
 
 #ifdef CONFIG_PM_SLEEP
        codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
        if (!codec->image)
-               snd_printk(KERN_WARNING "can't allocate apm buffer\n");
+               dev_warn(card->dev, "can't allocate apm buffer\n");
 #endif
 
        snd_ali_enable_address_interrupt(codec);
        codec->hw_initialized = 1;
 
        *r_ali = codec;
-       snd_ali_printk("created.\n");
+       dev_dbg(card->dev, "created.\n");
        return 0;
 }
 
@@ -2251,9 +2237,9 @@ static int snd_ali_probe(struct pci_dev *pci,
        struct snd_ali *codec;
        int err;
 
-       snd_ali_printk("probe ...\n");
+       dev_dbg(&pci->dev, "probe ...\n");
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -2262,12 +2248,12 @@ static int snd_ali_probe(struct pci_dev *pci,
                goto error;
        card->private_data = codec;
 
-       snd_ali_printk("mixer building ...\n");
+       dev_dbg(&pci->dev, "mixer building ...\n");
        err = snd_ali_mixer(codec);
        if (err < 0)
                goto error;
        
-       snd_ali_printk("pcm building ...\n");
+       dev_dbg(&pci->dev, "pcm building ...\n");
        err = snd_ali_build_pcms(codec);
        if (err < 0)
                goto error;
@@ -2280,7 +2266,7 @@ static int snd_ali_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, codec->port, codec->irq);
 
-       snd_ali_printk("register card.\n");
+       dev_dbg(&pci->dev, "register card.\n");
        err = snd_card_register(card);
        if (err < 0)
                goto error;
index 591efb6eef05687a93ce4cd3b77a8a9134b6aa33..cc9a15a1304ba191f902b91bdebbc835401200d7 100644 (file)
 #define PLAYBACK_BLOCK_COUNTER 0x9A
 #define RECORD_BLOCK_COUNTER   0x9B
 
-#define DEBUG_CALLS    0
 #define DEBUG_PLAY_REC 0
 
-#if DEBUG_CALLS
-#define snd_als300_dbgcalls(format, args...) printk(KERN_DEBUG format, ##args)
-#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
-#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
-#else
-#define snd_als300_dbgcalls(format, args...)
-#define snd_als300_dbgcallenter()
-#define snd_als300_dbgcallleave()
-#endif
-
 #if DEBUG_PLAY_REC
 #define snd_als300_dbgplay(format, args...) printk(KERN_ERR format, ##args)
 #else
@@ -177,7 +166,6 @@ static inline void snd_als300_gcr_write(unsigned long port,
 static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd)
 {
        u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL);
-       snd_als300_dbgcallenter();
 
        /* boolean XOR check, since old vs. new hardware have
           directly reversed bit setting for ENABLE and DISABLE.
@@ -188,19 +176,16 @@ static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd)
        else
                tmp &= ~IRQ_SET_BIT;
        snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp);
-       snd_als300_dbgcallleave();
 }
 
 static int snd_als300_free(struct snd_als300 *chip)
 {
-       snd_als300_dbgcallenter();
        snd_als300_set_irq_flag(chip, IRQ_DISABLE);
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip);
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -280,9 +265,7 @@ static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id)
 
 static void snd_als300_remove(struct pci_dev *pci)
 {
-       snd_als300_dbgcallenter();
        snd_card_free(pci_get_drvdata(pci));
-       snd_als300_dbgcallleave();
 }
 
 static unsigned short snd_als300_ac97_read(struct snd_ac97 *ac97,
@@ -330,14 +313,12 @@ static int snd_als300_ac97(struct snd_als300 *chip)
                .read = snd_als300_ac97_read,
        };
 
-       snd_als300_dbgcallenter();
        if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0)
                return err;
 
        memset(&ac97, 0, sizeof(ac97));
        ac97.private_data = chip;
 
-       snd_als300_dbgcallleave();
        return snd_ac97_mixer(bus, &ac97, &chip->ac97);
 }
 
@@ -395,13 +376,11 @@ static int snd_als300_playback_open(struct snd_pcm_substream *substream)
 
        if (!data)
                return -ENOMEM;
-       snd_als300_dbgcallenter();
        chip->playback_substream = substream;
        runtime->hw = snd_als300_playback_hw;
        runtime->private_data = data;
        data->control_register = PLAYBACK_CONTROL;
        data->block_counter_register = PLAYBACK_BLOCK_COUNTER;
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -411,11 +390,9 @@ static int snd_als300_playback_close(struct snd_pcm_substream *substream)
        struct snd_als300_substream_data *data;
 
        data = substream->runtime->private_data;
-       snd_als300_dbgcallenter();
        kfree(data);
        chip->playback_substream = NULL;
        snd_pcm_lib_free_pages(substream);
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -428,13 +405,11 @@ static int snd_als300_capture_open(struct snd_pcm_substream *substream)
 
        if (!data)
                return -ENOMEM;
-       snd_als300_dbgcallenter();
        chip->capture_substream = substream;
        runtime->hw = snd_als300_capture_hw;
        runtime->private_data = data;
        data->control_register = RECORD_CONTROL;
        data->block_counter_register = RECORD_BLOCK_COUNTER;
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -444,11 +419,9 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream)
        struct snd_als300_substream_data *data;
 
        data = substream->runtime->private_data;
-       snd_als300_dbgcallenter();
        kfree(data);
        chip->capture_substream = NULL;
        snd_pcm_lib_free_pages(substream);
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -472,7 +445,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
        unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
        unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
        
-       snd_als300_dbgcallenter();
        spin_lock_irq(&chip->reg_lock);
        tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
        tmp &= ~TRANSFER_START;
@@ -491,7 +463,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
        snd_als300_gcr_write(chip->port, PLAYBACK_END,
                                        runtime->dma_addr + buffer_bytes - 1);
        spin_unlock_irq(&chip->reg_lock);
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -503,7 +474,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
        unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
        unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
 
-       snd_als300_dbgcallenter();
        spin_lock_irq(&chip->reg_lock);
        tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL);
        tmp &= ~TRANSFER_START;
@@ -522,7 +492,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
        snd_als300_gcr_write(chip->port, RECORD_END,
                                        runtime->dma_addr + buffer_bytes - 1);
        spin_unlock_irq(&chip->reg_lock);
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -537,7 +506,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
        data = substream->runtime->private_data;
        reg = data->control_register;
 
-       snd_als300_dbgcallenter();
        spin_lock(&chip->reg_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -568,7 +536,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
                ret = -EINVAL;
        }
        spin_unlock(&chip->reg_lock);
-       snd_als300_dbgcallleave();
        return ret;
 }
 
@@ -582,7 +549,6 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
        data = substream->runtime->private_data;
        period_bytes = snd_pcm_lib_period_bytes(substream);
        
-       snd_als300_dbgcallenter();
        spin_lock(&chip->reg_lock);
        current_ptr = (u16) snd_als300_gcr_read(chip->port,
                                        data->block_counter_register) + 4;
@@ -595,7 +561,6 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
        if (data->period_flipflop == 0)
                current_ptr += period_bytes;
        snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr);
-       snd_als300_dbgcallleave();
        return bytes_to_frames(substream->runtime, current_ptr);
 }
 
@@ -626,7 +591,6 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
        struct snd_pcm *pcm;
        int err;
 
-       snd_als300_dbgcallenter();
        err = snd_pcm_new(chip->card, "ALS300", 0, 1, 1, &pcm);
        if (err < 0)
                return err;
@@ -643,7 +607,6 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
        /* pre-allocation of buffers */
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
        snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -652,7 +615,6 @@ static void snd_als300_init(struct snd_als300 *chip)
        unsigned long flags;
        u32 tmp;
        
-       snd_als300_dbgcallenter();
        spin_lock_irqsave(&chip->reg_lock, flags);
        chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16)
                                                                & 0x0000000F;
@@ -679,7 +641,6 @@ static void snd_als300_init(struct snd_als300 *chip)
        snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL,
                        tmp & ~TRANSFER_START);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_als300_dbgcallleave();
 }
 
 static int snd_als300_create(struct snd_card *card,
@@ -695,13 +656,12 @@ static int snd_als300_create(struct snd_card *card,
        };
        *rchip = NULL;
 
-       snd_als300_dbgcallenter();
        if ((err = pci_enable_device(pci)) < 0)
                return err;
 
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
                pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
-               printk(KERN_ERR "error setting 28bit DMA mask\n");
+               dev_err(card->dev, "error setting 28bit DMA mask\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -733,7 +693,7 @@ static int snd_als300_create(struct snd_card *card,
 
        if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_als300_free(chip);
                return -EBUSY;
        }
@@ -744,13 +704,13 @@ static int snd_als300_create(struct snd_card *card,
 
        err = snd_als300_ac97(chip);
        if (err < 0) {
-               snd_printk(KERN_WARNING "Could not create ac97\n");
+               dev_err(card->dev, "Could not create ac97\n");
                snd_als300_free(chip);
                return err;
        }
 
        if ((err = snd_als300_new_pcm(chip)) < 0) {
-               snd_printk(KERN_WARNING "Could not create PCM\n");
+               dev_err(card->dev, "Could not create PCM\n");
                snd_als300_free(chip);
                return err;
        }
@@ -761,10 +721,7 @@ static int snd_als300_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
-       snd_als300_dbgcallleave();
        return 0;
 }
 
@@ -794,8 +751,7 @@ static int snd_als300_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "als300: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -829,7 +785,8 @@ static int snd_als300_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
 
        if (err < 0)
                return err;
index ffc821b0139e9a3566ca56856667f443ba954d35..b751c381d25e841d541b61bfff22fe6995a24b4e 100644 (file)
@@ -578,7 +578,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
                snd_als4k_iobase_readb(chip->alt_port,
                                        ALS4K_IOB_16_ACK_FOR_CR1E);
 
-       /* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x\n",
+       /* dev_dbg(chip->card->dev, "als4000: irq 0x%04x 0x%04x\n",
                                         pci_irqstatus, sb_irqstatus); */
 
        /* only ack the things we actually handled above */
@@ -791,13 +791,13 @@ static int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev)
        }
 
        if (!r) {
-               printk(KERN_WARNING "als4000: cannot reserve joystick ports\n");
+               dev_warn(&acard->pci->dev, "cannot reserve joystick ports\n");
                return -EBUSY;
        }
 
        acard->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "als4000: cannot allocate memory for gameport\n");
+               dev_err(&acard->pci->dev, "cannot allocate memory for gameport\n");
                release_and_free_resource(r);
                return -ENOMEM;
        }
@@ -873,7 +873,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
        /* check, if we can restrict PCI DMA transfers to 24 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+               dev_err(&pci->dev, "architecture does not support 24bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -888,9 +888,9 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
        pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
        pci_set_master(pci);
        
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 
-                             sizeof(*acard) /* private_data: acard */,
-                             &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(*acard) /* private_data: acard */,
+                          &card);
        if (err < 0) {
                pci_release_regions(pci);
                pci_disable_device(pci);
@@ -920,7 +920,6 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
 
        chip->pci = pci;
        chip->alt_port = iobase;
-       snd_card_set_dev(card, &pci->dev);
 
        snd_als4000_configure(chip);
 
@@ -934,7 +933,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
                                        MPU401_INFO_INTEGRATED |
                                        MPU401_INFO_IRQ_HOOK,
                                        -1, &chip->rmidi)) < 0) {
-               printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n",
+               dev_err(&pci->dev, "no MPU-401 device at 0x%lx?\n",
                                iobase + ALS4K_IOB_30_MIDI_DATA);
                goto out_err;
        }
@@ -955,7 +954,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
                                iobase + ALS4K_IOB_10_ADLIB_ADDR0,
                                iobase + ALS4K_IOB_12_ADLIB_ADDR2,
                            OPL3_HW_AUTO, 1, &opl3) < 0) {
-               printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?\n",
+               dev_err(&pci->dev, "no OPL device at 0x%lx-0x%lx?\n",
                           iobase + ALS4K_IOB_10_ADLIB_ADDR0,
                           iobase + ALS4K_IOB_12_ADLIB_ADDR2);
        } else {
@@ -1015,8 +1014,7 @@ static int snd_als4000_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "als4000: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index 5f2acd35dcb9f4ccf26d6263e8fcba1f6a984683..901c9490398a15a254718b7ec3465b786fc41c5f 100644 (file)
@@ -1253,11 +1253,12 @@ static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device)
                        num_outstreams, num_instreams, &pcm);
        if (err < 0)
                return err;
+
        /* pointer to ops struct is stored, dont change ops afterwards! */
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-                               &snd_card_asihpi_playback_mmap_ops);
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-                               &snd_card_asihpi_capture_mmap_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_card_asihpi_playback_mmap_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_card_asihpi_capture_mmap_ops);
 
        pcm->private_data = asihpi;
        pcm->info_flags = 0;
@@ -2827,17 +2828,13 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
        hpi = pci_get_drvdata(pci_dev);
        adapter_index = hpi->adapter->index;
        /* first try to give the card the same index as its hardware index */
-       err = snd_card_create(adapter_index,
-                             id[adapter_index], THIS_MODULE,
-                             sizeof(struct snd_card_asihpi),
-                             &card);
+       err = snd_card_new(&pci_dev->dev, adapter_index, id[adapter_index],
+                          THIS_MODULE, sizeof(struct snd_card_asihpi), &card);
        if (err < 0) {
                /* if that fails, try the default index==next available */
-               err =
-                   snd_card_create(index[dev], id[dev],
-                                   THIS_MODULE,
-                                   sizeof(struct snd_card_asihpi),
-                                   &card);
+               err = snd_card_new(&pci_dev->dev, index[dev], id[dev],
+                                  THIS_MODULE, sizeof(struct snd_card_asihpi),
+                                  &card);
                if (err < 0)
                        return err;
                snd_printk(KERN_WARNING
@@ -2845,8 +2842,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
                        adapter_index, card->number);
        }
 
-       snd_card_set_dev(card, &pci_dev->dev);
-
        asihpi = card->private_data;
        asihpi->card = card;
        asihpi->pci = pci_dev;
index f6dec3ea371fa8c8e4e580af71d980e4c6595545..ae07b4926dc2266c562a934a9abb73f3d483bdd5 100644 (file)
@@ -432,7 +432,7 @@ static int snd_atiixp_acquire_codec(struct atiixp *chip)
 
        while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) {
                if (! timeout--) {
-                       snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n");
+                       dev_warn(chip->card->dev, "codec acquire timeout\n");
                        return -EBUSY;
                }
                udelay(1);
@@ -463,7 +463,7 @@ static unsigned short snd_atiixp_codec_read(struct atiixp *chip, unsigned short
        } while (--timeout);
        /* time out may happen during reset */
        if (reg < 0x7c)
-               snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg);
+               dev_warn(chip->card->dev, "codec read timeout (reg %x)\n", reg);
        return 0xffff;
 }
 
@@ -523,7 +523,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
                mdelay(1);
                atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
                if (!--timeout) {
-                       snd_printk(KERN_ERR "atiixp: codec reset timeout\n");
+                       dev_err(chip->card->dev, "codec reset timeout\n");
                        break;
                }
        }
@@ -567,9 +567,8 @@ static int ac97_probing_bugs(struct pci_dev *pci)
 
        q = snd_pci_quirk_lookup(pci, atiixp_quirks);
        if (q) {
-               snd_printdd(KERN_INFO
-                           "Atiixp quirk for %s.  Forcing codec %d\n",
-                           snd_pci_quirk_name(q), q->value);
+               dev_dbg(&pci->dev, "atiixp quirk for %s.  Forcing codec %d\n",
+                       snd_pci_quirk_name(q), q->value);
                return q->value;
        }
        /* this hardware doesn't need workarounds.  Probe for codec */
@@ -600,7 +599,7 @@ static int snd_atiixp_codec_detect(struct atiixp *chip)
        atiixp_write(chip, IER, 0); /* disable irqs */
 
        if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) {
-               snd_printk(KERN_ERR "atiixp: no codec detected!\n");
+               dev_err(chip->card->dev, "no codec detected!\n");
                return -ENXIO;
        }
        return 0;
@@ -676,7 +675,7 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substr
                        continue;
                return bytes_to_frames(runtime, curptr);
        }
-       snd_printd("atiixp: invalid DMA pointer read 0x%x (buf=%x)\n",
+       dev_dbg(chip->card->dev, "invalid DMA pointer read 0x%x (buf=%x)\n",
                   readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr);
        return 0;
 }
@@ -688,7 +687,7 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
 {
        if (! dma->substream || ! dma->running)
                return;
-       snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
+       dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
        snd_pcm_stream_lock(dma->substream);
        snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
        snd_pcm_stream_unlock(dma->substream);
@@ -1453,14 +1452,15 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock,
                        ac97.scaps |= AC97_SCAP_NO_SPDIF;
                if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
                        chip->ac97[i] = NULL; /* to be sure */
-                       snd_printdd("atiixp: codec %d not available for audio\n", i);
+                       dev_dbg(chip->card->dev,
+                               "codec %d not available for audio\n", i);
                        continue;
                }
                codec_count++;
        }
 
        if (! codec_count) {
-               snd_printk(KERN_ERR "atiixp: no codec available\n");
+               dev_err(chip->card->dev, "no codec available\n");
                return -ENODEV;
        }
 
@@ -1511,8 +1511,7 @@ static int snd_atiixp_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "atiixp: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -1637,14 +1636,14 @@ static int snd_atiixp_create(struct snd_card *card,
        chip->addr = pci_resource_start(pci, 0);
        chip->remap_addr = pci_ioremap_bar(pci, 0);
        if (chip->remap_addr == NULL) {
-               snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+               dev_err(card->dev, "AC'97 space ioremap problem\n");
                snd_atiixp_free(chip);
                return -EIO;
        }
 
        if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_atiixp_free(chip);
                return -EBUSY;
        }
@@ -1657,8 +1656,6 @@ static int snd_atiixp_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_chip = chip;
        return 0;
 }
@@ -1671,7 +1668,7 @@ static int snd_atiixp_probe(struct pci_dev *pci,
        struct atiixp *chip;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index 289563ecb6dd704e0a3f89d81ca19afef63cf98a..b9dc96c5d21ea37c11e502ce884769cbc746dc81 100644 (file)
@@ -400,7 +400,7 @@ static int snd_atiixp_acquire_codec(struct atiixp_modem *chip)
 
        while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) {
                if (! timeout--) {
-                       snd_printk(KERN_WARNING "atiixp-modem: codec acquire timeout\n");
+                       dev_warn(chip->card->dev, "codec acquire timeout\n");
                        return -EBUSY;
                }
                udelay(1);
@@ -433,7 +433,7 @@ static unsigned short snd_atiixp_codec_read(struct atiixp_modem *chip,
        } while (--timeout);
        /* time out may happen during reset */
        if (reg < 0x7c)
-               snd_printk(KERN_WARNING "atiixp-modem: codec read timeout (reg %x)\n", reg);
+               dev_warn(chip->card->dev, "codec read timeout (reg %x)\n", reg);
        return 0xffff;
 }
 
@@ -499,7 +499,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
                msleep(1);
                atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
                if (!--timeout) {
-                       snd_printk(KERN_ERR "atiixp-modem: codec reset timeout\n");
+                       dev_err(chip->card->dev, "codec reset timeout\n");
                        break;
                }
        }
@@ -553,7 +553,7 @@ static int snd_atiixp_codec_detect(struct atiixp_modem *chip)
        atiixp_write(chip, IER, 0); /* disable irqs */
 
        if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) {
-               snd_printk(KERN_ERR "atiixp-modem: no codec detected!\n");
+               dev_err(chip->card->dev, "no codec detected!\n");
                return -ENXIO;
        }
        return 0;
@@ -624,7 +624,7 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substr
                        continue;
                return bytes_to_frames(runtime, curptr);
        }
-       snd_printd("atiixp-modem: invalid DMA pointer read 0x%x (buf=%x)\n",
+       dev_dbg(chip->card->dev, "invalid DMA pointer read 0x%x (buf=%x)\n",
                   readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr);
        return 0;
 }
@@ -637,7 +637,7 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
 {
        if (! dma->substream || ! dma->running)
                return;
-       snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type);
+       dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
        snd_pcm_stream_lock(dma->substream);
        snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
        snd_pcm_stream_unlock(dma->substream);
@@ -1098,14 +1098,15 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
                ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
                if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
                        chip->ac97[i] = NULL; /* to be sure */
-                       snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
+                       dev_dbg(chip->card->dev,
+                               "codec %d not available for modem\n", i);
                        continue;
                }
                codec_count++;
        }
 
        if (! codec_count) {
-               snd_printk(KERN_ERR "atiixp-modem: no codec available\n");
+               dev_err(chip->card->dev, "no codec available\n");
                return -ENODEV;
        }
 
@@ -1150,8 +1151,7 @@ static int snd_atiixp_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "atiixp-modem: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -1262,14 +1262,14 @@ static int snd_atiixp_create(struct snd_card *card,
        chip->addr = pci_resource_start(pci, 0);
        chip->remap_addr = pci_ioremap_bar(pci, 0);
        if (chip->remap_addr == NULL) {
-               snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+               dev_err(card->dev, "AC'97 space ioremap problem\n");
                snd_atiixp_free(chip);
                return -EIO;
        }
 
        if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_atiixp_free(chip);
                return -EBUSY;
        }
@@ -1282,8 +1282,6 @@ static int snd_atiixp_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_chip = chip;
        return 0;
 }
@@ -1296,7 +1294,7 @@ static int snd_atiixp_probe(struct pci_dev *pci,
        struct atiixp_modem *chip;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index 7059dd69e5e611598530edf8ba6b6beba7a16050..afb1b44b741e0d31c51ad0afa92150cb9bf0ec54 100644 (file)
@@ -211,8 +211,6 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
                goto alloc_out;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
 
        return 0;
@@ -250,7 +248,8 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
        // (2)
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
index 2925220d3fcf84afdd27c0636b5b1939cd087f3f..120d0d320a6094bb788b3c5bc6cc14ef2c9df8b7 100644 (file)
@@ -262,7 +262,7 @@ static int snd_aw2_create(struct snd_card *card,
        /* check PCI availability (32bit DMA) */
        if ((pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) ||
            (pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0)) {
-               printk(KERN_ERR "aw2: Impossible to set 32bit mask DMA\n");
+               dev_err(card->dev, "Impossible to set 32bit mask DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -290,7 +290,7 @@ static int snd_aw2_create(struct snd_card *card,
                                pci_resource_len(pci, 0));
 
        if (chip->iobase_virt == NULL) {
-               printk(KERN_ERR "aw2: unable to remap memory region");
+               dev_err(card->dev, "unable to remap memory region");
                pci_release_regions(pci);
                pci_disable_device(pci);
                kfree(chip);
@@ -302,7 +302,7 @@ static int snd_aw2_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq);
+               dev_err(card->dev, "Cannot grab irq %d\n", pci->irq);
 
                iounmap(chip->iobase_virt);
                pci_release_regions(chip->pci);
@@ -322,12 +322,10 @@ static int snd_aw2_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
        *rchip = chip;
 
-       printk(KERN_INFO
-              "Audiowerk 2 sound card (saa7146 chipset) detected and "
-              "managed\n");
+       dev_info(card->dev,
+                "Audiowerk 2 sound card (saa7146 chipset) detected and managed\n");
        return 0;
 }
 
@@ -349,7 +347,8 @@ static int snd_aw2_probe(struct pci_dev *pci,
        }
 
        /* (2) Create card instance */
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -399,7 +398,7 @@ static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_printdd(KERN_DEBUG "aw2: Playback_open\n");
+       dev_dbg(substream->pcm->card->dev, "Playback_open\n");
        runtime->hw = snd_aw2_playback_hw;
        return 0;
 }
@@ -415,7 +414,7 @@ static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_printdd(KERN_DEBUG "aw2: Capture_open\n");
+       dev_dbg(substream->pcm->card->dev, "Capture_open\n");
        runtime->hw = snd_aw2_capture_hw;
        return 0;
 }
@@ -603,7 +602,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
        err = snd_pcm_new(chip->card, "Audiowerk2 analog playback", 0, 1, 0,
                          &pcm_playback_ana);
        if (err < 0) {
-               printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+               dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
                return err;
        }
 
@@ -633,14 +632,15 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
                                                    (chip->pci),
                                                    64 * 1024, 64 * 1024);
        if (err)
-               printk(KERN_ERR "aw2: snd_pcm_lib_preallocate_pages_for_all "
-                      "error (0x%X)\n", err);
+               dev_err(chip->card->dev,
+                       "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n",
+                       err);
 
        err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0,
                          &pcm_playback_num);
 
        if (err < 0) {
-               printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+               dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
                return err;
        }
        /* Creation ok */
@@ -669,17 +669,15 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
                                                    (chip->pci),
                                                    64 * 1024, 64 * 1024);
        if (err)
-               printk(KERN_ERR
-                      "aw2: snd_pcm_lib_preallocate_pages_for_all error "
-                      "(0x%X)\n", err);
-
-
+               dev_err(chip->card->dev,
+                       "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n",
+                       err);
 
        err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1,
                          &pcm_capture);
 
        if (err < 0) {
-               printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+               dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
                return err;
        }
 
@@ -709,15 +707,15 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
                                                    (chip->pci),
                                                    64 * 1024, 64 * 1024);
        if (err)
-               printk(KERN_ERR
-                      "aw2: snd_pcm_lib_preallocate_pages_for_all error "
-                      "(0x%X)\n", err);
+               dev_err(chip->card->dev,
+                       "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n",
+                       err);
 
 
        /* Create control */
        err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip));
        if (err < 0) {
-               printk(KERN_ERR "aw2: snd_ctl_add error (0x%X)\n", err);
+               dev_err(chip->card->dev, "snd_ctl_add error (0x%X)\n", err);
                return err;
        }
 
index 4439636971eb4c4c215ba49cff8c0b6015b873b2..6d24e95367772c352f6ed903ca410e876d1812e5 100644 (file)
@@ -204,8 +204,7 @@ void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
                /* Define upper limit for DMA access */
                WRITEREG(dma_addr + buffer_size, ProtA1_out);
        } else {
-               printk(KERN_ERR
-                      "aw2: snd_aw2_saa7146_pcm_init_playback: "
+               pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: "
                       "Substream number is not 0 or 1 -> not managed\n");
        }
 }
@@ -251,8 +250,7 @@ void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
                /* Define upper limit for DMA access  */
                WRITEREG(dma_addr + buffer_size, ProtA1_in);
        } else {
-               printk(KERN_ERR
-                      "aw2: snd_aw2_saa7146_pcm_init_capture: "
+               pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: "
                       "Substream number is not 0 -> not managed\n");
        }
 }
index 1aef7128f7caa97e0daacaeb312ee60d1ec9225f..c9216c0a9c8b06cfa284401d5f280ad80be13d31 100644 (file)
@@ -238,61 +238,6 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
     2>/dev/null
 */
 
-#define DEBUG_MISC     0
-#define DEBUG_CALLS    0
-#define DEBUG_MIXER    0
-#define DEBUG_CODEC    0
-#define DEBUG_TIMER    0
-#define DEBUG_GAME     0
-#define DEBUG_PM       0
-#define MIXER_TESTING  0
-
-#if DEBUG_MISC
-#define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgmisc(format, args...)
-#endif
-
-#if DEBUG_CALLS
-#define snd_azf3328_dbgcalls(format, args...) printk(format, ##args)
-#define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__)
-#define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__)
-#else
-#define snd_azf3328_dbgcalls(format, args...)
-#define snd_azf3328_dbgcallenter()
-#define snd_azf3328_dbgcallleave()
-#endif
-
-#if DEBUG_MIXER
-#define snd_azf3328_dbgmixer(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgmixer(format, args...)
-#endif
-
-#if DEBUG_CODEC
-#define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgcodec(format, args...)
-#endif
-
-#if DEBUG_MISC
-#define snd_azf3328_dbgtimer(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgtimer(format, args...)
-#endif
-
-#if DEBUG_GAME
-#define snd_azf3328_dbggame(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbggame(format, args...)
-#endif
-
-#if DEBUG_PM
-#define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgpm(format, args...)
-#endif
-
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard.");
@@ -475,6 +420,12 @@ snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg)
        return inb(chip->ctrl_io + reg);
 }
 
+static inline u16
+snd_azf3328_ctrl_inw(const struct snd_azf3328 *chip, unsigned reg)
+{
+       return inw(chip->ctrl_io + reg);
+}
+
 static inline void
 snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
 {
@@ -578,11 +529,12 @@ snd_azf3328_mixer_reset(const struct snd_azf3328 *chip)
 #ifdef AZF_USE_AC97_LAYER
 
 static inline void
-snd_azf3328_mixer_ac97_map_unsupported(unsigned short reg, const char *mode)
+snd_azf3328_mixer_ac97_map_unsupported(const struct snd_azf3328 *chip,
+                                      unsigned short reg, const char *mode)
 {
        /* need to add some more or less clever emulation? */
-       printk(KERN_WARNING
-               "azt3328: missing %s emulation for AC97 register 0x%02x!\n",
+       dev_warn(chip->card->dev,
+               "missing %s emulation for AC97 register 0x%02x!\n",
                mode, reg);
 }
 
@@ -717,10 +669,8 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
        unsigned short reg_val = 0;
        bool unsupported = false;
 
-       snd_azf3328_dbgmixer(
-               "snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
-                       reg_ac97
-       );
+       dev_dbg(chip->card->dev, "snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
+               reg_ac97);
        if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
                unsupported = true;
        else {
@@ -765,7 +715,7 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
                }
        }
        if (unsupported)
-               snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "read");
+               snd_azf3328_mixer_ac97_map_unsupported(chip, reg_ac97, "read");
 
        return reg_val;
 }
@@ -778,10 +728,9 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
        unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
        bool unsupported = false;
 
-       snd_azf3328_dbgmixer(
+       dev_dbg(chip->card->dev,
                "snd_azf3328_mixer_ac97_write reg_ac97 %u val %u\n",
-                       reg_ac97, val
-       );
+               reg_ac97, val);
        if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
                unsupported = true;
        else {
@@ -814,7 +763,7 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
                }
        }
        if (unsupported)
-               snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "write");
+               snd_azf3328_mixer_ac97_map_unsupported(chip, reg_ac97, "write");
 }
 
 static int
@@ -850,7 +799,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
                 * due to this card being a very quirky AC97 "lookalike".
                 */
        if (rc)
-               printk(KERN_ERR "azt3328: AC97 init failed, err %d!\n", rc);
+               dev_err(chip->card->dev, "AC97 init failed, err %d!\n", rc);
 
        /* If we return an error here, then snd_card_free() should
         * free up any ac97 codecs that got created, as well as the bus.
@@ -870,8 +819,6 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
        unsigned char curr_vol_left = 0, curr_vol_right = 0;
        int left_change = 0, right_change = 0;
 
-       snd_azf3328_dbgcallenter();
-
        if (chan_sel & SET_CHAN_LEFT) {
                curr_vol_left  = inb(portbase + 1);
 
@@ -912,7 +859,6 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
                if (delay)
                        mdelay(delay);
        } while ((left_change) || (right_change));
-       snd_azf3328_dbgcallleave();
 }
 
 /*
@@ -990,14 +936,12 @@ snd_azf3328_info_mixer(struct snd_kcontrol *kcontrol,
 {
        struct azf3328_mixer_reg reg;
 
-       snd_azf3328_dbgcallenter();
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
        uinfo->type = reg.mask == 1 ?
                SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = reg.stereo + 1;
        uinfo->value.integer.min = 0;
        uinfo->value.integer.max = reg.mask;
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -1009,7 +953,6 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol,
        struct azf3328_mixer_reg reg;
        u16 oreg, val;
 
-       snd_azf3328_dbgcallenter();
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
 
        oreg = snd_azf3328_mixer_inw(chip, reg.reg);
@@ -1023,12 +966,11 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol,
                        val = reg.mask - val;
                ucontrol->value.integer.value[1] = val;
        }
-       snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx "
-                            "(shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n",
+       dev_dbg(chip->card->dev,
+               "get: %02x is %04x -> vol %02lx|%02lx (shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n",
                reg.reg, oreg,
                ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
                reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo);
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -1040,7 +982,6 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol,
        struct azf3328_mixer_reg reg;
        u16 oreg, nreg, val;
 
-       snd_azf3328_dbgcallenter();
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
        oreg = snd_azf3328_mixer_inw(chip, reg.reg);
        val = ucontrol->value.integer.value[0] & reg.mask;
@@ -1064,12 +1005,11 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol,
        else
                snd_azf3328_mixer_outw(chip, reg.reg, nreg);
 
-       snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, "
-                            "oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n",
+       dev_dbg(chip->card->dev,
+               "put: %02x to %02lx|%02lx, oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n",
                reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
                oreg, reg.lchan_shift, reg.rchan_shift,
                nreg, snd_azf3328_mixer_inw(chip, reg.reg));
-       snd_azf3328_dbgcallleave();
        return (nreg != oreg);
 }
 
@@ -1135,7 +1075,8 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol,
        } else
                ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1);
 
-       snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n",
+       dev_dbg(chip->card->dev,
+               "get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n",
                reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1],
                reg.lchan_shift, reg.enum_c);
         return 0;
@@ -1167,7 +1108,8 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
        snd_azf3328_mixer_outw(chip, reg.reg, val);
        nreg = val;
 
-       snd_azf3328_dbgmixer("put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg);
+       dev_dbg(chip->card->dev,
+               "put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg);
        return (nreg != oreg);
 }
 
@@ -1253,7 +1195,6 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
        unsigned int idx;
        int err;
 
-       snd_azf3328_dbgcallenter();
        if (snd_BUG_ON(!chip || !chip->card))
                return -EINVAL;
 
@@ -1279,7 +1220,6 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
        snd_component_add(card, "AZF3328 mixer");
        strcpy(card->mixername, "AZF3328 mixer");
 
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 #endif /* AZF_USE_AC97_LAYER */
@@ -1288,19 +1228,13 @@ static int
 snd_azf3328_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *hw_params)
 {
-       int res;
-       snd_azf3328_dbgcallenter();
-       res = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-       snd_azf3328_dbgcallleave();
-       return res;
+       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
 
 static int
 snd_azf3328_hw_free(struct snd_pcm_substream *substream)
 {
-       snd_azf3328_dbgcallenter();
        snd_pcm_lib_free_pages(substream);
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -1315,7 +1249,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
        u16 val = 0xff00;
        u8 freq = 0;
 
-       snd_azf3328_dbgcallenter();
        switch (bitrate) {
        case AZF_FREQ_4000:  freq = SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
        case AZF_FREQ_4800:  freq = SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
@@ -1379,7 +1312,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
                );
 
        spin_unlock_irqrestore(codec->lock, flags);
-       snd_azf3328_dbgcallleave();
 }
 
 static inline void
@@ -1404,15 +1336,16 @@ snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip,
                chip->shadow_reg_ctrl_6AH |= bitmask;
        else
                chip->shadow_reg_ctrl_6AH &= ~bitmask;
-       snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n",
-                       bitmask, do_mask, chip->shadow_reg_ctrl_6AH);
+       dev_dbg(chip->card->dev,
+               "6AH_update mask 0x%04x do_mask %d: val 0x%04x\n",
+               bitmask, do_mask, chip->shadow_reg_ctrl_6AH);
        snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH);
 }
 
 static inline void
 snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable)
 {
-       snd_azf3328_dbgcodec("codec_enable %d\n", enable);
+       dev_dbg(chip->card->dev, "codec_enable %d\n", enable);
        /* no idea what exactly is being done here, but I strongly assume it's
         * PM related */
        snd_azf3328_ctrl_reg_6AH_update(
@@ -1429,7 +1362,7 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
        struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
        bool need_change = (codec->running != enable);
 
-       snd_azf3328_dbgcodec(
+       dev_dbg(chip->card->dev,
                "codec_activity: %s codec, enable %d, need_change %d\n",
                                codec->name, enable, need_change
        );
@@ -1470,13 +1403,13 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
 }
 
 static void
-snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
-                               unsigned long addr,
-                               unsigned int period_bytes,
-                               unsigned int buffer_bytes
+snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
+                         struct snd_azf3328_codec_data *codec,
+                         unsigned long addr,
+                         unsigned int period_bytes,
+                         unsigned int buffer_bytes
 )
 {
-       snd_azf3328_dbgcallenter();
        WARN_ONCE(period_bytes & 1, "odd period length!?\n");
        WARN_ONCE(buffer_bytes != 2 * period_bytes,
                 "missed our input expectations! %u vs. %u\n",
@@ -1499,7 +1432,7 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
                setup_io.dma_start_1 = addr;
                setup_io.dma_start_2 = addr+area_length;
 
-               snd_azf3328_dbgcodec(
+               dev_dbg(chip->card->dev,
                        "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n",
                                setup_io.dma_start_1, area_length,
                                setup_io.dma_start_2, area_length,
@@ -1522,7 +1455,6 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
                );
                spin_unlock_irqrestore(codec->lock, flags);
        }
-       snd_azf3328_dbgcallleave();
 }
 
 static int
@@ -1535,8 +1467,6 @@ snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 #endif
 
-       snd_azf3328_dbgcallenter();
-
        codec->dma_base = runtime->dma_addr;
 
 #if 0
@@ -1544,10 +1474,9 @@ snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
                runtime->rate,
                snd_pcm_format_width(runtime->format),
                runtime->channels);
-       snd_azf3328_codec_setdmaa(codec,
+       snd_azf3328_codec_setdmaa(chip, codec,
                                        runtime->dma_addr, count, size);
 #endif
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -1562,11 +1491,9 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        bool previously_muted = false;
        bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type);
 
-       snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd);
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               snd_azf3328_dbgcodec("START %s\n", codec->name);
+               dev_dbg(chip->card->dev, "START PCM %s\n", codec->name);
 
                if (is_main_mixer_playback_codec) {
                        /* mute WaveOut (avoid clicking during setup) */
@@ -1593,7 +1520,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
                spin_unlock(codec->lock);
 
-               snd_azf3328_codec_setdmaa(codec, runtime->dma_addr,
+               snd_azf3328_codec_setdmaa(chip, codec, runtime->dma_addr,
                        snd_pcm_lib_period_bytes(substream),
                        snd_pcm_lib_buffer_bytes(substream)
                );
@@ -1633,10 +1560,10 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                                );
                }
 
-               snd_azf3328_dbgcodec("STARTED %s\n", codec->name);
+               dev_dbg(chip->card->dev, "PCM STARTED %s\n", codec->name);
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
-               snd_azf3328_dbgcodec("RESUME %s\n", codec->name);
+               dev_dbg(chip->card->dev, "PCM RESUME %s\n", codec->name);
                /* resume codec if we were active */
                spin_lock(codec->lock);
                if (codec->running)
@@ -1648,7 +1575,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                spin_unlock(codec->lock);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               snd_azf3328_dbgcodec("STOP %s\n", codec->name);
+               dev_dbg(chip->card->dev, "PCM STOP %s\n", codec->name);
 
                if (is_main_mixer_playback_codec) {
                        /* mute WaveOut (avoid clicking during setup) */
@@ -1684,10 +1611,10 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                                );
                }
 
-               snd_azf3328_dbgcodec("STOPPED %s\n", codec->name);
+               dev_dbg(chip->card->dev, "PCM STOPPED %s\n", codec->name);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name);
+               dev_dbg(chip->card->dev, "PCM SUSPEND %s\n", codec->name);
                /* make sure codec is stopped */
                snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
                        snd_azf3328_codec_inw(
@@ -1696,17 +1623,16 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                );
                break;
         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
+               WARN(1, "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
                 break;
         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
+               WARN(1, "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
                 break;
         default:
-               snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n");
+               WARN(1, "FIXME: unknown trigger mode!\n");
                 return -EINVAL;
        }
 
-       snd_azf3328_dbgcallleave();
        return result;
 }
 
@@ -1728,8 +1654,8 @@ snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream
        result -= codec->dma_base;
 #endif
        frmres = bytes_to_frames( substream->runtime, result);
-       snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n",
-                               jiffies, codec->name, result, frmres);
+       dev_dbg(substream->pcm->card->dev, "%08li %s @ 0x%8lx, frames %8ld\n",
+               jiffies, codec->name, result, frmres);
        return frmres;
 }
 
@@ -1792,7 +1718,7 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
         * skeleton handler only
         * (we do not want axis reading in interrupt handler - too much load!)
         */
-       snd_azf3328_dbggame("gameport irq\n");
+       dev_dbg(chip->card->dev, "gameport irq\n");
 
         /* this should ACK the gameport IRQ properly, hopefully. */
        snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE);
@@ -1804,7 +1730,7 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode)
        struct snd_azf3328 *chip = gameport_get_port_data(gameport);
        int res;
 
-       snd_azf3328_dbggame("gameport_open, mode %d\n", mode);
+       dev_dbg(chip->card->dev, "gameport_open, mode %d\n", mode);
        switch (mode) {
        case GAMEPORT_MODE_COOKED:
        case GAMEPORT_MODE_RAW:
@@ -1827,7 +1753,7 @@ snd_azf3328_gameport_close(struct gameport *gameport)
 {
        struct snd_azf3328 *chip = gameport_get_port_data(gameport);
 
-       snd_azf3328_dbggame("gameport_close\n");
+       dev_dbg(chip->card->dev, "gameport_close\n");
        snd_azf3328_gameport_set_counter_frequency(chip,
                                GAME_HWCFG_ADC_COUNTER_FREQ_1_200);
        snd_azf3328_gameport_axis_circuit_enable(chip, 0);
@@ -1892,9 +1818,8 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
                        axes[i] = -1;
        }
 
-       snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n",
-               axes[0], axes[1], axes[2], axes[3], *buttons
-       );
+       dev_dbg(chip->card->dev, "cooked_read: axes %d %d %d %d buttons %d\n",
+               axes[0], axes[1], axes[2], axes[3], *buttons);
 
        return 0;
 }
@@ -1906,7 +1831,7 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev)
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n");
+               dev_err(chip->card->dev, "cannot alloc memory for gameport\n");
                return -ENOMEM;
        }
 
@@ -1950,23 +1875,23 @@ snd_azf3328_gameport_free(struct snd_azf3328 *chip) { }
 static inline void
 snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
 {
-       printk(KERN_WARNING "huh, game port IRQ occurred!?\n");
+       dev_warn(chip->card->dev, "huh, game port IRQ occurred!?\n");
 }
 #endif /* SUPPORT_GAMEPORT */
 
 /******************************************************************/
 
 static inline void
-snd_azf3328_irq_log_unknown_type(u8 which)
+snd_azf3328_irq_log_unknown_type(struct snd_azf3328 *chip, u8 which)
 {
-       snd_azf3328_dbgcodec(
-       "azt3328: unknown IRQ type (%x) occurred, please report!\n",
-               which
-       );
+       dev_dbg(chip->card->dev,
+               "unknown IRQ type (%x) occurred, please report!\n",
+               which);
 }
 
 static inline void
-snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
+snd_azf3328_pcm_interrupt(struct snd_azf3328 *chip,
+                         const struct snd_azf3328_codec_data *first_codec,
                          u8 status
 )
 {
@@ -1990,17 +1915,15 @@ snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
 
                if (codec->substream) {
                        snd_pcm_period_elapsed(codec->substream);
-                       snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n",
+                       dev_dbg(chip->card->dev, "%s period done (#%x), @ %x\n",
                                codec->name,
                                which,
                                snd_azf3328_codec_inl(
-                                       codec, IDX_IO_CODEC_DMA_CURRPOS
-                               )
-                       );
+                                       codec, IDX_IO_CODEC_DMA_CURRPOS));
                } else
-                       printk(KERN_WARNING "azt3328: irq handler problem!\n");
+                       dev_warn(chip->card->dev, "irq handler problem!\n");
                if (which & IRQ_SOMETHING)
-                       snd_azf3328_irq_log_unknown_type(which);
+                       snd_azf3328_irq_log_unknown_type(chip, which);
        }
 }
 
@@ -2009,9 +1932,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
 {
        struct snd_azf3328 *chip = dev_id;
        u8 status;
-#if DEBUG_CODEC
        static unsigned long irq_count;
-#endif
 
        status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS);
 
@@ -2022,14 +1943,13 @@ snd_azf3328_interrupt(int irq, void *dev_id)
        ))
                return IRQ_NONE; /* must be interrupt for another device */
 
-       snd_azf3328_dbgcodec(
+       dev_dbg(chip->card->dev,
                "irq_count %ld! IDX_IO_IRQSTATUS %04x\n",
                        irq_count++ /* debug-only */,
-                       status
-       );
+                       status);
 
        if (status & IRQ_TIMER) {
-               /* snd_azf3328_dbgcodec("timer %ld\n",
+               /* dev_dbg(chip->card->dev, "timer %ld\n",
                        snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE)
                                & TIMER_VALUE_MASK
                ); */
@@ -2039,11 +1959,11 @@ snd_azf3328_interrupt(int irq, void *dev_id)
                 spin_lock(&chip->reg_lock);
                snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);
                spin_unlock(&chip->reg_lock);
-               snd_azf3328_dbgcodec("azt3328: timer IRQ\n");
+               dev_dbg(chip->card->dev, "timer IRQ\n");
        }
 
        if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT))
-               snd_azf3328_pcm_interrupt(chip->codecs, status);
+               snd_azf3328_pcm_interrupt(chip, chip->codecs, status);
 
        if (status & IRQ_GAMEPORT)
                snd_azf3328_gameport_interrupt(chip);
@@ -2055,7 +1975,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
 
                /* hmm, do we have to ack the IRQ here somehow?
                 * If so, then I don't know how yet... */
-               snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n");
+               dev_dbg(chip->card->dev, "MPU401 IRQ\n");
        }
        return IRQ_HANDLED;
 }
@@ -2133,7 +2053,6 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
 
-       snd_azf3328_dbgcallenter();
        codec->substream = substream;
 
        /* same parameters for all our codecs - at least we think so... */
@@ -2142,7 +2061,6 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                   &snd_azf3328_hw_constraints_rates);
        runtime->private_data = codec;
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -2171,9 +2089,7 @@ snd_azf3328_pcm_close(struct snd_pcm_substream *substream
        struct snd_azf3328_codec_data *codec =
                substream->runtime->private_data;
 
-       snd_azf3328_dbgcallenter();
        codec->substream = NULL;
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -2220,8 +2136,6 @@ enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
        struct snd_pcm *pcm;
        int err;
 
-       snd_azf3328_dbgcallenter();
-
        err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD,
                                                                1, 1, &pcm);
        if (err < 0)
@@ -2258,7 +2172,6 @@ enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
                                                snd_dma_pci_data(chip->pci),
                                                        64*1024, 64*1024);
 
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -2281,7 +2194,6 @@ snd_azf3328_timer_start(struct snd_timer *timer)
        unsigned long flags;
        unsigned int delay;
 
-       snd_azf3328_dbgcallenter();
        chip = snd_timer_chip(timer);
        delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK;
        if (delay < 49) {
@@ -2289,15 +2201,14 @@ snd_azf3328_timer_start(struct snd_timer *timer)
                 * this timing tweak
                 * (we need to do it to avoid a lockup, though) */
 
-               snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay);
+               dev_dbg(chip->card->dev, "delay was too low (%d)!\n", delay);
                delay = 49; /* minimum time is 49 ticks */
        }
-       snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay);
+       dev_dbg(chip->card->dev, "setting timer countdown value %d\n", delay);
        delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -2307,7 +2218,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
        struct snd_azf3328 *chip;
        unsigned long flags;
 
-       snd_azf3328_dbgcallenter();
        chip = snd_timer_chip(timer);
        spin_lock_irqsave(&chip->reg_lock, flags);
        /* disable timer countdown and interrupt */
@@ -2319,7 +2229,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
           the hardware/ALSA interrupt activity. */
        snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -2328,10 +2237,8 @@ static int
 snd_azf3328_timer_precise_resolution(struct snd_timer *timer,
                                               unsigned long *num, unsigned long *den)
 {
-       snd_azf3328_dbgcallenter();
        *num = 1;
        *den = 1024000 / seqtimer_scaling;
-       snd_azf3328_dbgcallleave();
        return 0;
 }
 
@@ -2351,7 +2258,6 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
        struct snd_timer_id tid;
        int err;
 
-       snd_azf3328_dbgcallenter();
        tid.dev_class = SNDRV_TIMER_CLASS_CARD;
        tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
        tid.card = chip->card->number;
@@ -2376,7 +2282,6 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
        err = 0;
 
 out:
-       snd_azf3328_dbgcallleave();
        return err;
 }
 
@@ -2438,34 +2343,34 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit)
 static inline void
 snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
 {
-#if DEBUG_MISC
        u16 tmp;
 
-       snd_azf3328_dbgmisc(
+       dev_dbg(chip->card->dev,
                "ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, "
                "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n",
                chip->ctrl_io, chip->game_io, chip->mpu_io,
-               chip->opl3_io, chip->mixer_io, chip->irq
-       );
+               chip->opl3_io, chip->mixer_io, chip->irq);
 
-       snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n",
+       dev_dbg(chip->card->dev,
+               "game %02x %02x %02x %02x %02x %02x\n",
                snd_azf3328_game_inb(chip, 0),
                snd_azf3328_game_inb(chip, 1),
                snd_azf3328_game_inb(chip, 2),
                snd_azf3328_game_inb(chip, 3),
                snd_azf3328_game_inb(chip, 4),
-               snd_azf3328_game_inb(chip, 5)
-       );
+               snd_azf3328_game_inb(chip, 5));
 
        for (tmp = 0; tmp < 0x07; tmp += 1)
-               snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp));
+               dev_dbg(chip->card->dev,
+                       "mpu_io 0x%04x\n", inb(chip->mpu_io + tmp));
 
        for (tmp = 0; tmp <= 0x07; tmp += 1)
-               snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n",
+               dev_dbg(chip->card->dev,
+                       "0x%02x: game200 0x%04x, game208 0x%04x\n",
                        tmp, inb(0x200 + tmp), inb(0x208 + tmp));
 
        for (tmp = 0; tmp <= 0x01; tmp += 1)
-               snd_azf3328_dbgmisc(
+               dev_dbg(chip->card->dev,
                        "0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, "
                        "mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n",
                                tmp,
@@ -2474,19 +2379,17 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
                                inb(0x320 + tmp),
                                inb(0x330 + tmp),
                                inb(0x388 + tmp),
-                               inb(0x38c + tmp)
-               );
+                               inb(0x38c + tmp));
 
        for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2)
-               snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n",
-                       tmp, snd_azf3328_ctrl_inw(chip, tmp)
-               );
+               dev_dbg(chip->card->dev,
+                       "ctrl 0x%02x: 0x%04x\n",
+                       tmp, snd_azf3328_ctrl_inw(chip, tmp));
 
        for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2)
-               snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n",
-                       tmp, snd_azf3328_mixer_inw(chip, tmp)
-               );
-#endif /* DEBUG_MISC */
+               dev_dbg(chip->card->dev,
+                       "mixer 0x%02x: 0x%04x\n",
+                       tmp, snd_azf3328_mixer_inw(chip, tmp));
 }
 
 static int
@@ -2523,8 +2426,8 @@ snd_azf3328_create(struct snd_card *card,
        /* check if we can restrict PCI DMA transfers to 24 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support "
-                                       "24bit PCI busmaster DMA\n"
+               dev_err(card->dev,
+                       "architecture does not support 24bit PCI busmaster DMA\n"
                );
                err = -ENXIO;
                goto out_err;
@@ -2560,7 +2463,7 @@ snd_azf3328_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_azf3328_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto out_err;
        }
@@ -2599,8 +2502,6 @@ snd_azf3328_create(struct snd_card *card,
                spin_unlock_irq(codec->lock);
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
 
        err = 0;
@@ -2624,7 +2525,6 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        struct snd_opl3 *opl3;
        int err;
 
-       snd_azf3328_dbgcallenter();
        if (dev >= SNDRV_CARDS) {
                err = -ENODEV;
                goto out;
@@ -2635,7 +2535,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                goto out;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                goto out;
 
@@ -2657,7 +2558,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                -1, &chip->rmidi
        );
        if (err < 0) {
-               snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n",
+               dev_err(card->dev, "no MPU-401 device at 0x%lx?\n",
                                chip->mpu_io
                );
                goto out_err;
@@ -2673,7 +2574,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 
        if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2,
                            OPL3_HW_AUTO, 1, &opl3) < 0) {
-               snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n",
+               dev_err(card->dev, "no OPL3 device at 0x%lx-0x%lx?\n",
                           chip->opl3_io, chip->opl3_io+2
                );
        } else {
@@ -2695,12 +2596,15 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                goto out_err;
 
 #ifdef MODULE
-       printk(KERN_INFO
-"azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n"
-"azt3328: Hardware was completely undocumented, unfortunately.\n"
-"azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n"
-"azt3328: User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n",
-       1024000 / seqtimer_scaling, seqtimer_scaling);
+       dev_info(card->dev,
+                "Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n");
+       dev_info(card->dev,
+                "Hardware was completely undocumented, unfortunately.\n");
+       dev_info(card->dev,
+                "Feel free to contact andi AT lisas.de for bug reports etc.!\n");
+       dev_info(card->dev,
+                "User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n",
+                1024000 / seqtimer_scaling, seqtimer_scaling);
 #endif
 
        snd_azf3328_gameport(chip, dev);
@@ -2712,31 +2616,29 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        goto out;
 
 out_err:
-       snd_printk(KERN_ERR "azf3328: something failed, exiting\n");
+       dev_err(card->dev, "something failed, exiting\n");
        snd_card_free(card);
 
 out:
-       snd_azf3328_dbgcallleave();
        return err;
 }
 
 static void
 snd_azf3328_remove(struct pci_dev *pci)
 {
-       snd_azf3328_dbgcallenter();
        snd_card_free(pci_get_drvdata(pci));
-       snd_azf3328_dbgcallleave();
 }
 
 #ifdef CONFIG_PM_SLEEP
 static inline void
-snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
+snd_azf3328_suspend_regs(const struct snd_azf3328 *chip,
+                        unsigned long io_addr, unsigned count, u32 *saved_regs)
 {
        unsigned reg;
 
        for (reg = 0; reg < count; ++reg) {
                *saved_regs = inl(io_addr);
-               snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n",
+               dev_dbg(chip->card->dev, "suspend: io 0x%04lx: 0x%08x\n",
                        io_addr, *saved_regs);
                ++saved_regs;
                io_addr += sizeof(*saved_regs);
@@ -2744,7 +2646,8 @@ snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
 }
 
 static inline void
-snd_azf3328_resume_regs(const u32 *saved_regs,
+snd_azf3328_resume_regs(const struct snd_azf3328 *chip,
+                       const u32 *saved_regs,
                        unsigned long io_addr,
                        unsigned count
 )
@@ -2753,7 +2656,8 @@ snd_azf3328_resume_regs(const u32 *saved_regs,
 
        for (reg = 0; reg < count; ++reg) {
                outl(*saved_regs, io_addr);
-               snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
+               dev_dbg(chip->card->dev,
+                       "resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
                        io_addr, *saved_regs, inl(io_addr));
                ++saved_regs;
                io_addr += sizeof(*saved_regs);
@@ -2766,7 +2670,7 @@ snd_azf3328_suspend_ac97(struct snd_azf3328 *chip)
 #ifdef AZF_USE_AC97_LAYER
        snd_ac97_suspend(chip->ac97);
 #else
-       snd_azf3328_suspend_regs(chip->mixer_io,
+       snd_azf3328_suspend_regs(chip, chip->mixer_io,
                ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
 
        /* make sure to disable master volume etc. to prevent looping sound */
@@ -2781,7 +2685,7 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip)
 #ifdef AZF_USE_AC97_LAYER
        snd_ac97_resume(chip->ac97);
 #else
-       snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io,
+       snd_azf3328_resume_regs(chip, chip->saved_regs_mixer, chip->mixer_io,
                                        ARRAY_SIZE(chip->saved_regs_mixer));
 
        /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
@@ -2808,18 +2712,18 @@ snd_azf3328_suspend(struct device *dev)
 
        snd_azf3328_suspend_ac97(chip);
 
-       snd_azf3328_suspend_regs(chip->ctrl_io,
+       snd_azf3328_suspend_regs(chip, chip->ctrl_io,
                ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl);
 
        /* manually store the one currently relevant write-only reg, too */
        saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl;
        saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH;
 
-       snd_azf3328_suspend_regs(chip->game_io,
+       snd_azf3328_suspend_regs(chip, chip->game_io,
                ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game);
-       snd_azf3328_suspend_regs(chip->mpu_io,
+       snd_azf3328_suspend_regs(chip, chip->mpu_io,
                ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu);
-       snd_azf3328_suspend_regs(chip->opl3_io,
+       snd_azf3328_suspend_regs(chip, chip->opl3_io,
                ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3);
 
        pci_disable_device(pci);
@@ -2838,23 +2742,22 @@ snd_azf3328_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "azt3328: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
        pci_set_master(pci);
 
-       snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io,
+       snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io,
                                        ARRAY_SIZE(chip->saved_regs_game));
-       snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io,
+       snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io,
                                        ARRAY_SIZE(chip->saved_regs_mpu));
-       snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io,
+       snd_azf3328_resume_regs(chip, chip->saved_regs_opl3, chip->opl3_io,
                                        ARRAY_SIZE(chip->saved_regs_opl3));
 
        snd_azf3328_resume_ac97(chip);
 
-       snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io,
+       snd_azf3328_resume_regs(chip, chip->saved_regs_ctrl, chip->ctrl_io,
                                        ARRAY_SIZE(chip->saved_regs_ctrl));
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
index 18802039497afd3dfcafdd53dd1d0d62e503c4cc..8546711d12f9275c9dba94bbfc1a59476e1c041a 100644 (file)
@@ -293,17 +293,23 @@ static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status)
                PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY;
        pci_write_config_word(chip->pci, PCI_STATUS, pci_status);
        if (pci_status != PCI_STATUS_DETECTED_PARITY)
-               snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n",
+               dev_err(chip->card->dev,
+                       "Aieee - PCI error! status %#08x, PCI status %#04x\n",
                           status & ERROR_INTERRUPTS, pci_status);
        else {
-               snd_printk(KERN_ERR "Aieee - PCI parity error detected!\n");
+               dev_err(chip->card->dev,
+                       "Aieee - PCI parity error detected!\n");
                /* error 'handling' similar to aic7xxx_pci.c: */
                chip->pci_parity_errors++;
                if (chip->pci_parity_errors > 20) {
-                       snd_printk(KERN_ERR "Too many PCI parity errors observed.\n");
-                       snd_printk(KERN_ERR "Some device on this bus is generating bad parity.\n");
-                       snd_printk(KERN_ERR "This is an error *observed by*, not *generated by*, this card.\n");
-                       snd_printk(KERN_ERR "PCI parity error checking has been disabled.\n");
+                       dev_err(chip->card->dev,
+                               "Too many PCI parity errors observed.\n");
+                       dev_err(chip->card->dev,
+                               "Some device on this bus is generating bad parity.\n");
+                       dev_err(chip->card->dev,
+                               "This is an error *observed by*, not *generated by*, this card.\n");
+                       dev_err(chip->card->dev,
+                               "PCI parity error checking has been disabled.\n");
                        chip->interrupt_mask &= ~(INT_PPERR | INT_RIPERR);
                        snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask);
                }
@@ -323,9 +329,11 @@ static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id)
 
        if (irq_status & ERROR_INTERRUPTS) {
                if (irq_status & (INT_FBUS | INT_FTRGT))
-                       snd_printk(KERN_WARNING "FIFO overrun, status %#08x\n", status);
+                       dev_warn(chip->card->dev,
+                                "FIFO overrun, status %#08x\n", status);
                if (irq_status & INT_OCERR)
-                       snd_printk(KERN_ERR "internal RISC error, status %#08x\n", status);
+                       dev_err(chip->card->dev,
+                               "internal RISC error, status %#08x\n", status);
                if (irq_status & (INT_PPERR | INT_RIPERR | INT_PABORT))
                        snd_bt87x_pci_error(chip, irq_status);
        }
@@ -747,7 +755,7 @@ static int snd_bt87x_create(struct snd_card *card,
        }
        chip->mmio = pci_ioremap_bar(pci, 0);
        if (!chip->mmio) {
-               snd_printk(KERN_ERR "cannot remap io memory\n");
+               dev_err(card->dev, "cannot remap io memory\n");
                err = -ENOMEM;
                goto fail;
        }
@@ -762,7 +770,7 @@ static int snd_bt87x_create(struct snd_card *card,
        err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
                          KBUILD_MODNAME, chip);
        if (err < 0) {
-               snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
+               dev_err(card->dev, "cannot grab irq %d\n", pci->irq);
                goto fail;
        }
        chip->irq = pci->irq;
@@ -773,7 +781,6 @@ static int snd_bt87x_create(struct snd_card *card,
        if (err < 0)
                goto fail;
 
-       snd_card_set_dev(card, &pci->dev);
        *rchip = chip;
        return 0;
 
@@ -851,14 +858,15 @@ static int snd_bt87x_detect_card(struct pci_dev *pci)
        for (i = 0; i < ARRAY_SIZE(blacklist); ++i)
                if (blacklist[i].subvendor == pci->subsystem_vendor &&
                    blacklist[i].subdevice == pci->subsystem_device) {
-                       snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n",
+                       dev_dbg(&pci->dev,
+                               "card %#04x-%#04x:%#04x has no audio\n",
                                    pci->device, pci->subsystem_vendor, pci->subsystem_device);
                        return -EBUSY;
                }
 
-       snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n",
+       dev_info(&pci->dev, "unknown card %#04x-%#04x:%#04x\n",
                   pci->device, pci->subsystem_vendor, pci->subsystem_device);
-       snd_printk(KERN_DEBUG "please mail id, board name, and, "
+       dev_info(&pci->dev, "please mail id, board name, and, "
                   "if it works, the correct digital_rate option to "
                   "<alsa-devel@alsa-project.org>\n");
        return SND_BT87X_BOARD_UNKNOWN;
@@ -888,7 +896,8 @@ static int snd_bt87x_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -925,7 +934,7 @@ static int snd_bt87x_probe(struct pci_dev *pci,
                if (err < 0)
                        goto _error;
        }
-       snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital "
+       dev_info(card->dev, "bt87x%d: Using board %d, %sanalog, %sdigital "
                   "(rate %d Hz)\n", dev, boardid,
                   chip->board.no_analog ? "no " : "",
                   chip->board.no_digital ? "no " : "", chip->board.dig_rate);
index f4db5587e86ee9b3f509d1541b9ae85c0a64cbab..f94cc6e97d4ab8cec22ddff2134f96139ba89d92 100644 (file)
@@ -417,13 +417,13 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
        int status;
        int retry;
        if ((reg > 0x7f) || (value > 0x1ff)) {
-               snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+               dev_err(emu->card->dev, "i2c_write: invalid values.\n");
                return -EINVAL;
        }
 
        tmp = reg << 25 | value << 16;
        /*
-       snd_printk(KERN_DEBUG "I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+       dev_dbg(emu->card->dev, "I2C-write:reg=0x%x, value=0x%x\n", reg, value);
        */
        /* Not sure what this I2C channel controls. */
        /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
@@ -442,7 +442,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
                /* Wait till the transaction ends */
                while (1) {
                        status = snd_ca0106_ptr_read(emu, I2C_A, 0);
-                       /*snd_printk(KERN_DEBUG "I2C:status=0x%x\n", status);*/
+                       /*dev_dbg(emu->card->dev, "I2C:status=0x%x\n", status);*/
                        timeout++;
                        if ((status & I2C_A_ADC_START) == 0)
                                break;
@@ -456,7 +456,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
        }
 
        if (retry == 10) {
-               snd_printk(KERN_ERR "Writing to ADC failed!\n");
+               dev_err(emu->card->dev, "Writing to ADC failed!\n");
                return -EINVAL;
        }
     
@@ -516,7 +516,8 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
        }
 }
 
-static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+static int snd_ca0106_channel_dac(struct snd_ca0106 *chip,
+                                 struct snd_ca0106_details *details,
                                  int channel_id)
 {
        switch (channel_id) {
@@ -529,7 +530,7 @@ static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
        case PCM_UNKNOWN_CHANNEL:
                return (details->spi_dac & 0x000f) >> (4 * 0);
        default:
-               snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+               dev_dbg(chip->card->dev, "ca0106: unknown channel_id %d\n",
                           channel_id);
        }
        return 0;
@@ -539,7 +540,7 @@ static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
                                    int power)
 {
        if (chip->details->spi_dac) {
-               const int dac = snd_ca0106_channel_dac(chip->details,
+               const int dac = snd_ca0106_channel_dac(chip, chip->details,
                                                       channel_id);
                const int reg = spi_dacd_reg[dac];
                const int bit = spi_dacd_bit[dac];
@@ -583,7 +584,7 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
 
        channel->use = 1;
        /*
-       printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+       dev_dbg(chip->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
               channel_id, chip, channel);
        */
         //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
@@ -660,7 +661,8 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre
 
        epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
        if (epcm == NULL) {
-               snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n");
+               dev_err(chip->card->dev,
+                       "open_capture_channel: failed epcm alloc\n");
                return -ENOMEM;
         }
        epcm->emu = chip;
@@ -677,7 +679,7 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre
 
        channel->use = 1;
        /*
-        printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+       dev_dbg(chip->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
               channel_id, chip, channel);
        */
         //channel->interrupt = snd_ca0106_pcm_channel_interrupt;
@@ -771,7 +773,7 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
        int i;
        
 #if 0 /* debug */
-       snd_printk(KERN_DEBUG
+       dev_dbg(emu->card->dev,
                   "prepare:channel_number=%d, rate=%d, format=0x%x, "
                   "channels=%d, buffer_size=%ld, period_size=%ld, "
                   "periods=%u, frames_to_bytes=%d\n",
@@ -779,9 +781,11 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
                   runtime->channels, runtime->buffer_size,
                   runtime->period_size, runtime->periods,
                   frames_to_bytes(runtime, 1));
-       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+       dev_dbg(emu->card->dev,
+               "dma_addr=%x, dma_area=%p, table_base=%p\n",
                   runtime->dma_addr, runtime->dma_area, table_base);
-       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+       dev_dbg(emu->card->dev,
+               "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
                   emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
 #endif /* debug */
        /* Rate can be set per channel. */
@@ -876,7 +880,7 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
        u32 reg71;
        
 #if 0 /* debug */
-       snd_printk(KERN_DEBUG
+       dev_dbg(emu->card->dev,
                   "prepare:channel_number=%d, rate=%d, format=0x%x, "
                   "channels=%d, buffer_size=%ld, period_size=%ld, "
                   "periods=%u, frames_to_bytes=%d\n",
@@ -884,9 +888,11 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
                   runtime->channels, runtime->buffer_size,
                   runtime->period_size, runtime->periods,
                   frames_to_bytes(runtime, 1));
-        snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+       dev_dbg(emu->card->dev,
+               "dma_addr=%x, dma_area=%p, table_base=%p\n",
                   runtime->dma_addr, runtime->dma_area, table_base);
-       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+       dev_dbg(emu->card->dev,
+               "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
                   emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
 #endif /* debug */
        /* reg71 controls ADC rate. */
@@ -934,7 +940,7 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
 
 
        /*
-       printk(KERN_DEBUG
+       dev_dbg(emu->card->dev,
               "prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, "
               "buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",
               channel, runtime->rate, runtime->format, runtime->channels,
@@ -982,13 +988,13 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream,
                runtime = s->runtime;
                epcm = runtime->private_data;
                channel = epcm->channel_id;
-               /* snd_printk(KERN_DEBUG "channel=%d\n", channel); */
+               /* dev_dbg(emu->card->dev, "channel=%d\n", channel); */
                epcm->running = running;
                basic |= (0x1 << channel);
                extended |= (0x10 << channel);
                 snd_pcm_trigger_done(s, substream);
         }
-       /* snd_printk(KERN_DEBUG "basic=0x%x, extended=0x%x\n",basic, extended); */
+       /* dev_dbg(emu->card->dev, "basic=0x%x, extended=0x%x\n",basic, extended); */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -1070,7 +1076,7 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
                        return ptr;
                prev_ptr = ptr;
        } while (--timeout);
-       snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+       dev_warn(emu->card->dev, "ca0106: unstable DMA pointer!\n");
        return 0;
 }
 
@@ -1093,7 +1099,7 @@ snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream)
         if (ptr >= runtime->buffer_size)
                ptr -= runtime->buffer_size;
        /*
-       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+       dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
               "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
               ptr1, ptr2, ptr, (int)runtime->buffer_size,
               (int)runtime->period_size, (int)runtime->frame_bits,
@@ -1284,9 +1290,9 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
 
         stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0);
        /*
-       snd_printk(KERN_DEBUG "interrupt status = 0x%08x, stat76=0x%08x\n",
+       dev_dbg(emu->card->dev, "interrupt status = 0x%08x, stat76=0x%08x\n",
                   status, stat76);
-       snd_printk(KERN_DEBUG "ptr=0x%08x\n",
+       dev_dbg(emu->card->dev, "ptr=0x%08x\n",
                   snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
        */
         mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */
@@ -1296,11 +1302,13 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
 /* FIXME: Select the correct substream for period elapsed */
                        if(pchannel->use) {
                                snd_pcm_period_elapsed(pchannel->epcm->substream);
-                               //printk(KERN_INFO "interrupt [%d] used\n", i);
+                               /* dev_dbg(emu->card->dev, "interrupt [%d] used\n", i); */
                         }
                }
-               //printk(KERN_INFO "channel=%p\n",pchannel);
-               //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+               /*
+               dev_dbg(emu->card->dev, "channel=%p\n", pchannel);
+               dev_dbg(emu->card->dev, "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+               */
                mask <<= 1;
        }
         mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */
@@ -1310,11 +1318,13 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
 /* FIXME: Select the correct substream for period elapsed */
                        if(pchannel->use) {
                                snd_pcm_period_elapsed(pchannel->epcm->substream);
-                               //printk(KERN_INFO "interrupt [%d] used\n", i);
+                               /* dev_dbg(emu->card->dev, "interrupt [%d] used\n", i); */
                         }
                }
-               //printk(KERN_INFO "channel=%p\n",pchannel);
-               //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+               /*
+               dev_dbg(emu->card->dev, "channel=%p\n", pchannel);
+               dev_dbg(emu->card->dev, "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+               */
                mask <<= 1;
        }
 
@@ -1603,7 +1613,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                int size, n;
 
                size = ARRAY_SIZE(i2c_adc_init);
-               /* snd_printk(KERN_DEBUG "I2C:array size=0x%x\n", size); */
+               /* dev_dbg(emu->card->dev, "I2C:array size=0x%x\n", size); */
                for (n = 0; n < size; n++)
                        snd_ca0106_i2c_write(chip, i2c_adc_init[n][0],
                                             i2c_adc_init[n][1]);
@@ -1668,7 +1678,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
                return err;
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-               printk(KERN_ERR "error to set 32bit mask DMA\n");
+               dev_err(card->dev, "error to set 32bit mask DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -1689,14 +1699,14 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
        chip->res_port = request_region(chip->port, 0x20, "snd_ca0106");
        if (!chip->res_port) {
                snd_ca0106_free(chip);
-               printk(KERN_ERR "cannot allocate the port\n");
+               dev_err(card->dev, "cannot allocate the port\n");
                return -EBUSY;
        }
 
        if (request_irq(pci->irq, snd_ca0106_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
                snd_ca0106_free(chip);
-               printk(KERN_ERR "cannot grab irq\n");
+               dev_err(card->dev, "cannot grab irq\n");
                return -EBUSY;
        }
        chip->irq = pci->irq;
@@ -1712,7 +1722,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
        /* read serial */
        pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
        pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
-       printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n",
+       dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n",
               chip->model, pci->revision, chip->serial);
        strcpy(card->driver, "CA0106");
        strcpy(card->shortname, "CA0106");
@@ -1726,7 +1736,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
        }
        chip->details = c;
        if (subsystem[dev]) {
-               printk(KERN_INFO "snd-ca0106: Sound card name=%s, "
+               dev_info(card->dev, "Sound card name=%s, "
                       "subsystem=0x%x. Forced to subsystem=0x%x\n",
                       c->name, chip->serial, subsystem[dev]);
        }
@@ -1843,7 +1853,8 @@ static int snd_ca0106_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -1868,18 +1879,16 @@ static int snd_ca0106_probe(struct pci_dev *pci,
        if (err < 0)
                goto error;
 
-       snd_printdd("ca0106: probe for MIDI channel A ...");
+       dev_dbg(card->dev, "probe for MIDI channel A ...");
        err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A);
        if (err < 0)
                goto error;
-       snd_printdd(" done.\n");
+       dev_dbg(card->dev, " done.\n");
 
 #ifdef CONFIG_PROC_FS
        snd_ca0106_proc_init(chip);
 #endif
 
-       snd_card_set_dev(card, &pci->dev);
-
        err = snd_card_register(card);
        if (err < 0)
                goto error;
index 8bbdf265d11d240ab6798b8b6d67a65a693a8d2d..b91c7f6d19f9ee28005a91f3af210c3e60c6ea3d 100644 (file)
@@ -46,7 +46,7 @@ static void ca_midi_clear_rx(struct snd_ca_midi *midi)
                ca_midi_read_data(midi);
 #ifdef CONFIG_SND_DEBUG
        if (timeout <= 0)
-               snd_printk(KERN_ERR "ca_midi_clear_rx: timeout (status = 0x%x)\n",
+               pr_err("ca_midi_clear_rx: timeout (status = 0x%x)\n",
                           ca_midi_read_stat(midi));
 #endif
 }
@@ -113,7 +113,7 @@ static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack)
        }
        spin_unlock_irqrestore(&midi->input_lock, flags);
        if (!ok)
-               snd_printk(KERN_ERR "ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
+               pr_err("ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
                           cmd,
                           midi->get_dev_id_port(midi->dev_id),
                           ca_midi_read_stat(midi),
index 2755ec5bcc258d695d534f3ca99d895218c49215..12c318e175f4c0a461695eb101a4158b0eb1a12a 100644 (file)
@@ -796,7 +796,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
        if (runtime->channels > 1)
                rec->fmt |= 0x01;
        if (rec->is_dac && set_dac_channels(cm, rec, runtime->channels) < 0) {
-               snd_printd("cannot set dac channels\n");
+               dev_dbg(cm->card->dev, "cannot set dac channels\n");
                return -EINVAL;
        }
 
@@ -827,7 +827,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
        else
                cm->ctrl |= val;
        snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
-       //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl);
+       /* dev_dbg(cm->card->dev, "functrl0 = %08x\n", cm->ctrl); */
 
        /* set sample rate */
        freq = 0;
@@ -850,7 +850,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
                val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK;
        }
        snd_cmipci_write(cm, CM_REG_FUNCTRL1, val);
-       //snd_printd("cmipci: functrl1 = %08x\n", val);
+       dev_dbg(cm->card->dev, "functrl1 = %08x\n", val);
 
        /* set format */
        val = snd_cmipci_read(cm, CM_REG_CHFORMAT);
@@ -866,7 +866,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
                val |= freq_ext << (rec->ch * 2);
        }
        snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
-       //snd_printd("cmipci: chformat = %08x\n", val);
+       dev_dbg(cm->card->dev, "chformat = %08x\n", val);
 
        if (!rec->is_dac && cm->chip_version) {
                if (runtime->rate > 44100)
@@ -904,7 +904,7 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec,
                cm->ctrl |= chen;
                /* enable channel */
                snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
-               //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl);
+               dev_dbg(cm->card->dev, "functrl0 = %08x\n", cm->ctrl);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                rec->running = 0;
@@ -952,7 +952,7 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci
                if (rem < rec->dma_size)
                        goto ok;
        } 
-       printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem);
+       dev_err(cm->card->dev, "invalid PCM pointer: %#x\n", rem);
        return SNDRV_PCM_POS_XRUN;
 ok:
        ptr = (rec->dma_size - (rem + 1)) >> rec->shift;
@@ -2889,13 +2889,13 @@ static int snd_cmipci_create_gameport(struct cmipci *cm, int dev)
        }
 
        if (!r) {
-               printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+               dev_warn(cm->card->dev, "cannot reserve joystick ports\n");
                return -EBUSY;
        }
 
        cm->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n");
+               dev_err(cm->card->dev, "cannot allocate memory for gameport\n");
                release_and_free_resource(r);
                return -ENOMEM;
        }
@@ -2995,13 +2995,14 @@ static int snd_cmipci_create_fm(struct cmipci *cm, long fm_port)
 
                if (snd_opl3_create(cm->card, iosynth, iosynth + 2,
                                    OPL3_HW_OPL3, 0, &opl3) < 0) {
-                       printk(KERN_ERR "cmipci: no OPL device at %#lx, "
-                              "skipping...\n", iosynth);
+                       dev_err(cm->card->dev,
+                               "no OPL device at %#lx, skipping...\n",
+                               iosynth);
                        goto disable_fm;
                }
        }
        if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
-               printk(KERN_ERR "cmipci: cannot create OPL3 hwdep\n");
+               dev_err(cm->card->dev, "cannot create OPL3 hwdep\n");
                return err;
        }
        return 0;
@@ -3060,7 +3061,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
 
        if (request_irq(pci->irq, snd_cmipci_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, cm)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_cmipci_free(cm);
                return -EBUSY;
        }
@@ -3192,8 +3193,9 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
                        /* enable UART */
                        snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN);
                        if (inb(iomidi + 1) == 0xff) {
-                               snd_printk(KERN_ERR "cannot enable MPU-401 port"
-                                          " at %#lx\n", iomidi);
+                               dev_err(cm->card->dev,
+                                       "cannot enable MPU-401 port at %#lx\n",
+                                       iomidi);
                                snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1,
                                                     CM_UART_EN);
                                iomidi = 0;
@@ -3237,7 +3239,8 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
                                                MPU401_INFO_INTEGRATED : 0) |
                                               MPU401_INFO_IRQ_HOOK,
                                               -1, &cm->rmidi)) < 0) {
-                       printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi);
+                       dev_err(cm->card->dev,
+                               "no UART401 device at 0x%lx\n", iomidi);
                }
        }
 
@@ -3254,8 +3257,6 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
        if (snd_cmipci_create_gameport(cm, dev) < 0)
                snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rcmipci = cm;
        return 0;
 }
@@ -3280,7 +3281,8 @@ static int snd_cmipci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        
@@ -3381,8 +3383,7 @@ static int snd_cmipci_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "cmipci: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index 1dc793e742d79845b3e92d6da1ac204f971a6ef8..43d1f912c6419db171b9fc12144ec5e2c33b367a 100644 (file)
@@ -564,7 +564,8 @@ static void snd_cs4281_ac97_write(struct snd_ac97 *ac97,
                        return;
                }
        }
-       snd_printk(KERN_ERR "AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
+       dev_err(chip->card->dev,
+               "AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
 }
 
 static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97,
@@ -624,7 +625,8 @@ static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97,
                        goto __ok1;
        }
 
-       snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
+       dev_err(chip->card->dev,
+               "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
        result = 0xffff;
        goto __end;
        
@@ -643,7 +645,8 @@ static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97,
                udelay(10);
        }
        
-       snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg);
+       dev_err(chip->card->dev,
+               "AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg);
        result = 0xffff;
        goto __end;
 
@@ -835,8 +838,9 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream)
        struct cs4281 *chip = snd_pcm_substream_chip(substream);
 
        /*
-       printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
-              snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
+       dev_dbg(chip->card->dev,
+               "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
+               snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
               jiffies);
        */
        return runtime->buffer_size -
@@ -1265,7 +1269,8 @@ static int snd_cs4281_create_gameport(struct cs4281 *chip)
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                return -ENOMEM;
        }
 
@@ -1361,7 +1366,7 @@ static int snd_cs4281_create(struct snd_card *card,
        chip->irq = -1;
        pci_set_master(pci);
        if (dual_codec < 0 || dual_codec > 3) {
-               snd_printk(KERN_ERR "invalid dual_codec option %d\n", dual_codec);
+               dev_err(card->dev, "invalid dual_codec option %d\n", dual_codec);
                dual_codec = 0;
        }
        chip->dual_codec = dual_codec;
@@ -1383,7 +1388,7 @@ static int snd_cs4281_create(struct snd_card *card,
        
        if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_cs4281_free(chip);
                return -ENOMEM;
        }
@@ -1402,8 +1407,6 @@ static int snd_cs4281_create(struct snd_card *card,
 
        snd_cs4281_proc_init(chip);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        return 0;
 }
@@ -1425,7 +1428,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT);
                tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);
                if (tmp != BA0_CFLR_DEFAULT) {
-                       snd_printk(KERN_ERR "CFLR setup failed (0x%x)\n", tmp);
+                       dev_err(chip->card->dev,
+                               "CFLR setup failed (0x%x)\n", tmp);
                        return -EIO;
                }
        }
@@ -1436,11 +1440,13 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
        snd_cs4281_pokeBA0(chip, BA0_CWPR, 0x4281);
        
        if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) {
-               snd_printk(KERN_ERR "SERC1 AC'97 check failed (0x%x)\n", tmp);
+               dev_err(chip->card->dev,
+                       "SERC1 AC'97 check failed (0x%x)\n", tmp);
                return -EIO;
        }
        if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) {
-               snd_printk(KERN_ERR "SERC2 AC'97 check failed (0x%x)\n", tmp);
+               dev_err(chip->card->dev,
+                       "SERC2 AC'97 check failed (0x%x)\n", tmp);
                return -EIO;
        }
 
@@ -1502,7 +1508,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                schedule_timeout_uninterruptible(1);
        } while (time_after_eq(end_time, jiffies));
 
-       snd_printk(KERN_ERR "DLLRDY not seen\n");
+       dev_err(chip->card->dev, "DLLRDY not seen\n");
        return -EIO;
 
       __ok0:
@@ -1528,7 +1534,9 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                schedule_timeout_uninterruptible(1);
        } while (time_after_eq(end_time, jiffies));
 
-       snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
+       dev_err(chip->card->dev,
+               "never read codec ready from AC'97 (0x%x)\n",
+               snd_cs4281_peekBA0(chip, BA0_ACSTS));
        return -EIO;
 
       __ok1:
@@ -1539,7 +1547,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                                goto __codec2_ok;
                        schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
-               snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
+               dev_info(chip->card->dev,
+                        "secondary codec doesn't respond. disable it...\n");
                chip->dual_codec = 0;
        __codec2_ok: ;
        }
@@ -1569,7 +1578,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
 
        if (--retry_count > 0)
                goto __retry;
-       snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n");
+       dev_err(chip->card->dev, "never read ISV3 and ISV4 from AC'97\n");
        return -EIO;
 
       __ok2:
@@ -1917,7 +1926,8 @@ static int snd_cs4281_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -2055,8 +2065,7 @@ static int cs4281_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "cs4281: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index b03498325d661d091ca18d84614fdebd1fb22032..af0eacbc8bd2097ab6c5112b116381194d7db730 100644 (file)
@@ -88,7 +88,8 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        if ((err = snd_cs46xx_create(card, pci,
index 062398ec5335f613b2b8e78e49d6374fc98bcdfc..32b44f25b5c8240a8b40e414a2e09ec7d43b2cc8 100644 (file)
@@ -116,7 +116,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
 
        tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL);
        if ((tmp & ACCTL_VFRM) == 0) {
-               snd_printk(KERN_WARNING  "cs46xx: ACCTL_VFRM not set 0x%x\n",tmp);
+               dev_warn(chip->card->dev, "ACCTL_VFRM not set 0x%x\n", tmp);
                snd_cs46xx_pokeBA0(chip, BA0_ACCTL, (tmp & (~ACCTL_ESYN)) | ACCTL_VFRM );
                msleep(50);
                tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL + offset);
@@ -168,7 +168,8 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
                        goto ok1;
        }
 
-       snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
+       dev_err(chip->card->dev,
+               "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
        result = 0xffff;
        goto end;
        
@@ -187,7 +188,9 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
                udelay(10);
        }
        
-       snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", codec_index, reg);
+       dev_err(chip->card->dev,
+               "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n",
+               codec_index, reg);
        result = 0xffff;
        goto end;
 
@@ -197,7 +200,8 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
         *  ACSDA = Status Data Register = 474h
         */
 #if 0
-       printk(KERN_DEBUG "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
+       dev_dbg(chip->card->dev,
+               "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
                        snd_cs46xx_peekBA0(chip, BA0_ACSDA),
                        snd_cs46xx_peekBA0(chip, BA0_ACCAD));
 #endif
@@ -286,7 +290,9 @@ static void snd_cs46xx_codec_write(struct snd_cs46xx *chip,
                        goto end;
                }
        }
-       snd_printk(KERN_ERR "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", codec_index, reg, val);
+       dev_err(chip->card->dev,
+               "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n",
+               codec_index, reg, val);
  end:
        chip->active_ctrl(chip, -1);
 }
@@ -608,8 +614,8 @@ static int cs46xx_wait_for_fifo(struct snd_cs46xx * chip,int retry_timeout)
        }
   
        if(status & SERBST_WBSY) {
-               snd_printk(KERN_ERR "cs46xx: failure waiting for "
-                          "FIFO command to complete\n");
+               dev_err(chip->card->dev,
+                       "failure waiting for FIFO command to complete\n");
                return -EINVAL;
        }
 
@@ -646,7 +652,9 @@ static void snd_cs46xx_clear_serial_FIFOs(struct snd_cs46xx *chip)
                 *  Make sure the previous FIFO write operation has completed.
                 */
                if (cs46xx_wait_for_fifo(chip,1)) {
-                       snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx);
+                       dev_dbg(chip->card->dev,
+                               "failed waiting for FIFO at addr (%02X)\n",
+                               idx);
 
                        if (powerdown)
                                snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);
@@ -694,7 +702,7 @@ static void snd_cs46xx_proc_start(struct snd_cs46xx *chip)
        }
 
        if (snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR)
-               snd_printk(KERN_ERR "SPCR_RUNFR never reset\n");
+               dev_err(chip->card->dev, "SPCR_RUNFR never reset\n");
 }
 
 static void snd_cs46xx_proc_stop(struct snd_cs46xx *chip)
@@ -1054,7 +1062,8 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x
                cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, 
                                                                   cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id);
                if (cpcm->pcm_channel == NULL) {
-                       snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
+                       dev_err(chip->card->dev,
+                               "failed to create virtual PCM channel\n");
                        return -ENOMEM;
                }
                cpcm->pcm_channel->sample_rate = sample_rate;
@@ -1067,7 +1076,8 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x
                if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, 
                                                                         cpcm->hw_buf.addr,
                                                                         cpcm->pcm_channel_id)) == NULL) {
-                       snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
+                       dev_err(chip->card->dev,
+                               "failed to re-create virtual PCM channel\n");
                        return -ENOMEM;
                }
 
@@ -1116,7 +1126,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
                 return -EINVAL;
         }
 
-       snd_printdd ("period_size (%d), periods (%d) buffer_size(%d)\n",
+       dev_dbg(chip->card->dev,
+               "period_size (%d), periods (%d) buffer_size(%d)\n",
                     period_size, params_periods(hw_params),
                     params_buffer_bytes(hw_params));
 #endif
@@ -1531,22 +1542,20 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in
 
 static int snd_cs46xx_playback_open(struct snd_pcm_substream *substream)
 {
-       snd_printdd("open front channel\n");
+       dev_dbg(substream->pcm->card->dev, "open front channel\n");
        return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL);
 }
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 static int snd_cs46xx_playback_open_rear(struct snd_pcm_substream *substream)
 {
-       snd_printdd("open rear channel\n");
-
+       dev_dbg(substream->pcm->card->dev, "open rear channel\n");
        return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL);
 }
 
 static int snd_cs46xx_playback_open_clfe(struct snd_pcm_substream *substream)
 {
-       snd_printdd("open center - LFE channel\n");
-
+       dev_dbg(substream->pcm->card->dev, "open center - LFE channel\n");
        return _cs46xx_playback_open_channel(substream,DSP_PCM_CENTER_LFE_CHANNEL);
 }
 
@@ -1554,7 +1563,7 @@ static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream)
 {
        struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
 
-       snd_printdd("open raw iec958 channel\n");
+       dev_dbg(chip->card->dev, "open raw iec958 channel\n");
 
        mutex_lock(&chip->spos_mutex);
        cs46xx_iec958_pre_open (chip);
@@ -1570,7 +1579,7 @@ static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream)
        int err;
        struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
   
-       snd_printdd("close raw iec958 channel\n");
+       dev_dbg(chip->card->dev, "close raw iec958 channel\n");
 
        err = snd_cs46xx_playback_close(substream);
 
@@ -2421,10 +2430,10 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
 
        /* set the desired CODEC mode */
        if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) {
-               snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0);
+               dev_dbg(ac97->bus->card->dev, "CODEC1 mode %04x\n", 0x0);
                snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0);
        } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) {
-               snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3);
+               dev_dbg(ac97->bus->card->dev, "CODEC2 mode %04x\n", 0x3);
                snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3);
        } else {
                snd_BUG(); /* should never happen ... */
@@ -2456,7 +2465,8 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
                msleep(10);
        } while (time_after_eq(end_time, jiffies));
 
-       snd_printk(KERN_ERR "CS46xx secondary codec doesn't respond!\n");  
+       dev_err(ac97->bus->card->dev,
+               "CS46xx secondary codec doesn't respond!\n");
 }
 #endif
 
@@ -2476,7 +2486,8 @@ static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec)
                snd_cs46xx_codec_write(chip, AC97_RESET, 0, codec);
                udelay(10);
                if (snd_cs46xx_codec_read(chip, AC97_RESET, codec) & 0x8000) {
-                       snd_printdd("snd_cs46xx: seconadry codec not present\n");
+                       dev_dbg(chip->card->dev,
+                               "seconadry codec not present\n");
                        return -ENXIO;
                }
        }
@@ -2489,7 +2500,7 @@ static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec)
                }
                msleep(10);
        }
-       snd_printdd("snd_cs46xx: codec %d detection timeout\n", codec);
+       dev_dbg(chip->card->dev, "codec %d detection timeout\n", codec);
        return -ENXIO;
 }
 
@@ -2509,7 +2520,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
 
        /* detect primary codec */
        chip->nr_ac97_codecs = 0;
-       snd_printdd("snd_cs46xx: detecting primary codec\n");
+       dev_dbg(chip->card->dev, "detecting primary codec\n");
        if ((err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus)) < 0)
                return err;
        chip->ac97_bus->private_free = snd_cs46xx_mixer_free_ac97_bus;
@@ -2519,7 +2530,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
        chip->nr_ac97_codecs = 1;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-       snd_printdd("snd_cs46xx: detecting seconadry codec\n");
+       dev_dbg(chip->card->dev, "detecting seconadry codec\n");
        /* try detect a secondary codec */
        if (! cs46xx_detect_codec(chip, CS46XX_SECONDARY_CODEC_INDEX))
                chip->nr_ac97_codecs = 2;
@@ -2554,7 +2565,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
        }
        /* do soundcard specific mixer setup */
        if (chip->mixer_init) {
-               snd_printdd ("calling chip->mixer_init(chip);\n");
+               dev_dbg(chip->card->dev, "calling chip->mixer_init(chip);\n");
                chip->mixer_init(chip);
        }
 #endif
@@ -2801,7 +2812,8 @@ int snd_cs46xx_gameport(struct snd_cs46xx *chip)
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "cs46xx: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                return -ENOMEM;
        }
 
@@ -3138,8 +3150,10 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
        }
 
 
-       snd_printk(KERN_ERR "create - never read codec ready from AC'97\n");
-       snd_printk(KERN_ERR "it is not probably bug, try to use CS4236 driver\n");
+       dev_err(chip->card->dev,
+               "create - never read codec ready from AC'97\n");
+       dev_err(chip->card->dev,
+               "it is not probably bug, try to use CS4236 driver\n");
        return -EIO;
  ok1:
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -3157,7 +3171,8 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
                 *  Make sure CODEC is READY.
                 */
                if (!(snd_cs46xx_peekBA0(chip, BA0_ACSTS2) & ACSTS_CRDY))
-                       snd_printdd("cs46xx: never read card ready from secondary AC'97\n");
+                       dev_dbg(chip->card->dev,
+                               "never read card ready from secondary AC'97\n");
        }
 #endif
 
@@ -3187,17 +3202,21 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
        }
 
 #ifndef CONFIG_SND_CS46XX_NEW_DSP
-       snd_printk(KERN_ERR "create - never read ISV3 & ISV4 from AC'97\n");
+       dev_err(chip->card->dev,
+               "create - never read ISV3 & ISV4 from AC'97\n");
        return -EIO;
 #else
        /* This may happen on a cold boot with a Terratec SiXPack 5.1.
           Reloading the driver may help, if there's other soundcards 
           with the same problem I would like to know. (Benny) */
 
-       snd_printk(KERN_ERR "ERROR: snd-cs46xx: never read ISV3 & ISV4 from AC'97\n");
-       snd_printk(KERN_ERR "       Try reloading the ALSA driver, if you find something\n");
-        snd_printk(KERN_ERR "       broken or not working on your soundcard upon\n");
-       snd_printk(KERN_ERR "       this message please report to alsa-devel@alsa-project.org\n");
+       dev_err(chip->card->dev, "never read ISV3 & ISV4 from AC'97\n");
+       dev_err(chip->card->dev,
+               "Try reloading the ALSA driver, if you find something\n");
+       dev_err(chip->card->dev,
+               "broken or not working on your soundcard upon\n");
+       dev_err(chip->card->dev,
+               "this message please report to alsa-devel@alsa-project.org\n");
 
        return -EIO;
 #endif
@@ -3266,13 +3285,13 @@ int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
        for (i = 0; i < CS46XX_DSP_MODULES; i++) {
                err = load_firmware(chip, &chip->modules[i], module_names[i]);
                if (err < 0) {
-                       snd_printk(KERN_ERR "firmware load error [%s]\n",
+                       dev_err(chip->card->dev, "firmware load error [%s]\n",
                                   module_names[i]);
                        return err;
                }
                err = cs46xx_dsp_load_module(chip, chip->modules[i]);
                if (err < 0) {
-                       snd_printk(KERN_ERR "image download error [%s]\n",
+                       dev_err(chip->card->dev, "image download error [%s]\n",
                                   module_names[i]);
                        return err;
                }
@@ -3288,7 +3307,7 @@ int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
        /* old image */
        err = snd_cs46xx_download_image(chip);
        if (err < 0) {
-               snd_printk(KERN_ERR "image download error\n");
+               dev_err(chip->card->dev, "image download error\n");
                return err;
        }
 
@@ -3341,7 +3360,7 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
        u32 idx, valid_slots,tmp,powerdown = 0;
        u16 modem_power,pin_config,logic_type;
 
-       snd_printdd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
+       dev_dbg(chip->card->dev, "cs46xx_setup_eapd_slot()+\n");
 
        /*
         *  See if the devices are powered down.  If so, we must power them up first
@@ -3359,7 +3378,8 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
         * stuff.
         */
        if(chip->nr_ac97_codecs != 2) {
-               snd_printk (KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() - no secondary codec configured\n");
+               dev_err(chip->card->dev,
+                       "cs46xx_setup_eapd_slot() - no secondary codec configured\n");
                return -EINVAL;
        }
 
@@ -3400,7 +3420,7 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
        snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
 
        if ( cs46xx_wait_for_fifo(chip,1) ) {
-         snd_printdd("FIFO is busy\n");
+               dev_dbg(chip->card->dev, "FIFO is busy\n");
          
          return -EINVAL;
        }
@@ -3421,7 +3441,9 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
                 * Wait for command to complete
                 */
                if ( cs46xx_wait_for_fifo(chip,200) ) {
-                       snd_printdd("failed waiting for FIFO at addr (%02X)\n",idx);
+                       dev_dbg(chip->card->dev,
+                               "failed waiting for FIFO at addr (%02X)\n",
+                               idx);
 
                        return -EINVAL;
                }
@@ -3510,14 +3532,14 @@ static void amp_hercules(struct snd_cs46xx *chip, int change)
 
        chip->amplifier += change;
        if (chip->amplifier && !old) {
-               snd_printdd ("Hercules amplifier ON\n");
+               dev_dbg(chip->card->dev, "Hercules amplifier ON\n");
 
                snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, 
                                   EGPIODR_GPOE2 | val1);     /* enable EGPIO2 output */
                snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, 
                                   EGPIOPTR_GPPT2 | val2);   /* open-drain on output */
        } else if (old && !chip->amplifier) {
-               snd_printdd ("Hercules amplifier OFF\n");
+               dev_dbg(chip->card->dev, "Hercules amplifier OFF\n");
                snd_cs46xx_pokeBA0(chip, BA0_EGPIODR,  val1 & ~EGPIODR_GPOE2); /* disable */
                snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, val2 & ~EGPIOPTR_GPPT2); /* disable */
        }
@@ -3525,7 +3547,7 @@ static void amp_hercules(struct snd_cs46xx *chip, int change)
 
 static void voyetra_mixer_init (struct snd_cs46xx *chip)
 {
-       snd_printdd ("initializing Voyetra mixer\n");
+       dev_dbg(chip->card->dev, "initializing Voyetra mixer\n");
 
        /* Enable SPDIF out */
        snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0);
@@ -3543,7 +3565,7 @@ static void hercules_mixer_init (struct snd_cs46xx *chip)
        /* set EGPIO to default */
        hercules_init(chip);
 
-       snd_printdd ("initializing Hercules mixer\n");
+       dev_dbg(chip->card->dev, "initializing Hercules mixer\n");
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        if (chip->in_suspend)
@@ -3554,7 +3576,9 @@ static void hercules_mixer_init (struct snd_cs46xx *chip)
 
                kctl = snd_ctl_new1(&snd_hercules_controls[idx], chip);
                if ((err = snd_ctl_add(card, kctl)) < 0) {
-                       printk (KERN_ERR "cs46xx: failed to initialize Hercules mixer (%d)\n",err);
+                       dev_err(card->dev,
+                               "failed to initialize Hercules mixer (%d)\n",
+                               err);
                        break;
                }
        }
@@ -3826,8 +3850,7 @@ static int snd_cs46xx_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "cs46xx: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -3932,7 +3955,8 @@ int snd_cs46xx_create(struct snd_card *card,
        chip->ba1_addr = pci_resource_start(pci, 1);
        if (chip->ba0_addr == 0 || chip->ba0_addr == (unsigned long)~0 ||
            chip->ba1_addr == 0 || chip->ba1_addr == (unsigned long)~0) {
-               snd_printk(KERN_ERR "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n",
+               dev_err(chip->card->dev,
+                       "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n",
                           chip->ba0_addr, chip->ba1_addr);
                snd_cs46xx_free(chip);
                return -ENOMEM;
@@ -3969,7 +3993,8 @@ int snd_cs46xx_create(struct snd_card *card,
 
        for (cp = &cards[0]; cp->name; cp++) {
                if (cp->vendor == ss_vendor && cp->id == ss_card) {
-                       snd_printdd ("hack for %s enabled\n", cp->name);
+                       dev_dbg(chip->card->dev, "hack for %s enabled\n",
+                               cp->name);
 
                        chip->amplifier_ctrl = cp->amp;
                        chip->active_ctrl = cp->active;
@@ -3982,12 +4007,14 @@ int snd_cs46xx_create(struct snd_card *card,
        }
 
        if (external_amp) {
-               snd_printk(KERN_INFO "Crystal EAPD support forced on.\n");
+               dev_info(chip->card->dev,
+                        "Crystal EAPD support forced on.\n");
                chip->amplifier_ctrl = amp_voyetra;
        }
 
        if (thinkpad) {
-               snd_printk(KERN_INFO "Activating CLKRUN hack for Thinkpad.\n");
+               dev_info(chip->card->dev,
+                        "Activating CLKRUN hack for Thinkpad.\n");
                chip->active_ctrl = clkrun_hack;
                clkrun_init(chip);
        }
@@ -4005,14 +4032,16 @@ int snd_cs46xx_create(struct snd_card *card,
                region = &chip->region.idx[idx];
                if ((region->resource = request_mem_region(region->base, region->size,
                                                           region->name)) == NULL) {
-                       snd_printk(KERN_ERR "unable to request memory region 0x%lx-0x%lx\n",
+                       dev_err(chip->card->dev,
+                               "unable to request memory region 0x%lx-0x%lx\n",
                                   region->base, region->base + region->size - 1);
                        snd_cs46xx_free(chip);
                        return -EBUSY;
                }
                region->remap_addr = ioremap_nocache(region->base, region->size);
                if (region->remap_addr == NULL) {
-                       snd_printk(KERN_ERR "%s ioremap problem\n", region->name);
+                       dev_err(chip->card->dev,
+                               "%s ioremap problem\n", region->name);
                        snd_cs46xx_free(chip);
                        return -ENOMEM;
                }
@@ -4020,7 +4049,7 @@ int snd_cs46xx_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_cs46xx_free(chip);
                return -EBUSY;
        }
@@ -4058,8 +4087,6 @@ int snd_cs46xx_create(struct snd_card *card,
 
        chip->active_ctrl(chip, -1); /* disable CLKRUN */
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        return 0;
 }
index 1686b4f4c44fb493538ada5bf14f4965ed645443..1c4a0fb3ffefd4144b32acfc4f81fdb2bd19259c 100644 (file)
@@ -85,12 +85,15 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
                                                address  = (hival & 0x00FFF) << 5;
                                                address |=  loval >> 15;
             
-                                               snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address);
+                                               dev_dbg(chip->card->dev,
+                                                       "handle_wideop[1]: %05x:%05x addr %04x\n",
+                                                       hival, loval, address);
             
                                                if ( !(address & 0x8000) ) {
                                                        address += (ins->code.offset / 2) - overlay_begin_address;
                                                } else {
-                                                       snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n");
+                                                       dev_dbg(chip->card->dev,
+                                                               "handle_wideop[1]: ROM symbol not reallocated\n");
                                                }
             
                                                hival &= 0xFF000;
@@ -102,8 +105,9 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
                                                address  = (hival & 0x00FFF) << 5;
                                                address |=  loval >> 15;
             
-                                               snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address);            
-                                               nreallocated ++;
+                                               dev_dbg(chip->card->dev,
+                                                       "handle_wideop:[2] %05x:%05x addr %04x\n",
+                                                       hival, loval, address);                                         nreallocated++;
                                        } /* wide_opcodes[j] == wide_op */
                                } /* for */
                        } /* mod_type == 0 ... */
@@ -113,7 +117,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
                ins->code.data[ins->code.size++] = hival;
        }
 
-       snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated);
+       dev_dbg(chip->card->dev,
+               "dsp_spos: %d instructions reallocated\n", nreallocated);
        return nreallocated;
 }
 
@@ -157,7 +162,8 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul
 
        for (i = 0;i < module->symbol_table.nsymbols; ++i) {
                if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
-                       snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: symbol table is full\n");
                        return -ENOMEM;
                }
 
@@ -176,8 +182,11 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul
 
                        ins->symbol_table.nsymbols++;
                } else {
-          /* if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
-                             module->symbol_table.symbols[i].symbol_name); */
+#if 0
+                       dev_dbg(chip->card->dev,
+                               "dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
+                               module->symbol_table.symbols[i].symbol_name); */
+#endif
                }
        }
 
@@ -192,14 +201,15 @@ add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type)
        int index;
 
        if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
-               snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
+               dev_err(chip->card->dev, "dsp_spos: symbol table is full\n");
                return NULL;
        }
   
        if (cs46xx_dsp_lookup_symbol(chip,
                                     symbol_name,
                                     type) != NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name);
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol <%s> duplicated\n", symbol_name);
                return NULL;
        }
 
@@ -305,19 +315,20 @@ static int dsp_load_parameter(struct snd_cs46xx *chip,
        u32 doffset, dsize;
 
        if (!parameter) {
-               snd_printdd("dsp_spos: module got no parameter segment\n");
+               dev_dbg(chip->card->dev,
+                       "dsp_spos: module got no parameter segment\n");
                return 0;
        }
 
        doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
        dsize   = parameter->size * 4;
 
-       snd_printdd("dsp_spos: "
-                   "downloading parameter data to chip (%08x-%08x)\n",
+       dev_dbg(chip->card->dev,
+               "dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
                    doffset,doffset + dsize);
        if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
-               snd_printk(KERN_ERR "dsp_spos: "
-                          "failed to download parameter data to DSP\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: failed to download parameter data to DSP\n");
                return -EINVAL;
        }
        return 0;
@@ -329,18 +340,21 @@ static int dsp_load_sample(struct snd_cs46xx *chip,
        u32 doffset, dsize;
 
        if (!sample) {
-               snd_printdd("dsp_spos: module got no sample segment\n");
+               dev_dbg(chip->card->dev,
+                       "dsp_spos: module got no sample segment\n");
                return 0;
        }
 
        doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
        dsize   =  sample->size * 4;
 
-       snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+       dev_dbg(chip->card->dev,
+               "dsp_spos: downloading sample data to chip (%08x-%08x)\n",
                    doffset,doffset + dsize);
 
        if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
-               snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: failed to sample data to DSP\n");
                return -EINVAL;
        }
        return 0;
@@ -354,14 +368,16 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
        int err;
 
        if (ins->nmodules == DSP_MAX_MODULES - 1) {
-               snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: to many modules loaded into DSP\n");
                return -ENOMEM;
        }
 
-       snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name);
+       dev_dbg(chip->card->dev,
+               "dsp_spos: loading module %s into DSP\n", module->module_name);
   
        if (ins->nmodules == 0) {
-               snd_printdd("dsp_spos: clearing parameter area\n");
+               dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n");
                snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
        }
   
@@ -371,7 +387,7 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
                return err;
 
        if (ins->nmodules == 0) {
-               snd_printdd("dsp_spos: clearing sample area\n");
+               dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n");
                snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
        }
 
@@ -381,15 +397,17 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
                return err;
 
        if (ins->nmodules == 0) {
-               snd_printdd("dsp_spos: clearing code area\n");
+               dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n");
                snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
        }
 
        if (code == NULL) {
-               snd_printdd("dsp_spos: module got no code segment\n");
+               dev_dbg(chip->card->dev,
+                       "dsp_spos: module got no code segment\n");
        } else {
                if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
-                       snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: no space available in DSP\n");
                        return -ENOMEM;
                }
 
@@ -401,19 +419,22 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
                if (snd_BUG_ON(!module->symbol_table.symbols))
                        return -ENOMEM;
                if (add_symbols(chip,module)) {
-                       snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: failed to load symbol table\n");
                        return -ENOMEM;
                }
     
                doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
                dsize   = code->size * 4;
-               snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n",
+               dev_dbg(chip->card->dev,
+                       "dsp_spos: downloading code to chip (%08x-%08x)\n",
                            doffset,doffset + dsize);   
 
                module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
 
                if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
-                       snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: failed to download code to DSP\n");
                        return -EINVAL;
                }
 
@@ -447,7 +468,7 @@ cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symb
        }
 
 #if 0
-       printk ("dsp_spos: symbol <%s> type %02x not found\n",
+       dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n",
                symbol_name,symbol_type);
 #endif
 
@@ -910,7 +931,6 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
 }
 #endif /* CONFIG_PROC_FS */
 
-static int debug_tree;
 static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
                                   u32  dest, int size)
 {
@@ -919,13 +939,13 @@ static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
        int i;
 
        for (i = 0; i < size; ++i) {
-               if (debug_tree) printk ("addr %p, val %08x\n",spdst,task_data[i]);
+               dev_dbg(chip->card->dev, "addr %p, val %08x\n",
+                       spdst, task_data[i]);
                writel(task_data[i],spdst);
                spdst += sizeof(u32);
        }
 }
 
-static int debug_scb;
 static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
 {
        void __iomem *spdst = chip->region.idx[1].remap_addr + 
@@ -933,7 +953,8 @@ static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
        int i;
 
        for (i = 0; i < 0x10; ++i) {
-               if (debug_scb) printk ("addr %p, val %08x\n",spdst,scb_data[i]);
+               dev_dbg(chip->card->dev, "addr %p, val %08x\n",
+                       spdst, scb_data[i]);
                writel(scb_data[i],spdst);
                spdst += sizeof(u32);
        }
@@ -960,7 +981,8 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam
        int index;
 
        if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
-               snd_printk(KERN_ERR "dsp_spos: got no place for other SCB\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: got no place for other SCB\n");
                return NULL;
        }
 
@@ -991,7 +1013,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
        struct dsp_task_descriptor * desc = NULL;
 
        if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
-               snd_printk(KERN_ERR "dsp_spos: got no place for other TASK\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: got no place for other TASK\n");
                return NULL;
        }
 
@@ -1031,7 +1054,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
                desc->data = scb_data;
                _dsp_create_scb(chip,scb_data,dest);
        } else {
-               snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
+               dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n");
 #ifdef CONFIG_PM_SLEEP
                kfree(scb_data);
 #endif
@@ -1052,7 +1075,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da
                desc->data = task_data;
                _dsp_create_task_tree(chip,task_data,dest,size);
        } else {
-               snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
+               dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n");
        }
 
        return desc;
@@ -1105,31 +1128,36 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
 
        null_algorithm  = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
        if (null_algorithm == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol NULLALGORITHM not found\n");
                return -EIO;
        }
 
        fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);  
        if (fg_task_tree_header_code == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
                return -EIO;
        }
 
        task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);  
        if (task_tree_header_code == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
                return -EIO;
        }
   
        task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
        if (task_tree_thread == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol TASKTREETHREAD not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol TASKTREETHREAD not found\n");
                return -EIO;
        }
 
        magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
        if (magic_snoop_task == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol MAGICSNOOPTASK not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol MAGICSNOOPTASK not found\n");
                return -EIO;
        }
   
@@ -1476,7 +1504,7 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
        return 0;
 
  _fail_end:
-       snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n");
+       dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n");
        return -EINVAL;
 }
 
@@ -1491,18 +1519,21 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
 
        s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
        if (s16_async_codec_input_task == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
                return -EIO;
        }
        spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
        if (spdifo_task == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol SPDIFOTASK not found\n");
                return -EIO;
        }
 
        spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
        if (spdifi_task == NULL) {
-               snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol SPDIFITASK not found\n");
                return -EIO;
        }
 
@@ -1883,7 +1914,8 @@ int cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data)
        }
 
        if (i == 25) {
-               snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: SPIOWriteTask not responding\n");
                return -EBUSY;
        }
 
index 409e8764fbeb2a3678b4c01446a699fc631bc2a5..8284bc9b585822a12ffba887a3233fd077af98b3 100644 (file)
@@ -233,8 +233,11 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
 {
        if (scb->proc_info) {
                struct proc_scb_info * scb_info = scb->proc_info->private_data;
+               struct snd_cs46xx *chip = scb_info->chip;
 
-               snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
+               dev_dbg(chip->card->dev,
+                       "cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
+                       scb->scb_name);
 
                snd_info_free_entry(scb->proc_info);
                scb->proc_info = NULL;
@@ -305,7 +308,7 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
        scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
        scb_data[SCBfuncEntryPtr] |= task_entry->address;
 
-       snd_printdd("dsp_spos: creating SCB <%s>\n",name);
+       dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
 
        scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
 
@@ -320,9 +323,15 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
        /* update parent SCB */
        if (scb->parent_scb_ptr) {
 #if 0
-               printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
-               printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
-               printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
+               dev_dbg(chip->card->dev,
+                       "scb->parent_scb_ptr = %s\n",
+                       scb->parent_scb_ptr->scb_name);
+               dev_dbg(chip->card->dev,
+                       "scb->parent_scb_ptr->next_scb_ptr = %s\n",
+                       scb->parent_scb_ptr->next_scb_ptr->scb_name);
+               dev_dbg(chip->card->dev,
+                       "scb->parent_scb_ptr->sub_list_ptr = %s\n",
+                       scb->parent_scb_ptr->sub_list_ptr->scb_name);
 #endif
                /* link to  parent SCB */
                if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
@@ -368,7 +377,8 @@ cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_d
                                               SYMBOL_CODE);
   
        if (task_entry == NULL) {
-               snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
+               dev_err(chip->card->dev,
+                       "dsp_spos: symbol %s not found\n", task_entry_name);
                return NULL;
        }
   
@@ -582,7 +592,8 @@ cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
                                                                 SYMBOL_CODE);
     
                if (ins->null_algorithm == NULL) {
-                       snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: symbol NULLALGORITHM not found\n");
                        return NULL;
                }    
        }
@@ -612,7 +623,8 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
        unsigned int phiIncr;
        unsigned int correctionPerGOF, correctionPerSec;
 
-       snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
+       dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
+               scb_name, rate);
 
        /*
         *  Compute the values used to drive the actual sample rate conversion.
@@ -670,7 +682,8 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
                                                                 SYMBOL_CODE);
                        
                        if (ins->s16_up == NULL) {
-                               snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
+                               dev_err(chip->card->dev,
+                                       "dsp_spos: symbol S16_UPSRC not found\n");
                                return NULL;
                        }    
                }
@@ -1265,7 +1278,7 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
                   the Sample Rate Converted (which could
                   alter the raw data stream ...) */
                if (sample_rate == 48000) {
-                       snd_printdd ("IEC958 pass through\n");
+                       dev_dbg(chip->card->dev, "IEC958 pass through\n");
                        /* Hack to bypass creating a new SRC */
                        pass_through = 1;
                }
@@ -1299,13 +1312,14 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
        }
 
        if (pcm_index == -1) {
-               snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
+               dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
                return NULL;
        }
 
        if (src_scb == NULL) {
                if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
-                       snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: to many SRC instances\n!");
                        return NULL;
                }
 
@@ -1331,7 +1345,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
 
                snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
                
-               snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
+               dev_dbg(chip->card->dev,
+                       "dsp_spos: creating SRC \"%s\"\n", scb_name);
                src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
                                                         sample_rate,
                                                         src_output_buffer_addr[src_index],
@@ -1343,7 +1358,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
                                                         pass_through);
 
                if (!src_scb) {
-                       snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
+                       dev_err(chip->card->dev,
+                               "dsp_spos: failed to create SRCtaskSCB\n");
                        return NULL;
                }
 
@@ -1355,8 +1371,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
   
        snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
 
-       snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
-                 pcm_channel_id);
+       dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
+               scb_name, pcm_channel_id);
 
        pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
                                                   pcm_reader_buffer_addr[pcm_index],
@@ -1369,7 +1385,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
                            );
 
        if (!pcm_scb) {
-               snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
+               dev_err(chip->card->dev,
+                       "dsp_spos: failed to create PCMreaderSCB\n");
                return NULL;
        }
        
@@ -1419,7 +1436,8 @@ int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
                temp |= DMA_RQ_C1_SOURCE_MOD16;
                break; 
        default:
-               snd_printdd ("period size (%d) not supported by HW\n", period_size);
+               dev_dbg(chip->card->dev,
+                       "period size (%d) not supported by HW\n", period_size);
                return -EINVAL;
        }
 
@@ -1457,7 +1475,8 @@ int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
                temp |= DMA_RQ_C1_DEST_MOD16;
                break; 
        default:
-               snd_printdd ("period size (%d) not supported by HW\n", period_size);
+               dev_dbg(chip->card->dev,
+                       "period size (%d) not supported by HW\n", period_size);
                return -EINVAL;
        }
 
index c6b82c85e044b9eec35e212f2dc487452651430e..b4e0ff6a99a331b4b3e06ca3ccc3330251687d0d 100644 (file)
@@ -160,17 +160,17 @@ static int snd_cs5530_create(struct snd_card *card,
        sb_base = 0x220 + 0x20 * (map & 3);
 
        if (map & (1<<2))
-               printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base);
+               dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base);
        else {
-               printk(KERN_ERR "Could not find XpressAudio!\n");
+               dev_err(card->dev, "Could not find XpressAudio!\n");
                snd_cs5530_free(chip);
                return -ENODEV;
        }
 
        if (map & (1<<5))
-               printk(KERN_INFO "CS5530: MPU at 0x300\n");
+               dev_info(card->dev, "MPU at 0x300\n");
        else if (map & (1<<6))
-               printk(KERN_INFO "CS5530: MPU at 0x330\n");
+               dev_info(card->dev, "MPU at 0x330\n");
 
        irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
        dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
@@ -182,7 +182,7 @@ static int snd_cs5530_create(struct snd_card *card,
        else if (dma8 & 0x80)
                dma16 = 7;
        else {
-               printk(KERN_ERR "CS5530: No 16bit DMA enabled\n");
+               dev_err(card->dev, "No 16bit DMA enabled\n");
                snd_cs5530_free(chip);
                return -ENODEV;
        }
@@ -194,7 +194,7 @@ static int snd_cs5530_create(struct snd_card *card,
        else if (dma8 & 0x08)
                dma8 = 3;
        else {
-               printk(KERN_ERR "CS5530: No 8bit DMA enabled\n");
+               dev_err(card->dev, "No 8bit DMA enabled\n");
                snd_cs5530_free(chip);
                return -ENODEV;
        }
@@ -208,32 +208,31 @@ static int snd_cs5530_create(struct snd_card *card,
        else if (irq & 8)
                irq = 10;
        else {
-               printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n");
+               dev_err(card->dev, "SoundBlaster IRQ not set\n");
                snd_cs5530_free(chip);
                return -ENODEV;
        }
 
-       printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, 
-                                                                       dma16);
+       dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16);
 
        err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
                                                dma16, SB_HW_CS5530, &chip->sb);
        if (err < 0) {
-               printk(KERN_ERR "CS5530: Could not create SoundBlaster\n");
+               dev_err(card->dev, "Could not create SoundBlaster\n");
                snd_cs5530_free(chip);
                return err;
        }
 
        err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
        if (err < 0) {
-               printk(KERN_ERR "CS5530: Could not create PCM\n");
+               dev_err(card->dev, "Could not create PCM\n");
                snd_cs5530_free(chip);
                return err;
        }
 
        err = snd_sbmixer_new(chip->sb);
        if (err < 0) {
-               printk(KERN_ERR "CS5530: Could not create Mixer\n");
+               dev_err(card->dev, "Could not create Mixer\n");
                snd_cs5530_free(chip);
                return err;
        }
@@ -244,7 +243,6 @@ static int snd_cs5530_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
        *rchip = chip;
        return 0;
 }
@@ -264,7 +262,8 @@ static int snd_cs5530_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
 
        if (err < 0)
                return err;
index c0d2835344dab60a8f2fef5f934a103d6fdd933f..edcbbda5c48854a00b0bb00f4d530d18f7bbf43f 100644 (file)
@@ -84,7 +84,8 @@ static void wait_till_cmd_acked(struct cs5535audio *cs5535au, unsigned long time
                udelay(1);
        } while (--timeout);
        if (!timeout)
-               snd_printk(KERN_ERR "Failure writing to cs5535 codec\n");
+               dev_err(cs5535au->card->dev,
+                       "Failure writing to cs5535 codec\n");
 }
 
 static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
@@ -109,8 +110,9 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
                udelay(1);
        } while (--timeout);
        if (!timeout)
-               snd_printk(KERN_ERR "Failure reading codec reg 0x%x,"
-                                       "Last value=0x%x\n", reg, val);
+               dev_err(cs5535au->card->dev,
+                       "Failure reading codec reg 0x%x, Last value=0x%x\n",
+                       reg, val);
 
        return (unsigned short) val;
 }
@@ -168,7 +170,7 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
        olpc_prequirks(card, &ac97);
 
        if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
-               snd_printk(KERN_ERR "mixer failed\n");
+               dev_err(card->dev, "mixer failed\n");
                return err;
        }
 
@@ -176,7 +178,7 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
 
        err = olpc_quirks(card, cs5535au->ac97);
        if (err < 0) {
-               snd_printk(KERN_ERR "olpc quirks failed\n");
+               dev_err(card->dev, "olpc quirks failed\n");
                return err;
        }
 
@@ -194,8 +196,9 @@ static void process_bm0_irq(struct cs5535audio *cs5535au)
                dma = cs5535au->playback_substream->runtime->private_data;
                snd_pcm_period_elapsed(cs5535au->playback_substream);
        } else {
-               snd_printk(KERN_ERR "unexpected bm0 irq src, bm_stat=%x\n",
-                                       bm_stat);
+               dev_err(cs5535au->card->dev,
+                       "unexpected bm0 irq src, bm_stat=%x\n",
+                       bm_stat);
        }
 }
 
@@ -241,8 +244,9 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
                                process_bm1_irq(cs5535au);
                                break;
                        default:
-                               snd_printk(KERN_ERR "Unexpected irq src: "
-                                               "0x%x\n", acc_irq_stat);
+                               dev_err(cs5535au->card->dev,
+                                       "Unexpected irq src: 0x%x\n",
+                                       acc_irq_stat);
                                break;
                        }
                }
@@ -287,7 +291,7 @@ static int snd_cs5535audio_create(struct snd_card *card,
 
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-               printk(KERN_WARNING "unable to get 32bit dma\n");
+               dev_warn(card->dev, "unable to get 32bit dma\n");
                err = -ENXIO;
                goto pcifail;
        }
@@ -312,7 +316,7 @@ static int snd_cs5535audio_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_cs5535audio_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, cs5535au)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto sndfail;
        }
@@ -324,8 +328,6 @@ static int snd_cs5535audio_create(struct snd_card *card,
                                  cs5535au, &ops)) < 0)
                goto sndfail;
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rcs5535au = cs5535au;
        return 0;
 
@@ -353,7 +355,8 @@ static int snd_cs5535audio_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
index e6a44507d55700ef689d6b98438452a53b008a24..3b0fdaca8dc7cdc005dfa35f0844f55068988af5 100644 (file)
@@ -36,7 +36,8 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on)
        err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
                        1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT);
        if (err < 0) {
-               snd_printk(KERN_ERR "setting High Pass Filter - %d\n", err);
+               dev_err(ac97->bus->card->dev,
+                       "setting High Pass Filter - %d\n", err);
                return;
        }
 
@@ -58,7 +59,7 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on)
        err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
                        1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT);
        if (err < 0)
-               snd_printk(KERN_ERR "setting MIC Bias - %d\n", err);
+               dev_err(ac97->bus->card->dev, "setting MIC Bias - %d\n", err);
 }
 
 static int olpc_dc_info(struct snd_kcontrol *kctl,
@@ -153,7 +154,7 @@ int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
                return 0;
 
        if (gpio_request(OLPC_GPIO_MIC_AC, DRV_NAME)) {
-               printk(KERN_ERR DRV_NAME ": unable to allocate MIC GPIO\n");
+               dev_err(card->dev, "unable to allocate MIC GPIO\n");
                return -EIO;
        }
        gpio_direction_output(OLPC_GPIO_MIC_AC, 0);
index 9ab01a7047cfe3230bbf41c3944c1ab260887c02..9c2dc911d8d7f0fa8231ac5296e361c4097b47a4 100644 (file)
@@ -317,7 +317,7 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
                dma->ops->disable_dma(cs5535au);
                break;
        default:
-               snd_printk(KERN_ERR "unhandled trigger\n");
+               dev_err(cs5535au->card->dev, "unhandled trigger\n");
                err = -EINVAL;
                break;
        }
@@ -335,13 +335,13 @@ static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream
        dma = substream->runtime->private_data;
        curdma = dma->ops->read_dma_pntr(cs5535au);
        if (curdma < dma->buf_addr) {
-               snd_printk(KERN_ERR "curdma=%x < %x bufaddr.\n",
+               dev_err(cs5535au->card->dev, "curdma=%x < %x bufaddr.\n",
                                        curdma, dma->buf_addr);
                return 0;
        }
        curdma -= dma->buf_addr;
        if (curdma >= dma->buf_bytes) {
-               snd_printk(KERN_ERR "diff=%x >= %x buf_bytes.\n",
+               dev_err(cs5535au->card->dev, "diff=%x >= %x buf_bytes.\n",
                                        curdma, dma->buf_bytes);
                return 0;
        }
index 6c34def5986d76415eb87f07c227b694dc0005c4..34cc60057d0c45c34da1f852a87e19be252c5a3d 100644 (file)
@@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev)
        snd_cs5535audio_stop_hardware(cs5535au);
 
        if (pci_save_state(pci)) {
-               printk(KERN_ERR "cs5535audio: pci_save_state failed!\n");
+               dev_err(dev, "pci_save_state failed!\n");
                return -EIO;
        }
        pci_disable_device(pci);
@@ -94,8 +94,7 @@ static int snd_cs5535audio_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -113,7 +112,7 @@ static int snd_cs5535audio_resume(struct device *dev)
        } while (--timeout);
 
        if (!timeout)
-               snd_printk(KERN_ERR "Failure getting AC Link ready\n");
+               dev_err(cs5535au->card->dev, "Failure getting AC Link ready\n");
 
        /* set up rate regs, dma. actual initiation is done in trig */
        for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
index eb86829529eb3e7f56da61324f8f16a87f3a44c6..af632bd08323feaf0f9ab2d3098375e12f38d46b 100644 (file)
@@ -1739,8 +1739,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        if (err < 0)
                goto error1;
 
-       snd_card_set_dev(card, &pci->dev);
-
        *ratc = atc;
        return 0;
 
index d464ad2fc7b71632afd81df4ef0e3ea4dda265f2..98426d09c8bd7ac6e46dd7b49ef272fc0a99bfb8 100644 (file)
@@ -71,7 +71,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                dev++;
                return -ENOENT;
        }
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err)
                return err;
        if ((reference_rate != 48000) && (reference_rate != 44100)) {
index 05cfe551ce425b6d4049755688d6d76883e768c8..9f10c9e0df5e853950f9244487261454099a4d59 100644 (file)
@@ -58,7 +58,8 @@ static int get_firmware(const struct firmware **fw_entry,
        snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
        err = request_firmware(fw_entry, name, pci_device(chip));
        if (err < 0)
-               snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
+               dev_err(chip->card->dev,
+                       "get_firmware(): Firmware not available (%d)\n", err);
 #ifdef CONFIG_PM_SLEEP
        else
                chip->fw_cache[fw_index] = *fw_entry;
@@ -563,7 +564,7 @@ static int init_engine(struct snd_pcm_substream *substream,
        err = snd_pcm_lib_malloc_pages(substream,
                                       params_buffer_bytes(hw_params));
        if (err < 0) {
-               snd_printk(KERN_ERR "malloc_pages err=%d\n", err);
+               dev_err(chip->card->dev, "malloc_pages err=%d\n", err);
                spin_lock_irq(&chip->lock);
                free_pipes(chip, pipe);
                spin_unlock_irq(&chip->lock);
@@ -1989,8 +1990,8 @@ static int snd_echo_create(struct snd_card *card,
 
        if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,
                                              ECHOCARD_NAME)) == NULL) {
+               dev_err(chip->card->dev, "cannot get memory region\n");
                snd_echo_free(chip);
-               snd_printk(KERN_ERR "cannot get memory region\n");
                return -EBUSY;
        }
        chip->dsp_registers = (volatile u32 __iomem *)
@@ -1998,8 +1999,8 @@ static int snd_echo_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
+               dev_err(chip->card->dev, "cannot grab irq\n");
                snd_echo_free(chip);
-               snd_printk(KERN_ERR "cannot grab irq\n");
                return -EBUSY;
        }
        chip->irq = pci->irq;
@@ -2011,8 +2012,8 @@ static int snd_echo_create(struct snd_card *card,
        if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
                                sizeof(struct comm_page),
                                &chip->commpage_dma_buf) < 0) {
+               dev_err(chip->card->dev, "cannot allocate the comm page\n");
                snd_echo_free(chip);
-               snd_printk(KERN_ERR "cannot allocate the comm page\n");
                return -ENOMEM;
        }
        chip->comm_page_phys = chip->commpage_dma_buf.addr;
@@ -2058,12 +2059,11 @@ static int snd_echo_probe(struct pci_dev *pci,
 
        DE_INIT(("Echoaudio driver starting...\n"));
        i = 0;
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
-       snd_card_set_dev(card, &pci->dev);
-
        chip = NULL;    /* Tells snd_echo_create to allocate chip */
        if ((err = snd_echo_create(card, pci, &chip)) < 0) {
                snd_card_free(card);
@@ -2082,7 +2082,7 @@ static int snd_echo_probe(struct pci_dev *pci,
                chip->dsp_registers_phys, chip->irq);
 
        if ((err = snd_echo_new_pcm(chip)) < 0) {
-               snd_printk(KERN_ERR "new pcm error %d\n", err);
+               dev_err(chip->card->dev, "new pcm error %d\n", err);
                snd_card_free(card);
                return err;
        }
@@ -2090,7 +2090,7 @@ static int snd_echo_probe(struct pci_dev *pci,
 #ifdef ECHOCARD_HAS_MIDI
        if (chip->has_midi) {   /* Some Mia's do not have midi */
                if ((err = snd_echo_midi_create(card, chip)) < 0) {
-                       snd_printk(KERN_ERR "new midi error %d\n", err);
+                       dev_err(chip->card->dev, "new midi error %d\n", err);
                        snd_card_free(card);
                        return err;
                }
@@ -2189,14 +2189,14 @@ static int snd_echo_probe(struct pci_dev *pci,
        err = snd_card_register(card);
        if (err < 0)
                goto ctl_error;
-       snd_printk(KERN_INFO "Card registered: %s\n", card->longname);
+       dev_info(card->dev, "Card registered: %s\n", card->longname);
 
        pci_set_drvdata(pci, chip);
        dev++;
        return 0;
 
 ctl_error:
-       snd_printk(KERN_ERR "new control error %d\n", err);
+       dev_err(card->dev, "new control error %d\n", err);
        snd_card_free(card);
        return err;
 }
@@ -2291,8 +2291,8 @@ static int snd_echo_resume(struct device *dev)
 
        if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
+               dev_err(chip->card->dev, "cannot grab irq\n");
                snd_echo_free(chip);
-               snd_printk(KERN_ERR "cannot grab irq\n");
                return -EBUSY;
        }
        chip->irq = pci->irq;
index d8c670c9d62c4e35cab25ac6e36d09466e2716d9..5a6a217b82e0ae47cd43607a9908663530a1bf1d 100644 (file)
@@ -53,7 +53,7 @@ static int wait_handshake(struct echoaudio *chip)
                udelay(1);
        }
 
-       snd_printk(KERN_ERR "wait_handshake(): Timeout waiting for DSP\n");
+       dev_err(chip->card->dev, "wait_handshake(): Timeout waiting for DSP\n");
        return -EBUSY;
 }
 
@@ -149,7 +149,8 @@ static int read_sn(struct echoaudio *chip)
 
        for (i = 0; i < 5; i++) {
                if (read_dsp(chip, &sn[i])) {
-                       snd_printk(KERN_ERR "Failed to read serial number\n");
+                       dev_err(chip->card->dev,
+                               "Failed to read serial number\n");
                        return -EIO;
                }
        }
@@ -184,7 +185,7 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
 
        err = get_firmware(&fw, chip, asic);
        if (err < 0) {
-               snd_printk(KERN_WARNING "Firmware not found !\n");
+               dev_warn(chip->card->dev, "Firmware not found !\n");
                return err;
        }
 
@@ -247,7 +248,7 @@ static int install_resident_loader(struct echoaudio *chip)
 
        i = get_firmware(&fw, chip, FW_361_LOADER);
        if (i < 0) {
-               snd_printk(KERN_WARNING "Firmware not found !\n");
+               dev_warn(chip->card->dev, "Firmware not found !\n");
                return i;
        }
 
index abfd51c2530ed9172cba8e98fef3714ad4e6b690..7f4dfae0323ad4f8bd8a83b4389b102d7aa5bccc 100644 (file)
@@ -221,7 +221,8 @@ static void snd_echo_midi_output_write(unsigned long data)
                DE_MID(("Try to send %d bytes...\n", bytes));
                sent = write_midi(chip, buf, bytes);
                if (sent < 0) {
-                       snd_printk(KERN_ERR "write_midi() error %d\n", sent);
+                       dev_err(chip->card->dev,
+                               "write_midi() error %d\n", sent);
                        /* retry later */
                        sent = 9000;
                        chip->midi_full = 1;
index 9e1bd0c39a8cf27230bd50196a525d1c2c3f525d..ad9d9f8b48ed0d5bc737a04bfeab404ac20179d2 100644 (file)
@@ -117,7 +117,8 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        if (max_buffer_size[dev] < 32)
@@ -169,7 +170,8 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
        if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
                               sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 ||
            wave == NULL) {
-               snd_printk(KERN_WARNING "can't initialize Emu10k1 wavetable synth\n");
+               dev_warn(emu->card->dev,
+                        "can't initialize Emu10k1 wavetable synth\n");
        } else {
                struct snd_emu10k1_synth_arg *arg;
                arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
@@ -246,8 +248,7 @@ static int snd_emu10k1_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "emu10k1: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index cae36597aa718c3fc13abe95221a2308627c2c8c..3f3ef38d9b6e5f9facddfbddb0d1b2ebfaa8c7d9 100644 (file)
@@ -105,7 +105,7 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
                        vp = &emu->voices[best[i].voice];
                        if ((ch = vp->ch) < 0) {
                                /*
-                               printk(KERN_WARNING
+                               dev_warn(emu->card->dev,
                                       "synth_get_voice: ch < 0 (%d) ??", i);
                                */
                                continue;
@@ -339,7 +339,7 @@ start_voice(struct snd_emux_voice *vp)
                return -EINVAL;
        emem->map_locked++;
        if (snd_emu10k1_memblk_map(hw, emem) < 0) {
-               /* printk(KERN_ERR "emu: cannot map!\n"); */
+               /* dev_err(hw->card->devK, "emu: cannot map!\n"); */
                return -ENOMEM;
        }
        mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1;
index bdd888ec9a8422838144fd93e8c8b8cff92ee4fe..2292697880235b8dd6c440064ba9a7b266d6d370 100644 (file)
@@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
        }
        if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
                /* Hacks for Alice3 to work independent of haP16V driver */
-               snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
+               dev_info(emu->card->dev, "Audigy2 value: Special config.\n");
                /* Setup SRCMulti_I2S SamplingRate */
                tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
                tmp &= 0xfffff1ff;
@@ -723,7 +723,8 @@ static int emu1010_firmware_thread(void *data)
                if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
                        /* Audio Dock attached */
                        /* Return to Audio Dock programming mode */
-                       snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
+                       dev_info(emu->card->dev,
+                                "emu1010: Loading Audio Dock Firmware\n");
                        snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK);
 
                        if (!emu->dock_fw) {
@@ -756,19 +757,25 @@ static int emu1010_firmware_thread(void *data)
 
                        snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
                        snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);
-                       snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg);
+                       dev_info(emu->card->dev,
+                                "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n",
+                                reg);
                        /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
                        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
-                       snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
+                       dev_info(emu->card->dev,
+                                "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
                        if ((reg & 0x1f) != 0x15) {
                                /* FPGA failed to be programmed */
-                               snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg);
+                               dev_info(emu->card->dev,
+                                        "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
+                                        reg);
                                continue;
                        }
-                       snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
+                       dev_info(emu->card->dev,
+                                "emu1010: Audio Dock Firmware loaded\n");
                        snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
                        snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
-                       snd_printk(KERN_INFO "Audio Dock ver: %u.%u\n",
+                       dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n",
                                   tmp, tmp2);
                        /* Sync clocking between 1010 and Dock */
                        /* Allow DLL to settle */
@@ -777,7 +784,7 @@ static int emu1010_firmware_thread(void *data)
                        snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
                }
        }
-       snd_printk(KERN_INFO "emu1010: firmware thread stopping\n");
+       dev_info(emu->card->dev, "emu1010: firmware thread stopping\n");
        return 0;
 }
 
@@ -818,7 +825,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
        u32 tmp, tmp2, reg;
        int err;
 
-       snd_printk(KERN_INFO "emu1010: Special config.\n");
+       dev_info(emu->card->dev, "emu1010: Special config.\n");
        /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
         * Lock Sound Memory Cache, Lock Tank Memory Cache,
         * Mute all codecs.
@@ -843,7 +850,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
 
        /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
-       snd_printdd("reg1 = 0x%x\n", reg);
+       dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg);
        if ((reg & 0x3f) == 0x15) {
                /* FPGA netlist already present so clear it */
                /* Return to programming mode */
@@ -851,13 +858,14 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
                snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02);
        }
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
-       snd_printdd("reg2 = 0x%x\n", reg);
+       dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg);
        if ((reg & 0x3f) == 0x15) {
                /* FPGA failed to return to programming mode */
-               snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
+               dev_info(emu->card->dev,
+                        "emu1010: FPGA failed to return to programming mode\n");
                return -ENODEV;
        }
-       snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg);
+       dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg);
 
        if (!emu->firmware) {
                const char *filename;
@@ -880,16 +888,19 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
 
                err = request_firmware(&emu->firmware, filename, &emu->pci->dev);
                if (err != 0) {
-                       snd_printk(KERN_ERR "emu1010: firmware: %s not found. Err = %d\n", filename, err);
+                       dev_info(emu->card->dev,
+                                "emu1010: firmware: %s not found. Err = %d\n",
+                                filename, err);
                        return err;
                }
-               snd_printk(KERN_INFO "emu1010: firmware file = %s, size = 0x%zx\n",
+               dev_info(emu->card->dev,
+                        "emu1010: firmware file = %s, size = 0x%zx\n",
                           filename, emu->firmware->size);
        }
 
        err = snd_emu1010_load_firmware(emu, emu->firmware);
        if (err != 0) {
-               snd_printk(KERN_INFO "emu1010: Loading Firmware failed\n");
+               dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
                return err;
        }
 
@@ -897,21 +908,23 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
        if ((reg & 0x3f) != 0x15) {
                /* FPGA failed to be programmed */
-               snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg);
+               dev_info(emu->card->dev,
+                        "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
+                        reg);
                return -ENODEV;
        }
 
-       snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
+       dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
        snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp);
        snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2);
-       snd_printk(KERN_INFO "emu1010: Hana version: %u.%u\n", tmp, tmp2);
+       dev_info(emu->card->dev, "emu1010: Hana version: %u.%u\n", tmp, tmp2);
        /* Enable 48Volt power to Audio Dock */
        snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON);
 
        snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
-       snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+       dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
        snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
-       snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+       dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
        snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp);
        /* Optical -> ADAT I/O  */
        /* 0 : SPDIF
@@ -950,7 +963,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
        snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
 
        snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
-       snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg);
+       dev_info(emu->card->dev, "emu1010: Card options3 = 0x%x\n", reg);
        /* Default WCLK set to 48kHz. */
        snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00);
        /* Word Clock source, Internal 48kHz x1 */
@@ -1808,7 +1821,9 @@ int snd_emu10k1_create(struct snd_card *card,
        emu->revision = pci->revision;
        pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
        pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
-       snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model);
+       dev_dbg(card->dev,
+               "vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n",
+               pci->vendor, pci->device, emu->serial, emu->model);
 
        for (c = emu_chip_details; c->vendor; c++) {
                if (c->vendor == pci->vendor && c->device == pci->device) {
@@ -1827,21 +1842,21 @@ int snd_emu10k1_create(struct snd_card *card,
                }
        }
        if (c->vendor == 0) {
-               snd_printk(KERN_ERR "emu10k1: Card not recognised\n");
+               dev_err(card->dev, "emu10k1: Card not recognised\n");
                kfree(emu);
                pci_disable_device(pci);
                return -ENOENT;
        }
        emu->card_capabilities = c;
        if (c->subsystem && !subsystem)
-               snd_printdd("Sound card name = %s\n", c->name);
+               dev_dbg(card->dev, "Sound card name = %s\n", c->name);
        else if (subsystem)
-               snd_printdd("Sound card name = %s, "
+               dev_dbg(card->dev, "Sound card name = %s, "
                        "vendor = 0x%x, device = 0x%x, subsystem = 0x%x. "
                        "Forced to subsystem = 0x%x\n", c->name,
                        pci->vendor, pci->device, emu->serial, c->subsystem);
        else
-               snd_printdd("Sound card name = %s, "
+               dev_dbg(card->dev, "Sound card name = %s, "
                        "vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n",
                        c->name, pci->vendor, pci->device,
                        emu->serial);
@@ -1869,7 +1884,9 @@ int snd_emu10k1_create(struct snd_card *card,
        emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
        if (pci_set_dma_mask(pci, emu->dma_mask) < 0 ||
            pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) {
-               snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask);
+               dev_err(card->dev,
+                       "architecture does not support PCI busmaster DMA with mask 0x%lx\n",
+                       emu->dma_mask);
                kfree(emu);
                pci_disable_device(pci);
                return -ENXIO;
@@ -2021,7 +2038,6 @@ int snd_emu10k1_create(struct snd_card *card,
        snd_emu10k1_proc_init(emu);
 #endif
 
-       snd_card_set_dev(card, &pci->dev);
        *remu = emu;
        return 0;
 
index 662a45876a8b3d9b6e1008173216b32c705776bf..0e069aeab86d1075112daf01fe6384332017eb63 100644 (file)
@@ -50,7 +50,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
                return -EINVAL;
 
        if (sp->v.size == 0) {
-               snd_printd("emu: rom font for sample %d\n", sp->v.sample);
+               dev_dbg(emu->card->dev,
+                       "emu: rom font for sample %d\n", sp->v.sample);
                return 0;
        }
 
@@ -92,7 +93,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
                blocksize *= 2;
        sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
        if (sp->block == NULL) {
-               snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize);
+               dev_dbg(emu->card->dev,
+                       "synth malloc failed (size=%d)\n", blocksize);
                /* not ENOMEM (for compatibility with OSS) */
                return -ENOSPC;
        }
index 56ad9d6f200df7daa7de21fea6d7d59ef502c881..efe0175269771b0c674cc854bbe5e1896ef9e6b8 100644 (file)
@@ -369,7 +369,8 @@ static void snd_emu10k1x_pcm_interrupt(struct emu10k1x *emu, struct emu10k1x_voi
        if (epcm->substream == NULL)
                return;
 #if 0
-       snd_printk(KERN_INFO "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
+       dev_info(emu->card->dev,
+                "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
                   epcm->substream->ops->pointer(epcm->substream),
                   snd_pcm_lib_period_bytes(epcm->substream),
                   snd_pcm_lib_buffer_bytes(epcm->substream));
@@ -487,7 +488,11 @@ static int snd_emu10k1x_pcm_trigger(struct snd_pcm_substream *substream,
        int channel = epcm->voice->number;
        int result = 0;
 
-//     snd_printk(KERN_INFO "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream));
+       /*
+       dev_dbg(emu->card->dev,
+               "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n",
+               (int)emu, cmd, (int)substream->ops->pointer(substream));
+       */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -826,7 +831,7 @@ static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
        // acknowledge the interrupt if necessary
        outl(status, chip->port + IPR);
 
-       // snd_printk(KERN_INFO "interrupt %08x\n", status);
+       /* dev_dbg(chip->card->dev, "interrupt %08x\n", status); */
        return IRQ_HANDLED;
 }
 
@@ -919,7 +924,7 @@ static int snd_emu10k1x_create(struct snd_card *card,
                return err;
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
-               snd_printk(KERN_ERR "error to set 28bit mask DMA\n");
+               dev_err(card->dev, "error to set 28bit mask DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -940,14 +945,15 @@ static int snd_emu10k1x_create(struct snd_card *card,
        chip->port = pci_resource_start(pci, 0);
        if ((chip->res_port = request_region(chip->port, 8,
                                             "EMU10K1X")) == NULL) { 
-               snd_printk(KERN_ERR "emu10k1x: cannot allocate the port 0x%lx\n", chip->port);
+               dev_err(card->dev, "cannot allocate the port 0x%lx\n",
+                       chip->port);
                snd_emu10k1x_free(chip);
                return -EBUSY;
        }
 
        if (request_irq(pci->irq, snd_emu10k1x_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq);
+               dev_err(card->dev, "cannot grab irq %d\n", pci->irq);
                snd_emu10k1x_free(chip);
                return -EBUSY;
        }
@@ -964,7 +970,7 @@ static int snd_emu10k1x_create(struct snd_card *card,
        chip->revision = pci->revision;
        pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
        pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
-       snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
+       dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n", chip->model,
                   chip->revision, chip->serial);
 
        outl(0, chip->port + INTE);     
@@ -1248,7 +1254,9 @@ static void mpu401_clear_rx(struct emu10k1x *emu, struct emu10k1x_midi *mpu)
                mpu401_read_data(emu, mpu);
 #ifdef CONFIG_SND_DEBUG
        if (timeout <= 0)
-               snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
+               dev_err(emu->card->dev,
+                       "cmd: clear rx timeout (status = 0x%x)\n",
+                       mpu401_read_stat(emu, mpu));
 #endif
 }
 
@@ -1322,7 +1330,8 @@ static int snd_emu10k1x_midi_cmd(struct emu10k1x * emu,
        }
        spin_unlock_irqrestore(&midi->input_lock, flags);
        if (!ok) {
-               snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
+               dev_err(emu->card->dev,
+                       "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
                           cmd, emu->port,
                           mpu401_read_stat(emu, midi),
                           mpu401_read_data(emu, midi));
@@ -1564,7 +1573,8 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -1608,8 +1618,6 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s at 0x%lx irq %i",
                card->shortname, chip->port, chip->irq);
 
-       snd_card_set_dev(card, &pci->dev);
-
        if ((err = snd_card_register(card)) < 0) {
                snd_card_free(card);
                return err;
index 1f9c7c4bbcd8b0f3db5fb8552a24fba5dd9467f8..745f0627c634eb0f678ba1eec736f091f50bce9f 100644 (file)
@@ -1547,7 +1547,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
        /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
        if (emu->card_capabilities->emu_model) {
                /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
-               snd_printk(KERN_INFO "EMU outputs on\n");
+               dev_info(emu->card->dev, "EMU outputs on\n");
                for (z = 0; z < 8; z++) {
                        if (emu->card_capabilities->ca0108_chip) {
                                A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
@@ -1571,7 +1571,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
                if ((z==1) && (emu->card_capabilities->spdif_bug)) {
                        /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
-                       snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
+                       dev_info(emu->card->dev,
+                                "Installing spdif_bug patch: %s\n",
+                                emu->card_capabilities->name);
                        A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
                        A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
                } else {
@@ -1595,7 +1597,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
        if (emu->card_capabilities->emu_model) {
                if (emu->card_capabilities->ca0108_chip) {
-                       snd_printk(KERN_INFO "EMU2 inputs on\n");
+                       dev_info(emu->card->dev, "EMU2 inputs on\n");
                        for (z = 0; z < 0x10; z++) {
                                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, 
                                                                        bit_shifter16,
@@ -1603,11 +1605,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                                                                        A_FXBUS2(z*2) );
                        }
                } else {
-                       snd_printk(KERN_INFO "EMU inputs on\n");
+                       dev_info(emu->card->dev, "EMU inputs on\n");
                        /* Capture 16 (originally 8) channels of S32_LE sound */
 
                        /*
-                       printk(KERN_DEBUG "emufx.c: gpr=0x%x, tmp=0x%x\n",
+                       dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
                               gpr, tmp);
                        */
                        /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
index f6c3da0d377d19e5a2b0822e07a1c66cd8b7199b..c5ae2a24d8a53f9f31775b2c4ae51fff0db569cf 100644 (file)
@@ -1853,8 +1853,10 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
                        if (emu->card_capabilities->ac97_chip == 1)
                                return err;
-                       snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
-                       snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
+                       dev_info(emu->card->dev,
+                                "AC97 is optional on this board\n");
+                       dev_info(emu->card->dev,
+                                "Proceeding without ac97 mixers...\n");
                        snd_device_free(emu->card, pbus);
                        goto no_ac97; /* FIXME: get rid of ugly gotos.. */
                }
index 1ec91246dfee5cdff16bf2b68c939d3a90848efc..fdf2b0ada48977c9fd58b6e7794883f60a852146 100644 (file)
@@ -64,7 +64,9 @@ static void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mp
                mpu401_read_data(emu, mpu);
 #ifdef CONFIG_SND_DEBUG
        if (timeout <= 0)
-               snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
+               dev_err(emu->card->dev,
+                       "cmd: clear rx timeout (status = 0x%x)\n",
+                       mpu401_read_stat(emu, mpu));
 #endif
 }
 
@@ -141,7 +143,8 @@ static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_mid
        }
        spin_unlock_irqrestore(&midi->input_lock, flags);
        if (!ok) {
-               snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
+               dev_err(emu->card->dev,
+                       "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
                           cmd, emu->port,
                           mpu401_read_stat(emu, midi),
                           mpu401_read_data(emu, midi));
index 5ae1d045bdcb5f0bfad786ab3cc527adbeb3bc86..f82481bd2542a912924088e8725dc56bf9bbdf23 100644 (file)
@@ -44,7 +44,8 @@ static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu,
        if (epcm->substream == NULL)
                return;
 #if 0
-       printk(KERN_DEBUG "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
+       dev_dbg(emu->card->dev,
+               "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
                        epcm->substream->runtime->hw->pointer(emu, epcm->substream),
                        snd_pcm_lib_period_bytes(epcm->substream),
                        snd_pcm_lib_buffer_bytes(epcm->substream));
@@ -147,7 +148,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic
                                              &epcm->extra);
                if (err < 0) {
                        /*
-                       printk(KERN_DEBUG "pcm_channel_alloc: "
+                       dev_dbg(emu->card->dev, "pcm_channel_alloc: "
                               "failed extra: voices=%d, frame=%d\n",
                               voices, frame);
                        */
@@ -761,7 +762,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
        int result = 0;
 
        /*
-       printk(KERN_DEBUG "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
+       dev_dbg(emu->card->dev,
+               "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
               (int)emu, cmd, substream->ops->pointer(substream))
        */
        spin_lock(&emu->reg_lock);
@@ -815,7 +817,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
                outl(epcm->capture_ipr, emu->port + IPR);
                snd_emu10k1_intr_enable(emu, epcm->capture_inte);
                /*
-               printk(KERN_DEBUG "adccr = 0x%x, adcbs = 0x%x\n",
+               dev_dbg(emu->card->dev, "adccr = 0x%x, adcbs = 0x%x\n",
                       epcm->adccr, epcm->adcbs);
                */
                switch (epcm->type) {
@@ -826,7 +828,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
                        if (emu->audigy) {
                                snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);
                                snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);
-                               snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2);
+                               dev_dbg(emu->card->dev,
+                                       "cr_val=0x%x, cr_val2=0x%x\n",
+                                       epcm->capture_cr_val,
+                                       epcm->capture_cr_val2);
                        } else
                                snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
                        break;
@@ -889,7 +894,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
        }
 #endif
        /*
-       printk(KERN_DEBUG
+       dev_dbg(emu->card->dev,
               "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
               (long)ptr, (long)runtime->buffer_size,
               (long)runtime->period_size);
@@ -1594,7 +1599,8 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
                                                   unsigned int tram_shift)
 {
        /*
-       printk(KERN_DEBUG "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
+       dev_dbg(emu->card->dev,
+               "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
               "src = 0x%p, count = 0x%x\n",
               dst_left, dst_right, src, count);
        */
@@ -1675,7 +1681,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre
        unsigned int i;
        
        /*
-       printk(KERN_DEBUG "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
+       dev_dbg(emu->card->dev, "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
               "buffer_size = 0x%x (0x%x)\n",
               emu->fx8010.etram_pages, runtime->dma_area,
               runtime->buffer_size, runtime->buffer_size << 2);
index e4fba49fee4a9cd633e0968203832ac7a1dbc4fe..706b4f0c6806b00495e20cbb9bdccd5bba63491f 100644 (file)
@@ -71,11 +71,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
        unsigned long flags;
        unsigned int mask;
 
-       if (!emu) {
-               snd_printk(KERN_ERR "ptr_write: emu is null!\n");
-               dump_stack();
+       if (snd_BUG_ON(!emu))
                return;
-       }
        mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
        regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
 
@@ -199,7 +196,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
        int err = 0;
 
        if ((reg > 0x7f) || (value > 0x1ff)) {
-               snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+               dev_err(emu->card->dev, "i2c_write: invalid values.\n");
                return -EINVAL;
        }
 
@@ -227,7 +224,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
                                break;
 
                        if (timeout > 1000) {
-                               snd_printk(KERN_WARNING
+                               dev_warn(emu->card->dev,
                                           "emu10k1:I2C:timeout status=0x%x\n",
                                           status);
                                break;
@@ -239,8 +236,8 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
        }
 
        if (retry == 10) {
-               snd_printk(KERN_ERR "Writing to ADC failed!\n");
-               snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
+               dev_err(emu->card->dev, "Writing to ADC failed!\n");
+               dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
                        status, reg, value);
                /* dump_stack(); */
                err = -EINVAL;
index 30bfed6f83398d5f9b17fdf776ce2ab6ebac7a4e..3c5c5e3dc2d97b885bdf861594b82a3b52db12d1 100644 (file)
@@ -41,11 +41,12 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
                orig_status = status;
                handled = 1;
                if ((status & 0xffffffff) == 0xffffffff) {
-                       snd_printk(KERN_INFO "snd-emu10k1: Suspected sound card removal\n");
+                       dev_info(emu->card->dev,
+                                "Suspected sound card removal\n");
                        break;
                }
                if (status & IPR_PCIERROR) {
-                       snd_printk(KERN_ERR "interrupt: PCI error\n");
+                       dev_err(emu->card->dev, "interrupt: PCI error\n");
                        snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
                        status &= ~IPR_PCIERROR;
                }
@@ -157,19 +158,22 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
                                struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
                                struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);
 
-                               //printk(KERN_INFO "status2=0x%x\n", status2);
+                               /* dev_dbg(emu->card->dev, "status2=0x%x\n", status2); */
                                orig_status2 = status2;
                                if(status2 & mask) {
                                        if(pvoice->use) {
                                                snd_pcm_period_elapsed(pvoice->epcm->substream);
                                        } else { 
-                                               snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
+                                               dev_err(emu->card->dev,
+                                                       "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n",
+                                                       status2, mask, pvoice,
+                                                       pvoice->use);
                                        }
                                }
                                if(status2 & 0x110000) {
-                                       //printk(KERN_INFO "capture int found\n");
+                                       /* dev_info(emu->card->dev, "capture int found\n"); */
                                        if(cvoice->use) {
-                                               //printk(KERN_INFO "capture period_elapsed\n");
+                                               /* dev_info(emu->card->dev, "capture period_elapsed\n"); */
                                                snd_pcm_period_elapsed(cvoice->epcm->substream);
                                        }
                                }
@@ -180,7 +184,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
 
                if (status) {
                        unsigned int bits;
-                       snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
+                       dev_err(emu->card->dev,
+                               "unhandled interrupt: 0x%08x\n", status);
                        //make sure any interrupts we don't handle are disabled:
                        bits = INTE_FXDSPENABLE |
                                INTE_PCIERRORENABLE |
@@ -202,7 +207,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
                outl(orig_status, emu->port + IPR); /* ack all */
        }
        if (timeout == 1000)
-               snd_printk(KERN_INFO "emu10k1 irq routine failure\n");
+               dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
 
        return IRQ_RETVAL(handled);
 }
index ae709c1ab3a848e3b954d7e04747d423b30d1e55..c68e6dd2fa6772fc88cae359b1b7947f1c4e9796 100644 (file)
@@ -236,11 +236,13 @@ __found_pages:
 static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr)
 {
        if (addr & ~emu->dma_mask) {
-               snd_printk(KERN_ERR "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr);
+               dev_err(emu->card->dev,
+                       "max memory size is 0x%lx (addr = 0x%lx)!!\n",
+                       emu->dma_mask, (unsigned long)addr);
                return 0;
        }
        if (addr & (EMUPAGESIZE-1)) {
-               snd_printk(KERN_ERR "page is not aligned\n");
+               dev_err(emu->card->dev, "page is not aligned\n");
                return 0;
        }
        return 1;
@@ -331,7 +333,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
                else
                        addr = snd_pcm_sgbuf_get_addr(substream, ofs);
                if (! is_valid_page(emu, addr)) {
-                       printk(KERN_ERR "emu: failure page = %d\n", idx);
+                       dev_err(emu->card->dev,
+                               "emu: failure page = %d\n", idx);
                        mutex_unlock(&hdr->block_mutex);
                        return NULL;
                }
@@ -507,7 +510,8 @@ static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset)
                return NULL;
        ptr = emu->page_ptr_table[page];
        if (! ptr) {
-               printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page);
+               dev_err(emu->card->dev,
+                       "access to NULL ptr: page = %d\n", page);
                return NULL;
        }
        ptr += offset & (PAGE_SIZE - 1);
index 7e2025cd6d9cc07a3696cb4f1e038c8b5e3e6ef6..a4fe7f0c945809a5a4da90585d5f0a8a2b8fb4c1 100644 (file)
@@ -168,7 +168,7 @@ static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime)
        struct snd_emu10k1_pcm *epcm = runtime->private_data;
   
        if (epcm) {
-               /* snd_printk(KERN_DEBUG "epcm free: %p\n", epcm); */
+               /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */
                kfree(epcm);
        }
 }
@@ -183,14 +183,14 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
        int err;
 
        epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
-        /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */
+       /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */
 
        if (epcm == NULL)
                return -ENOMEM;
        epcm->emu = emu;
        epcm->substream = substream;
        /*
-       snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n",
+       dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n",
                   substream->pcm->device, channel_id);
        */
        runtime->private_data = epcm;
@@ -203,10 +203,10 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
 
         channel->use=1;
 #if 0 /* debug */
-       snd_printk(KERN_DEBUG
+       dev_dbg(emu->card->dev,
                   "p16v: open channel_id=%d, channel=%p, use=0x%x\n",
                   channel_id, channel, channel->use);
-       printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+       dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
               channel_id, chip, channel);
 #endif /* debug */
        /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */
@@ -231,14 +231,14 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream
        int err;
 
        epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
-       /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */
+       /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */
 
        if (epcm == NULL)
                return -ENOMEM;
        epcm->emu = emu;
        epcm->substream = substream;
        /*
-       snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n",
+       dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n",
                   substream->pcm->device, channel_id);
        */
        runtime->private_data = epcm;
@@ -251,10 +251,10 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream
 
        channel->use=1;
 #if 0 /* debug */
-       snd_printk(KERN_DEBUG
+       dev_dbg(emu->card->dev,
                   "p16v: open channel_id=%d, channel=%p, use=0x%x\n",
                   channel_id, channel, channel->use);
-       printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+       dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
               channel_id, chip, channel);
 #endif /* debug */
        /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */
@@ -349,15 +349,18 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
        u32 tmp;
        
 #if 0 /* debug */
-       snd_printk(KERN_DEBUG "prepare:channel_number=%d, rate=%d, "
+       dev_dbg(emu->card->dev,
+               "prepare:channel_number=%d, rate=%d, "
                   "format=0x%x, channels=%d, buffer_size=%ld, "
                   "period_size=%ld, periods=%u, frames_to_bytes=%d\n",
                   channel, runtime->rate, runtime->format, runtime->channels,
                   runtime->buffer_size, runtime->period_size,
                   runtime->periods, frames_to_bytes(runtime, 1));
-       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+       dev_dbg(emu->card->dev,
+               "dma_addr=%x, dma_area=%p, table_base=%p\n",
                   runtime->dma_addr, runtime->dma_area, table_base);
-       snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+       dev_dbg(emu->card->dev,
+               "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
                   emu->p16v_buffer.addr, emu->p16v_buffer.area,
                   emu->p16v_buffer.bytes);
 #endif /* debug */
@@ -405,7 +408,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)
        u32 tmp;
 
        /*
-       printk(KERN_DEBUG "prepare capture:channel_number=%d, rate=%d, "
+       dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, "
               "format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, "
               "frames_to_bytes=%d\n",
               channel, runtime->rate, runtime->format, runtime->channels,
@@ -491,13 +494,13 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
                runtime = s->runtime;
                epcm = runtime->private_data;
                channel = substream->pcm->device-emu->p16v_device_offset;
-               /* snd_printk(KERN_DEBUG "p16v channel=%d\n", channel); */
+               /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */
                epcm->running = running;
                basic |= (0x1<<channel);
                inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel);
                 snd_pcm_trigger_done(s, substream);
         }
-       /* snd_printk(KERN_DEBUG "basic=0x%x, inte=0x%x\n", basic, inte); */
+       /* dev_dbg(emu->card->dev, "basic=0x%x, inte=0x%x\n", basic, inte); */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -588,10 +591,10 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream)
        ptr=ptr2;
        if (ptr >= runtime->buffer_size) {
                ptr -= runtime->buffer_size;
-               printk(KERN_WARNING "buffer capture limited!\n");
+               dev_warn(emu->card->dev, "buffer capture limited!\n");
        }
        /*
-       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+       dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
               "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
               ptr1, ptr2, ptr, (int)runtime->buffer_size,
               (int)runtime->period_size, (int)runtime->frame_bits,
@@ -630,7 +633,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip)
        if (chip->p16v_buffer.area) {
                snd_dma_free_pages(&chip->p16v_buffer);
                /*
-               snd_printk(KERN_DEBUG "period lables free: %p\n",
+               dev_dbg(chip->card->dev, "period lables free: %p\n",
                           &chip->p16v_buffer);
                */
        }
@@ -644,7 +647,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
        int err;
         int capture=1;
   
-       /* snd_printk(KERN_DEBUG "snd_p16v_pcm called. device=%d\n", device); */
+       /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */
        emu->p16v_device_offset = device;
        if (rpcm)
                *rpcm = NULL;
@@ -672,7 +675,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
                                                         ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) 
                        return err;
                /*
-               snd_printk(KERN_DEBUG
+               dev_dbg(emu->card->dev,
                           "preallocate playback substream: err=%d\n", err);
                */
        }
@@ -686,7 +689,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
                                                   65536 - 64, 65536 - 64)) < 0)
                        return err;
                /*
-               snd_printk(KERN_DEBUG
+               dev_dbg(emu->card->dev,
                           "preallocate capture substream: err=%d\n", err);
                */
        }
index 101e7cb79cb260dd8f669cda3f952e5ad64a18b2..f16fd5cfb7cd86cac65d882b0a3c43304ac476a3 100644 (file)
@@ -55,7 +55,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
        first_voice = last_voice = 0;
        for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
                /*
-               printk(KERN_DEBUG "i %d j %d next free %d!\n",
+               dev_dbg(emu->card->dev, "i %d j %d next free %d!\n",
                       i, j, emu->next_free_voice);
                */
                i %= NUM_G;
@@ -75,7 +75,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
                        }
                }
                if (!skip) {
-                       /* printk(KERN_DEBUG "allocated voice %d\n", i); */
+                       /* dev_dbg(emu->card->dev, "allocated voice %d\n", i); */
                        first_voice = i;
                        last_voice = (i + number) % NUM_G;
                        emu->next_free_voice = last_voice;
@@ -89,7 +89,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
        for (i = 0; i < number; i++) {
                voice = &emu->voices[(first_voice + i) % NUM_G];
                /*
-               printk(kERN_DEBUG "voice alloc - %i, %i of %i\n",
+               dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n",
                       voice->number, idx-first_voice+1, number);
                */
                voice->use = 1;
index 61262f396004b50a2aca06af03bfaa9d37686b29..29cd339ffc374582f9e63c0eece91bc8b9a5ce76 100644 (file)
@@ -525,7 +525,7 @@ static unsigned int snd_es1371_wait_src_ready(struct ensoniq * ensoniq)
                        return r;
                cond_resched();
        }
-       snd_printk(KERN_ERR "wait src ready timeout 0x%lx [0x%x]\n",
+       dev_err(ensoniq->card->dev, "wait src ready timeout 0x%lx [0x%x]\n",
                   ES_REG(ensoniq, 1371_SMPRATE), r);
        return 0;
 }
@@ -587,7 +587,7 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531,
        unsigned long end_time = jiffies + HZ / 10;
 
 #if 0
-       printk(KERN_DEBUG
+       dev_dbg(ensoniq->card->dev,
               "CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n",
               reg, val, ES_1370_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1370_CODEC));
 #endif
@@ -598,7 +598,7 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531,
                }
                schedule_timeout_uninterruptible(1);
        } while (time_after(end_time, jiffies));
-       snd_printk(KERN_ERR "codec write timeout, status = 0x%x\n",
+       dev_err(ensoniq->card->dev, "codec write timeout, status = 0x%x\n",
                   inl(ES_REG(ensoniq, STATUS)));
 }
 
@@ -649,7 +649,7 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97,
                }
        }
        mutex_unlock(&ensoniq->src_mutex);
-       snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n",
+       dev_err(ensoniq->card->dev, "codec write timeout at 0x%lx [0x%x]\n",
                   ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
 }
 
@@ -706,8 +706,8 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97,
                        }
                        mutex_unlock(&ensoniq->src_mutex);
                        if (++fail > 10) {
-                               snd_printk(KERN_ERR "codec read timeout (final) "
-                                          "at 0x%lx, reg = 0x%x [0x%x]\n",
+                               dev_err(ensoniq->card->dev,
+                                       "codec read timeout (final) at 0x%lx, reg = 0x%x [0x%x]\n",
                                           ES_REG(ensoniq, 1371_CODEC), reg,
                                           inl(ES_REG(ensoniq, 1371_CODEC)));
                                return 0;
@@ -716,7 +716,7 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97,
                }
        }
        mutex_unlock(&ensoniq->src_mutex);
-       snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n",
+       dev_err(ensoniq->card->dev, "codec read timeout at 0x%lx [0x%x]\n",
                   ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
        return 0;
 }
@@ -1796,7 +1796,7 @@ static int snd_ensoniq_1370_mixer(struct ensoniq *ensoniq)
 #ifdef SUPPORT_JOYSTICK
 
 #ifdef CHIP1371
-static int snd_ensoniq_get_joystick_port(int dev)
+static int snd_ensoniq_get_joystick_port(struct ensoniq *ensoniq, int dev)
 {
        switch (joystick_port[dev]) {
        case 0: /* disabled */
@@ -1808,12 +1808,13 @@ static int snd_ensoniq_get_joystick_port(int dev)
                return joystick_port[dev];
 
        default:
-               printk(KERN_ERR "ens1371: invalid joystick port %#x", joystick_port[dev]);
+               dev_err(ensoniq->card->dev,
+                       "invalid joystick port %#x", joystick_port[dev]);
                return 0;
        }
 }
 #else
-static inline int snd_ensoniq_get_joystick_port(int dev)
+static int snd_ensoniq_get_joystick_port(struct ensoniq *ensoniq, int dev)
 {
        return joystick[dev] ? 0x200 : 0;
 }
@@ -1824,7 +1825,7 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev)
        struct gameport *gp;
        int io_port;
 
-       io_port = snd_ensoniq_get_joystick_port(dev);
+       io_port = snd_ensoniq_get_joystick_port(ensoniq, dev);
 
        switch (io_port) {
        case 0:
@@ -1835,14 +1836,16 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev)
                        if (request_region(io_port, 8, "ens137x: gameport"))
                                break;
                if (io_port > 0x218) {
-                       printk(KERN_WARNING "ens137x: no gameport ports available\n");
+                       dev_warn(ensoniq->card->dev,
+                                "no gameport ports available\n");
                        return -EBUSY;
                }
                break;
 
        default:
                if (!request_region(io_port, 8, "ens137x: gameport")) {
-                       printk(KERN_WARNING "ens137x: gameport io port %#x in use\n",
+                       dev_warn(ensoniq->card->dev,
+                                "gameport io port %#x in use\n",
                               io_port);
                        return -EBUSY;
                }
@@ -1851,7 +1854,8 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev)
 
        ensoniq->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "ens137x: cannot allocate memory for gameport\n");
+               dev_err(ensoniq->card->dev,
+                       "cannot allocate memory for gameport\n");
                release_region(io_port, 8);
                return -ENOMEM;
        }
@@ -2082,8 +2086,7 @@ static int snd_ensoniq_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR DRIVER_NAME ": pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2137,7 +2140,7 @@ static int snd_ensoniq_create(struct snd_card *card,
        ensoniq->port = pci_resource_start(pci, 0);
        if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, ensoniq)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_ensoniq_free(ensoniq);
                return -EBUSY;
        }
@@ -2145,7 +2148,7 @@ static int snd_ensoniq_create(struct snd_card *card,
 #ifdef CHIP1370
        if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
                                16, &ensoniq->dma_bug) < 0) {
-               snd_printk(KERN_ERR "unable to allocate space for phantom area - dma_bug\n");
+               dev_err(card->dev, "unable to allocate space for phantom area - dma_bug\n");
                snd_ensoniq_free(ensoniq);
                return -EBUSY;
        }
@@ -2180,8 +2183,6 @@ static int snd_ensoniq_create(struct snd_card *card,
 
        snd_ensoniq_proc_init(ensoniq);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rensoniq = ensoniq;
        return 0;
 }
@@ -2437,7 +2438,8 @@ static int snd_audiopci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
index 9213fb38921c6b7687bfaaa262c6c3b3de0a09d3..34d95bf916b5f2c51e9658ab6b363f611f05b2af 100644 (file)
@@ -254,7 +254,6 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids);
 #define WRITE_LOOP_TIMEOUT     0x10000
 #define GET_LOOP_TIMEOUT       0x01000
 
-#undef REG_DEBUG
 /* -----------------------------------------------------------------
  * Write to a mixer register
  * -----------------------------------------------------------------*/
@@ -265,9 +264,7 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig
        outb(reg, SLSB_REG(chip, MIXERADDR));
        outb(val, SLSB_REG(chip, MIXERDATA));
        spin_unlock_irqrestore(&chip->mixer_lock, flags);
-#ifdef REG_DEBUG
-       snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, val);
-#endif
+       dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val);
 }
 
 /* -----------------------------------------------------------------
@@ -281,9 +278,7 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg)
        outb(reg, SLSB_REG(chip, MIXERADDR));
        data = inb(SLSB_REG(chip, MIXERDATA));
        spin_unlock_irqrestore(&chip->mixer_lock, flags);
-#ifdef REG_DEBUG
-       snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data);
-#endif
+       dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data);
        return data;
 }
 
@@ -302,10 +297,9 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg,
        if (val != oval) {
                new = (old & ~mask) | (val & mask);
                outb(new, SLSB_REG(chip, MIXERDATA));
-#ifdef REG_DEBUG
-               snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n",
+               dev_dbg(chip->card->dev,
+                       "Mixer reg %02x was %02x, set to %02x\n",
                           reg, old, new);
-#endif
        }
        spin_unlock_irqrestore(&chip->mixer_lock, flags);
        return oval;
@@ -324,7 +318,8 @@ static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd)
                        return;
                }
        }
-       printk(KERN_ERR "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v);
+       dev_err(chip->card->dev,
+               "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v);
 }
 
 /* -----------------------------------------------------------------
@@ -337,7 +332,7 @@ static int snd_es1938_get_byte(struct es1938 *chip)
        for (i = GET_LOOP_TIMEOUT; i; i--)
                if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80)
                        return inb(SLSB_REG(chip, READDATA));
-       snd_printk(KERN_ERR "get_byte timeout: status 0x02%x\n", v);
+       dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v);
        return -ENODEV;
 }
 
@@ -351,9 +346,7 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch
        snd_es1938_write_cmd(chip, reg);
        snd_es1938_write_cmd(chip, val);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-#ifdef REG_DEBUG
-       snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, val);
-#endif
+       dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val);
 }
 
 /* -----------------------------------------------------------------
@@ -368,9 +361,7 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg)
        snd_es1938_write_cmd(chip, reg);
        val = snd_es1938_get_byte(chip);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
-#ifdef REG_DEBUG
-       snd_printk(KERN_DEBUG "Reg %02x now is %02x\n", reg, val);
-#endif
+       dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val);
        return val;
 }
 
@@ -391,10 +382,8 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char
                snd_es1938_write_cmd(chip, reg);
                new = (old & ~mask) | (val & mask);
                snd_es1938_write_cmd(chip, new);
-#ifdef REG_DEBUG
-               snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x\n",
+               dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n",
                           reg, old, new);
-#endif
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        return oval;
@@ -416,7 +405,7 @@ static void snd_es1938_reset(struct es1938 *chip)
                                goto __next;
                }
        }
-       snd_printk(KERN_ERR "ESS Solo-1 reset failed\n");
+       dev_err(chip->card->dev, "ESS Solo-1 reset failed\n");
 
      __next:
        snd_es1938_write_cmd(chip, ESS_CMD_ENABLEEXT);
@@ -1504,16 +1493,15 @@ static int es1938_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "es1938: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
 
        if (request_irq(pci->irq, snd_es1938_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR "es1938: unable to grab IRQ %d, "
-                      "disabling device\n", pci->irq);
+               dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+                       pci->irq);
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -1545,7 +1533,8 @@ static int snd_es1938_create_gameport(struct es1938 *chip)
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "es1938: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                return -ENOMEM;
        }
 
@@ -1612,7 +1601,8 @@ static int snd_es1938_create(struct snd_card *card,
         /* check, if we can restrict PCI DMA transfers to 24 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 24bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                 return -ENXIO;
         }
@@ -1639,15 +1629,14 @@ static int snd_es1938_create(struct snd_card *card,
        chip->game_port = pci_resource_start(pci, 4);
        if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_es1938_free(chip);
                return -EBUSY;
        }
        chip->irq = pci->irq;
-#ifdef ES1938_DDEBUG
-       snd_printk(KERN_DEBUG "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n",
+       dev_dbg(card->dev,
+               "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n",
                   chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port);
-#endif
 
        chip->ddma_port = chip->vc_port + 0x00;         /* fix from Thomas Sailer */
 
@@ -1658,8 +1647,6 @@ static int snd_es1938_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        return 0;
 }
@@ -1675,21 +1662,22 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
 
        status = inb(SLIO_REG(chip, IRQCONTROL));
 #if 0
-       printk(KERN_DEBUG "Es1938debug - interrupt status: =0x%x\n", status);
+       dev_dbg(chip->card->dev,
+               "Es1938debug - interrupt status: =0x%x\n", status);
 #endif
        
        /* AUDIO 1 */
        if (status & 0x10) {
 #if 0
-                printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 1 interrupt\n");
-               printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
                       inw(SLDM_REG(chip, DMACOUNT)));
-               printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
                       inl(SLDM_REG(chip, DMAADDR)));
-               printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
                       inl(SLDM_REG(chip, DMASTATUS)));
 #endif
@@ -1705,12 +1693,12 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
        /* AUDIO 2 */
        if (status & 0x20) {
 #if 0
-                printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 2 interrupt\n");
-               printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
                       inw(SLIO_REG(chip, AUDIO2DMACOUNT)));
-               printk(KERN_DEBUG
+               dev_dbg(chip->card->dev,
                       "Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
                       inl(SLIO_REG(chip, AUDIO2DMAADDR)));
 
@@ -1808,7 +1796,8 @@ static int snd_es1938_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        for (idx = 0; idx < 5; idx++) {
@@ -1843,7 +1832,7 @@ static int snd_es1938_probe(struct pci_dev *pci,
                            SLSB_REG(chip, FMLOWADDR),
                            SLSB_REG(chip, FMHIGHADDR),
                            OPL3_HW_OPL3, 1, &opl3) < 0) {
-               printk(KERN_ERR "es1938: OPL3 not detected at 0x%lx\n",
+               dev_err(card->dev, "OPL3 not detected at 0x%lx\n",
                           SLSB_REG(chip, FMLOWADDR));
        } else {
                if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
@@ -1859,7 +1848,7 @@ static int snd_es1938_probe(struct pci_dev *pci,
                                chip->mpu_port,
                                MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
                                -1, &chip->rmidi) < 0) {
-               printk(KERN_ERR "es1938: unable to initialize MPU-401\n");
+               dev_err(card->dev, "unable to initialize MPU-401\n");
        } else {
                // this line is vital for MIDI interrupt handling on ess-solo1
                // andreas@flying-snail.de
index 772cc36f951de1929d9ef69962688cd51f502537..5bb1cf603301e28ef937f7b4416a93dd5008e916 100644 (file)
@@ -632,7 +632,7 @@ static int snd_es1968_ac97_wait(struct es1968 *chip)
                        return 0;
                cond_resched();
        }
-       snd_printd("es1968: ac97 timeout\n");
+       dev_dbg(chip->card->dev, "ac97 timeout\n");
        return 1; /* timeout */
 }
 
@@ -644,7 +644,7 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
                if (!(inb(chip->io_port + ESM_AC97_INDEX) & 1))
                        return 0;
        }
-       snd_printd("es1968: ac97 timeout\n");
+       dev_dbg(chip->card->dev, "ac97 timeout\n");
        return 1; /* timeout */
 }
 
@@ -687,7 +687,7 @@ static void apu_index_set(struct es1968 *chip, u16 index)
        for (i = 0; i < 1000; i++)
                if (__maestro_read(chip, IDR1_CRAM_POINTER) == index)
                        return;
-       snd_printd("es1968: APU register select failed. (Timeout)\n");
+       dev_dbg(chip->card->dev, "APU register select failed. (Timeout)\n");
 }
 
 /* no spinlock */
@@ -699,7 +699,7 @@ static void apu_data_set(struct es1968 *chip, u16 data)
                        return;
                __maestro_write(chip, IDR0_DATA_PORT, data);
        }
-       snd_printd("es1968: APU register set probably failed (Timeout)!\n");
+       dev_dbg(chip->card->dev, "APU register set probably failed (Timeout)!\n");
 }
 
 /* no spinlock */
@@ -1442,13 +1442,14 @@ snd_es1968_init_dmabuf(struct es1968 *chip)
                                           snd_dma_pci_data(chip->pci),
                                           chip->total_bufsize, &chip->dma);
        if (err < 0 || ! chip->dma.area) {
-               snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n",
+               dev_err(chip->card->dev,
+                       "can't allocate dma pages for size %d\n",
                           chip->total_bufsize);
                return -ENOMEM;
        }
        if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) {
                snd_dma_free_pages(&chip->dma);
-               snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n");
+               dev_err(chip->card->dev, "DMA buffer beyond 256MB.\n");
                return -ENOMEM;
        }
 
@@ -1489,7 +1490,8 @@ static int snd_es1968_hw_params(struct snd_pcm_substream *substream,
        }
        chan->memory = snd_es1968_new_memory(chip, size);
        if (chan->memory == NULL) {
-               // snd_printd("cannot allocate dma buffer: size = %d\n", size);
+               dev_dbg(chip->card->dev,
+                       "cannot allocate dma buffer: size = %d\n", size);
                return -ENOMEM;
        }
        snd_pcm_set_runtime_buffer(substream, &chan->memory->buf);
@@ -1715,11 +1717,13 @@ static void es1968_measure_clock(struct es1968 *chip)
 
        /* search 2 APUs (although one apu is enough) */
        if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) {
-               snd_printk(KERN_ERR "Hmm, cannot find empty APU pair!?\n");
+               dev_err(chip->card->dev, "Hmm, cannot find empty APU pair!?\n");
                return;
        }
        if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) {
-               snd_printk(KERN_ERR "cannot allocate dma buffer - using default clock %d\n", chip->clock);
+               dev_warn(chip->card->dev,
+                        "cannot allocate dma buffer - using default clock %d\n",
+                        chip->clock);
                snd_es1968_free_apu_pair(chip, apu);
                return;
        }
@@ -1780,7 +1784,7 @@ static void es1968_measure_clock(struct es1968 *chip)
        else
                t += stop_time.tv_usec - start_time.tv_usec;
        if (t == 0) {
-               snd_printk(KERN_ERR "?? calculation error..\n");
+               dev_err(chip->card->dev, "?? calculation error..\n");
        } else {
                offset *= 1000;
                offset = (offset / t) * 1000 + ((offset % t) * 1000) / t;
@@ -1788,7 +1792,7 @@ static void es1968_measure_clock(struct es1968 *chip)
                        if (offset >= 40000 && offset <= 50000)
                                chip->clock = (chip->clock * offset) / 48000;
                }
-               printk(KERN_INFO "es1968: clocking to %d\n", chip->clock);
+               dev_info(chip->card->dev, "clocking to %d\n", chip->clock);
        }
        snd_es1968_free_memory(chip, memory);
        snd_es1968_free_apu_pair(chip, apu);
@@ -2108,7 +2112,7 @@ static void snd_es1968_ac97_reset(struct es1968 *chip)
        outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
 
 #if 0                          /* the loop here needs to be much better if we want it.. */
-       snd_printk(KERN_INFO "trying software reset\n");
+       dev_info(chip->card->dev, "trying software reset\n");
        /* try and do a software reset */
        outb(0x80 | 0x7c, ioaddr + 0x30);
        for (w = 0;; w++) {
@@ -2416,8 +2420,7 @@ static int es1968_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "es1968: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2479,7 +2482,8 @@ static int snd_es1968_create_gameport(struct es1968 *chip, int dev)
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "es1968: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                release_and_free_resource(r);
                return -ENOMEM;
        }
@@ -2706,7 +2710,8 @@ static int snd_es1968_create(struct snd_card *card,
        /* check, if we can restrict PCI DMA transfers to 28 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 28bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -2740,7 +2745,7 @@ static int snd_es1968_create(struct snd_card *card,
        chip->io_port = pci_resource_start(pci, 0);
        if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_es1968_free(chip);
                return -EBUSY;
        }
@@ -2770,7 +2775,7 @@ static int snd_es1968_create(struct snd_card *card,
                }
                if (do_pm > 1) {
                        /* not matched; disabling pm */
-                       printk(KERN_INFO "es1968: not attempting power management.\n");
+                       dev_info(card->dev, "not attempting power management.\n");
                        do_pm = 0;
                }
        }
@@ -2783,8 +2788,6 @@ static int snd_es1968_create(struct snd_card *card,
                return err;
        }
 
-       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)
@@ -2802,7 +2805,7 @@ static int snd_es1968_create(struct snd_card *card,
        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",
+                       dev_info(card->dev, "detected TEA575x radio type %s\n",
                                   get_tea575x_gpio(chip)->name);
                        strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
                                sizeof(chip->tea.card));
@@ -2836,7 +2839,8 @@ static int snd_es1968_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
                 
@@ -2900,7 +2904,7 @@ static int snd_es1968_probe(struct pci_dev *pci,
                                               MPU401_INFO_INTEGRATED |
                                               MPU401_INFO_IRQ_HOOK,
                                               -1, &chip->rmidi)) < 0) {
-                       printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n");
+                       dev_warn(card->dev, "skipping MPU-401 MIDI support..\n");
                }
        }
 
@@ -2909,8 +2913,8 @@ static int snd_es1968_probe(struct pci_dev *pci,
 #ifdef CONFIG_SND_ES1968_INPUT
        err = snd_es1968_input_register(chip);
        if (err)
-               snd_printk(KERN_WARNING "Input device registration "
-                       "failed with error %i", err);
+               dev_warn(card->dev,
+                        "Input device registration failed with error %i", err);
 #endif
 
        snd_es1968_start_irq(chip);
index 45bc8a95b7c44f2f35fdd0013e6695d328bdc69f..db18ccabadd6abb3914b9b1d70c314232fda92ac 100644 (file)
@@ -254,7 +254,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97,
                        goto ok1;
                udelay(10);
        }
-       snd_printk(KERN_ERR "AC'97 interface is busy (1)\n");
+       dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
        return;
 
  ok1:
@@ -269,7 +269,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97,
                        return;
                udelay(10);
        }
-       snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num);
+       dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
 }
 
 static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short reg)
@@ -285,7 +285,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short
                        goto ok1;
                udelay(10);
        }
-       snd_printk(KERN_ERR "AC'97 interface is busy (1)\n");
+       dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
        return 0;
 
  ok1:
@@ -297,7 +297,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short
                        goto ok2;
                udelay(10);
        }
-       snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num);
+       dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
        return 0;
 
  ok2:
@@ -306,7 +306,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short
                        goto ok3;
                udelay(10);
        }
-       snd_printk(KERN_ERR "AC'97 interface #%d is not valid (2)\n", ac97->num);
+       dev_err(chip->card->dev, "AC'97 interface #%d is not valid (2)\n", ac97->num);
        return 0;
 
  ok3:
@@ -1100,8 +1100,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
 
        if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
                if (!resume) {
-                       snd_printk(KERN_INFO "Primary AC'97 codec not found, "
-                                           "assume SF64-PCR (tuner-only)\n");
+                       dev_info(chip->card->dev,
+                                "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
                        chip->tea575x_tuner = 3 | TUNER_ONLY;
                        goto __ac97_ok;
                }
@@ -1225,7 +1225,7 @@ static int snd_fm801_create(struct snd_card *card,
        if ((tea575x_tuner & TUNER_ONLY) == 0) {
                if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
                                KBUILD_MODNAME, chip)) {
-                       snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
+                       dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
                        snd_fm801_free(chip);
                        return -EBUSY;
                }
@@ -1251,8 +1251,6 @@ static int snd_fm801_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
        err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
        if (err < 0) {
@@ -1267,7 +1265,7 @@ static int snd_fm801_create(struct snd_card *card,
        if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
            (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
                if (snd_tea575x_init(&chip->tea, THIS_MODULE)) {
-                       snd_printk(KERN_ERR "TEA575x radio not found\n");
+                       dev_err(card->dev, "TEA575x radio not found\n");
                        snd_fm801_free(chip);
                        return -ENODEV;
                }
@@ -1276,13 +1274,14 @@ static int snd_fm801_create(struct snd_card *card,
                for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
                        chip->tea575x_tuner = tea575x_tuner;
                        if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
-                               snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
+                               dev_info(card->dev,
+                                        "detected TEA575x radio type %s\n",
                                           get_tea575x_gpio(chip)->name);
                                break;
                        }
                }
                if (tea575x_tuner == 4) {
-                       snd_printk(KERN_ERR "TEA575x radio not found\n");
+                       dev_err(card->dev, "TEA575x radio not found\n");
                        chip->tea575x_tuner = TUNER_DISABLED;
                }
        }
@@ -1312,7 +1311,8 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) {
@@ -1411,8 +1411,7 @@ static int snd_fm801_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "fm801: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index 0e53634dbbd85825249f68a7e4460b6a543d3361..ac17c3fc93883a98eade37bf58a13e5bff56abb3 100644 (file)
@@ -1,8 +1,15 @@
-menuconfig SND_HDA_INTEL
-       tristate "Intel HD Audio"
+menu "HD-Audio"
+
+config SND_HDA
+       tristate
        select SND_PCM
        select SND_VMASTER
        select SND_KCTL_JACK
+
+config SND_HDA_INTEL
+       tristate "HD Audio PCI"
+       depends on SND_PCI
+       select SND_HDA
        help
          Say Y here to include support for Intel "High Definition
          Audio" (Azalia) and its compatible devices.
@@ -13,7 +20,7 @@ menuconfig SND_HDA_INTEL
          To compile this driver as a module, choose M here: the module
          will be called snd-hda-intel.
 
-if SND_HDA_INTEL
+if SND_HDA
 
 config SND_HDA_DSP_LOADER
        bool
@@ -41,7 +48,6 @@ config SND_HDA_HWDEP
 
 config SND_HDA_RECONFIG
        bool "Allow dynamic codec reconfiguration"
-       depends on SND_HDA_HWDEP
        help
          Say Y here to enable the HD-audio codec re-configuration feature.
          This adds the sysfs interfaces to allow user to clear the whole
@@ -50,7 +56,7 @@ config SND_HDA_RECONFIG
 
 config SND_HDA_INPUT_BEEP
        bool "Support digital beep via input layer"
-       depends on INPUT=y || INPUT=SND_HDA_INTEL
+       depends on INPUT=y || INPUT=SND_HDA
        help
          Say Y here to build a digital beep interface for HD-audio
          driver. This interface is used to generate digital beeps.
@@ -76,7 +82,6 @@ config SND_HDA_INPUT_JACK
 config SND_HDA_PATCH_LOADER
        bool "Support initialization patch loading for HD-audio"
        select FW_LOADER
-       select SND_HDA_HWDEP
        select SND_HDA_RECONFIG
        help
          Say Y here to allow the HD-audio driver to load a pseudo
@@ -84,8 +89,6 @@ config SND_HDA_PATCH_LOADER
          start up.  The "patch" file can be specified via patch module
          option, such as patch=hda-init.
 
-         This option turns on hwdep and reconfig features automatically.
-
 config SND_HDA_CODEC_REALTEK
        tristate "Build Realtek HD-audio codec support"
        select SND_HDA_GENERIC
@@ -94,7 +97,7 @@ config SND_HDA_CODEC_REALTEK
          snd-hda-intel driver, such as ALC880.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_REALTEK=m
+       depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
 
 config SND_HDA_CODEC_ANALOG
        tristate "Build Analog Device HD-audio codec support"
@@ -104,7 +107,7 @@ config SND_HDA_CODEC_ANALOG
          snd-hda-intel driver, such as AD1986A.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_ANALOG=m
+       depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m
 
 config SND_HDA_CODEC_SIGMATEL
        tristate "Build IDT/Sigmatel HD-audio codec support"
@@ -114,7 +117,7 @@ config SND_HDA_CODEC_SIGMATEL
          snd-hda-intel driver, such as STAC9200.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_SIGMATEL=m
+       depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m
 
 config SND_HDA_CODEC_VIA
        tristate "Build VIA HD-audio codec support"
@@ -124,7 +127,7 @@ config SND_HDA_CODEC_VIA
          snd-hda-intel driver, such as VT1708.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_VIA=m
+       depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
 
 config SND_HDA_CODEC_HDMI
        tristate "Build HDMI/DisplayPort HD-audio codec support"
@@ -134,7 +137,7 @@ config SND_HDA_CODEC_HDMI
          Intel and Nvidia HDMI/DisplayPort codecs.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_HDMI=m
+       depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
 
 config SND_HDA_I915
        bool
@@ -149,7 +152,7 @@ config SND_HDA_CODEC_CIRRUS
          snd-hda-intel driver, such as CS4206.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CIRRUS=m
+       depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
 
 config SND_HDA_CODEC_CONEXANT
        tristate "Build Conexant HD-audio codec support"
@@ -159,7 +162,7 @@ config SND_HDA_CODEC_CONEXANT
          snd-hda-intel driver, such as CX20549.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CONEXANT=m
+       depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
 
 config SND_HDA_CODEC_CA0110
        tristate "Build Creative CA0110-IBG codec support"
@@ -169,7 +172,7 @@ config SND_HDA_CODEC_CA0110
          snd-hda-intel driver, found on some Creative X-Fi cards.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CA0110=m
+       depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m
 
 config SND_HDA_CODEC_CA0132
        tristate "Build Creative CA0132 codec support"
@@ -178,7 +181,7 @@ config SND_HDA_CODEC_CA0132
          snd-hda-intel driver.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CA0132=m
+       depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m
 
 config SND_HDA_CODEC_CA0132_DSP
        bool "Support new DSP code for CA0132 codec"
@@ -200,7 +203,7 @@ config SND_HDA_CODEC_CMEDIA
          snd-hda-intel driver, such as CMI9880.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CMEDIA=m
+       depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
 
 config SND_HDA_CODEC_SI3054
        tristate "Build Silicon Labs 3054 HD-modem codec support"
@@ -209,7 +212,7 @@ config SND_HDA_CODEC_SI3054
          (and compatibles) support in snd-hda-intel driver.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_CODEC_SI3054=m
+       depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m
 
 config SND_HDA_GENERIC
        tristate "Enable generic HD-audio codec parser"
@@ -218,7 +221,7 @@ config SND_HDA_GENERIC
          in snd-hda-intel driver.
 
 comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA_INTEL=y && SND_HDA_GENERIC=m
+       depends on SND_HDA=y && SND_HDA_GENERIC=m
 
 config SND_HDA_POWER_SAVE_DEFAULT
        int "Default time-out for HD-audio power-save mode"
@@ -229,3 +232,5 @@ config SND_HDA_POWER_SAVE_DEFAULT
          power-save mode.  0 means to disable the power-save mode.
 
 endif
+
+endmenu
index 1fcb118e480afc77617c01c6c681f0e24891a27d..d0d0c19ddfc2f83bc23ad6a40c0ef4d069d351c8 100644 (file)
@@ -1,15 +1,16 @@
 snd-hda-intel-objs := hda_intel.o
+snd-hda-controller-objs := hda_controller.o
 # for haswell power well
 snd-hda-intel-$(CONFIG_SND_HDA_I915) +=        hda_i915.o
 
-snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
+snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 
 # for trace-points
 CFLAGS_hda_codec.o := -I$(src)
-CFLAGS_hda_intel.o := -I$(src)
+CFLAGS_hda_controller.o := -I$(src)
 
 snd-hda-codec-generic-objs :=  hda_generic.o
 snd-hda-codec-realtek-objs :=  patch_realtek.o
@@ -25,7 +26,8 @@ snd-hda-codec-via-objs :=     patch_via.o
 snd-hda-codec-hdmi-objs :=     patch_hdmi.o hda_eld.o
 
 # common driver
-obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
+obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
+obj-$(CONFIG_SND_HDA) += snd-hda-controller.o
 
 # codec drivers
 obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
index 47ad31c6aa702c1e0783b75f7b5f9ac8ed5bc5dc..90d2fda6c8f99935b810425e64d98b6840e333a4 100644 (file)
@@ -227,10 +227,18 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                                continue;
                        if (!assoc_line_out)
                                assoc_line_out = assoc;
-                       else if (assoc_line_out != assoc)
+                       else if (assoc_line_out != assoc) {
+                               codec_info(codec,
+                                          "ignore pin 0x%x with mismatching assoc# 0x%x vs 0x%x\n",
+                                          nid, assoc, assoc_line_out);
                                continue;
-                       if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
+                       }
+                       if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) {
+                               codec_info(codec,
+                                          "ignore pin 0x%x, too many assigned pins\n",
+                                          nid);
                                continue;
+                       }
                        line_out[cfg->line_outs].pin = nid;
                        line_out[cfg->line_outs].seq = seq;
                        cfg->line_outs++;
@@ -238,8 +246,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                case AC_JACK_SPEAKER:
                        seq = get_defcfg_sequence(def_conf);
                        assoc = get_defcfg_association(def_conf);
-                       if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
+                       if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) {
+                               codec_info(codec,
+                                          "ignore pin 0x%x, too many assigned pins\n",
+                                          nid);
                                continue;
+                       }
                        speaker_out[cfg->speaker_outs].pin = nid;
                        speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq;
                        cfg->speaker_outs++;
@@ -247,8 +259,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                case AC_JACK_HP_OUT:
                        seq = get_defcfg_sequence(def_conf);
                        assoc = get_defcfg_association(def_conf);
-                       if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
+                       if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) {
+                               codec_info(codec,
+                                          "ignore pin 0x%x, too many assigned pins\n",
+                                          nid);
                                continue;
+                       }
                        hp_out[cfg->hp_outs].pin = nid;
                        hp_out[cfg->hp_outs].seq = (assoc << 4) | seq;
                        cfg->hp_outs++;
@@ -267,8 +283,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                        break;
                case AC_JACK_SPDIF_OUT:
                case AC_JACK_DIG_OTHER_OUT:
-                       if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
+                       if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) {
+                               codec_info(codec,
+                                          "ignore pin 0x%x, too many assigned pins\n",
+                                          nid);
                                continue;
+                       }
                        cfg->dig_out_pins[cfg->dig_outs] = nid;
                        cfg->dig_out_type[cfg->dig_outs] =
                                (loc == AC_JACK_LOC_HDMI) ?
@@ -313,9 +333,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                }
 
                if (hsmic)
-                       snd_printdd("Told to look for a headset mic, but didn't find any.\n");
+                       codec_dbg(codec, "Told to look for a headset mic, but didn't find any.\n");
                if (hpmic)
-                       snd_printdd("Told to look for a headphone mic, but didn't find any.\n");
+                       codec_dbg(codec, "Told to look for a headphone mic, but didn't find any.\n");
        }
 
        /* FIX-UP:
@@ -384,33 +404,33 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        /*
         * debug prints of the parsed results
         */
-       snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+       codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
                   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
                   cfg->line_out_pins[2], cfg->line_out_pins[3],
                   cfg->line_out_pins[4],
                   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
                   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
                    "speaker" : "line"));
-       snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+       codec_info(codec, "   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   cfg->speaker_outs, cfg->speaker_pins[0],
                   cfg->speaker_pins[1], cfg->speaker_pins[2],
                   cfg->speaker_pins[3], cfg->speaker_pins[4]);
-       snd_printd("   hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+       codec_info(codec, "   hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   cfg->hp_outs, cfg->hp_pins[0],
                   cfg->hp_pins[1], cfg->hp_pins[2],
                   cfg->hp_pins[3], cfg->hp_pins[4]);
-       snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
+       codec_info(codec, "   mono: mono_out=0x%x\n", cfg->mono_out_pin);
        if (cfg->dig_outs)
-               snd_printd("   dig-out=0x%x/0x%x\n",
+               codec_info(codec, "   dig-out=0x%x/0x%x\n",
                           cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-       snd_printd("   inputs:\n");
+       codec_info(codec, "   inputs:\n");
        for (i = 0; i < cfg->num_inputs; i++) {
-               snd_printd("     %s=0x%x\n",
+               codec_info(codec, "     %s=0x%x\n",
                            hda_get_autocfg_input_label(codec, cfg, i),
                            cfg->inputs[i].pin);
        }
        if (cfg->dig_in_pin)
-               snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
+               codec_info(codec, "   dig-in=0x%x\n", cfg->dig_in_pin);
 
        return 0;
 }
@@ -774,38 +794,33 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
                case HDA_FIXUP_PINS:
                        if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
                                break;
-                       snd_printdd(KERN_INFO SFX
-                                   "%s: Apply pincfg for %s\n",
+                       codec_dbg(codec, "%s: Apply pincfg for %s\n",
                                    codec->chip_name, modelname);
                        snd_hda_apply_pincfgs(codec, fix->v.pins);
                        break;
                case HDA_FIXUP_VERBS:
                        if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
                                break;
-                       snd_printdd(KERN_INFO SFX
-                                   "%s: Apply fix-verbs for %s\n",
+                       codec_dbg(codec, "%s: Apply fix-verbs for %s\n",
                                    codec->chip_name, modelname);
                        snd_hda_add_verbs(codec, fix->v.verbs);
                        break;
                case HDA_FIXUP_FUNC:
                        if (!fix->v.func)
                                break;
-                       snd_printdd(KERN_INFO SFX
-                                   "%s: Apply fix-func for %s\n",
+                       codec_dbg(codec, "%s: Apply fix-func for %s\n",
                                    codec->chip_name, modelname);
                        fix->v.func(codec, fix, action);
                        break;
                case HDA_FIXUP_PINCTLS:
                        if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins)
                                break;
-                       snd_printdd(KERN_INFO SFX
-                                   "%s: Apply pinctl for %s\n",
+                       codec_dbg(codec, "%s: Apply pinctl for %s\n",
                                    codec->chip_name, modelname);
                        set_pin_targets(codec, fix->v.pins);
                        break;
                default:
-                       snd_printk(KERN_ERR SFX
-                                  "%s: Invalid fixup type %d\n",
+                       codec_err(codec, "%s: Invalid fixup type %d\n",
                                   codec->chip_name, fix->type);
                        break;
                }
index 0589b39cda6e413a5ef76025638cf80a6bc025b5..8c6c50afc0b732796d3c6d5aa7586d72751de55f 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/input.h>
-#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/export.h>
@@ -140,7 +139,10 @@ static void turn_off_beep(struct hda_beep *beep)
 
 static void snd_hda_do_detach(struct hda_beep *beep)
 {
-       input_unregister_device(beep->dev);
+       if (beep->registered)
+               input_unregister_device(beep->dev);
+       else
+               input_free_device(beep->dev);
        beep->dev = NULL;
        turn_off_beep(beep);
 }
@@ -149,7 +151,6 @@ static int snd_hda_do_attach(struct hda_beep *beep)
 {
        struct input_dev *input_dev;
        struct hda_codec *codec = beep->codec;
-       int err;
 
        input_dev = input_allocate_device();
        if (!input_dev)
@@ -167,15 +168,9 @@ static int snd_hda_do_attach(struct hda_beep *beep)
        input_dev->evbit[0] = BIT_MASK(EV_SND);
        input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
        input_dev->event = snd_hda_beep_event;
-       input_dev->dev.parent = &codec->bus->pci->dev;
+       input_dev->dev.parent = &codec->dev;
        input_set_drvdata(input_dev, beep);
 
-       err = input_register_device(input_dev);
-       if (err < 0) {
-               input_free_device(input_dev);
-               printk(KERN_INFO "hda_beep: unable to register input device\n");
-               return err;
-       }
        beep->dev = input_dev;
        return 0;
 }
@@ -245,6 +240,27 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
 
+int snd_hda_register_beep_device(struct hda_codec *codec)
+{
+       struct hda_beep *beep = codec->beep;
+       int err;
+
+       if (!beep || !beep->dev)
+               return 0;
+
+       err = input_register_device(beep->dev);
+       if (err < 0) {
+               codec_err(codec, "hda_beep: unable to register input device\n");
+               input_free_device(beep->dev);
+               codec->beep = NULL;
+               kfree(beep);
+               return err;
+       }
+       beep->registered = true;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_register_beep_device);
+
 static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
index cb88464676b656e109bd452ffbe1a94114cdcdd4..a63b5e077332a94e5a8e29457d2f6818c258ed6d 100644 (file)
@@ -34,6 +34,7 @@ struct hda_beep {
        char phys[32];
        int tone;
        hda_nid_t nid;
+       unsigned int registered:1;
        unsigned int enabled:1;
        unsigned int linear_tone:1;     /* linear tone for IDT/STAC codec */
        unsigned int playing:1;
@@ -45,6 +46,7 @@ struct hda_beep {
 int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
 void snd_hda_detach_beep_device(struct hda_codec *codec);
+int snd_hda_register_beep_device(struct hda_codec *codec);
 #else
 static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
 {
@@ -53,5 +55,9 @@ static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
 static inline void snd_hda_detach_beep_device(struct hda_codec *codec)
 {
 }
+static inline int snd_hda_register_beep_device(struct hda_codec *codec)
+{
+       return 0;
+}
 #endif
 #endif
index dafcf82139e2bbdcdb4bad0539ad6c616661d892..4c20277a683531fccf5be99f9995d438e961fe92 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/async.h>
@@ -68,6 +67,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
        { 0x17e8, "Chrontel" },
        { 0x1854, "LG" },
        { 0x1aec, "Wolfson Microelectronics" },
+       { 0x1af4, "QEMU" },
        { 0x434d, "C-Media" },
        { 0x8086, "Intel" },
        { 0x8384, "SigmaTel" },
@@ -201,7 +201,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
 
        if ((codec->addr & ~0xf) || (nid & ~0x7f) ||
            (verb & ~0xfff) || (parm & ~0xffff)) {
-               printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x\n",
+               codec_err(codec, "hda-codec: out of range cmd %x:%x:%x:%x\n",
                       codec->addr, nid, verb, parm);
                return ~0;
        }
@@ -249,8 +249,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
        snd_hda_power_down(codec);
        if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
                if (bus->response_reset) {
-                       snd_printd("hda_codec: resetting BUS due to "
-                                  "fatal communication error\n");
+                       codec_dbg(codec,
+                                 "resetting BUS due to fatal communication error\n");
                        trace_hda_bus_reset(bus);
                        bus->ops.bus_reset(bus);
                }
@@ -475,8 +475,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 
        if (len > 0 && conn_list) {
                if (len > max_conns) {
-                       snd_printk(KERN_ERR "hda_codec: "
-                                  "Too many connections %d for NID 0x%x\n",
+                       codec_err(codec, "Too many connections %d for NID 0x%x\n",
                                   len, nid);
                        return -EINVAL;
                }
@@ -574,8 +573,8 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                range_val = !!(parm & (1 << (shift-1))); /* ranges */
                val = parm & mask;
                if (val == 0 && null_count++) {  /* no second chance */
-                       snd_printdd("hda_codec: "
-                                  "invalid CONNECT_LIST verb %x[%i]:%x\n",
+                       codec_dbg(codec,
+                                 "invalid CONNECT_LIST verb %x[%i]:%x\n",
                                    nid, i, parm);
                        return 0;
                }
@@ -583,7 +582,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
                if (range_val) {
                        /* ranges between the previous and this one */
                        if (!prev_nid || prev_nid >= val) {
-                               snd_printk(KERN_WARNING "hda_codec: "
+                               codec_warn(codec,
                                           "invalid dep_range_val %x:%x\n",
                                           prev_nid, val);
                                continue;
@@ -660,7 +659,7 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
        if (!recursive)
                return -1;
        if (recursive > 10) {
-               snd_printd("hda_codec: too deep connection for 0x%x\n", nid);
+               codec_dbg(codec, "too deep connection for 0x%x\n", nid);
                return -1;
        }
        recursive++;
@@ -808,8 +807,7 @@ static int init_unsol_queue(struct hda_bus *bus)
 
        unsol = kzalloc(sizeof(*unsol), GFP_KERNEL);
        if (!unsol) {
-               snd_printk(KERN_ERR "hda_codec: "
-                          "can't allocate unsolicited queue\n");
+               dev_err(bus->card->dev, "can't allocate unsolicited queue\n");
                return -ENOMEM;
        }
        INIT_WORK(&unsol->work, process_unsol_events);
@@ -821,51 +819,36 @@ static int init_unsol_queue(struct hda_bus *bus)
 /*
  * destructor
  */
-static void snd_hda_codec_free(struct hda_codec *codec);
-
-static int snd_hda_bus_free(struct hda_bus *bus)
+static void snd_hda_bus_free(struct hda_bus *bus)
 {
-       struct hda_codec *codec, *n;
-
        if (!bus)
-               return 0;
+               return;
+
+       WARN_ON(!list_empty(&bus->codec_list));
        if (bus->workq)
                flush_workqueue(bus->workq);
        if (bus->unsol)
                kfree(bus->unsol);
-       list_for_each_entry_safe(codec, n, &bus->codec_list, list) {
-               snd_hda_codec_free(codec);
-       }
        if (bus->ops.private_free)
                bus->ops.private_free(bus);
        if (bus->workq)
                destroy_workqueue(bus->workq);
 
        kfree(bus);
-       return 0;
 }
 
 static int snd_hda_bus_dev_free(struct snd_device *device)
 {
-       struct hda_bus *bus = device->device_data;
-       bus->shutdown = 1;
-       return snd_hda_bus_free(bus);
+       snd_hda_bus_free(device->device_data);
+       return 0;
 }
 
-#ifdef CONFIG_SND_HDA_HWDEP
-static int snd_hda_bus_dev_register(struct snd_device *device)
+static int snd_hda_bus_dev_disconnect(struct snd_device *device)
 {
        struct hda_bus *bus = device->device_data;
-       struct hda_codec *codec;
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               snd_hda_hwdep_add_sysfs(codec);
-               snd_hda_hwdep_add_power_sysfs(codec);
-       }
+       bus->shutdown = 1;
        return 0;
 }
-#else
-#define snd_hda_bus_dev_register       NULL
-#endif
 
 /**
  * snd_hda_bus_new - create a HDA bus
@@ -882,7 +865,7 @@ int snd_hda_bus_new(struct snd_card *card,
        struct hda_bus *bus;
        int err;
        static struct snd_device_ops dev_ops = {
-               .dev_register = snd_hda_bus_dev_register,
+               .dev_disconnect = snd_hda_bus_dev_disconnect,
                .dev_free = snd_hda_bus_dev_free,
        };
 
@@ -896,7 +879,7 @@ int snd_hda_bus_new(struct snd_card *card,
 
        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
        if (bus == NULL) {
-               snd_printk(KERN_ERR "can't allocate struct hda_bus\n");
+               dev_err(card->dev, "can't allocate struct hda_bus\n");
                return -ENOMEM;
        }
 
@@ -915,7 +898,7 @@ int snd_hda_bus_new(struct snd_card *card,
                 "hd-audio%d", card->number);
        bus->workq = create_singlethread_workqueue(bus->workq_name);
        if (!bus->workq) {
-               snd_printk(KERN_ERR "cannot create workqueue %s\n",
+               dev_err(card->dev, "cannot create workqueue %s\n",
                           bus->workq_name);
                kfree(bus);
                return -ENOMEM;
@@ -959,7 +942,7 @@ find_codec_preset(struct hda_codec *codec)
        mutex_lock(&preset_mutex);
        list_for_each_entry(tbl, &hda_preset_tables, list) {
                if (!try_module_get(tbl->owner)) {
-                       snd_printk(KERN_ERR "hda_codec: cannot module_get\n");
+                       codec_err(codec, "cannot module_get\n");
                        continue;
                }
                for (preset = tbl->preset; preset->id; preset++) {
@@ -1185,7 +1168,7 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
 {
        struct hda_pincfg *pin;
 
-#ifdef CONFIG_SND_HDA_HWDEP
+#ifdef CONFIG_SND_HDA_RECONFIG
        {
                unsigned int cfg = 0;
                mutex_lock(&codec->user_mutex);
@@ -1300,7 +1283,7 @@ static void free_hda_cache(struct hda_cache_rec *cache);
 static void free_init_pincfgs(struct hda_codec *codec)
 {
        snd_array_free(&codec->driver_pins);
-#ifdef CONFIG_SND_HDA_HWDEP
+#ifdef CONFIG_SND_HDA_RECONFIG
        snd_array_free(&codec->user_pins);
 #endif
        snd_array_free(&codec->init_pins);
@@ -1374,6 +1357,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
        hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
+       snd_hda_sysfs_clear(codec);
        unload_parser(codec);
        module_put(codec->owner);
        free_hda_cache(&codec->amp_cache);
@@ -1383,7 +1367,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        kfree(codec->modelname);
        kfree(codec->wcaps);
        codec->bus->num_codecs--;
-       kfree(codec);
+       put_device(&codec->dev);
 }
 
 static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
@@ -1392,6 +1376,38 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
 static unsigned int hda_set_power_state(struct hda_codec *codec,
                                unsigned int power_state);
 
+static int snd_hda_codec_dev_register(struct snd_device *device)
+{
+       struct hda_codec *codec = device->device_data;
+       int err = device_add(&codec->dev);
+
+       if (err < 0)
+               return err;
+       snd_hda_register_beep_device(codec);
+       return 0;
+}
+
+static int snd_hda_codec_dev_disconnect(struct snd_device *device)
+{
+       struct hda_codec *codec = device->device_data;
+
+       snd_hda_detach_beep_device(codec);
+       device_del(&codec->dev);
+       return 0;
+}
+
+static int snd_hda_codec_dev_free(struct snd_device *device)
+{
+       snd_hda_codec_free(device->device_data);
+       return 0;
+}
+
+/* just free the container */
+static void snd_hda_codec_dev_release(struct device *dev)
+{
+       kfree(container_of(dev, struct hda_codec, dev));
+}
+
 /**
  * snd_hda_codec_new - create a HDA codec
  * @bus: the bus to assign
@@ -1408,6 +1424,11 @@ int snd_hda_codec_new(struct hda_bus *bus,
        char component[31];
        hda_nid_t fg;
        int err;
+       static struct snd_device_ops dev_ops = {
+               .dev_register = snd_hda_codec_dev_register,
+               .dev_disconnect = snd_hda_codec_dev_disconnect,
+               .dev_free = snd_hda_codec_dev_free,
+       };
 
        if (snd_BUG_ON(!bus))
                return -EINVAL;
@@ -1415,17 +1436,27 @@ int snd_hda_codec_new(struct hda_bus *bus,
                return -EINVAL;
 
        if (bus->caddr_tbl[codec_addr]) {
-               snd_printk(KERN_ERR "hda_codec: "
-                          "address 0x%x is already occupied\n", codec_addr);
+               dev_err(bus->card->dev,
+                       "address 0x%x is already occupied\n",
+                       codec_addr);
                return -EBUSY;
        }
 
        codec = kzalloc(sizeof(*codec), GFP_KERNEL);
        if (codec == NULL) {
-               snd_printk(KERN_ERR "can't allocate struct hda_codec\n");
+               dev_err(bus->card->dev, "can't allocate struct hda_codec\n");
                return -ENOMEM;
        }
 
+       device_initialize(&codec->dev);
+       codec->dev.parent = &bus->card->card_dev;
+       codec->dev.class = sound_class;
+       codec->dev.release = snd_hda_codec_dev_release;
+       codec->dev.groups = snd_hda_dev_attr_groups;
+       dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number,
+                    codec_addr);
+       dev_set_drvdata(&codec->dev, codec); /* for sysfs */
+
        codec->bus = bus;
        codec->addr = codec_addr;
        mutex_init(&codec->spdif_mutex);
@@ -1456,11 +1487,13 @@ int snd_hda_codec_new(struct hda_bus *bus,
        hda_keep_power_on(codec);
 #endif
 
+       snd_hda_sysfs_init(codec);
+
        if (codec->bus->modelname) {
                codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
                if (!codec->modelname) {
-                       snd_hda_codec_free(codec);
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto error;
                }
        }
 
@@ -1484,7 +1517,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
 
        setup_fg_nodes(codec);
        if (!codec->afg && !codec->mfg) {
-               snd_printdd("hda_codec: no AFG or MFG node found\n");
+               dev_err(bus->card->dev, "no AFG or MFG node found\n");
                err = -ENODEV;
                goto error;
        }
@@ -1492,7 +1525,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
        fg = codec->afg ? codec->afg : codec->mfg;
        err = read_widget_caps(codec, fg);
        if (err < 0) {
-               snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
+               dev_err(bus->card->dev, "cannot malloc\n");
                goto error;
        }
        err = read_pin_defaults(codec);
@@ -1528,6 +1561,10 @@ int snd_hda_codec_new(struct hda_bus *bus,
                codec->subsystem_id, codec->revision_id);
        snd_component_add(codec->bus->card, component);
 
+       err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops);
+       if (err < 0)
+               goto error;
+
        if (codecp)
                *codecp = codec;
        return 0;
@@ -1550,7 +1587,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
        fg = codec->afg ? codec->afg : codec->mfg;
        err = read_widget_caps(codec, fg);
        if (err < 0) {
-               snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
+               codec_err(codec, "cannot malloc\n");
                return err;
        }
 
@@ -1627,7 +1664,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
 #endif
                }
                if (!patch) {
-                       printk(KERN_ERR "hda-codec: No codec parser is available\n");
+                       codec_err(codec, "No codec parser is available\n");
                        return -ENODEV;
                }
        }
@@ -1711,9 +1748,9 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        if (!nid)
                return;
 
-       snd_printdd("hda_codec_setup_stream: "
-                   "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
-                   nid, stream_tag, channel_id, format);
+       codec_dbg(codec,
+                 "hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
+                 nid, stream_tag, channel_id, format);
        p = get_hda_cvt_setup(codec, nid);
        if (!p)
                return;
@@ -1760,7 +1797,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
        if (codec->no_sticky_stream)
                do_now = 1;
 
-       snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
+       codec_dbg(codec, "hda_codec_cleanup_stream: NID=0x%x\n", nid);
        p = get_hda_cvt_setup(codec, nid);
        if (p) {
                /* here we just clear the active flag when do_now isn't set;
@@ -2282,9 +2319,9 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
        uinfo->value.integer.min = 0;
        uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
        if (!uinfo->value.integer.max) {
-               printk(KERN_WARNING "hda_codec: "
-                      "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
-                      kcontrol->id.name);
+               codec_warn(codec,
+                          "num_steps = 0 for NID=0x%x (ctl = %s)\n",
+                          nid, kcontrol->id.name);
                return -EINVAL;
        }
        return 0;
@@ -2558,8 +2595,8 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
                item->nid = nid;
                return 0;
        }
-       printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n",
-              kctl->id.name, kctl->id.index, index);
+       codec_err(codec, "no NID for mapping control %s:%d:%d\n",
+                 kctl->id.name, kctl->id.index, index);
        return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(snd_hda_add_nid);
@@ -2660,6 +2697,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
                                  bus->pcm_dev_bits);
                }
        }
+       snd_hda_detach_beep_device(codec);
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
        memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
@@ -2751,7 +2789,7 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check)
                        return -1;
                if (*step_to_check && *step_to_check != step) {
                        snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n",
-                                  *step_to_check, step);
+-                                 *step_to_check, step);
                        return -1;
                }
                *step_to_check = step;
@@ -2821,7 +2859,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 
        err = map_slaves(codec, slaves, suffix, check_slave_present, NULL);
        if (err != 1) {
-               snd_printdd("No slave found for %s\n", name);
+               codec_dbg(codec, "No slave found for %s\n", name);
                return 0;
        }
        kctl = snd_ctl_make_virtual_master(name, tlv);
@@ -3487,7 +3525,7 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
 
        idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", idx);
        if (idx < 0) {
-               printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
+               codec_err(codec, "too many IEC958 outputs\n");
                return -EBUSY;
        }
        spdif = snd_array_new(&codec->spdif_out);
@@ -3691,7 +3729,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
 
        idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0);
        if (idx < 0) {
-               printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
+               codec_err(codec, "too many IEC958 inputs\n");
                return -EBUSY;
        }
        for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
@@ -4010,7 +4048,7 @@ static void sync_power_up_states(struct hda_codec *codec)
        }
 }
 
-#ifdef CONFIG_SND_HDA_HWDEP
+#ifdef CONFIG_SND_HDA_RECONFIG
 /* execute additional init verbs */
 static void hda_exec_init_verbs(struct hda_codec *codec)
 {
@@ -4118,12 +4156,13 @@ int snd_hda_build_controls(struct hda_bus *bus)
        list_for_each_entry(codec, &bus->codec_list, list) {
                int err = snd_hda_codec_build_controls(codec);
                if (err < 0) {
-                       printk(KERN_ERR "hda_codec: cannot build controls "
-                              "for #%d (error %d)\n", codec->addr, err);
+                       codec_err(codec,
+                                 "cannot build controls for #%d (error %d)\n",
+                                 codec->addr, err);
                        err = snd_hda_codec_reset(codec);
                        if (err < 0) {
-                               printk(KERN_ERR
-                                      "hda_codec: cannot revert codec\n");
+                               codec_err(codec,
+                                         "cannot revert codec\n");
                                return err;
                        }
                }
@@ -4294,7 +4333,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
                break;
        default:
                snd_printdd("invalid format width %d\n",
-                           snd_pcm_format_width(format));
+                         snd_pcm_format_width(format));
                return 0;
        }
 
@@ -4370,10 +4409,10 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                                rates |= rate_bits[i].alsa_bits;
                }
                if (rates == 0) {
-                       snd_printk(KERN_ERR "hda_codec: rates == 0 "
-                                  "(nid=0x%x, val=0x%x, ovrd=%i)\n",
-                                       nid, val,
-                                       (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0);
+                       codec_err(codec,
+                                 "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n",
+                                 nid, val,
+                                 (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0);
                        return -EIO;
                }
                *ratesp = rates;
@@ -4433,12 +4472,11 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                        bps = 8;
                }
                if (formats == 0) {
-                       snd_printk(KERN_ERR "hda_codec: formats == 0 "
-                                  "(nid=0x%x, val=0x%x, ovrd=%i, "
-                                  "streams=0x%x)\n",
-                                       nid, val,
-                                       (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0,
-                                       streams);
+                       codec_err(codec,
+                                 "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n",
+                                 nid, val,
+                                 (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0,
+                                 streams);
                        return -EIO;
                }
                if (formatsp)
@@ -4629,7 +4667,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
        int i;
 
        if (type >= HDA_PCM_NTYPES) {
-               snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
+               dev_err(bus->card->dev, "Invalid PCM type %d\n", type);
                return -EINVAL;
        }
 
@@ -4650,10 +4688,11 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
        }
 #endif
 
-       snd_printk(KERN_WARNING "Too many %s devices\n",
+       dev_warn(bus->card->dev, "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");
+       dev_warn(bus->card->dev,
+                "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
 #endif
        return -EAGAIN;
 }
@@ -4691,12 +4730,13 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
                        return 0;
                err = codec->patch_ops.build_pcms(codec);
                if (err < 0) {
-                       printk(KERN_ERR "hda_codec: cannot build PCMs"
-                              "for #%d (error %d)\n", codec->addr, err);
+                       codec_err(codec,
+                                 "cannot build PCMs for #%d (error %d)\n",
+                                 codec->addr, err);
                        err = snd_hda_codec_reset(codec);
                        if (err < 0) {
-                               printk(KERN_ERR
-                                      "hda_codec: cannot revert codec\n");
+                               codec_err(codec,
+                                         "cannot revert codec\n");
                                return err;
                        }
                }
@@ -4715,9 +4755,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
                        cpcm->device = dev;
                        err = snd_hda_attach_pcm(codec, cpcm);
                        if (err < 0) {
-                               printk(KERN_ERR "hda_codec: cannot attach "
-                                      "PCM stream %d for codec #%d\n",
-                                      dev, codec->addr);
+                               codec_err(codec,
+                                         "cannot attach PCM stream %d for codec #%d\n",
+                                         dev, codec->addr);
                                continue; /* no fatal error */
                        }
                }
@@ -4786,8 +4826,8 @@ int snd_hda_check_board_config(struct hda_codec *codec,
                for (i = 0; i < num_configs; i++) {
                        if (models[i] &&
                            !strcmp(codec->modelname, models[i])) {
-                               snd_printd(KERN_INFO "hda_codec: model '%s' is "
-                                          "selected\n", models[i]);
+                               codec_info(codec, "model '%s' is selected\n",
+                                          models[i]);
                                return i;
                        }
                }
@@ -4809,10 +4849,9 @@ int snd_hda_check_board_config(struct hda_codec *codec,
                        sprintf(tmp, "#%d", tbl->value);
                        model = tmp;
                }
-               snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
-                           "for config %x:%x (%s)\n",
-                           model, tbl->subvendor, tbl->subdevice,
-                           (tbl->name ? tbl->name : "Unknown device"));
+               codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
+                          model, tbl->subvendor, tbl->subdevice,
+                          (tbl->name ? tbl->name : "Unknown device"));
 #endif
                return tbl->value;
        }
@@ -4870,10 +4909,9 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
                        sprintf(tmp, "#%d", tbl->value);
                        model = tmp;
                }
-               snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
-                           "for config %x:%x (%s)\n",
-                           model, tbl->subvendor, tbl->subdevice,
-                           (tbl->name ? tbl->name : "Unknown device"));
+               codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
+                          model, tbl->subvendor, tbl->subdevice,
+                          (tbl->name ? tbl->name : "Unknown device"));
 #endif
                return tbl->value;
        }
index ab2a444ba5017b6cab3afa91119355f798e29917..a4233136cb93d83b0ca3f2f583a7896d1b8e0567 100644 (file)
@@ -271,6 +271,7 @@ struct hda_pcm {
 
 /* codec information */
 struct hda_codec {
+       struct device dev;
        struct hda_bus *bus;
        unsigned int addr;      /* codec addr*/
        struct list_head list;  /* list point */
@@ -332,14 +333,17 @@ struct hda_codec {
        struct snd_array driver_pins;   /* pin configs set by codec parser */
        struct snd_array cvt_setups;    /* audio convert setups */
 
-#ifdef CONFIG_SND_HDA_HWDEP
        struct mutex user_mutex;
-       struct snd_hwdep *hwdep;        /* assigned hwdep device */
+#ifdef CONFIG_SND_HDA_RECONFIG
        struct snd_array init_verbs;    /* additional init verbs */
        struct snd_array hints;         /* additional hints */
        struct snd_array user_pins;     /* default pin configs to override */
 #endif
 
+#ifdef CONFIG_SND_HDA_HWDEP
+       struct snd_hwdep *hwdep;        /* assigned hwdep device */
+#endif
+
        /* misc flags */
        unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
                                             * status change
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
new file mode 100644 (file)
index 0000000..97993e1
--- /dev/null
@@ -0,0 +1,2031 @@
+/*
+ *
+ *  Implementation of primary alsa driver code base for Intel HD Audio.
+ *
+ *  Copyright(c) 2004 Intel Corporation. All rights reserved.
+ *
+ *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *                     PeiSen Hou <pshou@realtek.com.tw>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  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/clocksource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "hda_priv.h"
+#include "hda_controller.h"
+
+#define CREATE_TRACE_POINTS
+#include "hda_intel_trace.h"
+
+/* DSP lock helpers */
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+#define dsp_lock_init(dev)     mutex_init(&(dev)->dsp_mutex)
+#define dsp_lock(dev)          mutex_lock(&(dev)->dsp_mutex)
+#define dsp_unlock(dev)                mutex_unlock(&(dev)->dsp_mutex)
+#define dsp_is_locked(dev)     ((dev)->locked)
+#else
+#define dsp_lock_init(dev)     do {} while (0)
+#define dsp_lock(dev)          do {} while (0)
+#define dsp_unlock(dev)                do {} while (0)
+#define dsp_is_locked(dev)     0
+#endif
+
+/*
+ * AZX stream operations.
+ */
+
+/* start a stream */
+static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
+{
+       /*
+        * Before stream start, initialize parameter
+        */
+       azx_dev->insufficient = 1;
+
+       /* enable SIE */
+       azx_writel(chip, INTCTL,
+                  azx_readl(chip, INTCTL) | (1 << azx_dev->index));
+       /* set DMA start and interrupt mask */
+       azx_sd_writeb(chip, azx_dev, SD_CTL,
+                     azx_sd_readb(chip, azx_dev, SD_CTL) |
+                     SD_CTL_DMA_START | SD_INT_MASK);
+}
+
+/* stop DMA */
+static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
+{
+       azx_sd_writeb(chip, azx_dev, SD_CTL,
+                     azx_sd_readb(chip, azx_dev, SD_CTL) &
+                     ~(SD_CTL_DMA_START | SD_INT_MASK));
+       azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+}
+
+/* stop a stream */
+void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
+{
+       azx_stream_clear(chip, azx_dev);
+       /* disable SIE */
+       azx_writel(chip, INTCTL,
+                  azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
+}
+EXPORT_SYMBOL_GPL(azx_stream_stop);
+
+/* reset stream */
+static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
+{
+       unsigned char val;
+       int timeout;
+
+       azx_stream_clear(chip, azx_dev);
+
+       azx_sd_writeb(chip, azx_dev, SD_CTL,
+                     azx_sd_readb(chip, azx_dev, SD_CTL) |
+                     SD_CTL_STREAM_RESET);
+       udelay(3);
+       timeout = 300;
+       while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
+                SD_CTL_STREAM_RESET) && --timeout)
+               ;
+       val &= ~SD_CTL_STREAM_RESET;
+       azx_sd_writeb(chip, azx_dev, SD_CTL, val);
+       udelay(3);
+
+       timeout = 300;
+       /* waiting for hardware to report that the stream is out of reset */
+       while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
+               SD_CTL_STREAM_RESET) && --timeout)
+               ;
+
+       /* reset first position - may not be synced with hw at this time */
+       *azx_dev->posbuf = 0;
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
+{
+       unsigned int val;
+       /* make sure the run bit is zero for SD */
+       azx_stream_clear(chip, azx_dev);
+       /* program the stream_tag */
+       val = azx_sd_readl(chip, azx_dev, SD_CTL);
+       val = (val & ~SD_CTL_STREAM_TAG_MASK) |
+               (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
+       if (!azx_snoop(chip))
+               val |= SD_CTL_TRAFFIC_PRIO;
+       azx_sd_writel(chip, azx_dev, SD_CTL, val);
+
+       /* program the length of samples in cyclic buffer */
+       azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize);
+
+       /* program the stream format */
+       /* this value needs to be the same as the one programmed */
+       azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val);
+
+       /* program the stream LVI (last valid index) of the BDL */
+       azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1);
+
+       /* program the BDL address */
+       /* lower BDL address */
+       azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
+       /* upper BDL address */
+       azx_sd_writel(chip, azx_dev, SD_BDLPU,
+                     upper_32_bits(azx_dev->bdl.addr));
+
+       /* enable the position buffer */
+       if (chip->position_fix[0] != POS_FIX_LPIB ||
+           chip->position_fix[1] != POS_FIX_LPIB) {
+               if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+                       azx_writel(chip, DPLBASE,
+                               (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+       }
+
+       /* set the interrupt enable bits in the descriptor control register */
+       azx_sd_writel(chip, azx_dev, SD_CTL,
+                     azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK);
+
+       return 0;
+}
+
+/* assign a stream for the PCM */
+static inline struct azx_dev *
+azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
+{
+       int dev, i, nums;
+       struct azx_dev *res = NULL;
+       /* make a non-zero unique key for the substream */
+       int key = (substream->pcm->device << 16) | (substream->number << 2) |
+               (substream->stream + 1);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dev = chip->playback_index_offset;
+               nums = chip->playback_streams;
+       } else {
+               dev = chip->capture_index_offset;
+               nums = chip->capture_streams;
+       }
+       for (i = 0; i < nums; i++, dev++) {
+               struct azx_dev *azx_dev = &chip->azx_dev[dev];
+               dsp_lock(azx_dev);
+               if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
+                       res = azx_dev;
+                       if (res->assigned_key == key) {
+                               res->opened = 1;
+                               res->assigned_key = key;
+                               dsp_unlock(azx_dev);
+                               return azx_dev;
+                       }
+               }
+               dsp_unlock(azx_dev);
+       }
+       if (res) {
+               dsp_lock(res);
+               res->opened = 1;
+               res->assigned_key = key;
+               dsp_unlock(res);
+       }
+       return res;
+}
+
+/* release the assigned stream */
+static inline void azx_release_device(struct azx_dev *azx_dev)
+{
+       azx_dev->opened = 0;
+}
+
+static cycle_t azx_cc_read(const struct cyclecounter *cc)
+{
+       struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc);
+       struct snd_pcm_substream *substream = azx_dev->substream;
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+
+       return azx_readl(chip, WALLCLK);
+}
+
+static void azx_timecounter_init(struct snd_pcm_substream *substream,
+                               bool force, cycle_t last)
+{
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       struct timecounter *tc = &azx_dev->azx_tc;
+       struct cyclecounter *cc = &azx_dev->azx_cc;
+       u64 nsec;
+
+       cc->read = azx_cc_read;
+       cc->mask = CLOCKSOURCE_MASK(32);
+
+       /*
+        * Converting from 24 MHz to ns means applying a 125/3 factor.
+        * To avoid any saturation issues in intermediate operations,
+        * the 125 factor is applied first. The division is applied
+        * last after reading the timecounter value.
+        * Applying the 1/3 factor as part of the multiplication
+        * requires at least 20 bits for a decent precision, however
+        * overflows occur after about 4 hours or less, not a option.
+        */
+
+       cc->mult = 125; /* saturation after 195 years */
+       cc->shift = 0;
+
+       nsec = 0; /* audio time is elapsed time since trigger */
+       timecounter_init(tc, cc, nsec);
+       if (force)
+               /*
+                * force timecounter to use predefined value,
+                * used for synchronized starts
+                */
+               tc->cycle_last = last;
+}
+
+static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
+                               u64 nsec)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       u64 codec_frames, codec_nsecs;
+
+       if (!hinfo->ops.get_delay)
+               return nsec;
+
+       codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
+       codec_nsecs = div_u64(codec_frames * 1000000000LL,
+                             substream->runtime->rate);
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               return nsec + codec_nsecs;
+
+       return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
+}
+
+/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct azx *chip,
+                     struct snd_dma_buffer *dmab,
+                     struct azx_dev *azx_dev, u32 **bdlp,
+                     int ofs, int size, int with_ioc)
+{
+       u32 *bdl = *bdlp;
+
+       while (size > 0) {
+               dma_addr_t addr;
+               int chunk;
+
+               if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
+                       return -EINVAL;
+
+               addr = snd_sgbuf_get_addr(dmab, ofs);
+               /* program the address field of the BDL entry */
+               bdl[0] = cpu_to_le32((u32)addr);
+               bdl[1] = cpu_to_le32(upper_32_bits(addr));
+               /* program the size field of the BDL entry */
+               chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
+               /* one BDLE cannot cross 4K boundary on CTHDA chips */
+               if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
+                       u32 remain = 0x1000 - (ofs & 0xfff);
+                       if (chunk > remain)
+                               chunk = remain;
+               }
+               bdl[2] = cpu_to_le32(chunk);
+               /* program the IOC to enable interrupt
+                * only when the whole fragment is processed
+                */
+               size -= chunk;
+               bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+               bdl += 4;
+               azx_dev->frags++;
+               ofs += chunk;
+       }
+       *bdlp = bdl;
+       return ofs;
+}
+
+/*
+ * set up BDL entries
+ */
+static int azx_setup_periods(struct azx *chip,
+                            struct snd_pcm_substream *substream,
+                            struct azx_dev *azx_dev)
+{
+       u32 *bdl;
+       int i, ofs, periods, period_bytes;
+       int pos_adj = 0;
+
+       /* reset BDL address */
+       azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+       azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+
+       period_bytes = azx_dev->period_bytes;
+       periods = azx_dev->bufsize / period_bytes;
+
+       /* program the initial BDL entries */
+       bdl = (u32 *)azx_dev->bdl.area;
+       ofs = 0;
+       azx_dev->frags = 0;
+
+       if (chip->bdl_pos_adj)
+               pos_adj = chip->bdl_pos_adj[chip->dev_index];
+       if (!azx_dev->no_period_wakeup && pos_adj > 0) {
+               struct snd_pcm_runtime *runtime = substream->runtime;
+               int pos_align = pos_adj;
+               pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
+               if (!pos_adj)
+                       pos_adj = pos_align;
+               else
+                       pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
+                               pos_align;
+               pos_adj = frames_to_bytes(runtime, pos_adj);
+               if (pos_adj >= period_bytes) {
+                       dev_warn(chip->card->dev,"Too big adjustment %d\n",
+                                pos_adj);
+                       pos_adj = 0;
+               } else {
+                       ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+                                        azx_dev,
+                                        &bdl, ofs, pos_adj, true);
+                       if (ofs < 0)
+                               goto error;
+               }
+       } else
+               pos_adj = 0;
+
+       for (i = 0; i < periods; i++) {
+               if (i == periods - 1 && pos_adj)
+                       ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+                                        azx_dev, &bdl, ofs,
+                                        period_bytes - pos_adj, 0);
+               else
+                       ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+                                        azx_dev, &bdl, ofs,
+                                        period_bytes,
+                                        !azx_dev->no_period_wakeup);
+               if (ofs < 0)
+                       goto error;
+       }
+       return 0;
+
+ error:
+       dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n",
+               azx_dev->bufsize, period_bytes);
+       return -EINVAL;
+}
+
+/*
+ * PCM ops
+ */
+
+static int azx_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct azx *chip = apcm->chip;
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       unsigned long flags;
+
+       mutex_lock(&chip->open_mutex);
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       azx_dev->substream = NULL;
+       azx_dev->running = 0;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       azx_release_device(azx_dev);
+       hinfo->ops.close(hinfo, apcm->codec, substream);
+       snd_hda_power_down(apcm->codec);
+       mutex_unlock(&chip->open_mutex);
+       return 0;
+}
+
+static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       int ret;
+
+       dsp_lock(get_azx_dev(substream));
+       if (dsp_is_locked(get_azx_dev(substream))) {
+               ret = -EBUSY;
+               goto unlock;
+       }
+
+       ret = chip->ops->substream_alloc_pages(chip, substream,
+                                         params_buffer_bytes(hw_params));
+unlock:
+       dsp_unlock(get_azx_dev(substream));
+       return ret;
+}
+
+static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       struct azx *chip = apcm->chip;
+       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       int err;
+
+       /* reset BDL address */
+       dsp_lock(azx_dev);
+       if (!dsp_is_locked(azx_dev)) {
+               azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+               azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+               azx_sd_writel(chip, azx_dev, SD_CTL, 0);
+               azx_dev->bufsize = 0;
+               azx_dev->period_bytes = 0;
+               azx_dev->format_val = 0;
+       }
+
+       snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
+
+       err = chip->ops->substream_free_pages(chip, substream);
+       azx_dev->prepared = 0;
+       dsp_unlock(azx_dev);
+       return err;
+}
+
+static int azx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int bufsize, period_bytes, format_val, stream_tag;
+       int err;
+       struct hda_spdif_out *spdif =
+               snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
+       unsigned short ctls = spdif ? spdif->ctls : 0;
+
+       dsp_lock(azx_dev);
+       if (dsp_is_locked(azx_dev)) {
+               err = -EBUSY;
+               goto unlock;
+       }
+
+       azx_stream_reset(chip, azx_dev);
+       format_val = snd_hda_calc_stream_format(runtime->rate,
+                                               runtime->channels,
+                                               runtime->format,
+                                               hinfo->maxbps,
+                                               ctls);
+       if (!format_val) {
+               dev_err(chip->card->dev,
+                       "invalid format_val, rate=%d, ch=%d, format=%d\n",
+                       runtime->rate, runtime->channels, runtime->format);
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       bufsize = snd_pcm_lib_buffer_bytes(substream);
+       period_bytes = snd_pcm_lib_period_bytes(substream);
+
+       dev_dbg(chip->card->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+               bufsize, format_val);
+
+       if (bufsize != azx_dev->bufsize ||
+           period_bytes != azx_dev->period_bytes ||
+           format_val != azx_dev->format_val ||
+           runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
+               azx_dev->bufsize = bufsize;
+               azx_dev->period_bytes = period_bytes;
+               azx_dev->format_val = format_val;
+               azx_dev->no_period_wakeup = runtime->no_period_wakeup;
+               err = azx_setup_periods(chip, substream, azx_dev);
+               if (err < 0)
+                       goto unlock;
+       }
+
+       /* when LPIB delay correction gives a small negative value,
+        * we ignore it; currently set the threshold statically to
+        * 64 frames
+        */
+       if (runtime->period_size > 64)
+               azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
+       else
+               azx_dev->delay_negative_threshold = 0;
+
+       /* wallclk has 24Mhz clock source */
+       azx_dev->period_wallclk = (((runtime->period_size * 24000) /
+                                               runtime->rate) * 1000);
+       azx_setup_controller(chip, azx_dev);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               azx_dev->fifo_size =
+                       azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1;
+       else
+               azx_dev->fifo_size = 0;
+
+       stream_tag = azx_dev->stream_tag;
+       /* CA-IBG chips need the playback stream starting from 1 */
+       if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
+           stream_tag > chip->capture_streams)
+               stream_tag -= chip->capture_streams;
+       err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
+                                    azx_dev->format_val, substream);
+
+ unlock:
+       if (!err)
+               azx_dev->prepared = 1;
+       dsp_unlock(azx_dev);
+       return err;
+}
+
+static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       struct azx_dev *azx_dev;
+       struct snd_pcm_substream *s;
+       int rstart = 0, start, nsync = 0, sbits = 0;
+       int nwait, timeout;
+
+       azx_dev = get_azx_dev(substream);
+       trace_azx_pcm_trigger(chip, azx_dev, cmd);
+
+       if (dsp_is_locked(azx_dev) || !azx_dev->prepared)
+               return -EPIPE;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               rstart = 1;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               start = 1;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               start = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+               azx_dev = get_azx_dev(s);
+               sbits |= 1 << azx_dev->index;
+               nsync++;
+               snd_pcm_trigger_done(s, substream);
+       }
+
+       spin_lock(&chip->reg_lock);
+
+       /* first, set SYNC bits of corresponding streams */
+       if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+               azx_writel(chip, OLD_SSYNC,
+                       azx_readl(chip, OLD_SSYNC) | sbits);
+       else
+               azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+               azx_dev = get_azx_dev(s);
+               if (start) {
+                       azx_dev->start_wallclk = azx_readl(chip, WALLCLK);
+                       if (!rstart)
+                               azx_dev->start_wallclk -=
+                                               azx_dev->period_wallclk;
+                       azx_stream_start(chip, azx_dev);
+               } else {
+                       azx_stream_stop(chip, azx_dev);
+               }
+               azx_dev->running = start;
+       }
+       spin_unlock(&chip->reg_lock);
+       if (start) {
+               /* wait until all FIFOs get ready */
+               for (timeout = 5000; timeout; timeout--) {
+                       nwait = 0;
+                       snd_pcm_group_for_each_entry(s, substream) {
+                               if (s->pcm->card != substream->pcm->card)
+                                       continue;
+                               azx_dev = get_azx_dev(s);
+                               if (!(azx_sd_readb(chip, azx_dev, SD_STS) &
+                                     SD_STS_FIFO_READY))
+                                       nwait++;
+                       }
+                       if (!nwait)
+                               break;
+                       cpu_relax();
+               }
+       } else {
+               /* wait until all RUN bits are cleared */
+               for (timeout = 5000; timeout; timeout--) {
+                       nwait = 0;
+                       snd_pcm_group_for_each_entry(s, substream) {
+                               if (s->pcm->card != substream->pcm->card)
+                                       continue;
+                               azx_dev = get_azx_dev(s);
+                               if (azx_sd_readb(chip, azx_dev, SD_CTL) &
+                                   SD_CTL_DMA_START)
+                                       nwait++;
+                       }
+                       if (!nwait)
+                               break;
+                       cpu_relax();
+               }
+       }
+       spin_lock(&chip->reg_lock);
+       /* reset SYNC bits */
+       if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+               azx_writel(chip, OLD_SSYNC,
+                       azx_readl(chip, OLD_SSYNC) & ~sbits);
+       else
+               azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
+       if (start) {
+               azx_timecounter_init(substream, 0, 0);
+               if (nsync > 1) {
+                       cycle_t cycle_last;
+
+                       /* same start cycle for master and group */
+                       azx_dev = get_azx_dev(substream);
+                       cycle_last = azx_dev->azx_tc.cycle_last;
+
+                       snd_pcm_group_for_each_entry(s, substream) {
+                               if (s->pcm->card != substream->pcm->card)
+                                       continue;
+                               azx_timecounter_init(s, 1, cycle_last);
+                       }
+               }
+       }
+       spin_unlock(&chip->reg_lock);
+       return 0;
+}
+
+/* get the current DMA position with correction on VIA chips */
+static unsigned int azx_via_get_position(struct azx *chip,
+                                        struct azx_dev *azx_dev)
+{
+       unsigned int link_pos, mini_pos, bound_pos;
+       unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
+       unsigned int fifo_size;
+
+       link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+       if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* Playback, no problem using link position */
+               return link_pos;
+       }
+
+       /* Capture */
+       /* For new chipset,
+        * use mod to get the DMA position just like old chipset
+        */
+       mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
+       mod_dma_pos %= azx_dev->period_bytes;
+
+       /* azx_dev->fifo_size can't get FIFO size of in stream.
+        * Get from base address + offset.
+        */
+       fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
+
+       if (azx_dev->insufficient) {
+               /* Link position never gather than FIFO size */
+               if (link_pos <= fifo_size)
+                       return 0;
+
+               azx_dev->insufficient = 0;
+       }
+
+       if (link_pos <= fifo_size)
+               mini_pos = azx_dev->bufsize + link_pos - fifo_size;
+       else
+               mini_pos = link_pos - fifo_size;
+
+       /* Find nearest previous boudary */
+       mod_mini_pos = mini_pos % azx_dev->period_bytes;
+       mod_link_pos = link_pos % azx_dev->period_bytes;
+       if (mod_link_pos >= fifo_size)
+               bound_pos = link_pos - mod_link_pos;
+       else if (mod_dma_pos >= mod_mini_pos)
+               bound_pos = mini_pos - mod_mini_pos;
+       else {
+               bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
+               if (bound_pos >= azx_dev->bufsize)
+                       bound_pos = 0;
+       }
+
+       /* Calculate real DMA position we want */
+       return bound_pos + mod_dma_pos;
+}
+
+unsigned int azx_get_position(struct azx *chip,
+                             struct azx_dev *azx_dev,
+                             bool with_check)
+{
+       struct snd_pcm_substream *substream = azx_dev->substream;
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       unsigned int pos;
+       int stream = substream->stream;
+       struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
+       int delay = 0;
+
+       switch (chip->position_fix[stream]) {
+       case POS_FIX_LPIB:
+               /* read LPIB */
+               pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+               break;
+       case POS_FIX_VIACOMBO:
+               pos = azx_via_get_position(chip, azx_dev);
+               break;
+       default:
+               /* use the position buffer */
+               pos = le32_to_cpu(*azx_dev->posbuf);
+               if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
+                       if (!pos || pos == (u32)-1) {
+                               dev_info(chip->card->dev,
+                                        "Invalid position buffer, using LPIB read method instead.\n");
+                               chip->position_fix[stream] = POS_FIX_LPIB;
+                               pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+                       } else
+                               chip->position_fix[stream] = POS_FIX_POSBUF;
+               }
+               break;
+       }
+
+       if (pos >= azx_dev->bufsize)
+               pos = 0;
+
+       /* calculate runtime delay from LPIB */
+       if (substream->runtime &&
+           chip->position_fix[stream] == POS_FIX_POSBUF &&
+           (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
+               unsigned int lpib_pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       delay = pos - lpib_pos;
+               else
+                       delay = lpib_pos - pos;
+               if (delay < 0) {
+                       if (delay >= azx_dev->delay_negative_threshold)
+                               delay = 0;
+                       else
+                               delay += azx_dev->bufsize;
+               }
+               if (delay >= azx_dev->period_bytes) {
+                       dev_info(chip->card->dev,
+                                "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
+                                delay, azx_dev->period_bytes);
+                       delay = 0;
+                       chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
+               }
+               delay = bytes_to_frames(substream->runtime, delay);
+       }
+
+       if (substream->runtime) {
+               if (hinfo->ops.get_delay)
+                       delay += hinfo->ops.get_delay(hinfo, apcm->codec,
+                                                     substream);
+               substream->runtime->delay = delay;
+       }
+
+       trace_azx_get_position(chip, azx_dev, pos, delay);
+       return pos;
+}
+EXPORT_SYMBOL_GPL(azx_get_position);
+
+static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       return bytes_to_frames(substream->runtime,
+                              azx_get_position(chip, azx_dev, false));
+}
+
+static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
+                               struct timespec *ts)
+{
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       u64 nsec;
+
+       nsec = timecounter_read(&azx_dev->azx_tc);
+       nsec = div_u64(nsec, 3); /* can be optimized */
+       nsec = azx_adjust_codec_delay(substream, nsec);
+
+       *ts = ns_to_timespec(nsec);
+
+       return 0;
+}
+
+static struct snd_pcm_hardware azx_pcm_hw = {
+       .info =                 (SNDRV_PCM_INFO_MMAP |
+                                SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_MMAP_VALID |
+                                /* No full-resume yet implemented */
+                                /* SNDRV_PCM_INFO_RESUME |*/
+                                SNDRV_PCM_INFO_PAUSE |
+                                SNDRV_PCM_INFO_SYNC_START |
+                                SNDRV_PCM_INFO_HAS_WALL_CLOCK |
+                                SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
+       .rates =                SNDRV_PCM_RATE_48000,
+       .rate_min =             48000,
+       .rate_max =             48000,
+       .channels_min =         2,
+       .channels_max =         2,
+       .buffer_bytes_max =     AZX_MAX_BUF_SIZE,
+       .period_bytes_min =     128,
+       .period_bytes_max =     AZX_MAX_BUF_SIZE / 2,
+       .periods_min =          2,
+       .periods_max =          AZX_MAX_FRAG,
+       .fifo_size =            0,
+};
+
+static int azx_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct azx *chip = apcm->chip;
+       struct azx_dev *azx_dev;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long flags;
+       int err;
+       int buff_step;
+
+       mutex_lock(&chip->open_mutex);
+       azx_dev = azx_assign_device(chip, substream);
+       if (azx_dev == NULL) {
+               mutex_unlock(&chip->open_mutex);
+               return -EBUSY;
+       }
+       runtime->hw = azx_pcm_hw;
+       runtime->hw.channels_min = hinfo->channels_min;
+       runtime->hw.channels_max = hinfo->channels_max;
+       runtime->hw.formats = hinfo->formats;
+       runtime->hw.rates = hinfo->rates;
+       snd_pcm_limit_hw_rates(runtime);
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+       /* avoid wrap-around with wall-clock */
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
+                                    20,
+                                    178000000);
+
+       if (chip->align_buffer_size)
+               /* constrain buffer sizes to be multiple of 128
+                  bytes. This is more efficient in terms of memory
+                  access but isn't required by the HDA spec and
+                  prevents users from specifying exact period/buffer
+                  sizes. For example for 44.1kHz, a period size set
+                  to 20ms will be rounded to 19.59ms. */
+               buff_step = 128;
+       else
+               /* Don't enforce steps on buffer sizes, still need to
+                  be multiple of 4 bytes (HDA spec). Tested on Intel
+                  HDA controllers, may not work on all devices where
+                  option needs to be disabled */
+               buff_step = 4;
+
+       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                  buff_step);
+       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                  buff_step);
+       snd_hda_power_up_d3wait(apcm->codec);
+       err = hinfo->ops.open(hinfo, apcm->codec, substream);
+       if (err < 0) {
+               azx_release_device(azx_dev);
+               snd_hda_power_down(apcm->codec);
+               mutex_unlock(&chip->open_mutex);
+               return err;
+       }
+       snd_pcm_limit_hw_rates(runtime);
+       /* sanity check */
+       if (snd_BUG_ON(!runtime->hw.channels_min) ||
+           snd_BUG_ON(!runtime->hw.channels_max) ||
+           snd_BUG_ON(!runtime->hw.formats) ||
+           snd_BUG_ON(!runtime->hw.rates)) {
+               azx_release_device(azx_dev);
+               hinfo->ops.close(hinfo, apcm->codec, substream);
+               snd_hda_power_down(apcm->codec);
+               mutex_unlock(&chip->open_mutex);
+               return -EINVAL;
+       }
+
+       /* disable WALLCLOCK timestamps for capture streams
+          until we figure out how to handle digital inputs */
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK;
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       azx_dev->substream = substream;
+       azx_dev->running = 0;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       runtime->private_data = azx_dev;
+       snd_pcm_set_sync(substream);
+       mutex_unlock(&chip->open_mutex);
+       return 0;
+}
+
+static int azx_pcm_mmap(struct snd_pcm_substream *substream,
+                       struct vm_area_struct *area)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       if (chip->ops->pcm_mmap_prepare)
+               chip->ops->pcm_mmap_prepare(substream, area);
+       return snd_pcm_lib_default_mmap(substream, area);
+}
+
+static struct snd_pcm_ops azx_pcm_ops = {
+       .open = azx_pcm_open,
+       .close = azx_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = azx_pcm_hw_params,
+       .hw_free = azx_pcm_hw_free,
+       .prepare = azx_pcm_prepare,
+       .trigger = azx_pcm_trigger,
+       .pointer = azx_pcm_pointer,
+       .wall_clock =  azx_get_wallclock_tstamp,
+       .mmap = azx_pcm_mmap,
+       .page = snd_pcm_sgbuf_ops_page,
+};
+
+static void azx_pcm_free(struct snd_pcm *pcm)
+{
+       struct azx_pcm *apcm = pcm->private_data;
+       if (apcm) {
+               list_del(&apcm->list);
+               kfree(apcm);
+       }
+}
+
+#define MAX_PREALLOC_SIZE      (32 * 1024 * 1024)
+
+static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+                                struct hda_pcm *cpcm)
+{
+       struct azx *chip = bus->private_data;
+       struct snd_pcm *pcm;
+       struct azx_pcm *apcm;
+       int pcm_dev = cpcm->device;
+       unsigned int size;
+       int s, err;
+
+       list_for_each_entry(apcm, &chip->pcm_list, list) {
+               if (apcm->pcm->device == pcm_dev) {
+                       dev_err(chip->card->dev, "PCM %d already exists\n",
+                               pcm_dev);
+                       return -EBUSY;
+               }
+       }
+       err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+                         cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
+                         cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
+                         &pcm);
+       if (err < 0)
+               return err;
+       strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
+       apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+       if (apcm == NULL)
+               return -ENOMEM;
+       apcm->chip = chip;
+       apcm->pcm = pcm;
+       apcm->codec = codec;
+       pcm->private_data = apcm;
+       pcm->private_free = azx_pcm_free;
+       if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
+               pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
+       list_add_tail(&apcm->list, &chip->pcm_list);
+       cpcm->pcm = pcm;
+       for (s = 0; s < 2; s++) {
+               apcm->hinfo[s] = &cpcm->stream[s];
+               if (cpcm->stream[s].substreams)
+                       snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
+       }
+       /* buffer pre-allocation */
+       size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
+       if (size > MAX_PREALLOC_SIZE)
+               size = MAX_PREALLOC_SIZE;
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+                                             chip->card->dev,
+                                             size, MAX_PREALLOC_SIZE);
+       /* link to codec */
+       pcm->dev = &codec->dev;
+       return 0;
+}
+
+/*
+ * CORB / RIRB interface
+ */
+static int azx_alloc_cmd_io(struct azx *chip)
+{
+       int err;
+
+       /* single page (at least 4096 bytes) must suffice for both ringbuffes */
+       err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+                                        PAGE_SIZE, &chip->rb);
+       if (err < 0)
+               dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
+       return err;
+}
+EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
+
+static void azx_init_cmd_io(struct azx *chip)
+{
+       int timeout;
+
+       spin_lock_irq(&chip->reg_lock);
+       /* CORB set up */
+       chip->corb.addr = chip->rb.addr;
+       chip->corb.buf = (u32 *)chip->rb.area;
+       azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
+       azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
+
+       /* set the corb size to 256 entries (ULI requires explicitly) */
+       azx_writeb(chip, CORBSIZE, 0x02);
+       /* set the corb write pointer to 0 */
+       azx_writew(chip, CORBWP, 0);
+
+       /* reset the corb hw read pointer */
+       azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
+       for (timeout = 1000; timeout > 0; timeout--) {
+               if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
+                       break;
+               udelay(1);
+       }
+       if (timeout <= 0)
+               dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
+                       azx_readw(chip, CORBRP));
+
+       azx_writew(chip, CORBRP, 0);
+       for (timeout = 1000; timeout > 0; timeout--) {
+               if (azx_readw(chip, CORBRP) == 0)
+                       break;
+               udelay(1);
+       }
+       if (timeout <= 0)
+               dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
+                       azx_readw(chip, CORBRP));
+
+       /* enable corb dma */
+       azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
+
+       /* RIRB set up */
+       chip->rirb.addr = chip->rb.addr + 2048;
+       chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+       chip->rirb.wp = chip->rirb.rp = 0;
+       memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
+       azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
+       azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
+
+       /* set the rirb size to 256 entries (ULI requires explicitly) */
+       azx_writeb(chip, RIRBSIZE, 0x02);
+       /* reset the rirb hw write pointer */
+       azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
+       /* set N=1, get RIRB response interrupt for new entry */
+       if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
+               azx_writew(chip, RINTCNT, 0xc0);
+       else
+               azx_writew(chip, RINTCNT, 1);
+       /* enable rirb dma and response irq */
+       azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
+       spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL_GPL(azx_init_cmd_io);
+
+static void azx_free_cmd_io(struct azx *chip)
+{
+       spin_lock_irq(&chip->reg_lock);
+       /* disable ringbuffer DMAs */
+       azx_writeb(chip, RIRBCTL, 0);
+       azx_writeb(chip, CORBCTL, 0);
+       spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL_GPL(azx_free_cmd_io);
+
+static unsigned int azx_command_addr(u32 cmd)
+{
+       unsigned int addr = cmd >> 28;
+
+       if (addr >= AZX_MAX_CODECS) {
+               snd_BUG();
+               addr = 0;
+       }
+
+       return addr;
+}
+
+/* send a command */
+static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
+{
+       struct azx *chip = bus->private_data;
+       unsigned int addr = azx_command_addr(val);
+       unsigned int wp, rp;
+
+       spin_lock_irq(&chip->reg_lock);
+
+       /* add command to corb */
+       wp = azx_readw(chip, CORBWP);
+       if (wp == 0xffff) {
+               /* something wrong, controller likely turned to D3 */
+               spin_unlock_irq(&chip->reg_lock);
+               return -EIO;
+       }
+       wp++;
+       wp %= ICH6_MAX_CORB_ENTRIES;
+
+       rp = azx_readw(chip, CORBRP);
+       if (wp == rp) {
+               /* oops, it's full */
+               spin_unlock_irq(&chip->reg_lock);
+               return -EAGAIN;
+       }
+
+       chip->rirb.cmds[addr]++;
+       chip->corb.buf[wp] = cpu_to_le32(val);
+       azx_writew(chip, CORBWP, wp);
+
+       spin_unlock_irq(&chip->reg_lock);
+
+       return 0;
+}
+
+#define ICH6_RIRB_EX_UNSOL_EV  (1<<4)
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void azx_update_rirb(struct azx *chip)
+{
+       unsigned int rp, wp;
+       unsigned int addr;
+       u32 res, res_ex;
+
+       wp = azx_readw(chip, RIRBWP);
+       if (wp == 0xffff) {
+               /* something wrong, controller likely turned to D3 */
+               return;
+       }
+
+       if (wp == chip->rirb.wp)
+               return;
+       chip->rirb.wp = wp;
+
+       while (chip->rirb.rp != wp) {
+               chip->rirb.rp++;
+               chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
+
+               rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+               res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+               res = le32_to_cpu(chip->rirb.buf[rp]);
+               addr = res_ex & 0xf;
+               if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
+                       dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
+                               res, res_ex,
+                               chip->rirb.rp, wp);
+                       snd_BUG();
+               }
+               else if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
+                       snd_hda_queue_unsol_event(chip->bus, res, res_ex);
+               else if (chip->rirb.cmds[addr]) {
+                       chip->rirb.res[addr] = res;
+                       smp_wmb();
+                       chip->rirb.cmds[addr]--;
+               } else if (printk_ratelimit()) {
+                       dev_err(chip->card->dev, "spurious response %#x:%#x, last cmd=%#08x\n",
+                               res, res_ex,
+                               chip->last_cmd[addr]);
+               }
+       }
+}
+
+/* receive a response */
+static unsigned int azx_rirb_get_response(struct hda_bus *bus,
+                                         unsigned int addr)
+{
+       struct azx *chip = bus->private_data;
+       unsigned long timeout;
+       unsigned long loopcounter;
+       int do_poll = 0;
+
+ again:
+       timeout = jiffies + msecs_to_jiffies(1000);
+
+       for (loopcounter = 0;; loopcounter++) {
+               if (chip->polling_mode || do_poll) {
+                       spin_lock_irq(&chip->reg_lock);
+                       azx_update_rirb(chip);
+                       spin_unlock_irq(&chip->reg_lock);
+               }
+               if (!chip->rirb.cmds[addr]) {
+                       smp_rmb();
+                       bus->rirb_error = 0;
+
+                       if (!do_poll)
+                               chip->poll_count = 0;
+                       return chip->rirb.res[addr]; /* the last value */
+               }
+               if (time_after(jiffies, timeout))
+                       break;
+               if (bus->needs_damn_long_delay || loopcounter > 3000)
+                       msleep(2); /* temporary workaround */
+               else {
+                       udelay(10);
+                       cond_resched();
+               }
+       }
+
+       if (!bus->no_response_fallback)
+               return -1;
+
+       if (!chip->polling_mode && chip->poll_count < 2) {
+               dev_dbg(chip->card->dev,
+                       "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
+                       chip->last_cmd[addr]);
+               do_poll = 1;
+               chip->poll_count++;
+               goto again;
+       }
+
+
+       if (!chip->polling_mode) {
+               dev_warn(chip->card->dev,
+                        "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
+                        chip->last_cmd[addr]);
+               chip->polling_mode = 1;
+               goto again;
+       }
+
+       if (chip->msi) {
+               dev_warn(chip->card->dev,
+                        "No response from codec, disabling MSI: last cmd=0x%08x\n",
+                        chip->last_cmd[addr]);
+               if (chip->ops->disable_msi_reset_irq(chip) &&
+                   chip->ops->disable_msi_reset_irq(chip) < 0) {
+                       bus->rirb_error = 1;
+                       return -1;
+               }
+               goto again;
+       }
+
+       if (chip->probing) {
+               /* If this critical timeout happens during the codec probing
+                * phase, this is likely an access to a non-existing codec
+                * slot.  Better to return an error and reset the system.
+                */
+               return -1;
+       }
+
+       /* a fatal communication error; need either to reset or to fallback
+        * to the single_cmd mode
+        */
+       bus->rirb_error = 1;
+       if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
+               bus->response_reset = 1;
+               return -1; /* give a chance to retry */
+       }
+
+       dev_err(chip->card->dev,
+               "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
+               chip->last_cmd[addr]);
+       chip->single_cmd = 1;
+       bus->response_reset = 0;
+       /* release CORB/RIRB */
+       azx_free_cmd_io(chip);
+       /* disable unsolicited responses */
+       azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL);
+       return -1;
+}
+
+/*
+ * Use the single immediate command instead of CORB/RIRB for simplicity
+ *
+ * Note: according to Intel, this is not preferred use.  The command was
+ *       intended for the BIOS only, and may get confused with unsolicited
+ *       responses.  So, we shouldn't use it for normal operation from the
+ *       driver.
+ *       I left the codes, however, for debugging/testing purposes.
+ */
+
+/* receive a response */
+static int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
+{
+       int timeout = 50;
+
+       while (timeout--) {
+               /* check IRV busy bit */
+               if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
+                       /* reuse rirb.res as the response return value */
+                       chip->rirb.res[addr] = azx_readl(chip, IR);
+                       return 0;
+               }
+               udelay(1);
+       }
+       if (printk_ratelimit())
+               dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n",
+                       azx_readw(chip, IRS));
+       chip->rirb.res[addr] = -1;
+       return -EIO;
+}
+
+/* send a command */
+static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
+{
+       struct azx *chip = bus->private_data;
+       unsigned int addr = azx_command_addr(val);
+       int timeout = 50;
+
+       bus->rirb_error = 0;
+       while (timeout--) {
+               /* check ICB busy bit */
+               if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
+                       /* Clear IRV valid bit */
+                       azx_writew(chip, IRS, azx_readw(chip, IRS) |
+                                  ICH6_IRS_VALID);
+                       azx_writel(chip, IC, val);
+                       azx_writew(chip, IRS, azx_readw(chip, IRS) |
+                                  ICH6_IRS_BUSY);
+                       return azx_single_wait_for_response(chip, addr);
+               }
+               udelay(1);
+       }
+       if (printk_ratelimit())
+               dev_dbg(chip->card->dev,
+                       "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+                       azx_readw(chip, IRS), val);
+       return -EIO;
+}
+
+/* receive a response */
+static unsigned int azx_single_get_response(struct hda_bus *bus,
+                                           unsigned int addr)
+{
+       struct azx *chip = bus->private_data;
+       return chip->rirb.res[addr];
+}
+
+/*
+ * The below are the main callbacks from hda_codec.
+ *
+ * They are just the skeleton to call sub-callbacks according to the
+ * current setting of chip->single_cmd.
+ */
+
+/* send a command */
+static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
+{
+       struct azx *chip = bus->private_data;
+
+       if (chip->disabled)
+               return 0;
+       chip->last_cmd[azx_command_addr(val)] = val;
+       if (chip->single_cmd)
+               return azx_single_send_cmd(bus, val);
+       else
+               return azx_corb_send_cmd(bus, val);
+}
+EXPORT_SYMBOL_GPL(azx_send_cmd);
+
+/* get a response */
+static unsigned int azx_get_response(struct hda_bus *bus,
+                                    unsigned int addr)
+{
+       struct azx *chip = bus->private_data;
+       if (chip->disabled)
+               return 0;
+       if (chip->single_cmd)
+               return azx_single_get_response(bus, addr);
+       else
+               return azx_rirb_get_response(bus, addr);
+}
+EXPORT_SYMBOL_GPL(azx_get_response);
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+/*
+ * DSP loading code (e.g. for CA0132)
+ */
+
+/* use the first stream for loading DSP */
+static struct azx_dev *
+azx_get_dsp_loader_dev(struct azx *chip)
+{
+       return &chip->azx_dev[chip->playback_index_offset];
+}
+
+static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
+                               unsigned int byte_size,
+                               struct snd_dma_buffer *bufp)
+{
+       u32 *bdl;
+       struct azx *chip = bus->private_data;
+       struct azx_dev *azx_dev;
+       int err;
+
+       azx_dev = azx_get_dsp_loader_dev(chip);
+
+       dsp_lock(azx_dev);
+       spin_lock_irq(&chip->reg_lock);
+       if (azx_dev->running || azx_dev->locked) {
+               spin_unlock_irq(&chip->reg_lock);
+               err = -EBUSY;
+               goto unlock;
+       }
+       azx_dev->prepared = 0;
+       chip->saved_azx_dev = *azx_dev;
+       azx_dev->locked = 1;
+       spin_unlock_irq(&chip->reg_lock);
+
+       err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV_SG,
+                                        byte_size, bufp);
+       if (err < 0)
+               goto err_alloc;
+
+       azx_dev->bufsize = byte_size;
+       azx_dev->period_bytes = byte_size;
+       azx_dev->format_val = format;
+
+       azx_stream_reset(chip, azx_dev);
+
+       /* reset BDL address */
+       azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+       azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+
+       azx_dev->frags = 0;
+       bdl = (u32 *)azx_dev->bdl.area;
+       err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
+       if (err < 0)
+               goto error;
+
+       azx_setup_controller(chip, azx_dev);
+       dsp_unlock(azx_dev);
+       return azx_dev->stream_tag;
+
+ error:
+       chip->ops->dma_free_pages(chip, bufp);
+ err_alloc:
+       spin_lock_irq(&chip->reg_lock);
+       if (azx_dev->opened)
+               *azx_dev = chip->saved_azx_dev;
+       azx_dev->locked = 0;
+       spin_unlock_irq(&chip->reg_lock);
+ unlock:
+       dsp_unlock(azx_dev);
+       return err;
+}
+
+static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
+{
+       struct azx *chip = bus->private_data;
+       struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
+
+       if (start)
+               azx_stream_start(chip, azx_dev);
+       else
+               azx_stream_stop(chip, azx_dev);
+       azx_dev->running = start;
+}
+
+static void azx_load_dsp_cleanup(struct hda_bus *bus,
+                                struct snd_dma_buffer *dmab)
+{
+       struct azx *chip = bus->private_data;
+       struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
+
+       if (!dmab->area || !azx_dev->locked)
+               return;
+
+       dsp_lock(azx_dev);
+       /* reset BDL address */
+       azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+       azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+       azx_sd_writel(chip, azx_dev, SD_CTL, 0);
+       azx_dev->bufsize = 0;
+       azx_dev->period_bytes = 0;
+       azx_dev->format_val = 0;
+
+       chip->ops->dma_free_pages(chip, dmab);
+       dmab->area = NULL;
+
+       spin_lock_irq(&chip->reg_lock);
+       if (azx_dev->opened)
+               *azx_dev = chip->saved_azx_dev;
+       azx_dev->locked = 0;
+       spin_unlock_irq(&chip->reg_lock);
+       dsp_unlock(azx_dev);
+}
+#endif /* CONFIG_SND_HDA_DSP_LOADER */
+
+int azx_alloc_stream_pages(struct azx *chip)
+{
+       int i, err;
+       struct snd_card *card = chip->card;
+
+       for (i = 0; i < chip->num_streams; i++) {
+               dsp_lock_init(&chip->azx_dev[i]);
+               /* allocate memory for the BDL for each stream */
+               err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+                                                BDL_SIZE,
+                                                &chip->azx_dev[i].bdl);
+               if (err < 0) {
+                       dev_err(card->dev, "cannot allocate BDL\n");
+                       return -ENOMEM;
+               }
+       }
+       /* allocate memory for the position buffer */
+       err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+                                        chip->num_streams * 8, &chip->posbuf);
+       if (err < 0) {
+               dev_err(card->dev, "cannot allocate posbuf\n");
+               return -ENOMEM;
+       }
+
+       /* allocate CORB/RIRB */
+       err = azx_alloc_cmd_io(chip);
+       if (err < 0)
+               return err;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(azx_alloc_stream_pages);
+
+void azx_free_stream_pages(struct azx *chip)
+{
+       int i;
+       if (chip->azx_dev) {
+               for (i = 0; i < chip->num_streams; i++)
+                       if (chip->azx_dev[i].bdl.area)
+                               chip->ops->dma_free_pages(
+                                       chip, &chip->azx_dev[i].bdl);
+       }
+       if (chip->rb.area)
+               chip->ops->dma_free_pages(chip, &chip->rb);
+       if (chip->posbuf.area)
+               chip->ops->dma_free_pages(chip, &chip->posbuf);
+}
+EXPORT_SYMBOL_GPL(azx_free_stream_pages);
+
+/*
+ * Lowlevel interface
+ */
+
+/* enter link reset */
+void azx_enter_link_reset(struct azx *chip)
+{
+       unsigned long timeout;
+
+       /* reset controller */
+       azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
+
+       timeout = jiffies + msecs_to_jiffies(100);
+       while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
+                       time_before(jiffies, timeout))
+               usleep_range(500, 1000);
+}
+EXPORT_SYMBOL_GPL(azx_enter_link_reset);
+
+/* exit link reset */
+static void azx_exit_link_reset(struct azx *chip)
+{
+       unsigned long timeout;
+
+       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_writew(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);
+
+      __skip:
+       /* check to see if controller is ready */
+       if (!azx_readb(chip, GCTL)) {
+               dev_dbg(chip->card->dev, "azx_reset: controller not ready!\n");
+               return -EBUSY;
+       }
+
+       /* Accept unsolicited responses */
+       if (!chip->single_cmd)
+               azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
+                          ICH6_GCTL_UNSOL);
+
+       /* detect codecs */
+       if (!chip->codec_mask) {
+               chip->codec_mask = azx_readw(chip, STATESTS);
+               dev_dbg(chip->card->dev, "codec_mask = 0x%x\n",
+                       chip->codec_mask);
+       }
+
+       return 0;
+}
+
+/* enable interrupts */
+static void azx_int_enable(struct azx *chip)
+{
+       /* enable controller CIE and GIE */
+       azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
+                  ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
+}
+
+/* disable interrupts */
+static void azx_int_disable(struct azx *chip)
+{
+       int i;
+
+       /* disable interrupts in stream descriptor */
+       for (i = 0; i < chip->num_streams; i++) {
+               struct azx_dev *azx_dev = &chip->azx_dev[i];
+               azx_sd_writeb(chip, azx_dev, SD_CTL,
+                             azx_sd_readb(chip, azx_dev, SD_CTL) &
+                                       ~SD_INT_MASK);
+       }
+
+       /* disable SIE for all streams */
+       azx_writeb(chip, INTCTL, 0);
+
+       /* disable controller CIE and GIE */
+       azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
+                  ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
+}
+
+/* clear interrupts */
+static void azx_int_clear(struct azx *chip)
+{
+       int i;
+
+       /* clear stream status */
+       for (i = 0; i < chip->num_streams; i++) {
+               struct azx_dev *azx_dev = &chip->azx_dev[i];
+               azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
+       }
+
+       /* clear STATESTS */
+       azx_writew(chip, STATESTS, STATESTS_INT_MASK);
+
+       /* clear rirb status */
+       azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+
+       /* clear int status */
+       azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
+}
+
+/*
+ * reset and start the controller registers
+ */
+void azx_init_chip(struct azx *chip, int full_reset)
+{
+       if (chip->initialized)
+               return;
+
+       /* reset controller */
+       azx_reset(chip, full_reset);
+
+       /* initialize interrupts */
+       azx_int_clear(chip);
+       azx_int_enable(chip);
+
+       /* initialize the codec command I/O */
+       if (!chip->single_cmd)
+               azx_init_cmd_io(chip);
+
+       /* program the position buffer */
+       azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+       azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
+
+       chip->initialized = 1;
+}
+EXPORT_SYMBOL_GPL(azx_init_chip);
+
+void azx_stop_chip(struct azx *chip)
+{
+       if (!chip->initialized)
+               return;
+
+       /* disable interrupts */
+       azx_int_disable(chip);
+       azx_int_clear(chip);
+
+       /* disable CORB/RIRB */
+       azx_free_cmd_io(chip);
+
+       /* disable position buffer */
+       azx_writel(chip, DPLBASE, 0);
+       azx_writel(chip, DPUBASE, 0);
+
+       chip->initialized = 0;
+}
+EXPORT_SYMBOL_GPL(azx_stop_chip);
+
+/*
+ * interrupt handler
+ */
+irqreturn_t azx_interrupt(int irq, void *dev_id)
+{
+       struct azx *chip = dev_id;
+       struct azx_dev *azx_dev;
+       u32 status;
+       u8 sd_status;
+       int i;
+
+#ifdef CONFIG_PM_RUNTIME
+       if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+               if (chip->card->dev->power.runtime_status != RPM_ACTIVE)
+                       return IRQ_NONE;
+#endif
+
+       spin_lock(&chip->reg_lock);
+
+       if (chip->disabled) {
+               spin_unlock(&chip->reg_lock);
+               return IRQ_NONE;
+       }
+
+       status = azx_readl(chip, INTSTS);
+       if (status == 0 || status == 0xffffffff) {
+               spin_unlock(&chip->reg_lock);
+               return IRQ_NONE;
+       }
+
+       for (i = 0; i < chip->num_streams; i++) {
+               azx_dev = &chip->azx_dev[i];
+               if (status & azx_dev->sd_int_sta_mask) {
+                       sd_status = azx_sd_readb(chip, azx_dev, SD_STS);
+                       azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
+                       if (!azx_dev->substream || !azx_dev->running ||
+                           !(sd_status & SD_INT_COMPLETE))
+                               continue;
+                       /* check whether this IRQ is really acceptable */
+                       if (!chip->ops->position_check ||
+                           chip->ops->position_check(chip, azx_dev)) {
+                               spin_unlock(&chip->reg_lock);
+                               snd_pcm_period_elapsed(azx_dev->substream);
+                               spin_lock(&chip->reg_lock);
+                       }
+               }
+       }
+
+       /* clear rirb int */
+       status = azx_readb(chip, RIRBSTS);
+       if (status & RIRB_INT_MASK) {
+               if (status & RIRB_INT_RESPONSE) {
+                       if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
+                               udelay(80);
+                       azx_update_rirb(chip);
+               }
+               azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+       }
+
+       spin_unlock(&chip->reg_lock);
+
+       return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(azx_interrupt);
+
+/*
+ * Codec initerface
+ */
+
+/*
+ * Probe the given codec address
+ */
+static int probe_codec(struct azx *chip, int addr)
+{
+       unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+               (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+       unsigned int res;
+
+       mutex_lock(&chip->bus->cmd_mutex);
+       chip->probing = 1;
+       azx_send_cmd(chip->bus, cmd);
+       res = azx_get_response(chip->bus, addr);
+       chip->probing = 0;
+       mutex_unlock(&chip->bus->cmd_mutex);
+       if (res == -1)
+               return -EIO;
+       dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
+       return 0;
+}
+
+static void azx_bus_reset(struct hda_bus *bus)
+{
+       struct azx *chip = bus->private_data;
+
+       bus->in_reset = 1;
+       azx_stop_chip(chip);
+       azx_init_chip(chip, 1);
+#ifdef CONFIG_PM
+       if (chip->initialized) {
+               struct azx_pcm *p;
+               list_for_each_entry(p, &chip->pcm_list, list)
+                       snd_pcm_suspend_all(p->pcm);
+               snd_hda_suspend(chip->bus);
+               snd_hda_resume(chip->bus);
+       }
+#endif
+       bus->in_reset = 0;
+}
+
+#ifdef CONFIG_PM
+/* power-up/down the controller */
+static void azx_power_notify(struct hda_bus *bus, bool power_up)
+{
+       struct azx *chip = bus->private_data;
+
+       if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+               return;
+
+       if (power_up)
+               pm_runtime_get_sync(chip->card->dev);
+       else
+               pm_runtime_put_sync(chip->card->dev);
+}
+#endif
+
+static int get_jackpoll_interval(struct azx *chip)
+{
+       int i;
+       unsigned int j;
+
+       if (!chip->jackpoll_ms)
+               return 0;
+
+       i = chip->jackpoll_ms[chip->dev_index];
+       if (i == 0)
+               return 0;
+       if (i < 50 || i > 60000)
+               j = 0;
+       else
+               j = msecs_to_jiffies(i);
+       if (j == 0)
+               dev_warn(chip->card->dev,
+                        "jackpoll_ms value out of range: %d\n", i);
+       return j;
+}
+
+/* Codec initialization */
+int azx_codec_create(struct azx *chip, const char *model,
+                    unsigned int max_slots,
+                    int *power_save_to)
+{
+       struct hda_bus_template bus_temp;
+       int c, codecs, err;
+
+       memset(&bus_temp, 0, sizeof(bus_temp));
+       bus_temp.private_data = chip;
+       bus_temp.modelname = model;
+       bus_temp.pci = chip->pci;
+       bus_temp.ops.command = azx_send_cmd;
+       bus_temp.ops.get_response = azx_get_response;
+       bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
+       bus_temp.ops.bus_reset = azx_bus_reset;
+#ifdef CONFIG_PM
+       bus_temp.power_save = power_save_to;
+       bus_temp.ops.pm_notify = azx_power_notify;
+#endif
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+       bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
+       bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
+       bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
+#endif
+
+       err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
+       if (err < 0)
+               return err;
+
+       if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
+               dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
+               chip->bus->needs_damn_long_delay = 1;
+       }
+
+       codecs = 0;
+       if (!max_slots)
+               max_slots = AZX_DEFAULT_CODECS;
+
+       /* First try to probe all given codec slots */
+       for (c = 0; c < max_slots; c++) {
+               if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
+                       if (probe_codec(chip, c) < 0) {
+                               /* Some BIOSen give you wrong codec addresses
+                                * that don't exist
+                                */
+                               dev_warn(chip->card->dev,
+                                        "Codec #%d probe error; disabling it...\n", c);
+                               chip->codec_mask &= ~(1 << c);
+                               /* More badly, accessing to a non-existing
+                                * codec often screws up the controller chip,
+                                * and disturbs the further communications.
+                                * Thus if an error occurs during probing,
+                                * better to reset the controller chip to
+                                * get back to the sanity state.
+                                */
+                               azx_stop_chip(chip);
+                               azx_init_chip(chip, 1);
+                       }
+               }
+       }
+
+       /* AMD chipsets often cause the communication stalls upon certain
+        * sequence like the pin-detection.  It seems that forcing the synced
+        * access works around the stall.  Grrr...
+        */
+       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+               dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
+               chip->bus->sync_write = 1;
+               chip->bus->allow_bus_reset = 1;
+       }
+
+       /* Then create codec instances */
+       for (c = 0; c < max_slots; c++) {
+               if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
+                       struct hda_codec *codec;
+                       err = snd_hda_codec_new(chip->bus, c, &codec);
+                       if (err < 0)
+                               continue;
+                       codec->jackpoll_interval = get_jackpoll_interval(chip);
+                       codec->beep_mode = chip->beep_mode;
+                       codecs++;
+               }
+       }
+       if (!codecs) {
+               dev_err(chip->card->dev, "no codecs initialized\n");
+               return -ENXIO;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(azx_codec_create);
+
+/* configure each codec instance */
+int azx_codec_configure(struct azx *chip)
+{
+       struct hda_codec *codec;
+       list_for_each_entry(codec, &chip->bus->codec_list, list) {
+               snd_hda_codec_configure(codec);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(azx_codec_configure);
+
+/* mixer creation - all stuff is implemented in hda module */
+int azx_mixer_create(struct azx *chip)
+{
+       return snd_hda_build_controls(chip->bus);
+}
+EXPORT_SYMBOL_GPL(azx_mixer_create);
+
+
+/* initialize SD streams */
+int azx_init_stream(struct azx *chip)
+{
+       int i;
+
+       /* initialize each stream (aka device)
+        * assign the starting bdl address to each stream (device)
+        * and initialize
+        */
+       for (i = 0; i < chip->num_streams; i++) {
+               struct azx_dev *azx_dev = &chip->azx_dev[i];
+               azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
+               /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+               azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+               /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+               azx_dev->sd_int_sta_mask = 1 << i;
+               /* stream tag: must be non-zero and unique */
+               azx_dev->index = i;
+               azx_dev->stream_tag = i + 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(azx_init_stream);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Common HDA driver funcitons");
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
new file mode 100644 (file)
index 0000000..1d2e3be
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Common functionality for the alsa driver code base for HD Audio.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the 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 __SOUND_HDA_CONTROLLER_H
+#define __SOUND_HDA_CONTROLLER_H
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "hda_codec.h"
+#include "hda_priv.h"
+
+/* PCM setup */
+static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
+{
+       return substream->runtime->private_data;
+}
+unsigned int azx_get_position(struct azx *chip,
+                             struct azx_dev *azx_dev,
+                             bool with_check);
+
+/* Stream control. */
+void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev);
+
+/* Allocation functions. */
+int azx_alloc_stream_pages(struct azx *chip);
+void azx_free_stream_pages(struct azx *chip);
+
+/* Low level azx interface */
+void azx_init_chip(struct azx *chip, int full_reset);
+void azx_stop_chip(struct azx *chip);
+void azx_enter_link_reset(struct azx *chip);
+irqreturn_t azx_interrupt(int irq, void *dev_id);
+
+/* Codec interface */
+int azx_codec_create(struct azx *chip, const char *model,
+                    unsigned int max_slots,
+                    int *power_save_to);
+int azx_codec_configure(struct azx *chip);
+int azx_mixer_create(struct azx *chip);
+int azx_init_stream(struct azx *chip);
+
+#endif /* __SOUND_HDA_CONTROLLER_H */
index 79ca80f6c77ada6d182a86b9880f3ce9125726f5..46690a7f48f6eef0b8e60e530c0991938695c7ca 100644 (file)
@@ -153,7 +153,7 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
        val = snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_HDMI_ELDD, byte_index);
 #ifdef BE_PARANOID
-       printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+       codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
 #endif
        return val;
 }
@@ -332,11 +332,11 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
        size = snd_hdmi_get_eld_size(codec, nid);
        if (size == 0) {
                /* wfg: workaround for ASUS P5E-VM HDMI board */
-               snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
+               codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
                size = 128;
        }
        if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
-               snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
+               codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
                return -ERANGE;
        }
 
@@ -348,8 +348,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
                 * Just abort. The caller will repoll after a while.
                 */
                if (!(val & AC_ELDD_ELD_VALID)) {
-                       snd_printd(KERN_INFO
-                                 "HDMI: invalid ELD data byte %d\n", i);
+                       codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
                        ret = -EINVAL;
                        goto error;
                }
@@ -361,7 +360,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
                 * correctly writes ELD content before setting ELD_valid bit.
                 */
                if (!val && !i) {
-                       snd_printdd(KERN_INFO "HDMI: 0 ELD data\n");
+                       codec_dbg(codec, "HDMI: 0 ELD data\n");
                        ret = -EINVAL;
                        goto error;
                }
@@ -681,7 +680,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
        spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
 
        if (spkalloc <= 0) {
-               snd_printd(KERN_INFO "HDMI ATI/AMD: no speaker allocation for ELD\n");
+               codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
                return -EINVAL;
        }
 
@@ -722,7 +721,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
                sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
 
                if (sink_desc_len > ELD_MAX_MNL) {
-                       snd_printd(KERN_INFO "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
+                       codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
                                   sink_desc_len);
                        sink_desc_len = ELD_MAX_MNL;
                }
@@ -764,7 +763,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
        }
 
        if (pos == ELD_FIXED_BYTES + sink_desc_len) {
-               snd_printd(KERN_INFO "HDMI ATI/AMD: no audio descriptors for ELD\n");
+               codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
                return -EINVAL;
        }
 
index d9a09bdd09db656891aa51f910753b686dc79964..16133881e967074aa906c340ee9d87bd593e6983 100644 (file)
@@ -79,7 +79,7 @@ static void free_kctls(struct hda_gen_spec *spec)
        snd_array_free(&spec->kctls);
 }
 
-void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
+static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
 {
        if (!spec)
                return;
@@ -87,7 +87,6 @@ void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
        snd_array_free(&spec->paths);
        snd_array_free(&spec->loopback_list);
 }
-EXPORT_SYMBOL_GPL(snd_hda_gen_spec_free);
 
 /*
  * store user hints
@@ -347,7 +346,8 @@ static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
        return is_ctl_used(codec, val, type);
 }
 
-static void print_nid_path(const char *pfx, struct nid_path *path)
+static void print_nid_path(struct hda_codec *codec,
+                          const char *pfx, struct nid_path *path)
 {
        char buf[40];
        int i;
@@ -359,7 +359,7 @@ static void print_nid_path(const char *pfx, struct nid_path *path)
                sprintf(tmp, ":%02x", path->path[i]);
                strlcat(buf, tmp, sizeof(buf));
        }
-       snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf);
+       codec_dbg(codec, "%s path: depth=%d %s\n", pfx, path->depth, buf);
 }
 
 /* called recursively */
@@ -762,7 +762,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
                                                    AC_PWRST_D0);
                }
                if (enable && path->multi[i])
-                       snd_hda_codec_write_cache(codec, nid, 0,
+                       snd_hda_codec_update_cache(codec, nid, 0,
                                            AC_VERB_SET_CONNECT_SEL,
                                            path->idx[i]);
                if (has_amp_in(codec, path, i))
@@ -1261,7 +1261,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs,
                        dac = dacs[i] = 0;
                        badness += bad->no_dac;
                } else {
-                       /* print_nid_path("output", path); */
+                       /* print_nid_path(codec, "output", path); */
                        path->active = true;
                        path_idx[i] = snd_hda_get_path_idx(codec, path);
                        badness += assign_out_path_ctls(codec, path);
@@ -1388,7 +1388,7 @@ static int fill_multi_ios(struct hda_codec *codec,
                                badness++;
                                continue;
                        }
-                       /* print_nid_path("multiio", path); */
+                       /* print_nid_path(codec, "multiio", path); */
                        spec->multi_io[spec->multi_ios].pin = nid;
                        spec->multi_io[spec->multi_ios].dac = dac;
                        spec->out_paths[cfg->line_outs + spec->multi_ios] =
@@ -1445,7 +1445,7 @@ static bool map_singles(struct hda_codec *codec, int outs,
                if (path) {
                        dacs[i] = dac;
                        found = true;
-                       /* print_nid_path("output", path); */
+                       /* print_nid_path(codec, "output", path); */
                        path->active = true;
                        path_idx[i] = snd_hda_get_path_idx(codec, path);
                }
@@ -1483,7 +1483,7 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
        }
        if (!path)
                return 0;
-       /* print_nid_path("output-aamix", path); */
+       /* print_nid_path(codec, "output-aamix", path); */
        path->active = false; /* unused as default */
        return snd_hda_get_path_idx(codec, path);
 }
@@ -1700,7 +1700,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
 #define DEBUG_BADNESS
 
 #ifdef DEBUG_BADNESS
-#define debug_badness  snd_printdd
+#define debug_badness(fmt, args...)    codec_dbg(codec, fmt, ##args)
 #else
 #define debug_badness(...)
 #endif
@@ -1713,7 +1713,7 @@ static inline void print_nid_path_idx(struct hda_codec *codec,
 
        path = snd_hda_get_path_from_idx(codec, idx);
        if (path)
-               print_nid_path(pfx, path);
+               print_nid_path(codec, pfx, path);
 }
 
 static void debug_show_configs(struct hda_codec *codec,
@@ -1781,7 +1781,7 @@ static void fill_all_dac_nids(struct hda_codec *codec)
                if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
                        continue;
                if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
-                       snd_printk(KERN_ERR "hda: Too many DACs!\n");
+                       codec_err(codec, "Too many DACs!\n");
                        break;
                }
                spec->all_dacs[spec->num_all_dacs++] = nid;
@@ -2430,7 +2430,7 @@ static int create_hp_mic(struct hda_codec *codec)
        spec->hp_mic_pin = nid;
        /* we can't handle auto-mic together with HP-mic */
        spec->suppress_auto_mic = 1;
-       snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
+       codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid);
        return 0;
 }
 
@@ -2884,7 +2884,7 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
        path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
        if (!path)
                return -EINVAL;
-       print_nid_path("loopback", path);
+       print_nid_path(codec, "loopback", path);
        spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
 
        idx = path->idx[path->depth - 1];
@@ -2912,7 +2912,7 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
                path = snd_hda_add_new_path(codec, spec->mixer_nid,
                                            spec->mixer_merge_nid, 0);
                if (path) {
-                       print_nid_path("loopback-merge", path);
+                       print_nid_path(codec, "loopback-merge", path);
                        path->active = true;
                        spec->loopback_merge_path =
                                snd_hda_get_path_idx(codec, path);
@@ -2991,7 +2991,7 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
                        }
                }
 
-               snd_printdd("hda-codec: enabling ADC switching\n");
+               codec_dbg(codec, "enabling ADC switching\n");
                spec->dyn_adc_switch = 1;
        } else if (nums != spec->num_adc_nids) {
                /* shrink the invalid adcs and input paths */
@@ -3015,7 +3015,7 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
 
        if (imux->num_items == 1 ||
            (imux->num_items == 2 && spec->hp_mic)) {
-               snd_printdd("hda-codec: reducing to a single ADC\n");
+               codec_dbg(codec, "reducing to a single ADC\n");
                spec->num_adc_nids = 1; /* reduce to a single ADC */
        }
 
@@ -3046,7 +3046,7 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
                path = snd_hda_add_new_path(codec, pin, adc, anchor);
                if (!path)
                        continue;
-               print_nid_path("input", path);
+               print_nid_path(codec, "input", path);
                spec->input_paths[imux_idx][c] =
                        snd_hda_get_path_idx(codec, path);
 
@@ -3712,7 +3712,7 @@ static void parse_digital(struct hda_codec *codec)
                path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
                if (!path)
                        continue;
-               print_nid_path("digout", path);
+               print_nid_path(codec, "digout", path);
                path->active = true;
                spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
                set_pin_target(codec, pin, PIN_OUT, false);
@@ -3739,7 +3739,7 @@ static void parse_digital(struct hda_codec *codec)
                                continue;
                        path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
                        if (path) {
-                               print_nid_path("digin", path);
+                               print_nid_path(codec, "digin", path);
                                path->active = true;
                                spec->dig_in_nid = dig_nid;
                                spec->digin_path = snd_hda_get_path_idx(codec, path);
@@ -4170,8 +4170,7 @@ static int check_auto_mute_availability(struct hda_codec *codec)
                hda_nid_t nid = cfg->hp_pins[i];
                if (!is_jack_detectable(codec, nid))
                        continue;
-               snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n",
-                           nid);
+               codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
                snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
                                                    call_hp_automute);
                spec->detect_hp = 1;
@@ -4183,7 +4182,7 @@ static int check_auto_mute_availability(struct hda_codec *codec)
                                hda_nid_t nid = cfg->line_out_pins[i];
                                if (!is_jack_detectable(codec, nid))
                                        continue;
-                               snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid);
+                               codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
                                snd_hda_jack_detect_enable_callback(codec, nid,
                                                                    HDA_GEN_FRONT_EVENT,
                                                                    call_line_automute);
@@ -4303,7 +4302,7 @@ static int check_auto_mic_availability(struct hda_codec *codec)
        spec->auto_mic = 1;
        spec->num_adc_nids = 1;
        spec->cur_mux[0] = spec->am_entry[0].idx;
-       snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
+       codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
                    spec->am_entry[0].pin,
                    spec->am_entry[1].pin,
                    spec->am_entry[2].pin);
@@ -5350,7 +5349,7 @@ EXPORT_SYMBOL_GPL(snd_hda_gen_init);
  */
 void snd_hda_gen_free(struct hda_codec *codec)
 {
-       snd_hda_detach_beep_device(codec);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
        snd_hda_gen_spec_free(codec->spec);
        kfree(codec->spec);
        codec->spec = NULL;
index c908afbe4d94662fcaa92cf4009efc64b2114680..bb2dea743986b365813a9e55ed2342ecd4f25c07 100644 (file)
@@ -297,7 +297,6 @@ struct hda_gen_spec {
 };
 
 int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
-void snd_hda_gen_spec_free(struct hda_gen_spec *spec);
 
 int snd_hda_gen_init(struct hda_codec *codec);
 void snd_hda_gen_free(struct hda_codec *codec);
index 72d8389fb399c1802d645686ae0dbc2ee379a2b4..014a7849e8fdbf2a2f18c55e281f7499561f89db 100644 (file)
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/compat.h>
-#include <linux/mutex.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/export.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
 #include <sound/minors.h>
 
-/* hint string pair */
-struct hda_hint {
-       const char *key;
-       const char *val;        /* contained in the same alloc as key */
-};
-
 /*
  * write/read an out-of-bound verb
  */
@@ -105,26 +94,6 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
        return 0;
 }
 
-static void clear_hwdep_elements(struct hda_codec *codec)
-{
-       int i;
-
-       /* clear init verbs */
-       snd_array_free(&codec->init_verbs);
-       /* clear hints */
-       for (i = 0; i < codec->hints.used; i++) {
-               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
-               kfree(hint->key); /* we don't need to free hint->val */
-       }
-       snd_array_free(&codec->hints);
-       snd_array_free(&codec->user_pins);
-}
-
-static void hwdep_free(struct snd_hwdep *hwdep)
-{
-       clear_hwdep_elements(hwdep->private_data);
-}
-
 int snd_hda_create_hwdep(struct hda_codec *codec)
 {
        char hwname[16];
@@ -139,8 +108,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
        sprintf(hwdep->name, "HDA Codec %d", codec->addr);
        hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
        hwdep->private_data = codec;
-       hwdep->private_free = hwdep_free;
        hwdep->exclusive = 1;
+       hwdep->groups = snd_hda_dev_attr_groups;
 
        hwdep->ops.open = hda_hwdep_open;
        hwdep->ops.ioctl = hda_hwdep_ioctl;
@@ -148,740 +117,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
        hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
 #endif
 
-       mutex_init(&codec->user_mutex);
-       snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
-       snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
-       snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static ssize_t power_on_acct_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       snd_hda_update_power_acct(codec);
-       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
-}
-
-static ssize_t power_off_acct_show(struct device *dev,
-                                  struct device_attribute *attr,
-                                  char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       snd_hda_update_power_acct(codec);
-       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
-}
-
-static struct device_attribute power_attrs[] = {
-       __ATTR_RO(power_on_acct),
-       __ATTR_RO(power_off_acct),
-};
-
-int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
-{
-       struct snd_hwdep *hwdep = codec->hwdep;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(power_attrs); i++)
-               snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
-                                         hwdep->device, &power_attrs[i]);
-       return 0;
-}
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_SND_HDA_RECONFIG
-
-/*
- * sysfs interface
- */
-
-static int clear_codec(struct hda_codec *codec)
-{
-       int err;
-
-       err = snd_hda_codec_reset(codec);
-       if (err < 0) {
-               snd_printk(KERN_ERR "The codec is being used, can't free.\n");
-               return err;
-       }
-       clear_hwdep_elements(codec);
-       return 0;
-}
-
-static int reconfig_codec(struct hda_codec *codec)
-{
-       int err;
-
-       snd_hda_power_up(codec);
-       snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
-       err = snd_hda_codec_reset(codec);
-       if (err < 0) {
-               snd_printk(KERN_ERR
-                          "The codec is being used, can't reconfigure.\n");
-               goto error;
-       }
-       err = snd_hda_codec_configure(codec);
-       if (err < 0)
-               goto error;
-       /* rebuild PCMs */
-       err = snd_hda_codec_build_pcms(codec);
-       if (err < 0)
-               goto error;
-       /* rebuild mixers */
-       err = snd_hda_codec_build_controls(codec);
-       if (err < 0)
-               goto error;
-       err = snd_card_register(codec->bus->card);
- error:
-       snd_hda_power_down(codec);
-       return err;
-}
-
-/*
- * allocate a string at most len chars, and remove the trailing EOL
- */
-static char *kstrndup_noeol(const char *src, size_t len)
-{
-       char *s = kstrndup(src, len, GFP_KERNEL);
-       char *p;
-       if (!s)
-               return NULL;
-       p = strchr(s, '\n');
-       if (p)
-               *p = 0;
-       return s;
-}
-
-#define CODEC_INFO_SHOW(type)                                  \
-static ssize_t type##_show(struct device *dev,                 \
-                          struct device_attribute *attr,       \
-                          char *buf)                           \
-{                                                              \
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
-       struct hda_codec *codec = hwdep->private_data;          \
-       return sprintf(buf, "0x%x\n", codec->type);             \
-}
-
-#define CODEC_INFO_STR_SHOW(type)                              \
-static ssize_t type##_show(struct device *dev,                 \
-                            struct device_attribute *attr,     \
-                                       char *buf)              \
-{                                                              \
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
-       struct hda_codec *codec = hwdep->private_data;          \
-       return sprintf(buf, "%s\n",                             \
-                      codec->type ? codec->type : "");         \
-}
-
-CODEC_INFO_SHOW(vendor_id);
-CODEC_INFO_SHOW(subsystem_id);
-CODEC_INFO_SHOW(revision_id);
-CODEC_INFO_SHOW(afg);
-CODEC_INFO_SHOW(mfg);
-CODEC_INFO_STR_SHOW(vendor_name);
-CODEC_INFO_STR_SHOW(chip_name);
-CODEC_INFO_STR_SHOW(modelname);
-
-#define CODEC_INFO_STORE(type)                                 \
-static ssize_t type##_store(struct device *dev,                        \
-                           struct device_attribute *attr,      \
-                           const char *buf, size_t count)      \
-{                                                              \
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
-       struct hda_codec *codec = hwdep->private_data;          \
-       unsigned long val;                                      \
-       int err = kstrtoul(buf, 0, &val);                       \
-       if (err < 0)                                            \
-               return err;                                     \
-       codec->type = val;                                      \
-       return count;                                           \
-}
-
-#define CODEC_INFO_STR_STORE(type)                             \
-static ssize_t type##_store(struct device *dev,                        \
-                           struct device_attribute *attr,      \
-                           const char *buf, size_t count)      \
-{                                                              \
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
-       struct hda_codec *codec = hwdep->private_data;          \
-       char *s = kstrndup_noeol(buf, 64);                      \
-       if (!s)                                                 \
-               return -ENOMEM;                                 \
-       kfree(codec->type);                                     \
-       codec->type = s;                                        \
-       return count;                                           \
-}
-
-CODEC_INFO_STORE(vendor_id);
-CODEC_INFO_STORE(subsystem_id);
-CODEC_INFO_STORE(revision_id);
-CODEC_INFO_STR_STORE(vendor_name);
-CODEC_INFO_STR_STORE(chip_name);
-CODEC_INFO_STR_STORE(modelname);
-
-#define CODEC_ACTION_STORE(type)                               \
-static ssize_t type##_store(struct device *dev,                        \
-                           struct device_attribute *attr,      \
-                           const char *buf, size_t count)      \
-{                                                              \
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
-       struct hda_codec *codec = hwdep->private_data;          \
-       int err = 0;                                            \
-       if (*buf)                                               \
-               err = type##_codec(codec);                      \
-       return err < 0 ? err : count;                           \
-}
-
-CODEC_ACTION_STORE(reconfig);
-CODEC_ACTION_STORE(clear);
-
-static ssize_t init_verbs_show(struct device *dev,
-                              struct device_attribute *attr,
-                              char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       int i, len = 0;
-       mutex_lock(&codec->user_mutex);
-       for (i = 0; i < codec->init_verbs.used; i++) {
-               struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
-               len += snprintf(buf + len, PAGE_SIZE - len,
-                               "0x%02x 0x%03x 0x%04x\n",
-                               v->nid, v->verb, v->param);
-       }
-       mutex_unlock(&codec->user_mutex);
-       return len;
-}
-
-static int parse_init_verbs(struct hda_codec *codec, const char *buf)
-{
-       struct hda_verb *v;
-       int nid, verb, param;
-
-       if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
-               return -EINVAL;
-       if (!nid || !verb)
-               return -EINVAL;
-       mutex_lock(&codec->user_mutex);
-       v = snd_array_new(&codec->init_verbs);
-       if (!v) {
-               mutex_unlock(&codec->user_mutex);
-               return -ENOMEM;
-       }
-       v->nid = nid;
-       v->verb = verb;
-       v->param = param;
-       mutex_unlock(&codec->user_mutex);
-       return 0;
-}
-
-static ssize_t init_verbs_store(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t count)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       int err = parse_init_verbs(codec, buf);
-       if (err < 0)
-               return err;
-       return count;
-}
-
-static ssize_t hints_show(struct device *dev,
-                         struct device_attribute *attr,
-                         char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       int i, len = 0;
-       mutex_lock(&codec->user_mutex);
-       for (i = 0; i < codec->hints.used; i++) {
-               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
-               len += snprintf(buf + len, PAGE_SIZE - len,
-                               "%s = %s\n", hint->key, hint->val);
-       }
-       mutex_unlock(&codec->user_mutex);
-       return len;
-}
-
-static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
-{
-       int i;
-
-       for (i = 0; i < codec->hints.used; i++) {
-               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
-               if (!strcmp(hint->key, key))
-                       return hint;
-       }
-       return NULL;
-}
-
-static void remove_trail_spaces(char *str)
-{
-       char *p;
-       if (!*str)
-               return;
-       p = str + strlen(str) - 1;
-       for (; isspace(*p); p--) {
-               *p = 0;
-               if (p == str)
-                       return;
-       }
-}
-
-#define MAX_HINTS      1024
-
-static int parse_hints(struct hda_codec *codec, const char *buf)
-{
-       char *key, *val;
-       struct hda_hint *hint;
-       int err = 0;
-
-       buf = skip_spaces(buf);
-       if (!*buf || *buf == '#' || *buf == '\n')
-               return 0;
-       if (*buf == '=')
-               return -EINVAL;
-       key = kstrndup_noeol(buf, 1024);
-       if (!key)
-               return -ENOMEM;
-       /* extract key and val */
-       val = strchr(key, '=');
-       if (!val) {
-               kfree(key);
-               return -EINVAL;
-       }
-       *val++ = 0;
-       val = skip_spaces(val);
-       remove_trail_spaces(key);
-       remove_trail_spaces(val);
-       mutex_lock(&codec->user_mutex);
-       hint = get_hint(codec, key);
-       if (hint) {
-               /* replace */
-               kfree(hint->key);
-               hint->key = key;
-               hint->val = val;
-               goto unlock;
-       }
-       /* allocate a new hint entry */
-       if (codec->hints.used >= MAX_HINTS)
-               hint = NULL;
-       else
-               hint = snd_array_new(&codec->hints);
-       if (hint) {
-               hint->key = key;
-               hint->val = val;
-       } else {
-               err = -ENOMEM;
-       }
- unlock:
-       mutex_unlock(&codec->user_mutex);
-       if (err)
-               kfree(key);
-       return err;
-}
-
-static ssize_t hints_store(struct device *dev,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       int err = parse_hints(codec, buf);
-       if (err < 0)
-               return err;
-       return count;
-}
-
-static ssize_t pin_configs_show(struct hda_codec *codec,
-                               struct snd_array *list,
-                               char *buf)
-{
-       int i, len = 0;
-       mutex_lock(&codec->user_mutex);
-       for (i = 0; i < list->used; i++) {
-               struct hda_pincfg *pin = snd_array_elem(list, i);
-               len += sprintf(buf + len, "0x%02x 0x%08x\n",
-                              pin->nid, pin->cfg);
-       }
-       mutex_unlock(&codec->user_mutex);
-       return len;
-}
-
-static ssize_t init_pin_configs_show(struct device *dev,
-                                    struct device_attribute *attr,
-                                    char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       return pin_configs_show(codec, &codec->init_pins, buf);
-}
-
-static ssize_t user_pin_configs_show(struct device *dev,
-                                    struct device_attribute *attr,
-                                    char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       return pin_configs_show(codec, &codec->user_pins, buf);
-}
-
-static ssize_t driver_pin_configs_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       return pin_configs_show(codec, &codec->driver_pins, buf);
-}
-
-#define MAX_PIN_CONFIGS                32
-
-static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
-{
-       int nid, cfg, err;
-
-       if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
-               return -EINVAL;
-       if (!nid)
-               return -EINVAL;
-       mutex_lock(&codec->user_mutex);
-       err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
-       mutex_unlock(&codec->user_mutex);
-       return err;
-}
-
-static ssize_t user_pin_configs_store(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t count)
-{
-       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
-       struct hda_codec *codec = hwdep->private_data;
-       int err = parse_user_pin_configs(codec, buf);
-       if (err < 0)
-               return err;
-       return count;
-}
-
-#define CODEC_ATTR_RW(type) \
-       __ATTR(type, 0644, type##_show, type##_store)
-#define CODEC_ATTR_RO(type) \
-       __ATTR_RO(type)
-#define CODEC_ATTR_WO(type) \
-       __ATTR(type, 0200, NULL, type##_store)
-
-static struct device_attribute codec_attrs[] = {
-       CODEC_ATTR_RW(vendor_id),
-       CODEC_ATTR_RW(subsystem_id),
-       CODEC_ATTR_RW(revision_id),
-       CODEC_ATTR_RO(afg),
-       CODEC_ATTR_RO(mfg),
-       CODEC_ATTR_RW(vendor_name),
-       CODEC_ATTR_RW(chip_name),
-       CODEC_ATTR_RW(modelname),
-       CODEC_ATTR_RW(init_verbs),
-       CODEC_ATTR_RW(hints),
-       CODEC_ATTR_RO(init_pin_configs),
-       CODEC_ATTR_RW(user_pin_configs),
-       CODEC_ATTR_RO(driver_pin_configs),
-       CODEC_ATTR_WO(reconfig),
-       CODEC_ATTR_WO(clear),
-};
-
-/*
- * create sysfs files on hwdep directory
- */
-int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
-{
-       struct snd_hwdep *hwdep = codec->hwdep;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
-               snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
-                                         hwdep->device, &codec_attrs[i]);
-       return 0;
-}
-
-/*
- * Look for hint string
- */
-const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
-{
-       struct hda_hint *hint = get_hint(codec, key);
-       return hint ? hint->val : NULL;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_hint);
-
-int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
-{
-       const char *p;
-       int ret;
-
-       mutex_lock(&codec->user_mutex);
-       p = snd_hda_get_hint(codec, key);
-       if (!p || !*p)
-               ret = -ENOENT;
-       else {
-               switch (toupper(*p)) {
-               case 'T': /* true */
-               case 'Y': /* yes */
-               case '1':
-                       ret = 1;
-                       break;
-               default:
-                       ret = 0;
-                       break;
-               }
-       }
-       mutex_unlock(&codec->user_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
-
-int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
-{
-       const char *p;
-       unsigned long val;
-       int ret;
-
-       mutex_lock(&codec->user_mutex);
-       p = snd_hda_get_hint(codec, key);
-       if (!p)
-               ret = -ENOENT;
-       else if (kstrtoul(p, 0, &val))
-               ret = -EINVAL;
-       else {
-               *valp = val;
-               ret = 0;
-       }
-       mutex_unlock(&codec->user_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
-#endif /* CONFIG_SND_HDA_RECONFIG */
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       /* link to codec */
+       hwdep->dev = &codec->dev;
 
-/* parser mode */
-enum {
-       LINE_MODE_NONE,
-       LINE_MODE_CODEC,
-       LINE_MODE_MODEL,
-       LINE_MODE_PINCFG,
-       LINE_MODE_VERB,
-       LINE_MODE_HINT,
-       LINE_MODE_VENDOR_ID,
-       LINE_MODE_SUBSYSTEM_ID,
-       LINE_MODE_REVISION_ID,
-       LINE_MODE_CHIP_NAME,
-       NUM_LINE_MODES,
-};
-
-static inline int strmatch(const char *a, const char *b)
-{
-       return strnicmp(a, b, strlen(b)) == 0;
-}
-
-/* parse the contents after the line "[codec]"
- * accept only the line with three numbers, and assign the current codec
- */
-static void parse_codec_mode(char *buf, struct hda_bus *bus,
-                            struct hda_codec **codecp)
-{
-       int vendorid, subid, caddr;
-       struct hda_codec *codec;
-
-       *codecp = NULL;
-       if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
-               list_for_each_entry(codec, &bus->codec_list, list) {
-                       if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
-                           (subid <= 0 || codec->subsystem_id == subid) &&
-                           codec->addr == caddr) {
-                               *codecp = codec;
-                               break;
-                       }
-               }
-       }
-}
-
-/* parse the contents after the other command tags, [pincfg], [verb],
- * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
- * just pass to the sysfs helper (only when any codec was specified)
- */
-static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
-                             struct hda_codec **codecp)
-{
-       parse_user_pin_configs(*codecp, buf);
-}
-
-static void parse_verb_mode(char *buf, struct hda_bus *bus,
-                           struct hda_codec **codecp)
-{
-       parse_init_verbs(*codecp, buf);
-}
-
-static void parse_hint_mode(char *buf, struct hda_bus *bus,
-                           struct hda_codec **codecp)
-{
-       parse_hints(*codecp, buf);
-}
-
-static void parse_model_mode(char *buf, struct hda_bus *bus,
-                            struct hda_codec **codecp)
-{
-       kfree((*codecp)->modelname);
-       (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
-}
-
-static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
-                                struct hda_codec **codecp)
-{
-       kfree((*codecp)->chip_name);
-       (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
-}
-
-#define DEFINE_PARSE_ID_MODE(name) \
-static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
-                                struct hda_codec **codecp) \
-{ \
-       unsigned long val; \
-       if (!kstrtoul(buf, 0, &val)) \
-               (*codecp)->name = val; \
-}
-
-DEFINE_PARSE_ID_MODE(vendor_id);
-DEFINE_PARSE_ID_MODE(subsystem_id);
-DEFINE_PARSE_ID_MODE(revision_id);
-
-
-struct hda_patch_item {
-       const char *tag;
-       const char *alias;
-       void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
-};
-
-static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
-       [LINE_MODE_CODEC] = {
-               .tag = "[codec]",
-               .parser = parse_codec_mode,
-       },
-       [LINE_MODE_MODEL] = {
-               .tag = "[model]",
-               .parser = parse_model_mode,
-       },
-       [LINE_MODE_VERB] = {
-               .tag = "[verb]",
-               .alias = "[init_verbs]",
-               .parser = parse_verb_mode,
-       },
-       [LINE_MODE_PINCFG] = {
-               .tag = "[pincfg]",
-               .alias = "[user_pin_configs]",
-               .parser = parse_pincfg_mode,
-       },
-       [LINE_MODE_HINT] = {
-               .tag = "[hint]",
-               .alias = "[hints]",
-               .parser = parse_hint_mode
-       },
-       [LINE_MODE_VENDOR_ID] = {
-               .tag = "[vendor_id]",
-               .parser = parse_vendor_id_mode,
-       },
-       [LINE_MODE_SUBSYSTEM_ID] = {
-               .tag = "[subsystem_id]",
-               .parser = parse_subsystem_id_mode,
-       },
-       [LINE_MODE_REVISION_ID] = {
-               .tag = "[revision_id]",
-               .parser = parse_revision_id_mode,
-       },
-       [LINE_MODE_CHIP_NAME] = {
-               .tag = "[chip_name]",
-               .parser = parse_chip_name_mode,
-       },
-};
-
-/* check the line starting with '[' -- change the parser mode accodingly */
-static int parse_line_mode(char *buf, struct hda_bus *bus)
-{
-       int i;
-       for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
-               if (!patch_items[i].tag)
-                       continue;
-               if (strmatch(buf, patch_items[i].tag))
-                       return i;
-               if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
-                       return i;
-       }
-       return LINE_MODE_NONE;
-}
-
-/* copy one line from the buffer in fw, and update the fields in fw
- * return zero if it reaches to the end of the buffer, or non-zero
- * if successfully copied a line
- *
- * the spaces at the beginning and the end of the line are stripped
- */
-static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
-                           const void **fw_data_p)
-{
-       int len;
-       size_t fw_size = *fw_size_p;
-       const char *p = *fw_data_p;
-
-       while (isspace(*p) && fw_size) {
-               p++;
-               fw_size--;
-       }
-       if (!fw_size)
-               return 0;
-
-       for (len = 0; len < fw_size; len++) {
-               if (!*p)
-                       break;
-               if (*p == '\n') {
-                       p++;
-                       len++;
-                       break;
-               }
-               if (len < size)
-                       *buf++ = *p++;
-       }
-       *buf = 0;
-       *fw_size_p = fw_size - len;
-       *fw_data_p = p;
-       remove_trail_spaces(buf);
-       return 1;
-}
-
-/*
- * load a "patch" firmware file and parse it
- */
-int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
-{
-       char buf[128];
-       struct hda_codec *codec;
-       int line_mode;
-
-       line_mode = LINE_MODE_NONE;
-       codec = NULL;
-       while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
-               if (!*buf || *buf == '#' || *buf == '\n')
-                       continue;
-               if (*buf == '[')
-                       line_mode = parse_line_mode(buf, bus);
-               else if (patch_items[line_mode].parser &&
-                        (codec || line_mode <= LINE_MODE_CODEC))
-                       patch_items[line_mode].parser(buf, bus, &codec);
-       }
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hda_load_patch);
-#endif /* CONFIG_SND_HDA_PATCH_LOADER */
index 76c13d5b3ca0d7295d24e22f660ba1a4d733fa01..9d07e4edacdb4026fcd1b7cbdb7c85974b2a8489 100644 (file)
@@ -30,7 +30,7 @@ void hda_display_power(bool enable)
        if (!get_power || !put_power)
                return;
 
-       snd_printdd("HDA display power %s \n",
+       pr_debug("HDA display power %s \n",
                        enable ? "Enable" : "Disable");
        if (enable)
                get_power();
@@ -44,7 +44,7 @@ int hda_i915_init(void)
 
        get_power = symbol_request(i915_request_power_well);
        if (!get_power) {
-               snd_printk(KERN_WARNING "hda-i915: get_power symbol get fail\n");
+               pr_warn("hda-i915: get_power symbol get fail\n");
                return -ENODEV;
        }
 
@@ -55,7 +55,7 @@ int hda_i915_init(void)
                return -ENODEV;
        }
 
-       snd_printd("HDA driver get symbol successfully from i915 module\n");
+       pr_debug("HDA driver get symbol successfully from i915 module\n");
 
        return err;
 }
index e354ab1ec20f2dcd942931582761cc10b5543648..77ca894f82845964192cdc20476002f3cdec63a0 100644 (file)
@@ -63,6 +63,8 @@
 #include <linux/firmware.h>
 #include "hda_codec.h"
 #include "hda_i915.h"
+#include "hda_controller.h"
+#include "hda_priv.h"
 
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -127,6 +129,7 @@ static struct kernel_param_ops param_ops_xint = {
 #define param_check_xint param_check_int
 
 static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
+static int *power_save_addr = &power_save;
 module_param(power_save, xint, 0644);
 MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
                 "(in second, 0 = disable).");
@@ -138,6 +141,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
 static bool power_save_controller = 1;
 module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
+#else
+static int *power_save_addr;
 #endif /* CONFIG_PM */
 
 static int align_buffer_size = -1;
@@ -149,10 +154,8 @@ MODULE_PARM_DESC(align_buffer_size,
 static bool hda_snoop = true;
 module_param_named(snoop, hda_snoop, bool, 0444);
 MODULE_PARM_DESC(snoop, "Enable/disable snooping");
-#define azx_snoop(chip)                (chip)->snoop
 #else
 #define hda_snoop              true
-#define azx_snoop(chip)                true
 #endif
 
 
@@ -191,12 +194,6 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{ULI, M5461}}");
 MODULE_DESCRIPTION("Intel HDA driver");
 
-#ifdef CONFIG_SND_VERBOSE_PRINTK
-#define SFX    /* nop */
-#else
-#define SFX    "hda-intel "
-#endif
-
 #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
 #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
 #define SUPPORT_VGA_SWITCHEROO
@@ -204,366 +201,9 @@ MODULE_DESCRIPTION("Intel HDA driver");
 #endif
 
 
-/*
- * registers
- */
-#define ICH6_REG_GCAP                  0x00
-#define   ICH6_GCAP_64OK       (1 << 0)   /* 64bit address support */
-#define   ICH6_GCAP_NSDO       (3 << 1)   /* # of serial data out signals */
-#define   ICH6_GCAP_BSS                (31 << 3)  /* # of bidirectional streams */
-#define   ICH6_GCAP_ISS                (15 << 8)  /* # of input streams */
-#define   ICH6_GCAP_OSS                (15 << 12) /* # of output streams */
-#define ICH6_REG_VMIN                  0x02
-#define ICH6_REG_VMAJ                  0x03
-#define ICH6_REG_OUTPAY                        0x04
-#define ICH6_REG_INPAY                 0x06
-#define ICH6_REG_GCTL                  0x08
-#define   ICH6_GCTL_RESET      (1 << 0)   /* controller reset */
-#define   ICH6_GCTL_FCNTRL     (1 << 1)   /* flush control */
-#define   ICH6_GCTL_UNSOL      (1 << 8)   /* accept unsol. response enable */
-#define ICH6_REG_WAKEEN                        0x0c
-#define ICH6_REG_STATESTS              0x0e
-#define ICH6_REG_GSTS                  0x10
-#define   ICH6_GSTS_FSTS       (1 << 1)   /* flush status */
-#define ICH6_REG_INTCTL                        0x20
-#define ICH6_REG_INTSTS                        0x24
-#define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
-#define ICH6_REG_OLD_SSYNC             0x34    /* SSYNC for old ICH */
-#define ICH6_REG_SSYNC                 0x38
-#define ICH6_REG_CORBLBASE             0x40
-#define ICH6_REG_CORBUBASE             0x44
-#define ICH6_REG_CORBWP                        0x48
-#define ICH6_REG_CORBRP                        0x4a
-#define   ICH6_CORBRP_RST      (1 << 15)  /* read pointer reset */
-#define ICH6_REG_CORBCTL               0x4c
-#define   ICH6_CORBCTL_RUN     (1 << 1)   /* enable DMA */
-#define   ICH6_CORBCTL_CMEIE   (1 << 0)   /* enable memory error irq */
-#define ICH6_REG_CORBSTS               0x4d
-#define   ICH6_CORBSTS_CMEI    (1 << 0)   /* memory error indication */
-#define ICH6_REG_CORBSIZE              0x4e
-
-#define ICH6_REG_RIRBLBASE             0x50
-#define ICH6_REG_RIRBUBASE             0x54
-#define ICH6_REG_RIRBWP                        0x58
-#define   ICH6_RIRBWP_RST      (1 << 15)  /* write pointer reset */
-#define ICH6_REG_RINTCNT               0x5a
-#define ICH6_REG_RIRBCTL               0x5c
-#define   ICH6_RBCTL_IRQ_EN    (1 << 0)   /* enable IRQ */
-#define   ICH6_RBCTL_DMA_EN    (1 << 1)   /* enable DMA */
-#define   ICH6_RBCTL_OVERRUN_EN        (1 << 2)   /* enable overrun irq */
-#define ICH6_REG_RIRBSTS               0x5d
-#define   ICH6_RBSTS_IRQ       (1 << 0)   /* response irq */
-#define   ICH6_RBSTS_OVERRUN   (1 << 2)   /* overrun irq */
-#define ICH6_REG_RIRBSIZE              0x5e
-
-#define ICH6_REG_IC                    0x60
-#define ICH6_REG_IR                    0x64
-#define ICH6_REG_IRS                   0x68
-#define   ICH6_IRS_VALID       (1<<1)
-#define   ICH6_IRS_BUSY                (1<<0)
-
-#define ICH6_REG_DPLBASE               0x70
-#define ICH6_REG_DPUBASE               0x74
-#define   ICH6_DPLBASE_ENABLE  0x1     /* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define ICH6_REG_SD_CTL                        0x00
-#define ICH6_REG_SD_STS                        0x03
-#define ICH6_REG_SD_LPIB               0x04
-#define ICH6_REG_SD_CBL                        0x08
-#define ICH6_REG_SD_LVI                        0x0c
-#define ICH6_REG_SD_FIFOW              0x0e
-#define ICH6_REG_SD_FIFOSIZE           0x10
-#define ICH6_REG_SD_FORMAT             0x12
-#define ICH6_REG_SD_BDLPL              0x18
-#define ICH6_REG_SD_BDLPU              0x1c
-
-/* PCI space */
-#define ICH6_PCIREG_TCSEL      0x44
-
-/*
- * other constants
- */
-
-/* max number of SDs */
-/* ICH, ATI and VIA have 4 playback and 4 capture */
-#define ICH6_NUM_CAPTURE       4
-#define ICH6_NUM_PLAYBACK      4
-
-/* ULI has 6 playback and 5 capture */
-#define ULI_NUM_CAPTURE                5
-#define ULI_NUM_PLAYBACK       6
-
-/* ATI HDMI may have up to 8 playbacks and 0 capture */
-#define ATIHDMI_NUM_CAPTURE    0
-#define ATIHDMI_NUM_PLAYBACK   8
-
-/* TERA has 4 playback and 3 capture */
-#define TERA_NUM_CAPTURE       3
-#define TERA_NUM_PLAYBACK      4
-
-/* this number is statically defined for simplicity */
-#define MAX_AZX_DEV            16
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE               4096
-#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
-#define AZX_MAX_FRAG           32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE      0x01
-#define RIRB_INT_OVERRUN       0x04
-#define RIRB_INT_MASK          0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS         8
-#define AZX_DEFAULT_CODECS     4
-#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
-#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
-#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
-#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
-#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT        20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
-#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
-#define SD_INT_COMPLETE                0x04    /* completion interrupt */
-#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
-                                SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define ICH6_INT_ALL_STREAM    0xff       /* all stream interrupts */
-#define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
-#define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define ICH6_MAX_CORB_ENTRIES  256
-#define ICH6_MAX_RIRB_ENTRIES  256
-
-/* position fix mode */
-enum {
-       POS_FIX_AUTO,
-       POS_FIX_LPIB,
-       POS_FIX_POSBUF,
-       POS_FIX_VIACOMBO,
-       POS_FIX_COMBO,
-};
-
-/* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
-#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
-
-/* Defines for Nvidia HDA support */
-#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
-#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
-#define NVIDIA_HDA_ISTRM_COH          0x4d
-#define NVIDIA_HDA_OSTRM_COH          0x4c
-#define NVIDIA_HDA_ENABLE_COHBIT      0x01
-
-/* Defines for Intel SCH HDA snoop control */
-#define INTEL_SCH_HDA_DEVC      0x78
-#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
-
-/* Define IN stream 0 FIFO size offset in VIA controller */
-#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET        0x90
-/* Define VIA HD Audio Device ID*/
-#define VIA_HDAC_DEVICE_ID             0x3288
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
-
 /*
  */
 
-struct azx_dev {
-       struct snd_dma_buffer bdl; /* BDL buffer */
-       u32 *posbuf;            /* position buffer pointer */
-
-       unsigned int bufsize;   /* size of the play buffer in bytes */
-       unsigned int period_bytes; /* size of the period in bytes */
-       unsigned int frags;     /* number for period in the play buffer */
-       unsigned int fifo_size; /* FIFO size */
-       unsigned long start_wallclk;    /* start + minimum wallclk */
-       unsigned long period_wallclk;   /* wallclk for period */
-
-       void __iomem *sd_addr;  /* stream descriptor pointer */
-
-       u32 sd_int_sta_mask;    /* stream int status mask */
-
-       /* pcm support */
-       struct snd_pcm_substream *substream;    /* assigned substream,
-                                                * set in PCM open
-                                                */
-       unsigned int format_val;        /* format value to be set in the
-                                        * controller and the codec
-                                        */
-       unsigned char stream_tag;       /* assigned stream */
-       unsigned char index;            /* stream index */
-       int assigned_key;               /* last device# key assigned to */
-
-       unsigned int opened :1;
-       unsigned int running :1;
-       unsigned int irq_pending :1;
-       unsigned int prepared:1;
-       unsigned int locked:1;
-       /*
-        * For VIA:
-        *  A flag to ensure DMA position is 0
-        *  when link position is not greater than FIFO size
-        */
-       unsigned int insufficient :1;
-       unsigned int wc_marked:1;
-       unsigned int no_period_wakeup:1;
-
-       struct timecounter  azx_tc;
-       struct cyclecounter azx_cc;
-
-       int delay_negative_threshold;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-       struct mutex dsp_mutex;
-#endif
-};
-
-/* DSP lock helpers */
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-#define dsp_lock_init(dev)     mutex_init(&(dev)->dsp_mutex)
-#define dsp_lock(dev)          mutex_lock(&(dev)->dsp_mutex)
-#define dsp_unlock(dev)                mutex_unlock(&(dev)->dsp_mutex)
-#define dsp_is_locked(dev)     ((dev)->locked)
-#else
-#define dsp_lock_init(dev)     do {} while (0)
-#define dsp_lock(dev)          do {} while (0)
-#define dsp_unlock(dev)                do {} while (0)
-#define dsp_is_locked(dev)     0
-#endif
-
-/* CORB/RIRB */
-struct azx_rb {
-       u32 *buf;               /* CORB/RIRB buffer
-                                * Each CORB entry is 4byte, RIRB is 8byte
-                                */
-       dma_addr_t addr;        /* physical address of CORB/RIRB buffer */
-       /* for RIRB */
-       unsigned short rp, wp;  /* read/write pointers */
-       int cmds[AZX_MAX_CODECS];       /* number of pending requests */
-       u32 res[AZX_MAX_CODECS];        /* last read value */
-};
-
-struct azx_pcm {
-       struct azx *chip;
-       struct snd_pcm *pcm;
-       struct hda_codec *codec;
-       struct hda_pcm_stream *hinfo[2];
-       struct list_head list;
-};
-
-struct azx {
-       struct snd_card *card;
-       struct pci_dev *pci;
-       int dev_index;
-
-       /* chip type specific */
-       int driver_type;
-       unsigned int driver_caps;
-       int playback_streams;
-       int playback_index_offset;
-       int capture_streams;
-       int capture_index_offset;
-       int num_streams;
-
-       /* pci resources */
-       unsigned long addr;
-       void __iomem *remap_addr;
-       int irq;
-
-       /* locks */
-       spinlock_t reg_lock;
-       struct mutex open_mutex;
-       struct completion probe_wait;
-
-       /* streams (x num_streams) */
-       struct azx_dev *azx_dev;
-
-       /* PCM */
-       struct list_head pcm_list; /* azx_pcm list */
-
-       /* HD codec */
-       unsigned short codec_mask;
-       int  codec_probe_mask; /* copied from probe_mask option */
-       struct hda_bus *bus;
-       unsigned int beep_mode;
-
-       /* CORB/RIRB */
-       struct azx_rb corb;
-       struct azx_rb rirb;
-
-       /* CORB/RIRB and position buffers */
-       struct snd_dma_buffer rb;
-       struct snd_dma_buffer posbuf;
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
-       const struct firmware *fw;
-#endif
-
-       /* flags */
-       int position_fix[2]; /* for both playback/capture streams */
-       int poll_count;
-       unsigned int running :1;
-       unsigned int initialized :1;
-       unsigned int single_cmd :1;
-       unsigned int polling_mode :1;
-       unsigned int msi :1;
-       unsigned int irq_pending_warned :1;
-       unsigned int probing :1; /* codec probing phase */
-       unsigned int snoop:1;
-       unsigned int align_buffer_size:1;
-       unsigned int region_requested:1;
-
-       /* VGA-switcheroo setup */
-       unsigned int use_vga_switcheroo:1;
-       unsigned int vga_switcheroo_registered:1;
-       unsigned int init_failed:1; /* delayed init failed */
-       unsigned int disabled:1; /* disabled by VGA-switcher */
-
-       /* for debugging */
-       unsigned int last_cmd[AZX_MAX_CODECS];
-
-       /* for pending irqs */
-       struct work_struct irq_pending_work;
-
-       struct work_struct probe_work;
-
-       /* reboot notifier (for mysterious hangup problem at power-down) */
-       struct notifier_block reboot_notifier;
-
-       /* card list (for power_save trigger) */
-       struct list_head list;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-       struct azx_dev saved_azx_dev;
-#endif
-
-       /* secondary power domain for hdmi audio under vga device */
-       struct dev_pm_domain hdmi_pm_domain;
-};
-
-#define CREATE_TRACE_POINTS
-#include "hda_intel_trace.h"
-
 /* driver types */
 enum {
        AZX_DRIVER_ICH,
@@ -584,28 +224,6 @@ enum {
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
-/* driver quirks (capabilities) */
-/* bits 0-7 are used for indicating driver type */
-#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
-#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
-#define AZX_DCAPS_ATI_SNOOP    (1 << 10)       /* ATI snoop enable */
-#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11)       /* Nvidia snoop enable */
-#define AZX_DCAPS_SCH_SNOOP    (1 << 12)       /* SCH/PCH snoop enable */
-#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
-#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
-#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
-#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
-#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
-#define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
-#define AZX_DCAPS_BUFSIZE      (1 << 21)       /* no buffer size alignment */
-#define AZX_DCAPS_ALIGN_BUFSIZE        (1 << 22)       /* buffer size alignment */
-#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)   /* BDLE in 4k boundary */
-#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
-#define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
-#define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 power well support */
-
 /* quirks for Intel PCH */
 #define AZX_DCAPS_INTEL_PCH_NOPM \
        (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \
@@ -663,38 +281,6 @@ static char *driver_short_names[] = {
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
-/*
- * macros for easy use
- */
-#define azx_writel(chip,reg,value) \
-       writel(value, (chip)->remap_addr + ICH6_REG_##reg)
-#define azx_readl(chip,reg) \
-       readl((chip)->remap_addr + ICH6_REG_##reg)
-#define azx_writew(chip,reg,value) \
-       writew(value, (chip)->remap_addr + ICH6_REG_##reg)
-#define azx_readw(chip,reg) \
-       readw((chip)->remap_addr + ICH6_REG_##reg)
-#define azx_writeb(chip,reg,value) \
-       writeb(value, (chip)->remap_addr + ICH6_REG_##reg)
-#define azx_readb(chip,reg) \
-       readb((chip)->remap_addr + ICH6_REG_##reg)
-
-#define azx_sd_writel(dev,reg,value) \
-       writel(value, (dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_readl(dev,reg) \
-       readl((dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_writew(dev,reg,value) \
-       writew(value, (dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_readw(dev,reg) \
-       readw((dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_writeb(dev,reg,value) \
-       writeb(value, (dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_readb(dev,reg) \
-       readb((dev)->sd_addr + ICH6_REG_##reg)
-
-/* for pcm support */
-#define get_azx_dev(substream) (substream->runtime->private_data)
-
 #ifdef CONFIG_X86
 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
 {
@@ -749,1750 +335,97 @@ static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
 #endif
 
 static int azx_acquire_irq(struct azx *chip, int do_disconnect);
-static int azx_send_cmd(struct hda_bus *bus, unsigned int val);
-/*
- * Interface for HD codec
- */
-
-/*
- * CORB / RIRB interface
- */
-static int azx_alloc_cmd_io(struct azx *chip)
-{
-       int err;
-
-       /* single page (at least 4096 bytes) must suffice for both ringbuffes */
-       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-                                 snd_dma_pci_data(chip->pci),
-                                 PAGE_SIZE, &chip->rb);
-       if (err < 0) {
-               snd_printk(KERN_ERR SFX "%s: cannot allocate CORB/RIRB\n", pci_name(chip->pci));
-               return err;
-       }
-       mark_pages_wc(chip, &chip->rb, true);
-       return 0;
-}
-
-static void azx_init_cmd_io(struct azx *chip)
-{
-       spin_lock_irq(&chip->reg_lock);
-       /* CORB set up */
-       chip->corb.addr = chip->rb.addr;
-       chip->corb.buf = (u32 *)chip->rb.area;
-       azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
-       azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
-
-       /* set the corb size to 256 entries (ULI requires explicitly) */
-       azx_writeb(chip, CORBSIZE, 0x02);
-       /* set the corb write pointer to 0 */
-       azx_writew(chip, CORBWP, 0);
-       /* reset the corb hw read pointer */
-       azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
-       /* enable corb dma */
-       azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
-
-       /* RIRB set up */
-       chip->rirb.addr = chip->rb.addr + 2048;
-       chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
-       chip->rirb.wp = chip->rirb.rp = 0;
-       memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
-       azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
-       azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
-
-       /* set the rirb size to 256 entries (ULI requires explicitly) */
-       azx_writeb(chip, RIRBSIZE, 0x02);
-       /* reset the rirb hw write pointer */
-       azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
-       /* set N=1, get RIRB response interrupt for new entry */
-       if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
-               azx_writew(chip, RINTCNT, 0xc0);
-       else
-               azx_writew(chip, RINTCNT, 1);
-       /* enable rirb dma and response irq */
-       azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
-       spin_unlock_irq(&chip->reg_lock);
-}
-
-static void azx_free_cmd_io(struct azx *chip)
-{
-       spin_lock_irq(&chip->reg_lock);
-       /* disable ringbuffer DMAs */
-       azx_writeb(chip, RIRBCTL, 0);
-       azx_writeb(chip, CORBCTL, 0);
-       spin_unlock_irq(&chip->reg_lock);
-}
-
-static unsigned int azx_command_addr(u32 cmd)
-{
-       unsigned int addr = cmd >> 28;
-
-       if (addr >= AZX_MAX_CODECS) {
-               snd_BUG();
-               addr = 0;
-       }
-
-       return addr;
-}
-
-static unsigned int azx_response_addr(u32 res)
-{
-       unsigned int addr = res & 0xf;
-
-       if (addr >= AZX_MAX_CODECS) {
-               snd_BUG();
-               addr = 0;
-       }
-
-       return addr;
-}
-
-/* send a command */
-static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
-{
-       struct azx *chip = bus->private_data;
-       unsigned int addr = azx_command_addr(val);
-       unsigned int wp, rp;
-
-       spin_lock_irq(&chip->reg_lock);
-
-       /* add command to corb */
-       wp = azx_readw(chip, CORBWP);
-       if (wp == 0xffff) {
-               /* something wrong, controller likely turned to D3 */
-               spin_unlock_irq(&chip->reg_lock);
-               return -EIO;
-       }
-       wp++;
-       wp %= ICH6_MAX_CORB_ENTRIES;
-
-       rp = azx_readw(chip, CORBRP);
-       if (wp == rp) {
-               /* oops, it's full */
-               spin_unlock_irq(&chip->reg_lock);
-               return -EAGAIN;
-       }
-
-       chip->rirb.cmds[addr]++;
-       chip->corb.buf[wp] = cpu_to_le32(val);
-       azx_writel(chip, CORBWP, wp);
-
-       spin_unlock_irq(&chip->reg_lock);
-
-       return 0;
-}
-
-#define ICH6_RIRB_EX_UNSOL_EV  (1<<4)
-
-/* retrieve RIRB entry - called from interrupt handler */
-static void azx_update_rirb(struct azx *chip)
-{
-       unsigned int rp, wp;
-       unsigned int addr;
-       u32 res, res_ex;
-
-       wp = azx_readw(chip, RIRBWP);
-       if (wp == 0xffff) {
-               /* something wrong, controller likely turned to D3 */
-               return;
-       }
-
-       if (wp == chip->rirb.wp)
-               return;
-       chip->rirb.wp = wp;
-
-       while (chip->rirb.rp != wp) {
-               chip->rirb.rp++;
-               chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
-
-               rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
-               res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
-               res = le32_to_cpu(chip->rirb.buf[rp]);
-               addr = azx_response_addr(res_ex);
-               if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
-                       snd_hda_queue_unsol_event(chip->bus, res, res_ex);
-               else if (chip->rirb.cmds[addr]) {
-                       chip->rirb.res[addr] = res;
-                       smp_wmb();
-                       chip->rirb.cmds[addr]--;
-               } else if (printk_ratelimit()) {
-                       snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, last cmd=%#08x\n",
-                                  pci_name(chip->pci),
-                                  res, res_ex,
-                                  chip->last_cmd[addr]);
-               }
-       }
-}
-
-/* receive a response */
-static unsigned int azx_rirb_get_response(struct hda_bus *bus,
-                                         unsigned int addr)
-{
-       struct azx *chip = bus->private_data;
-       unsigned long timeout;
-       unsigned long loopcounter;
-       int do_poll = 0;
-
- again:
-       timeout = jiffies + msecs_to_jiffies(1000);
-
-       for (loopcounter = 0;; loopcounter++) {
-               if (chip->polling_mode || do_poll) {
-                       spin_lock_irq(&chip->reg_lock);
-                       azx_update_rirb(chip);
-                       spin_unlock_irq(&chip->reg_lock);
-               }
-               if (!chip->rirb.cmds[addr]) {
-                       smp_rmb();
-                       bus->rirb_error = 0;
-
-                       if (!do_poll)
-                               chip->poll_count = 0;
-                       return chip->rirb.res[addr]; /* the last value */
-               }
-               if (time_after(jiffies, timeout))
-                       break;
-               if (bus->needs_damn_long_delay || loopcounter > 3000)
-                       msleep(2); /* temporary workaround */
-               else {
-                       udelay(10);
-                       cond_resched();
-               }
-       }
-
-       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",
-                          pci_name(chip->pci), chip->last_cmd[addr]);
-               do_poll = 1;
-               chip->poll_count++;
-               goto again;
-       }
-
-
-       if (!chip->polling_mode) {
-               snd_printk(KERN_WARNING SFX "%s: azx_get_response timeout, "
-                          "switching to polling mode: last cmd=0x%08x\n",
-                          pci_name(chip->pci), chip->last_cmd[addr]);
-               chip->polling_mode = 1;
-               goto again;
-       }
-
-       if (chip->msi) {
-               snd_printk(KERN_WARNING SFX "%s: No response from codec, "
-                          "disabling MSI: last cmd=0x%08x\n",
-                          pci_name(chip->pci), chip->last_cmd[addr]);
-               free_irq(chip->irq, chip);
-               chip->irq = -1;
-               pci_disable_msi(chip->pci);
-               chip->msi = 0;
-               if (azx_acquire_irq(chip, 1) < 0) {
-                       bus->rirb_error = 1;
-                       return -1;
-               }
-               goto again;
-       }
-
-       if (chip->probing) {
-               /* If this critical timeout happens during the codec probing
-                * phase, this is likely an access to a non-existing codec
-                * slot.  Better to return an error and reset the system.
-                */
-               return -1;
-       }
-
-       /* a fatal communication error; need either to reset or to fallback
-        * to the single_cmd mode
-        */
-       bus->rirb_error = 1;
-       if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
-               bus->response_reset = 1;
-               return -1; /* give a chance to retry */
-       }
-
-       snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
-                  "switching to single_cmd mode: last cmd=0x%08x\n",
-                  chip->last_cmd[addr]);
-       chip->single_cmd = 1;
-       bus->response_reset = 0;
-       /* release CORB/RIRB */
-       azx_free_cmd_io(chip);
-       /* disable unsolicited responses */
-       azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL);
-       return -1;
-}
-
-/*
- * Use the single immediate command instead of CORB/RIRB for simplicity
- *
- * Note: according to Intel, this is not preferred use.  The command was
- *       intended for the BIOS only, and may get confused with unsolicited
- *       responses.  So, we shouldn't use it for normal operation from the
- *       driver.
- *       I left the codes, however, for debugging/testing purposes.
- */
-
-/* receive a response */
-static int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
-{
-       int timeout = 50;
-
-       while (timeout--) {
-               /* check IRV busy bit */
-               if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
-                       /* reuse rirb.res as the response return value */
-                       chip->rirb.res[addr] = azx_readl(chip, IR);
-                       return 0;
-               }
-               udelay(1);
-       }
-       if (printk_ratelimit())
-               snd_printd(SFX "%s: get_response timeout: IRS=0x%x\n",
-                          pci_name(chip->pci), azx_readw(chip, IRS));
-       chip->rirb.res[addr] = -1;
-       return -EIO;
-}
-
-/* send a command */
-static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
-{
-       struct azx *chip = bus->private_data;
-       unsigned int addr = azx_command_addr(val);
-       int timeout = 50;
-
-       bus->rirb_error = 0;
-       while (timeout--) {
-               /* check ICB busy bit */
-               if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
-                       /* Clear IRV valid bit */
-                       azx_writew(chip, IRS, azx_readw(chip, IRS) |
-                                  ICH6_IRS_VALID);
-                       azx_writel(chip, IC, val);
-                       azx_writew(chip, IRS, azx_readw(chip, IRS) |
-                                  ICH6_IRS_BUSY);
-                       return azx_single_wait_for_response(chip, addr);
-               }
-               udelay(1);
-       }
-       if (printk_ratelimit())
-               snd_printd(SFX "%s: send_cmd timeout: IRS=0x%x, val=0x%x\n",
-                          pci_name(chip->pci), azx_readw(chip, IRS), val);
-       return -EIO;
-}
-
-/* receive a response */
-static unsigned int azx_single_get_response(struct hda_bus *bus,
-                                           unsigned int addr)
-{
-       struct azx *chip = bus->private_data;
-       return chip->rirb.res[addr];
-}
 
 /*
- * The below are the main callbacks from hda_codec.
- *
- * They are just the skeleton to call sub-callbacks according to the
- * current setting of chip->single_cmd.
+ * initialize the PCI registers
  */
-
-/* send a command */
-static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
-{
-       struct azx *chip = bus->private_data;
-
-       if (chip->disabled)
-               return 0;
-       chip->last_cmd[azx_command_addr(val)] = val;
-       if (chip->single_cmd)
-               return azx_single_send_cmd(bus, val);
-       else
-               return azx_corb_send_cmd(bus, val);
-}
-
-/* get a response */
-static unsigned int azx_get_response(struct hda_bus *bus,
-                                    unsigned int addr)
-{
-       struct azx *chip = bus->private_data;
-       if (chip->disabled)
-               return 0;
-       if (chip->single_cmd)
-               return azx_single_get_response(bus, addr);
-       else
-               return azx_rirb_get_response(bus, addr);
-}
-
-#ifdef CONFIG_PM
-static void azx_power_notify(struct hda_bus *bus, bool power_up);
-#endif
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
-                               unsigned int byte_size,
-                               struct snd_dma_buffer *bufp);
-static void azx_load_dsp_trigger(struct hda_bus *bus, bool start);
-static void azx_load_dsp_cleanup(struct hda_bus *bus,
-                                struct snd_dma_buffer *dmab);
-#endif
-
-/* enter link reset */
-static void azx_enter_link_reset(struct azx *chip)
-{
-       unsigned long timeout;
-
-       /* reset controller */
-       azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
-
-       timeout = jiffies + msecs_to_jiffies(100);
-       while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
-                       time_before(jiffies, timeout))
-               usleep_range(500, 1000);
-}
-
-/* exit link reset */
-static void azx_exit_link_reset(struct azx *chip)
-{
-       unsigned long timeout;
-
-       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_writew(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);
-
-      __skip:
-       /* check to see if controller is ready */
-       if (!azx_readb(chip, GCTL)) {
-               snd_printd(SFX "%s: azx_reset: controller not ready!\n", pci_name(chip->pci));
-               return -EBUSY;
-       }
-
-       /* Accept unsolicited responses */
-       if (!chip->single_cmd)
-               azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
-                          ICH6_GCTL_UNSOL);
-
-       /* detect codecs */
-       if (!chip->codec_mask) {
-               chip->codec_mask = azx_readw(chip, STATESTS);
-               snd_printdd(SFX "%s: codec_mask = 0x%x\n", pci_name(chip->pci), chip->codec_mask);
-       }
-
-       return 0;
-}
-
-
-/*
- * Lowlevel interface
- */  
-
-/* enable interrupts */
-static void azx_int_enable(struct azx *chip)
-{
-       /* enable controller CIE and GIE */
-       azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
-                  ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
-}
-
-/* disable interrupts */
-static void azx_int_disable(struct azx *chip)
-{
-       int i;
-
-       /* disable interrupts in stream descriptor */
-       for (i = 0; i < chip->num_streams; i++) {
-               struct azx_dev *azx_dev = &chip->azx_dev[i];
-               azx_sd_writeb(azx_dev, SD_CTL,
-                             azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
-       }
-
-       /* disable SIE for all streams */
-       azx_writeb(chip, INTCTL, 0);
-
-       /* disable controller CIE and GIE */
-       azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
-                  ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
-}
-
-/* clear interrupts */
-static void azx_int_clear(struct azx *chip)
-{
-       int i;
-
-       /* clear stream status */
-       for (i = 0; i < chip->num_streams; i++) {
-               struct azx_dev *azx_dev = &chip->azx_dev[i];
-               azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
-       }
-
-       /* clear STATESTS */
-       azx_writew(chip, STATESTS, STATESTS_INT_MASK);
-
-       /* clear rirb status */
-       azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
-
-       /* clear int status */
-       azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
-}
-
-/* start a stream */
-static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
-{
-       /*
-        * Before stream start, initialize parameter
-        */
-       azx_dev->insufficient = 1;
-
-       /* enable SIE */
-       azx_writel(chip, INTCTL,
-                  azx_readl(chip, INTCTL) | (1 << azx_dev->index));
-       /* set DMA start and interrupt mask */
-       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
-                     SD_CTL_DMA_START | SD_INT_MASK);
-}
-
-/* stop DMA */
-static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
+/* update bits in a PCI register byte */
+static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
+                           unsigned char mask, unsigned char val)
 {
-       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
-                     ~(SD_CTL_DMA_START | SD_INT_MASK));
-       azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
-}
+       unsigned char data;
 
-/* stop a stream */
-static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
-{
-       azx_stream_clear(chip, azx_dev);
-       /* disable SIE */
-       azx_writel(chip, INTCTL,
-                  azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
+       pci_read_config_byte(pci, reg, &data);
+       data &= ~mask;
+       data |= (val & mask);
+       pci_write_config_byte(pci, reg, data);
 }
 
+static void azx_init_pci(struct azx *chip)
+{
+       /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
+        * TCSEL == Traffic Class Select Register, which sets PCI express QOS
+        * Ensuring these bits are 0 clears playback static on some HD Audio
+        * codecs.
+        * The PCI register TCSEL is defined in the Intel manuals.
+        */
+       if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
+               dev_dbg(chip->card->dev, "Clearing TCSEL\n");
+               update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+       }
 
-/*
- * reset and start the controller registers
- */
-static void azx_init_chip(struct azx *chip, int full_reset)
-{
-       if (chip->initialized)
-               return;
-
-       /* reset controller */
-       azx_reset(chip, full_reset);
-
-       /* initialize interrupts */
-       azx_int_clear(chip);
-       azx_int_enable(chip);
-
-       /* initialize the codec command I/O */
-       if (!chip->single_cmd)
-               azx_init_cmd_io(chip);
-
-       /* program the position buffer */
-       azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
-       azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
-
-       chip->initialized = 1;
-}
-
-/*
- * initialize the PCI registers
- */
-/* update bits in a PCI register byte */
-static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
-                           unsigned char mask, unsigned char val)
-{
-       unsigned char data;
-
-       pci_read_config_byte(pci, reg, &data);
-       data &= ~mask;
-       data |= (val & mask);
-       pci_write_config_byte(pci, reg, data);
-}
-
-static void azx_init_pci(struct azx *chip)
-{
-       /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
-        * TCSEL == Traffic Class Select Register, which sets PCI express QOS
-        * Ensuring these bits are 0 clears playback static on some HD Audio
-        * codecs.
-        * The PCI register TCSEL is defined in the Intel manuals.
-        */
-       if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
-               snd_printdd(SFX "%s: Clearing TCSEL\n", pci_name(chip->pci));
-               update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
-       }
-
-       /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
-        * we need to enable snoop.
-        */
-       if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
-               snd_printdd(SFX "%s: Setting ATI snoop: %d\n", pci_name(chip->pci), azx_snoop(chip));
-               update_pci_byte(chip->pci,
-                               ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07,
-                               azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0);
-       }
-
-       /* For NVIDIA HDA, enable snoop */
-       if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
-               snd_printdd(SFX "%s: Setting Nvidia snoop: %d\n", pci_name(chip->pci), azx_snoop(chip));
-               update_pci_byte(chip->pci,
-                               NVIDIA_HDA_TRANSREG_ADDR,
-                               0x0f, NVIDIA_HDA_ENABLE_COHBITS);
-               update_pci_byte(chip->pci,
-                               NVIDIA_HDA_ISTRM_COH,
-                               0x01, NVIDIA_HDA_ENABLE_COHBIT);
-               update_pci_byte(chip->pci,
-                               NVIDIA_HDA_OSTRM_COH,
-                               0x01, NVIDIA_HDA_ENABLE_COHBIT);
-       }
-
-       /* Enable SCH/PCH snoop if needed */
-       if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
-               unsigned short snoop;
-               pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
-               if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
-                   (azx_snoop(chip) && (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP))) {
-                       snoop &= ~INTEL_SCH_HDA_DEVC_NOSNOOP;
-                       if (!azx_snoop(chip))
-                               snoop |= INTEL_SCH_HDA_DEVC_NOSNOOP;
-                       pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop);
-                       pci_read_config_word(chip->pci,
-                               INTEL_SCH_HDA_DEVC, &snoop);
-               }
-               snd_printdd(SFX "%s: SCH snoop: %s\n",
-                               pci_name(chip->pci), (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
-                               ? "Disabled" : "Enabled");
-        }
-}
-
-
-static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
-
-/*
- * interrupt handler
- */
-static irqreturn_t azx_interrupt(int irq, void *dev_id)
-{
-       struct azx *chip = dev_id;
-       struct azx_dev *azx_dev;
-       u32 status;
-       u8 sd_status;
-       int i, ok;
-
-#ifdef CONFIG_PM_RUNTIME
-       if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
-               if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
-                       return IRQ_NONE;
-#endif
-
-       spin_lock(&chip->reg_lock);
-
-       if (chip->disabled) {
-               spin_unlock(&chip->reg_lock);
-               return IRQ_NONE;
-       }
-
-       status = azx_readl(chip, INTSTS);
-       if (status == 0 || status == 0xffffffff) {
-               spin_unlock(&chip->reg_lock);
-               return IRQ_NONE;
-       }
-       
-       for (i = 0; i < chip->num_streams; i++) {
-               azx_dev = &chip->azx_dev[i];
-               if (status & azx_dev->sd_int_sta_mask) {
-                       sd_status = azx_sd_readb(azx_dev, SD_STS);
-                       azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
-                       if (!azx_dev->substream || !azx_dev->running ||
-                           !(sd_status & SD_INT_COMPLETE))
-                               continue;
-                       /* check whether this IRQ is really acceptable */
-                       ok = azx_position_ok(chip, azx_dev);
-                       if (ok == 1) {
-                               azx_dev->irq_pending = 0;
-                               spin_unlock(&chip->reg_lock);
-                               snd_pcm_period_elapsed(azx_dev->substream);
-                               spin_lock(&chip->reg_lock);
-                       } else if (ok == 0 && chip->bus && chip->bus->workq) {
-                               /* bogus IRQ, process it later */
-                               azx_dev->irq_pending = 1;
-                               queue_work(chip->bus->workq,
-                                          &chip->irq_pending_work);
-                       }
-               }
-       }
-
-       /* clear rirb int */
-       status = azx_readb(chip, RIRBSTS);
-       if (status & RIRB_INT_MASK) {
-               if (status & RIRB_INT_RESPONSE) {
-                       if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
-                               udelay(80);
-                       azx_update_rirb(chip);
-               }
-               azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
-       }
-
-#if 0
-       /* clear state status int */
-       if (azx_readw(chip, STATESTS) & 0x04)
-               azx_writew(chip, STATESTS, 0x04);
-#endif
-       spin_unlock(&chip->reg_lock);
-       
-       return IRQ_HANDLED;
-}
-
-
-/*
- * set up a BDL entry
- */
-static int setup_bdle(struct azx *chip,
-                     struct snd_dma_buffer *dmab,
-                     struct azx_dev *azx_dev, u32 **bdlp,
-                     int ofs, int size, int with_ioc)
-{
-       u32 *bdl = *bdlp;
-
-       while (size > 0) {
-               dma_addr_t addr;
-               int chunk;
-
-               if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
-                       return -EINVAL;
-
-               addr = snd_sgbuf_get_addr(dmab, ofs);
-               /* program the address field of the BDL entry */
-               bdl[0] = cpu_to_le32((u32)addr);
-               bdl[1] = cpu_to_le32(upper_32_bits(addr));
-               /* program the size field of the BDL entry */
-               chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
-               /* one BDLE cannot cross 4K boundary on CTHDA chips */
-               if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
-                       u32 remain = 0x1000 - (ofs & 0xfff);
-                       if (chunk > remain)
-                               chunk = remain;
-               }
-               bdl[2] = cpu_to_le32(chunk);
-               /* program the IOC to enable interrupt
-                * only when the whole fragment is processed
-                */
-               size -= chunk;
-               bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
-               bdl += 4;
-               azx_dev->frags++;
-               ofs += chunk;
-       }
-       *bdlp = bdl;
-       return ofs;
-}
-
-/*
- * set up BDL entries
- */
-static int azx_setup_periods(struct azx *chip,
-                            struct snd_pcm_substream *substream,
-                            struct azx_dev *azx_dev)
-{
-       u32 *bdl;
-       int i, ofs, periods, period_bytes;
-       int pos_adj;
-
-       /* reset BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPL, 0);
-       azx_sd_writel(azx_dev, SD_BDLPU, 0);
-
-       period_bytes = azx_dev->period_bytes;
-       periods = azx_dev->bufsize / period_bytes;
-
-       /* program the initial BDL entries */
-       bdl = (u32 *)azx_dev->bdl.area;
-       ofs = 0;
-       azx_dev->frags = 0;
-       pos_adj = bdl_pos_adj[chip->dev_index];
-       if (!azx_dev->no_period_wakeup && pos_adj > 0) {
-               struct snd_pcm_runtime *runtime = substream->runtime;
-               int pos_align = pos_adj;
-               pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
-               if (!pos_adj)
-                       pos_adj = pos_align;
-               else
-                       pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
-                               pos_align;
-               pos_adj = frames_to_bytes(runtime, pos_adj);
-               if (pos_adj >= period_bytes) {
-                       snd_printk(KERN_WARNING SFX "%s: Too big adjustment %d\n",
-                                  pci_name(chip->pci), bdl_pos_adj[chip->dev_index]);
-                       pos_adj = 0;
-               } else {
-                       ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
-                                        azx_dev,
-                                        &bdl, ofs, pos_adj, true);
-                       if (ofs < 0)
-                               goto error;
-               }
-       } else
-               pos_adj = 0;
-       for (i = 0; i < periods; i++) {
-               if (i == periods - 1 && pos_adj)
-                       ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
-                                        azx_dev, &bdl, ofs,
-                                        period_bytes - pos_adj, 0);
-               else
-                       ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
-                                        azx_dev, &bdl, ofs,
-                                        period_bytes,
-                                        !azx_dev->no_period_wakeup);
-               if (ofs < 0)
-                       goto error;
-       }
-       return 0;
-
- error:
-       snd_printk(KERN_ERR SFX "%s: Too many BDL entries: buffer=%d, period=%d\n",
-                  pci_name(chip->pci), azx_dev->bufsize, period_bytes);
-       return -EINVAL;
-}
-
-/* reset stream */
-static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
-{
-       unsigned char val;
-       int timeout;
-
-       azx_stream_clear(chip, azx_dev);
-
-       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
-                     SD_CTL_STREAM_RESET);
-       udelay(3);
-       timeout = 300;
-       while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
-              --timeout)
-               ;
-       val &= ~SD_CTL_STREAM_RESET;
-       azx_sd_writeb(azx_dev, SD_CTL, val);
-       udelay(3);
-
-       timeout = 300;
-       /* waiting for hardware to report that the stream is out of reset */
-       while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
-              --timeout)
-               ;
-
-       /* reset first position - may not be synced with hw at this time */
-       *azx_dev->posbuf = 0;
-}
-
-/*
- * set up the SD for streaming
- */
-static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
-{
-       unsigned int val;
-       /* make sure the run bit is zero for SD */
-       azx_stream_clear(chip, azx_dev);
-       /* program the stream_tag */
-       val = azx_sd_readl(azx_dev, SD_CTL);
-       val = (val & ~SD_CTL_STREAM_TAG_MASK) |
-               (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
-       if (!azx_snoop(chip))
-               val |= SD_CTL_TRAFFIC_PRIO;
-       azx_sd_writel(azx_dev, SD_CTL, val);
-
-       /* program the length of samples in cyclic buffer */
-       azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize);
-
-       /* program the stream format */
-       /* this value needs to be the same as the one programmed */
-       azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val);
-
-       /* program the stream LVI (last valid index) of the BDL */
-       azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1);
-
-       /* program the BDL address */
-       /* lower BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
-       /* upper BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
-
-       /* enable the position buffer */
-       if (chip->position_fix[0] != POS_FIX_LPIB ||
-           chip->position_fix[1] != POS_FIX_LPIB) {
-               if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
-                       azx_writel(chip, DPLBASE,
-                               (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
-       }
-
-       /* set the interrupt enable bits in the descriptor control register */
-       azx_sd_writel(azx_dev, SD_CTL,
-                     azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
-
-       return 0;
-}
-
-/*
- * Probe the given codec address
- */
-static int probe_codec(struct azx *chip, int addr)
-{
-       unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
-               (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
-       unsigned int res;
-
-       mutex_lock(&chip->bus->cmd_mutex);
-       chip->probing = 1;
-       azx_send_cmd(chip->bus, cmd);
-       res = azx_get_response(chip->bus, addr);
-       chip->probing = 0;
-       mutex_unlock(&chip->bus->cmd_mutex);
-       if (res == -1)
-               return -EIO;
-       snd_printdd(SFX "%s: codec #%d probed OK\n", pci_name(chip->pci), addr);
-       return 0;
-}
-
-static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
-                                struct hda_pcm *cpcm);
-static void azx_stop_chip(struct azx *chip);
-
-static void azx_bus_reset(struct hda_bus *bus)
-{
-       struct azx *chip = bus->private_data;
-
-       bus->in_reset = 1;
-       azx_stop_chip(chip);
-       azx_init_chip(chip, 1);
-#ifdef CONFIG_PM
-       if (chip->initialized) {
-               struct azx_pcm *p;
-               list_for_each_entry(p, &chip->pcm_list, list)
-                       snd_pcm_suspend_all(p->pcm);
-               snd_hda_suspend(chip->bus);
-               snd_hda_resume(chip->bus);
-       }
-#endif
-       bus->in_reset = 0;
-}
-
-static int get_jackpoll_interval(struct azx *chip)
-{
-       int i = jackpoll_ms[chip->dev_index];
-       unsigned int j;
-       if (i == 0)
-               return 0;
-       if (i < 50 || i > 60000)
-               j = 0;
-       else
-               j = msecs_to_jiffies(i);
-       if (j == 0)
-               snd_printk(KERN_WARNING SFX
-                          "jackpoll_ms value out of range: %d\n", i);
-       return j;
-}
-
-/*
- * Codec initialization
- */
-
-/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
-static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
-       [AZX_DRIVER_NVIDIA] = 8,
-       [AZX_DRIVER_TERA] = 1,
-};
-
-static int azx_codec_create(struct azx *chip, const char *model)
-{
-       struct hda_bus_template bus_temp;
-       int c, codecs, err;
-       int max_slots;
-
-       memset(&bus_temp, 0, sizeof(bus_temp));
-       bus_temp.private_data = chip;
-       bus_temp.modelname = model;
-       bus_temp.pci = chip->pci;
-       bus_temp.ops.command = azx_send_cmd;
-       bus_temp.ops.get_response = azx_get_response;
-       bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
-       bus_temp.ops.bus_reset = azx_bus_reset;
-#ifdef CONFIG_PM
-       bus_temp.power_save = &power_save;
-       bus_temp.ops.pm_notify = azx_power_notify;
-#endif
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-       bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
-       bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
-       bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
-#endif
-
-       err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
-       if (err < 0)
-               return err;
-
-       if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
-               snd_printd(SFX "%s: Enable delay in RIRB handling\n", pci_name(chip->pci));
-               chip->bus->needs_damn_long_delay = 1;
-       }
-
-       codecs = 0;
-       max_slots = azx_max_codecs[chip->driver_type];
-       if (!max_slots)
-               max_slots = AZX_DEFAULT_CODECS;
-
-       /* First try to probe all given codec slots */
-       for (c = 0; c < max_slots; c++) {
-               if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
-                       if (probe_codec(chip, c) < 0) {
-                               /* Some BIOSen give you wrong codec addresses
-                                * that don't exist
-                                */
-                               snd_printk(KERN_WARNING SFX
-                                          "%s: Codec #%d probe error; "
-                                          "disabling it...\n", pci_name(chip->pci), c);
-                               chip->codec_mask &= ~(1 << c);
-                               /* More badly, accessing to a non-existing
-                                * codec often screws up the controller chip,
-                                * and disturbs the further communications.
-                                * Thus if an error occurs during probing,
-                                * better to reset the controller chip to
-                                * get back to the sanity state.
-                                */
-                               azx_stop_chip(chip);
-                               azx_init_chip(chip, 1);
-                       }
-               }
-       }
-
-       /* AMD chipsets often cause the communication stalls upon certain
-        * sequence like the pin-detection.  It seems that forcing the synced
-        * access works around the stall.  Grrr...
-        */
-       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
-               snd_printd(SFX "%s: Enable sync_write for stable communication\n",
-                       pci_name(chip->pci));
-               chip->bus->sync_write = 1;
-               chip->bus->allow_bus_reset = 1;
-       }
-
-       /* Then create codec instances */
-       for (c = 0; c < max_slots; c++) {
-               if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
-                       struct hda_codec *codec;
-                       err = snd_hda_codec_new(chip->bus, c, &codec);
-                       if (err < 0)
-                               continue;
-                       codec->jackpoll_interval = get_jackpoll_interval(chip);
-                       codec->beep_mode = chip->beep_mode;
-                       codecs++;
-               }
-       }
-       if (!codecs) {
-               snd_printk(KERN_ERR SFX "%s: no codecs initialized\n", pci_name(chip->pci));
-               return -ENXIO;
-       }
-       return 0;
-}
-
-/* configure each codec instance */
-static int azx_codec_configure(struct azx *chip)
-{
-       struct hda_codec *codec;
-       list_for_each_entry(codec, &chip->bus->codec_list, list) {
-               snd_hda_codec_configure(codec);
-       }
-       return 0;
-}
-
-
-/*
- * PCM support
- */
-
-/* assign a stream for the PCM */
-static inline struct azx_dev *
-azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
-{
-       int dev, i, nums;
-       struct azx_dev *res = NULL;
-       /* make a non-zero unique key for the substream */
-       int key = (substream->pcm->device << 16) | (substream->number << 2) |
-               (substream->stream + 1);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dev = chip->playback_index_offset;
-               nums = chip->playback_streams;
-       } else {
-               dev = chip->capture_index_offset;
-               nums = chip->capture_streams;
-       }
-       for (i = 0; i < nums; i++, dev++) {
-               struct azx_dev *azx_dev = &chip->azx_dev[dev];
-               dsp_lock(azx_dev);
-               if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
-                       res = azx_dev;
-                       if (res->assigned_key == key) {
-                               res->opened = 1;
-                               res->assigned_key = key;
-                               dsp_unlock(azx_dev);
-                               return azx_dev;
-                       }
-               }
-               dsp_unlock(azx_dev);
-       }
-       if (res) {
-               dsp_lock(res);
-               res->opened = 1;
-               res->assigned_key = key;
-               dsp_unlock(res);
-       }
-       return res;
-}
-
-/* release the assigned stream */
-static inline void azx_release_device(struct azx_dev *azx_dev)
-{
-       azx_dev->opened = 0;
-}
-
-static cycle_t azx_cc_read(const struct cyclecounter *cc)
-{
-       struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc);
-       struct snd_pcm_substream *substream = azx_dev->substream;
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-
-       return azx_readl(chip, WALLCLK);
-}
-
-static void azx_timecounter_init(struct snd_pcm_substream *substream,
-                               bool force, cycle_t last)
-{
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       struct timecounter *tc = &azx_dev->azx_tc;
-       struct cyclecounter *cc = &azx_dev->azx_cc;
-       u64 nsec;
-
-       cc->read = azx_cc_read;
-       cc->mask = CLOCKSOURCE_MASK(32);
-
-       /*
-        * Converting from 24 MHz to ns means applying a 125/3 factor.
-        * To avoid any saturation issues in intermediate operations,
-        * the 125 factor is applied first. The division is applied
-        * last after reading the timecounter value.
-        * Applying the 1/3 factor as part of the multiplication
-        * requires at least 20 bits for a decent precision, however
-        * overflows occur after about 4 hours or less, not a option.
-        */
-
-       cc->mult = 125; /* saturation after 195 years */
-       cc->shift = 0;
-
-       nsec = 0; /* audio time is elapsed time since trigger */
-       timecounter_init(tc, cc, nsec);
-       if (force)
-               /*
-                * force timecounter to use predefined value,
-                * used for synchronized starts
-                */
-               tc->cycle_last = last;
-}
-
-static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
-                               u64 nsec)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
-       u64 codec_frames, codec_nsecs;
-
-       if (!hinfo->ops.get_delay)
-               return nsec;
-
-       codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
-       codec_nsecs = div_u64(codec_frames * 1000000000LL,
-                             substream->runtime->rate);
-
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               return nsec + codec_nsecs;
-
-       return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
-}
-
-static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
-                               struct timespec *ts)
-{
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       u64 nsec;
-
-       nsec = timecounter_read(&azx_dev->azx_tc);
-       nsec = div_u64(nsec, 3); /* can be optimized */
-       nsec = azx_adjust_codec_delay(substream, nsec);
-
-       *ts = ns_to_timespec(nsec);
-
-       return 0;
-}
-
-static struct snd_pcm_hardware azx_pcm_hw = {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
-                                SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                SNDRV_PCM_INFO_MMAP_VALID |
-                                /* No full-resume yet implemented */
-                                /* SNDRV_PCM_INFO_RESUME |*/
-                                SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_HAS_WALL_CLOCK |
-                                SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
-       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
-       .rates =                SNDRV_PCM_RATE_48000,
-       .rate_min =             48000,
-       .rate_max =             48000,
-       .channels_min =         2,
-       .channels_max =         2,
-       .buffer_bytes_max =     AZX_MAX_BUF_SIZE,
-       .period_bytes_min =     128,
-       .period_bytes_max =     AZX_MAX_BUF_SIZE / 2,
-       .periods_min =          2,
-       .periods_max =          AZX_MAX_FRAG,
-       .fifo_size =            0,
-};
-
-static int azx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       int err;
-       int buff_step;
-
-       mutex_lock(&chip->open_mutex);
-       azx_dev = azx_assign_device(chip, substream);
-       if (azx_dev == NULL) {
-               mutex_unlock(&chip->open_mutex);
-               return -EBUSY;
-       }
-       runtime->hw = azx_pcm_hw;
-       runtime->hw.channels_min = hinfo->channels_min;
-       runtime->hw.channels_max = hinfo->channels_max;
-       runtime->hw.formats = hinfo->formats;
-       runtime->hw.rates = hinfo->rates;
-       snd_pcm_limit_hw_rates(runtime);
-       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-
-       /* avoid wrap-around with wall-clock */
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
-                               20,
-                               178000000);
-
-       if (chip->align_buffer_size)
-               /* constrain buffer sizes to be multiple of 128
-                  bytes. This is more efficient in terms of memory
-                  access but isn't required by the HDA spec and
-                  prevents users from specifying exact period/buffer
-                  sizes. For example for 44.1kHz, a period size set
-                  to 20ms will be rounded to 19.59ms. */
-               buff_step = 128;
-       else
-               /* Don't enforce steps on buffer sizes, still need to
-                  be multiple of 4 bytes (HDA spec). Tested on Intel
-                  HDA controllers, may not work on all devices where
-                  option needs to be disabled */
-               buff_step = 4;
-
-       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-                                  buff_step);
-       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-                                  buff_step);
-       snd_hda_power_up_d3wait(apcm->codec);
-       err = hinfo->ops.open(hinfo, apcm->codec, substream);
-       if (err < 0) {
-               azx_release_device(azx_dev);
-               snd_hda_power_down(apcm->codec);
-               mutex_unlock(&chip->open_mutex);
-               return err;
-       }
-       snd_pcm_limit_hw_rates(runtime);
-       /* sanity check */
-       if (snd_BUG_ON(!runtime->hw.channels_min) ||
-           snd_BUG_ON(!runtime->hw.channels_max) ||
-           snd_BUG_ON(!runtime->hw.formats) ||
-           snd_BUG_ON(!runtime->hw.rates)) {
-               azx_release_device(azx_dev);
-               hinfo->ops.close(hinfo, apcm->codec, substream);
-               snd_hda_power_down(apcm->codec);
-               mutex_unlock(&chip->open_mutex);
-               return -EINVAL;
-       }
-
-       /* disable WALLCLOCK timestamps for capture streams
-          until we figure out how to handle digital inputs */
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK;
-
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       azx_dev->substream = substream;
-       azx_dev->running = 0;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-
-       runtime->private_data = azx_dev;
-       snd_pcm_set_sync(substream);
-       mutex_unlock(&chip->open_mutex);
-       return 0;
-}
-
-static int azx_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       unsigned long flags;
-
-       mutex_lock(&chip->open_mutex);
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       azx_dev->substream = NULL;
-       azx_dev->running = 0;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       azx_release_device(azx_dev);
-       hinfo->ops.close(hinfo, apcm->codec, substream);
-       snd_hda_power_down(apcm->codec);
-       mutex_unlock(&chip->open_mutex);
-       return 0;
-}
-
-static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *hw_params)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       int ret;
-
-       dsp_lock(azx_dev);
-       if (dsp_is_locked(azx_dev)) {
-               ret = -EBUSY;
-               goto unlock;
-       }
-
-       mark_runtime_wc(chip, azx_dev, substream, false);
-       azx_dev->bufsize = 0;
-       azx_dev->period_bytes = 0;
-       azx_dev->format_val = 0;
-       ret = snd_pcm_lib_malloc_pages(substream,
-                                       params_buffer_bytes(hw_params));
-       if (ret < 0)
-               goto unlock;
-       mark_runtime_wc(chip, azx_dev, substream, true);
- unlock:
-       dsp_unlock(azx_dev);
-       return ret;
-}
-
-static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       struct azx *chip = apcm->chip;
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
-
-       /* reset BDL address */
-       dsp_lock(azx_dev);
-       if (!dsp_is_locked(azx_dev)) {
-               azx_sd_writel(azx_dev, SD_BDLPL, 0);
-               azx_sd_writel(azx_dev, SD_BDLPU, 0);
-               azx_sd_writel(azx_dev, SD_CTL, 0);
-               azx_dev->bufsize = 0;
-               azx_dev->period_bytes = 0;
-               azx_dev->format_val = 0;
-       }
-
-       snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
-
-       mark_runtime_wc(chip, azx_dev, substream, false);
-       azx_dev->prepared = 0;
-       dsp_unlock(azx_dev);
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int azx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int bufsize, period_bytes, format_val, stream_tag;
-       int err;
-       struct hda_spdif_out *spdif =
-               snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
-       unsigned short ctls = spdif ? spdif->ctls : 0;
-
-       dsp_lock(azx_dev);
-       if (dsp_is_locked(azx_dev)) {
-               err = -EBUSY;
-               goto unlock;
-       }
-
-       azx_stream_reset(chip, azx_dev);
-       format_val = snd_hda_calc_stream_format(runtime->rate,
-                                               runtime->channels,
-                                               runtime->format,
-                                               hinfo->maxbps,
-                                               ctls);
-       if (!format_val) {
-               snd_printk(KERN_ERR SFX
-                          "%s: invalid format_val, rate=%d, ch=%d, format=%d\n",
-                          pci_name(chip->pci), runtime->rate, runtime->channels, runtime->format);
-               err = -EINVAL;
-               goto unlock;
-       }
-
-       bufsize = snd_pcm_lib_buffer_bytes(substream);
-       period_bytes = snd_pcm_lib_period_bytes(substream);
-
-       snd_printdd(SFX "%s: azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
-                   pci_name(chip->pci), bufsize, format_val);
-
-       if (bufsize != azx_dev->bufsize ||
-           period_bytes != azx_dev->period_bytes ||
-           format_val != azx_dev->format_val ||
-           runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
-               azx_dev->bufsize = bufsize;
-               azx_dev->period_bytes = period_bytes;
-               azx_dev->format_val = format_val;
-               azx_dev->no_period_wakeup = runtime->no_period_wakeup;
-               err = azx_setup_periods(chip, substream, azx_dev);
-               if (err < 0)
-                       goto unlock;
-       }
-
-       /* when LPIB delay correction gives a small negative value,
-        * we ignore it; currently set the threshold statically to
-        * 64 frames
-        */
-       if (runtime->period_size > 64)
-               azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
-       else
-               azx_dev->delay_negative_threshold = 0;
-
-       /* wallclk has 24Mhz clock source */
-       azx_dev->period_wallclk = (((runtime->period_size * 24000) /
-                                               runtime->rate) * 1000);
-       azx_setup_controller(chip, azx_dev);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
-       else
-               azx_dev->fifo_size = 0;
-
-       stream_tag = azx_dev->stream_tag;
-       /* CA-IBG chips need the playback stream starting from 1 */
-       if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
-           stream_tag > chip->capture_streams)
-               stream_tag -= chip->capture_streams;
-       err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
-                                    azx_dev->format_val, substream);
-
- unlock:
-       if (!err)
-               azx_dev->prepared = 1;
-       dsp_unlock(azx_dev);
-       return err;
-}
-
-static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev;
-       struct snd_pcm_substream *s;
-       int rstart = 0, start, nsync = 0, sbits = 0;
-       int nwait, timeout;
-
-       azx_dev = get_azx_dev(substream);
-       trace_azx_pcm_trigger(chip, azx_dev, cmd);
-
-       if (dsp_is_locked(azx_dev) || !azx_dev->prepared)
-               return -EPIPE;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               rstart = 1;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               start = 1;
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_STOP:
-               start = 0;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       snd_pcm_group_for_each_entry(s, substream) {
-               if (s->pcm->card != substream->pcm->card)
-                       continue;
-               azx_dev = get_azx_dev(s);
-               sbits |= 1 << azx_dev->index;
-               nsync++;
-               snd_pcm_trigger_done(s, substream);
-       }
-
-       spin_lock(&chip->reg_lock);
-
-       /* first, set SYNC bits of corresponding streams */
-       if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
-               azx_writel(chip, OLD_SSYNC,
-                       azx_readl(chip, OLD_SSYNC) | sbits);
-       else
-               azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
-
-       snd_pcm_group_for_each_entry(s, substream) {
-               if (s->pcm->card != substream->pcm->card)
-                       continue;
-               azx_dev = get_azx_dev(s);
-               if (start) {
-                       azx_dev->start_wallclk = azx_readl(chip, WALLCLK);
-                       if (!rstart)
-                               azx_dev->start_wallclk -=
-                                               azx_dev->period_wallclk;
-                       azx_stream_start(chip, azx_dev);
-               } else {
-                       azx_stream_stop(chip, azx_dev);
-               }
-               azx_dev->running = start;
-       }
-       spin_unlock(&chip->reg_lock);
-       if (start) {
-               /* wait until all FIFOs get ready */
-               for (timeout = 5000; timeout; timeout--) {
-                       nwait = 0;
-                       snd_pcm_group_for_each_entry(s, substream) {
-                               if (s->pcm->card != substream->pcm->card)
-                                       continue;
-                               azx_dev = get_azx_dev(s);
-                               if (!(azx_sd_readb(azx_dev, SD_STS) &
-                                     SD_STS_FIFO_READY))
-                                       nwait++;
-                       }
-                       if (!nwait)
-                               break;
-                       cpu_relax();
-               }
-       } else {
-               /* wait until all RUN bits are cleared */
-               for (timeout = 5000; timeout; timeout--) {
-                       nwait = 0;
-                       snd_pcm_group_for_each_entry(s, substream) {
-                               if (s->pcm->card != substream->pcm->card)
-                                       continue;
-                               azx_dev = get_azx_dev(s);
-                               if (azx_sd_readb(azx_dev, SD_CTL) &
-                                   SD_CTL_DMA_START)
-                                       nwait++;
-                       }
-                       if (!nwait)
-                               break;
-                       cpu_relax();
-               }
-       }
-       spin_lock(&chip->reg_lock);
-       /* reset SYNC bits */
-       if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
-               azx_writel(chip, OLD_SSYNC,
-                       azx_readl(chip, OLD_SSYNC) & ~sbits);
-       else
-               azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
-       if (start) {
-               azx_timecounter_init(substream, 0, 0);
-               if (nsync > 1) {
-                       cycle_t cycle_last;
-
-                       /* same start cycle for master and group */
-                       azx_dev = get_azx_dev(substream);
-                       cycle_last = azx_dev->azx_tc.cycle_last;
-
-                       snd_pcm_group_for_each_entry(s, substream) {
-                               if (s->pcm->card != substream->pcm->card)
-                                       continue;
-                               azx_timecounter_init(s, 1, cycle_last);
-                       }
-               }
-       }
-       spin_unlock(&chip->reg_lock);
-       return 0;
-}
-
-/* get the current DMA position with correction on VIA chips */
-static unsigned int azx_via_get_position(struct azx *chip,
-                                        struct azx_dev *azx_dev)
-{
-       unsigned int link_pos, mini_pos, bound_pos;
-       unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
-       unsigned int fifo_size;
-
-       link_pos = azx_sd_readl(azx_dev, SD_LPIB);
-       if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* Playback, no problem using link position */
-               return link_pos;
-       }
-
-       /* Capture */
-       /* For new chipset,
-        * use mod to get the DMA position just like old chipset
-        */
-       mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
-       mod_dma_pos %= azx_dev->period_bytes;
-
-       /* azx_dev->fifo_size can't get FIFO size of in stream.
-        * Get from base address + offset.
-        */
-       fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
-
-       if (azx_dev->insufficient) {
-               /* Link position never gather than FIFO size */
-               if (link_pos <= fifo_size)
-                       return 0;
-
-               azx_dev->insufficient = 0;
-       }
-
-       if (link_pos <= fifo_size)
-               mini_pos = azx_dev->bufsize + link_pos - fifo_size;
-       else
-               mini_pos = link_pos - fifo_size;
-
-       /* Find nearest previous boudary */
-       mod_mini_pos = mini_pos % azx_dev->period_bytes;
-       mod_link_pos = link_pos % azx_dev->period_bytes;
-       if (mod_link_pos >= fifo_size)
-               bound_pos = link_pos - mod_link_pos;
-       else if (mod_dma_pos >= mod_mini_pos)
-               bound_pos = mini_pos - mod_mini_pos;
-       else {
-               bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
-               if (bound_pos >= azx_dev->bufsize)
-                       bound_pos = 0;
-       }
-
-       /* Calculate real DMA position we want */
-       return bound_pos + mod_dma_pos;
-}
-
-static unsigned int azx_get_position(struct azx *chip,
-                                    struct azx_dev *azx_dev,
-                                    bool with_check)
-{
-       struct snd_pcm_substream *substream = azx_dev->substream;
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       unsigned int pos;
-       int stream = substream->stream;
-       struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
-       int delay = 0;
-
-       switch (chip->position_fix[stream]) {
-       case POS_FIX_LPIB:
-               /* read LPIB */
-               pos = azx_sd_readl(azx_dev, SD_LPIB);
-               break;
-       case POS_FIX_VIACOMBO:
-               pos = azx_via_get_position(chip, azx_dev);
-               break;
-       default:
-               /* use the position buffer */
-               pos = le32_to_cpu(*azx_dev->posbuf);
-               if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
-                       if (!pos || pos == (u32)-1) {
-                               printk(KERN_WARNING
-                                      "hda-intel: Invalid position buffer, "
-                                      "using LPIB read method instead.\n");
-                               chip->position_fix[stream] = POS_FIX_LPIB;
-                               pos = azx_sd_readl(azx_dev, SD_LPIB);
-                       } else
-                               chip->position_fix[stream] = POS_FIX_POSBUF;
-               }
-               break;
-       }
-
-       if (pos >= azx_dev->bufsize)
-               pos = 0;
-
-       /* calculate runtime delay from LPIB */
-       if (substream->runtime &&
-           chip->position_fix[stream] == POS_FIX_POSBUF &&
-           (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
-               unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
-               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       delay = pos - lpib_pos;
-               else
-                       delay = lpib_pos - pos;
-               if (delay < 0) {
-                       if (delay >= azx_dev->delay_negative_threshold)
-                               delay = 0;
-                       else
-                               delay += azx_dev->bufsize;
-               }
-               if (delay >= azx_dev->period_bytes) {
-                       snd_printk(KERN_WARNING SFX
-                                  "%s: Unstable LPIB (%d >= %d); "
-                                  "disabling LPIB delay counting\n",
-                                  pci_name(chip->pci), delay, azx_dev->period_bytes);
-                       delay = 0;
-                       chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
-               }
-               delay = bytes_to_frames(substream->runtime, delay);
+       /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
+        * we need to enable snoop.
+        */
+       if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+               dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n",
+                       azx_snoop(chip));
+               update_pci_byte(chip->pci,
+                               ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07,
+                               azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0);
        }
 
-       if (substream->runtime) {
-               if (hinfo->ops.get_delay)
-                       delay += hinfo->ops.get_delay(hinfo, apcm->codec,
-                                                     substream);
-               substream->runtime->delay = delay;
+       /* For NVIDIA HDA, enable snoop */
+       if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+               dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n",
+                       azx_snoop(chip));
+               update_pci_byte(chip->pci,
+                               NVIDIA_HDA_TRANSREG_ADDR,
+                               0x0f, NVIDIA_HDA_ENABLE_COHBITS);
+               update_pci_byte(chip->pci,
+                               NVIDIA_HDA_ISTRM_COH,
+                               0x01, NVIDIA_HDA_ENABLE_COHBIT);
+               update_pci_byte(chip->pci,
+                               NVIDIA_HDA_OSTRM_COH,
+                               0x01, NVIDIA_HDA_ENABLE_COHBIT);
        }
 
-       trace_azx_get_position(chip, azx_dev, pos, delay);
-       return pos;
+       /* Enable SCH/PCH snoop if needed */
+       if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
+               unsigned short snoop;
+               pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
+               if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
+                   (azx_snoop(chip) && (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP))) {
+                       snoop &= ~INTEL_SCH_HDA_DEVC_NOSNOOP;
+                       if (!azx_snoop(chip))
+                               snoop |= INTEL_SCH_HDA_DEVC_NOSNOOP;
+                       pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop);
+                       pci_read_config_word(chip->pci,
+                               INTEL_SCH_HDA_DEVC, &snoop);
+               }
+               dev_dbg(chip->card->dev, "SCH snoop: %s\n",
+                       (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ?
+                       "Disabled" : "Enabled");
+        }
 }
 
-static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
+
+/* called from IRQ */
+static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
 {
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev = get_azx_dev(substream);
-       return bytes_to_frames(substream->runtime,
-                              azx_get_position(chip, azx_dev, false));
+       int ok;
+
+       ok = azx_position_ok(chip, azx_dev);
+       if (ok == 1) {
+               azx_dev->irq_pending = 0;
+               return ok;
+       } else if (ok == 0 && chip->bus && chip->bus->workq) {
+               /* bogus IRQ, process it later */
+               azx_dev->irq_pending = 1;
+               queue_work(chip->bus->workq, &chip->irq_pending_work);
+       }
+       return 0;
 }
 
 /*
@@ -2521,7 +454,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
        if (wallclk < (azx_dev->period_wallclk * 5) / 4 &&
            pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
                /* NG - it's below the first next period boundary */
-               return bdl_pos_adj[chip->dev_index] ? 0 : -1;
+               return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1;
        azx_dev->start_wallclk += wallclk;
        return 1; /* OK, it's fine */
 }
@@ -2535,10 +468,9 @@ static void azx_irq_pending_work(struct work_struct *work)
        int i, pending, ok;
 
        if (!chip->irq_pending_warned) {
-               printk(KERN_WARNING
-                      "hda-intel: IRQ timing workaround is activated "
-                      "for card #%d. Suggest a bigger bdl_pos_adj.\n",
-                      chip->card->number);
+               dev_info(chip->card->dev,
+                        "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n",
+                        chip->card->number);
                chip->irq_pending_warned = 1;
        }
 
@@ -2580,139 +512,14 @@ static void azx_clear_irq_pending(struct azx *chip)
        spin_unlock_irq(&chip->reg_lock);
 }
 
-#ifdef CONFIG_X86
-static int azx_pcm_mmap(struct snd_pcm_substream *substream,
-                       struct vm_area_struct *area)
-{
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-       if (!azx_snoop(chip))
-               area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
-       return snd_pcm_lib_default_mmap(substream, area);
-}
-#else
-#define azx_pcm_mmap   NULL
-#endif
-
-static struct snd_pcm_ops azx_pcm_ops = {
-       .open = azx_pcm_open,
-       .close = azx_pcm_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = azx_pcm_hw_params,
-       .hw_free = azx_pcm_hw_free,
-       .prepare = azx_pcm_prepare,
-       .trigger = azx_pcm_trigger,
-       .pointer = azx_pcm_pointer,
-       .wall_clock =  azx_get_wallclock_tstamp,
-       .mmap = azx_pcm_mmap,
-       .page = snd_pcm_sgbuf_ops_page,
-};
-
-static void azx_pcm_free(struct snd_pcm *pcm)
-{
-       struct azx_pcm *apcm = pcm->private_data;
-       if (apcm) {
-               list_del(&apcm->list);
-               kfree(apcm);
-       }
-}
-
-#define MAX_PREALLOC_SIZE      (32 * 1024 * 1024)
-
-static int
-azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
-                     struct hda_pcm *cpcm)
-{
-       struct azx *chip = bus->private_data;
-       struct snd_pcm *pcm;
-       struct azx_pcm *apcm;
-       int pcm_dev = cpcm->device;
-       unsigned int size;
-       int s, err;
-
-       list_for_each_entry(apcm, &chip->pcm_list, list) {
-               if (apcm->pcm->device == pcm_dev) {
-                       snd_printk(KERN_ERR SFX "%s: PCM %d already exists\n",
-                                  pci_name(chip->pci), pcm_dev);
-                       return -EBUSY;
-               }
-       }
-       err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
-                         cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
-                         cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
-                         &pcm);
-       if (err < 0)
-               return err;
-       strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
-       apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
-       if (apcm == NULL)
-               return -ENOMEM;
-       apcm->chip = chip;
-       apcm->pcm = pcm;
-       apcm->codec = codec;
-       pcm->private_data = apcm;
-       pcm->private_free = azx_pcm_free;
-       if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
-               pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
-       list_add_tail(&apcm->list, &chip->pcm_list);
-       cpcm->pcm = pcm;
-       for (s = 0; s < 2; s++) {
-               apcm->hinfo[s] = &cpcm->stream[s];
-               if (cpcm->stream[s].substreams)
-                       snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
-       }
-       /* buffer pre-allocation */
-       size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
-       if (size > MAX_PREALLOC_SIZE)
-               size = MAX_PREALLOC_SIZE;
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                             snd_dma_pci_data(chip->pci),
-                                             size, MAX_PREALLOC_SIZE);
-       return 0;
-}
-
-/*
- * mixer creation - all stuff is implemented in hda module
- */
-static int azx_mixer_create(struct azx *chip)
-{
-       return snd_hda_build_controls(chip->bus);
-}
-
-
-/*
- * initialize SD streams
- */
-static int azx_init_stream(struct azx *chip)
-{
-       int i;
-
-       /* initialize each stream (aka device)
-        * assign the starting bdl address to each stream (device)
-        * and initialize
-        */
-       for (i = 0; i < chip->num_streams; i++) {
-               struct azx_dev *azx_dev = &chip->azx_dev[i];
-               azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
-               /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-               azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
-               /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
-               azx_dev->sd_int_sta_mask = 1 << i;
-               /* stream tag: must be non-zero and unique */
-               azx_dev->index = i;
-               azx_dev->stream_tag = i + 1;
-       }
-
-       return 0;
-}
-
 static int azx_acquire_irq(struct azx *chip, int do_disconnect)
 {
        if (request_irq(chip->pci->irq, azx_interrupt,
                        chip->msi ? 0 : IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
-                      "disabling device\n", chip->pci->irq);
+               dev_err(chip->card->dev,
+                       "unable to grab IRQ %d, disabling device\n",
+                       chip->pci->irq);
                if (do_disconnect)
                        snd_card_disconnect(chip->card);
                return -1;
@@ -2722,160 +529,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
        return 0;
 }
 
-
-static void azx_stop_chip(struct azx *chip)
-{
-       if (!chip->initialized)
-               return;
-
-       /* disable interrupts */
-       azx_int_disable(chip);
-       azx_int_clear(chip);
-
-       /* disable CORB/RIRB */
-       azx_free_cmd_io(chip);
-
-       /* disable position buffer */
-       azx_writel(chip, DPLBASE, 0);
-       azx_writel(chip, DPUBASE, 0);
-
-       chip->initialized = 0;
-}
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-/*
- * DSP loading code (e.g. for CA0132)
- */
-
-/* use the first stream for loading DSP */
-static struct azx_dev *
-azx_get_dsp_loader_dev(struct azx *chip)
-{
-       return &chip->azx_dev[chip->playback_index_offset];
-}
-
-static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
-                               unsigned int byte_size,
-                               struct snd_dma_buffer *bufp)
-{
-       u32 *bdl;
-       struct azx *chip = bus->private_data;
-       struct azx_dev *azx_dev;
-       int err;
-
-       azx_dev = azx_get_dsp_loader_dev(chip);
-
-       dsp_lock(azx_dev);
-       spin_lock_irq(&chip->reg_lock);
-       if (azx_dev->running || azx_dev->locked) {
-               spin_unlock_irq(&chip->reg_lock);
-               err = -EBUSY;
-               goto unlock;
-       }
-       azx_dev->prepared = 0;
-       chip->saved_azx_dev = *azx_dev;
-       azx_dev->locked = 1;
-       spin_unlock_irq(&chip->reg_lock);
-
-       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG,
-                                 snd_dma_pci_data(chip->pci),
-                                 byte_size, bufp);
-       if (err < 0)
-               goto err_alloc;
-
-       mark_pages_wc(chip, bufp, true);
-       azx_dev->bufsize = byte_size;
-       azx_dev->period_bytes = byte_size;
-       azx_dev->format_val = format;
-
-       azx_stream_reset(chip, azx_dev);
-
-       /* reset BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPL, 0);
-       azx_sd_writel(azx_dev, SD_BDLPU, 0);
-
-       azx_dev->frags = 0;
-       bdl = (u32 *)azx_dev->bdl.area;
-       err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
-       if (err < 0)
-               goto error;
-
-       azx_setup_controller(chip, azx_dev);
-       dsp_unlock(azx_dev);
-       return azx_dev->stream_tag;
-
- error:
-       mark_pages_wc(chip, bufp, false);
-       snd_dma_free_pages(bufp);
- err_alloc:
-       spin_lock_irq(&chip->reg_lock);
-       if (azx_dev->opened)
-               *azx_dev = chip->saved_azx_dev;
-       azx_dev->locked = 0;
-       spin_unlock_irq(&chip->reg_lock);
- unlock:
-       dsp_unlock(azx_dev);
-       return err;
-}
-
-static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
-{
-       struct azx *chip = bus->private_data;
-       struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
-
-       if (start)
-               azx_stream_start(chip, azx_dev);
-       else
-               azx_stream_stop(chip, azx_dev);
-       azx_dev->running = start;
-}
-
-static void azx_load_dsp_cleanup(struct hda_bus *bus,
-                                struct snd_dma_buffer *dmab)
-{
-       struct azx *chip = bus->private_data;
-       struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
-
-       if (!dmab->area || !azx_dev->locked)
-               return;
-
-       dsp_lock(azx_dev);
-       /* reset BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPL, 0);
-       azx_sd_writel(azx_dev, SD_BDLPU, 0);
-       azx_sd_writel(azx_dev, SD_CTL, 0);
-       azx_dev->bufsize = 0;
-       azx_dev->period_bytes = 0;
-       azx_dev->format_val = 0;
-
-       mark_pages_wc(chip, dmab, false);
-       snd_dma_free_pages(dmab);
-       dmab->area = NULL;
-
-       spin_lock_irq(&chip->reg_lock);
-       if (azx_dev->opened)
-               *azx_dev = chip->saved_azx_dev;
-       azx_dev->locked = 0;
-       spin_unlock_irq(&chip->reg_lock);
-       dsp_unlock(azx_dev);
-}
-#endif /* CONFIG_SND_HDA_DSP_LOADER */
-
 #ifdef CONFIG_PM
-/* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus, bool power_up)
-{
-       struct azx *chip = bus->private_data;
-
-       if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
-               return;
-
-       if (power_up)
-               pm_runtime_get_sync(&chip->pci->dev);
-       else
-               pm_runtime_put_sync(&chip->pci->dev);
-}
-
 static DEFINE_MUTEX(card_list_lock);
 static LIST_HEAD(card_list);
 
@@ -2969,8 +623,8 @@ static int azx_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "hda-intel: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(chip->card->dev,
+                       "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -3127,36 +781,32 @@ static void azx_vs_set_state(struct pci_dev *pci,
        if (!chip->bus) {
                chip->disabled = disabled;
                if (!disabled) {
-                       snd_printk(KERN_INFO SFX
-                                  "%s: Start delayed initialization\n",
-                                  pci_name(chip->pci));
+                       dev_info(chip->card->dev,
+                                "Start delayed initialization\n");
                        if (azx_probe_continue(chip) < 0) {
-                               snd_printk(KERN_ERR SFX
-                                          "%s: initialization error\n",
-                                          pci_name(chip->pci));
+                               dev_err(chip->card->dev, "initialization error\n");
                                chip->init_failed = true;
                        }
                }
        } else {
-               snd_printk(KERN_INFO SFX
-                          "%s: %s via VGA-switcheroo\n", pci_name(chip->pci),
-                          disabled ? "Disabling" : "Enabling");
+               dev_info(chip->card->dev, "%s via VGA-switcheroo\n",
+                        disabled ? "Disabling" : "Enabling");
                if (disabled) {
-                       pm_runtime_put_sync_suspend(&pci->dev);
-                       azx_suspend(&pci->dev);
+                       pm_runtime_put_sync_suspend(card->dev);
+                       azx_suspend(card->dev);
                        /* when we get suspended by vga switcheroo we end up in D3cold,
                         * however we have no ACPI handle, so pci/acpi can't put us there,
                         * put ourselves there */
                        pci->current_state = PCI_D3cold;
                        chip->disabled = true;
                        if (snd_hda_lock_devices(chip->bus))
-                               snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n",
-                                          pci_name(chip->pci));
+                               dev_warn(chip->card->dev,
+                                        "Cannot lock devices!\n");
                } else {
                        snd_hda_unlock_devices(chip->bus);
-                       pm_runtime_get_noresume(&pci->dev);
+                       pm_runtime_get_noresume(card->dev);
                        chip->disabled = false;
-                       azx_resume(&pci->dev);
+                       azx_resume(card->dev);
                }
        }
 }
@@ -3181,9 +831,8 @@ static void init_vga_switcheroo(struct azx *chip)
 {
        struct pci_dev *p = get_bound_vga(chip->pci);
        if (p) {
-               snd_printk(KERN_INFO SFX
-                          "%s: Handle VGA-switcheroo audio client\n",
-                          pci_name(chip->pci));
+               dev_info(chip->card->dev,
+                        "Handle VGA-switcheroo audio client\n");
                chip->use_vga_switcheroo = 1;
                pci_dev_put(p);
        }
@@ -3211,7 +860,8 @@ static int register_vga_switcheroo(struct azx *chip)
        chip->vga_switcheroo_registered = 1;
 
        /* register as an optimus hdmi audio power domain */
-       vga_switcheroo_init_domain_pm_optimus_hdmi_audio(&chip->pci->dev, &chip->hdmi_pm_domain);
+       vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev,
+                                                        &chip->hdmi_pm_domain);
        return 0;
 }
 #else
@@ -3260,21 +910,7 @@ static int azx_free(struct azx *chip)
        if (chip->remap_addr)
                iounmap(chip->remap_addr);
 
-       if (chip->azx_dev) {
-               for (i = 0; i < chip->num_streams; i++)
-                       if (chip->azx_dev[i].bdl.area) {
-                               mark_pages_wc(chip, &chip->azx_dev[i].bdl, false);
-                               snd_dma_free_pages(&chip->azx_dev[i].bdl);
-                       }
-       }
-       if (chip->rb.area) {
-               mark_pages_wc(chip, &chip->rb, false);
-               snd_dma_free_pages(&chip->rb);
-       }
-       if (chip->posbuf.area) {
-               mark_pages_wc(chip, &chip->posbuf, false);
-               snd_dma_free_pages(&chip->posbuf);
-       }
+       azx_free_stream_pages(chip);
        if (chip->region_requested)
                pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
@@ -3374,20 +1010,19 @@ static int check_position_fix(struct azx *chip, int fix)
 
        q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
        if (q) {
-               printk(KERN_INFO
-                      "hda_intel: position_fix set to %d "
-                      "for device %04x:%04x\n",
-                      q->value, q->subvendor, q->subdevice);
+               dev_info(chip->card->dev,
+                        "position_fix set to %d for device %04x:%04x\n",
+                        q->value, q->subvendor, q->subdevice);
                return q->value;
        }
 
        /* Check VIA/ATI HD Audio Controller exist */
        if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
-               snd_printd(SFX "%s: Using VIACOMBO position fix\n", pci_name(chip->pci));
+               dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
                return POS_FIX_VIACOMBO;
        }
        if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
-               snd_printd(SFX "%s: Using LPIB position fix\n", pci_name(chip->pci));
+               dev_dbg(chip->card->dev, "Using LPIB position fix\n");
                return POS_FIX_LPIB;
        }
        return POS_FIX_AUTO;
@@ -3425,10 +1060,9 @@ static void check_probe_mask(struct azx *chip, int dev)
        if (chip->codec_probe_mask == -1) {
                q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
                if (q) {
-                       printk(KERN_INFO
-                              "hda_intel: probe_mask set to 0x%x "
-                              "for device %04x:%04x\n",
-                              q->value, q->subvendor, q->subdevice);
+                       dev_info(chip->card->dev,
+                                "probe_mask set to 0x%x for device %04x:%04x\n",
+                                q->value, q->subvendor, q->subdevice);
                        chip->codec_probe_mask = q->value;
                }
        }
@@ -3437,8 +1071,8 @@ static void check_probe_mask(struct azx *chip, int dev)
        if (chip->codec_probe_mask != -1 &&
            (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) {
                chip->codec_mask = chip->codec_probe_mask & 0xff;
-               printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n",
-                      chip->codec_mask);
+               dev_info(chip->card->dev, "codec_mask forced to 0x%x\n",
+                        chip->codec_mask);
        }
 }
 
@@ -3470,16 +1104,16 @@ static void check_msi(struct azx *chip)
        chip->msi = 1;  /* enable MSI as default */
        q = snd_pci_quirk_lookup(chip->pci, msi_black_list);
        if (q) {
-               printk(KERN_INFO
-                      "hda_intel: msi for device %04x:%04x set to %d\n",
-                      q->subvendor, q->subdevice, q->value);
+               dev_info(chip->card->dev,
+                        "msi for device %04x:%04x set to %d\n",
+                        q->subvendor, q->subdevice, q->value);
                chip->msi = q->value;
                return;
        }
 
        /* NVidia chipsets seem to cause troubles with MSI */
        if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
-               printk(KERN_INFO "hda_intel: Disabling MSI\n");
+               dev_info(chip->card->dev, "Disabling MSI\n");
                chip->msi = 0;
        }
 }
@@ -3511,8 +1145,8 @@ static void azx_check_snoop_available(struct azx *chip)
        }
 
        if (snoop != chip->snoop) {
-               snd_printk(KERN_INFO SFX "%s: Force to %s mode\n",
-                          pci_name(chip->pci), snoop ? "snoop" : "non-snoop");
+               dev_info(chip->card->dev, "Force to %s mode\n",
+                        snoop ? "snoop" : "non-snoop");
                chip->snoop = snoop;
        }
 }
@@ -3527,6 +1161,7 @@ static void azx_probe_work(struct work_struct *work)
  */
 static int azx_create(struct snd_card *card, struct pci_dev *pci,
                      int dev, unsigned int driver_caps,
+                     const struct hda_controller_ops *hda_ops,
                      struct azx **rchip)
 {
        static struct snd_device_ops ops = {
@@ -3543,7 +1178,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip) {
-               snd_printk(KERN_ERR SFX "%s: Cannot allocate chip\n", pci_name(pci));
+               dev_err(card->dev, "Cannot allocate chip\n");
                pci_disable_device(pci);
                return -ENOMEM;
        }
@@ -3552,11 +1187,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
        mutex_init(&chip->open_mutex);
        chip->card = card;
        chip->pci = pci;
+       chip->ops = hda_ops;
        chip->irq = -1;
        chip->driver_caps = driver_caps;
        chip->driver_type = driver_caps & 0xff;
        check_msi(chip);
        chip->dev_index = dev;
+       chip->jackpoll_ms = jackpoll_ms;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
        INIT_LIST_HEAD(&chip->pcm_list);
        INIT_LIST_HEAD(&chip->list);
@@ -3588,11 +1225,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
                        break;
                }
        }
+       chip->bdl_pos_adj = bdl_pos_adj;
 
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
        if (err < 0) {
-               snd_printk(KERN_ERR SFX "%s: Error creating device [card]!\n",
-                  pci_name(chip->pci));
+               dev_err(card->dev, "Error creating device [card]!\n");
                azx_free(chip);
                return err;
        }
@@ -3610,7 +1247,7 @@ static int azx_first_init(struct azx *chip)
        int dev = chip->dev_index;
        struct pci_dev *pci = chip->pci;
        struct snd_card *card = chip->card;
-       int i, err;
+       int err;
        unsigned short gcap;
 
 #if BITS_PER_LONG != 64
@@ -3631,7 +1268,7 @@ static int azx_first_init(struct azx *chip)
        chip->addr = pci_resource_start(pci, 0);
        chip->remap_addr = pci_ioremap_bar(pci, 0);
        if (chip->remap_addr == NULL) {
-               snd_printk(KERN_ERR SFX "%s: ioremap error\n", pci_name(chip->pci));
+               dev_err(card->dev, "ioremap error\n");
                return -ENXIO;
        }
 
@@ -3646,7 +1283,7 @@ static int azx_first_init(struct azx *chip)
        synchronize_irq(chip->irq);
 
        gcap = azx_readw(chip, GCAP);
-       snd_printdd(SFX "%s: chipset global capabilities = 0x%x\n", pci_name(chip->pci), gcap);
+       dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
 
        /* disable SB600 64bit support for safety */
        if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
@@ -3663,7 +1300,7 @@ static int azx_first_init(struct azx *chip)
 
        /* disable 64bit DMA address on some devices */
        if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
-               snd_printd(SFX "%s: Disabling 64bit DMA\n", pci_name(chip->pci));
+               dev_dbg(card->dev, "Disabling 64bit DMA\n");
                gcap &= ~ICH6_GCAP_64OK;
        }
 
@@ -3718,33 +1355,11 @@ static int azx_first_init(struct azx *chip)
        chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
                                GFP_KERNEL);
        if (!chip->azx_dev) {
-               snd_printk(KERN_ERR SFX "%s: cannot malloc azx_dev\n", pci_name(chip->pci));
+               dev_err(card->dev, "cannot malloc azx_dev\n");
                return -ENOMEM;
        }
 
-       for (i = 0; i < chip->num_streams; i++) {
-               dsp_lock_init(&chip->azx_dev[i]);
-               /* allocate memory for the BDL for each stream */
-               err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-                                         snd_dma_pci_data(chip->pci),
-                                         BDL_SIZE, &chip->azx_dev[i].bdl);
-               if (err < 0) {
-                       snd_printk(KERN_ERR SFX "%s: cannot allocate BDL\n", pci_name(chip->pci));
-                       return -ENOMEM;
-               }
-               mark_pages_wc(chip, &chip->azx_dev[i].bdl, true);
-       }
-       /* allocate memory for the position buffer */
-       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-                                 snd_dma_pci_data(chip->pci),
-                                 chip->num_streams * 8, &chip->posbuf);
-       if (err < 0) {
-               snd_printk(KERN_ERR SFX "%s: cannot allocate posbuf\n", pci_name(chip->pci));
-               return -ENOMEM;
-       }
-       mark_pages_wc(chip, &chip->posbuf, true);
-       /* allocate CORB/RIRB */
-       err = azx_alloc_cmd_io(chip);
+       err = azx_alloc_stream_pages(chip);
        if (err < 0)
                return err;
 
@@ -3757,7 +1372,7 @@ static int azx_first_init(struct azx *chip)
 
        /* codec detection */
        if (!chip->codec_mask) {
-               snd_printk(KERN_ERR SFX "%s: no codecs found!\n", pci_name(chip->pci));
+               dev_err(card->dev, "no codecs found!\n");
                return -ENODEV;
        }
 
@@ -3793,8 +1408,7 @@ static void azx_firmware_cb(const struct firmware *fw, void *context)
        struct pci_dev *pci = chip->pci;
 
        if (!fw) {
-               snd_printk(KERN_ERR SFX "%s: Cannot load firmware, aborting\n",
-                          pci_name(chip->pci));
+               dev_err(card->dev, "Cannot load firmware, aborting\n");
                goto error;
        }
 
@@ -3812,6 +1426,132 @@ static void azx_firmware_cb(const struct firmware *fw, void *context)
 }
 #endif
 
+/*
+ * HDA controller ops.
+ */
+
+/* PCI register access. */
+static void pci_azx_writel(u32 value, u32 __iomem *addr)
+{
+       writel(value, addr);
+}
+
+static u32 pci_azx_readl(u32 __iomem *addr)
+{
+       return readl(addr);
+}
+
+static void pci_azx_writew(u16 value, u16 __iomem *addr)
+{
+       writew(value, addr);
+}
+
+static u16 pci_azx_readw(u16 __iomem *addr)
+{
+       return readw(addr);
+}
+
+static void pci_azx_writeb(u8 value, u8 __iomem *addr)
+{
+       writeb(value, addr);
+}
+
+static u8 pci_azx_readb(u8 __iomem *addr)
+{
+       return readb(addr);
+}
+
+static int disable_msi_reset_irq(struct azx *chip)
+{
+       int err;
+
+       free_irq(chip->irq, chip);
+       chip->irq = -1;
+       pci_disable_msi(chip->pci);
+       chip->msi = 0;
+       err = azx_acquire_irq(chip, 1);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/* DMA page allocation helpers.  */
+static int dma_alloc_pages(struct azx *chip,
+                          int type,
+                          size_t size,
+                          struct snd_dma_buffer *buf)
+{
+       int err;
+
+       err = snd_dma_alloc_pages(type,
+                                 chip->card->dev,
+                                 size, buf);
+       if (err < 0)
+               return err;
+       mark_pages_wc(chip, buf, true);
+       return 0;
+}
+
+static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf)
+{
+       mark_pages_wc(chip, buf, false);
+       snd_dma_free_pages(buf);
+}
+
+static int substream_alloc_pages(struct azx *chip,
+                                struct snd_pcm_substream *substream,
+                                size_t size)
+{
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       int ret;
+
+       mark_runtime_wc(chip, azx_dev, substream, false);
+       azx_dev->bufsize = 0;
+       azx_dev->period_bytes = 0;
+       azx_dev->format_val = 0;
+       ret = snd_pcm_lib_malloc_pages(substream, size);
+       if (ret < 0)
+               return ret;
+       mark_runtime_wc(chip, azx_dev, substream, true);
+       return 0;
+}
+
+static int substream_free_pages(struct azx *chip,
+                               struct snd_pcm_substream *substream)
+{
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       mark_runtime_wc(chip, azx_dev, substream, false);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
+                            struct vm_area_struct *area)
+{
+#ifdef CONFIG_X86
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       if (!azx_snoop(chip))
+               area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+#endif
+}
+
+static const struct hda_controller_ops pci_hda_ops = {
+       .reg_writel = pci_azx_writel,
+       .reg_readl = pci_azx_readl,
+       .reg_writew = pci_azx_writew,
+       .reg_readw = pci_azx_readw,
+       .reg_writeb = pci_azx_writeb,
+       .reg_readb = pci_azx_readb,
+       .disable_msi_reset_irq = disable_msi_reset_irq,
+       .dma_alloc_pages = dma_alloc_pages,
+       .dma_free_pages = dma_free_pages,
+       .substream_alloc_pages = substream_alloc_pages,
+       .substream_free_pages = substream_free_pages,
+       .pcm_mmap_prepare = pcm_mmap_prepare,
+       .position_check = azx_position_check,
+};
+
 static int azx_probe(struct pci_dev *pci,
                     const struct pci_device_id *pci_id)
 {
@@ -3828,15 +1568,15 @@ static int azx_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
-               snd_printk(KERN_ERR "hda-intel: Error creating card!\n");
+               dev_err(&pci->dev, "Error creating card!\n");
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
-       err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
+       err = azx_create(card, pci, dev, pci_id->driver_data,
+                        &pci_hda_ops, &chip);
        if (err < 0)
                goto out_free;
        card->private_data = chip;
@@ -3845,15 +1585,13 @@ static int azx_probe(struct pci_dev *pci,
 
        err = register_vga_switcheroo(chip);
        if (err < 0) {
-               snd_printk(KERN_ERR SFX
-                          "%s: Error registering VGA-switcheroo client\n", pci_name(pci));
+               dev_err(card->dev, "Error registering VGA-switcheroo client\n");
                goto out_free;
        }
 
        if (check_hdmi_disabled(pci)) {
-               snd_printk(KERN_INFO SFX "%s: VGA controller is disabled\n",
-                          pci_name(pci));
-               snd_printk(KERN_INFO SFX "%s: Delaying initialization\n", pci_name(pci));
+               dev_info(card->dev, "VGA controller is disabled\n");
+               dev_info(card->dev, "Delaying initialization\n");
                chip->disabled = true;
        }
 
@@ -3861,8 +1599,8 @@ static int azx_probe(struct pci_dev *pci,
 
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
        if (patch[dev] && *patch[dev]) {
-               snd_printk(KERN_ERR SFX "%s: Applying patch firmware '%s'\n",
-                          pci_name(pci), patch[dev]);
+               dev_info(card->dev, "Applying patch firmware '%s'\n",
+                        patch[dev]);
                err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
                                              &pci->dev, GFP_KERNEL, card,
                                              azx_firmware_cb);
@@ -3874,7 +1612,7 @@ static int azx_probe(struct pci_dev *pci,
 
 #ifndef CONFIG_SND_HDA_I915
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               snd_printk(KERN_ERR SFX "Haswell must build in CONFIG_SND_HDA_I915\n");
+               dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n");
 #endif
 
        if (schedule_probe)
@@ -3890,6 +1628,12 @@ out_free:
        return err;
 }
 
+/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
+static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
+       [AZX_DRIVER_NVIDIA] = 8,
+       [AZX_DRIVER_TERA] = 1,
+};
+
 static int azx_probe_continue(struct azx *chip)
 {
        struct pci_dev *pci = chip->pci;
@@ -3901,7 +1645,8 @@ static int azx_probe_continue(struct azx *chip)
 #ifdef CONFIG_SND_HDA_I915
                err = hda_i915_init();
                if (err < 0) {
-                       snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
+                       dev_err(chip->card->dev,
+                               "Error request power-well from i915\n");
                        goto out_free;
                }
 #endif
@@ -3917,7 +1662,10 @@ static int azx_probe_continue(struct azx *chip)
 #endif
 
        /* create codec instances */
-       err = azx_codec_create(chip, model[dev]);
+       err = azx_codec_create(chip, model[dev],
+                              azx_max_codecs[chip->driver_type],
+                              power_save_addr);
+
        if (err < 0)
                goto out_free;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
@@ -4142,7 +1890,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
          .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
        { PCI_DEVICE(0x1102, 0x0012),
          .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
-#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
+#if !IS_ENABLED(CONFIG_SND_CTXFI)
        /* the following entry conflicts with snd-ctxfi driver,
         * as ctxfi driver mutates from HD-audio to native mode with
         * a special command sequence.
index da80c5bd7fd42ecacaa99e17befd8bef5c40099f..e51d155292155b522df246ee612e156a3d8a0a88 100644 (file)
@@ -597,23 +597,10 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
 static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
 #endif
 
-#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP)
-int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
-#else
-static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
-{
-       return 0;
-}
-#endif
+void snd_hda_sysfs_init(struct hda_codec *codec);
+void snd_hda_sysfs_clear(struct hda_codec *codec);
 
-#ifdef CONFIG_SND_HDA_RECONFIG
-int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
-#else
-static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
-{
-       return 0;
-}
-#endif
+extern const struct attribute_group *snd_hda_dev_attr_groups[];
 
 #ifdef CONFIG_SND_HDA_RECONFIG
 const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
@@ -771,4 +758,11 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
 #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
 
+/*
+ */
+#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args)
+#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args)
+#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args)
+#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args)
+
 #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
new file mode 100644 (file)
index 0000000..ba38b81
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ *  Common defines for the alsa driver code base for HD Audio.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the 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 __SOUND_HDA_PRIV_H
+#define __SOUND_HDA_PRIV_H
+
+#include <linux/clocksource.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP                  0x00
+#define   ICH6_GCAP_64OK       (1 << 0)   /* 64bit address support */
+#define   ICH6_GCAP_NSDO       (3 << 1)   /* # of serial data out signals */
+#define   ICH6_GCAP_BSS                (31 << 3)  /* # of bidirectional streams */
+#define   ICH6_GCAP_ISS                (15 << 8)  /* # of input streams */
+#define   ICH6_GCAP_OSS                (15 << 12) /* # of output streams */
+#define ICH6_REG_VMIN                  0x02
+#define ICH6_REG_VMAJ                  0x03
+#define ICH6_REG_OUTPAY                        0x04
+#define ICH6_REG_INPAY                 0x06
+#define ICH6_REG_GCTL                  0x08
+#define   ICH6_GCTL_RESET      (1 << 0)   /* controller reset */
+#define   ICH6_GCTL_FCNTRL     (1 << 1)   /* flush control */
+#define   ICH6_GCTL_UNSOL      (1 << 8)   /* accept unsol. response enable */
+#define ICH6_REG_WAKEEN                        0x0c
+#define ICH6_REG_STATESTS              0x0e
+#define ICH6_REG_GSTS                  0x10
+#define   ICH6_GSTS_FSTS       (1 << 1)   /* flush status */
+#define ICH6_REG_INTCTL                        0x20
+#define ICH6_REG_INTSTS                        0x24
+#define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
+#define ICH6_REG_OLD_SSYNC             0x34    /* SSYNC for old ICH */
+#define ICH6_REG_SSYNC                 0x38
+#define ICH6_REG_CORBLBASE             0x40
+#define ICH6_REG_CORBUBASE             0x44
+#define ICH6_REG_CORBWP                        0x48
+#define ICH6_REG_CORBRP                        0x4a
+#define   ICH6_CORBRP_RST      (1 << 15)  /* read pointer reset */
+#define ICH6_REG_CORBCTL               0x4c
+#define   ICH6_CORBCTL_RUN     (1 << 1)   /* enable DMA */
+#define   ICH6_CORBCTL_CMEIE   (1 << 0)   /* enable memory error irq */
+#define ICH6_REG_CORBSTS               0x4d
+#define   ICH6_CORBSTS_CMEI    (1 << 0)   /* memory error indication */
+#define ICH6_REG_CORBSIZE              0x4e
+
+#define ICH6_REG_RIRBLBASE             0x50
+#define ICH6_REG_RIRBUBASE             0x54
+#define ICH6_REG_RIRBWP                        0x58
+#define   ICH6_RIRBWP_RST      (1 << 15)  /* write pointer reset */
+#define ICH6_REG_RINTCNT               0x5a
+#define ICH6_REG_RIRBCTL               0x5c
+#define   ICH6_RBCTL_IRQ_EN    (1 << 0)   /* enable IRQ */
+#define   ICH6_RBCTL_DMA_EN    (1 << 1)   /* enable DMA */
+#define   ICH6_RBCTL_OVERRUN_EN        (1 << 2)   /* enable overrun irq */
+#define ICH6_REG_RIRBSTS               0x5d
+#define   ICH6_RBSTS_IRQ       (1 << 0)   /* response irq */
+#define   ICH6_RBSTS_OVERRUN   (1 << 2)   /* overrun irq */
+#define ICH6_REG_RIRBSIZE              0x5e
+
+#define ICH6_REG_IC                    0x60
+#define ICH6_REG_IR                    0x64
+#define ICH6_REG_IRS                   0x68
+#define   ICH6_IRS_VALID       (1<<1)
+#define   ICH6_IRS_BUSY                (1<<0)
+
+#define ICH6_REG_DPLBASE               0x70
+#define ICH6_REG_DPUBASE               0x74
+#define   ICH6_DPLBASE_ENABLE  0x1     /* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL                        0x00
+#define ICH6_REG_SD_STS                        0x03
+#define ICH6_REG_SD_LPIB               0x04
+#define ICH6_REG_SD_CBL                        0x08
+#define ICH6_REG_SD_LVI                        0x0c
+#define ICH6_REG_SD_FIFOW              0x0e
+#define ICH6_REG_SD_FIFOSIZE           0x10
+#define ICH6_REG_SD_FORMAT             0x12
+#define ICH6_REG_SD_BDLPL              0x18
+#define ICH6_REG_SD_BDLPU              0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL      0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_NUM_CAPTURE       4
+#define ICH6_NUM_PLAYBACK      4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_NUM_CAPTURE                5
+#define ULI_NUM_PLAYBACK       6
+
+/* ATI HDMI may have up to 8 playbacks and 0 capture */
+#define ATIHDMI_NUM_CAPTURE    0
+#define ATIHDMI_NUM_PLAYBACK   8
+
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE       3
+#define TERA_NUM_PLAYBACK      4
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV            16
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE               4096
+#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
+#define AZX_MAX_FRAG           32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE      0x01
+#define RIRB_INT_OVERRUN       0x04
+#define RIRB_INT_MASK          0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS         8
+#define AZX_DEFAULT_CODECS     4
+#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
+#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
+#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
+#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT        20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
+#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
+#define SD_INT_COMPLETE                0x04    /* completion interrupt */
+#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+                                SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM    0xff       /* all stream interrupts */
+#define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES  256
+#define ICH6_MAX_RIRB_ENTRIES  256
+
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
+#define AZX_DCAPS_ATI_SNOOP    (1 << 10)       /* ATI snoop enable */
+#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11)       /* Nvidia snoop enable */
+#define AZX_DCAPS_SCH_SNOOP    (1 << 12)       /* SCH/PCH snoop enable */
+#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
+#define AZX_DCAPS_BUFSIZE      (1 << 21)       /* no buffer size alignment */
+#define AZX_DCAPS_ALIGN_BUFSIZE        (1 << 22)       /* buffer size alignment */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)   /* BDLE in 4k boundary */
+#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
+#define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
+
+/* position fix mode */
+enum {
+       POS_FIX_AUTO,
+       POS_FIX_LPIB,
+       POS_FIX_POSBUF,
+       POS_FIX_VIACOMBO,
+       POS_FIX_COMBO,
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
+
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
+#define NVIDIA_HDA_ISTRM_COH          0x4d
+#define NVIDIA_HDA_OSTRM_COH          0x4c
+#define NVIDIA_HDA_ENABLE_COHBIT      0x01
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET        0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID             0x3288
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
+
+struct azx_dev {
+       struct snd_dma_buffer bdl; /* BDL buffer */
+       u32 *posbuf;            /* position buffer pointer */
+
+       unsigned int bufsize;   /* size of the play buffer in bytes */
+       unsigned int period_bytes; /* size of the period in bytes */
+       unsigned int frags;     /* number for period in the play buffer */
+       unsigned int fifo_size; /* FIFO size */
+       unsigned long start_wallclk;    /* start + minimum wallclk */
+       unsigned long period_wallclk;   /* wallclk for period */
+
+       void __iomem *sd_addr;  /* stream descriptor pointer */
+
+       u32 sd_int_sta_mask;    /* stream int status mask */
+
+       /* pcm support */
+       struct snd_pcm_substream *substream;    /* assigned substream,
+                                                * set in PCM open
+                                                */
+       unsigned int format_val;        /* format value to be set in the
+                                        * controller and the codec
+                                        */
+       unsigned char stream_tag;       /* assigned stream */
+       unsigned char index;            /* stream index */
+       int assigned_key;               /* last device# key assigned to */
+
+       unsigned int opened:1;
+       unsigned int running:1;
+       unsigned int irq_pending:1;
+       unsigned int prepared:1;
+       unsigned int locked:1;
+       /*
+        * For VIA:
+        *  A flag to ensure DMA position is 0
+        *  when link position is not greater than FIFO size
+        */
+       unsigned int insufficient:1;
+       unsigned int wc_marked:1;
+       unsigned int no_period_wakeup:1;
+
+       struct timecounter  azx_tc;
+       struct cyclecounter azx_cc;
+
+       int delay_negative_threshold;
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+       /* Allows dsp load to have sole access to the playback stream. */
+       struct mutex dsp_mutex;
+#endif
+};
+
+/* CORB/RIRB */
+struct azx_rb {
+       u32 *buf;               /* CORB/RIRB buffer
+                                * Each CORB entry is 4byte, RIRB is 8byte
+                                */
+       dma_addr_t addr;        /* physical address of CORB/RIRB buffer */
+       /* for RIRB */
+       unsigned short rp, wp;  /* read/write pointers */
+       int cmds[AZX_MAX_CODECS];       /* number of pending requests */
+       u32 res[AZX_MAX_CODECS];        /* last read value */
+};
+
+struct azx;
+
+/* Functions to read/write to hda registers. */
+struct hda_controller_ops {
+       /* Register Access */
+       void (*reg_writel)(u32 value, u32 __iomem *addr);
+       u32 (*reg_readl)(u32 __iomem *addr);
+       void (*reg_writew)(u16 value, u16 __iomem *addr);
+       u16 (*reg_readw)(u16 __iomem *addr);
+       void (*reg_writeb)(u8 value, u8 __iomem *addr);
+       u8 (*reg_readb)(u8 __iomem *addr);
+       /* Disable msi if supported, PCI only */
+       int (*disable_msi_reset_irq)(struct azx *);
+       /* Allocation ops */
+       int (*dma_alloc_pages)(struct azx *chip,
+                              int type,
+                              size_t size,
+                              struct snd_dma_buffer *buf);
+       void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf);
+       int (*substream_alloc_pages)(struct azx *chip,
+                                    struct snd_pcm_substream *substream,
+                                    size_t size);
+       int (*substream_free_pages)(struct azx *chip,
+                                   struct snd_pcm_substream *substream);
+       void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
+                                struct vm_area_struct *area);
+       /* Check if current position is acceptable */
+       int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
+};
+
+struct azx_pcm {
+       struct azx *chip;
+       struct snd_pcm *pcm;
+       struct hda_codec *codec;
+       struct hda_pcm_stream *hinfo[2];
+       struct list_head list;
+};
+
+struct azx {
+       struct snd_card *card;
+       struct pci_dev *pci;
+       int dev_index;
+
+       /* chip type specific */
+       int driver_type;
+       unsigned int driver_caps;
+       int playback_streams;
+       int playback_index_offset;
+       int capture_streams;
+       int capture_index_offset;
+       int num_streams;
+       const int *jackpoll_ms; /* per-card jack poll interval */
+
+       /* Register interaction. */
+       const struct hda_controller_ops *ops;
+
+       /* pci resources */
+       unsigned long addr;
+       void __iomem *remap_addr;
+       int irq;
+
+       /* locks */
+       spinlock_t reg_lock;
+       struct mutex open_mutex; /* Prevents concurrent open/close operations */
+       struct completion probe_wait;
+
+       /* streams (x num_streams) */
+       struct azx_dev *azx_dev;
+
+       /* PCM */
+       struct list_head pcm_list; /* azx_pcm list */
+
+       /* HD codec */
+       unsigned short codec_mask;
+       int  codec_probe_mask; /* copied from probe_mask option */
+       struct hda_bus *bus;
+       unsigned int beep_mode;
+
+       /* CORB/RIRB */
+       struct azx_rb corb;
+       struct azx_rb rirb;
+
+       /* CORB/RIRB and position buffers */
+       struct snd_dma_buffer rb;
+       struct snd_dma_buffer posbuf;
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       const struct firmware *fw;
+#endif
+
+       /* flags */
+       int position_fix[2]; /* for both playback/capture streams */
+       const int *bdl_pos_adj;
+       int poll_count;
+       unsigned int running:1;
+       unsigned int initialized:1;
+       unsigned int single_cmd:1;
+       unsigned int polling_mode:1;
+       unsigned int msi:1;
+       unsigned int irq_pending_warned:1;
+       unsigned int probing:1; /* codec probing phase */
+       unsigned int snoop:1;
+       unsigned int align_buffer_size:1;
+       unsigned int region_requested:1;
+
+       /* VGA-switcheroo setup */
+       unsigned int use_vga_switcheroo:1;
+       unsigned int vga_switcheroo_registered:1;
+       unsigned int init_failed:1; /* delayed init failed */
+       unsigned int disabled:1; /* disabled by VGA-switcher */
+
+       /* for debugging */
+       unsigned int last_cmd[AZX_MAX_CODECS];
+
+       /* for pending irqs */
+       struct work_struct irq_pending_work;
+
+       struct work_struct probe_work;
+
+       /* reboot notifier (for mysterious hangup problem at power-down) */
+       struct notifier_block reboot_notifier;
+
+       /* card list (for power_save trigger) */
+       struct list_head list;
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+       struct azx_dev saved_azx_dev;
+#endif
+
+       /* secondary power domain for hdmi audio under vga device */
+       struct dev_pm_domain hdmi_pm_domain;
+};
+
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+#define SFX    /* nop */
+#else
+#define SFX    "hda-intel "
+#endif
+
+#ifdef CONFIG_X86
+#define azx_snoop(chip)                ((chip)->snoop)
+#else
+#define azx_snoop(chip)                true
+#endif
+
+/*
+ * macros for easy use
+ */
+
+#define azx_writel(chip, reg, value) \
+       ((chip)->ops->reg_writel(value, (chip)->remap_addr + ICH6_REG_##reg))
+#define azx_readl(chip, reg) \
+       ((chip)->ops->reg_readl((chip)->remap_addr + ICH6_REG_##reg))
+#define azx_writew(chip, reg, value) \
+       ((chip)->ops->reg_writew(value, (chip)->remap_addr + ICH6_REG_##reg))
+#define azx_readw(chip, reg) \
+       ((chip)->ops->reg_readw((chip)->remap_addr + ICH6_REG_##reg))
+#define azx_writeb(chip, reg, value) \
+       ((chip)->ops->reg_writeb(value, (chip)->remap_addr + ICH6_REG_##reg))
+#define azx_readb(chip, reg) \
+       ((chip)->ops->reg_readb((chip)->remap_addr + ICH6_REG_##reg))
+
+#define azx_sd_writel(chip, dev, reg, value) \
+       ((chip)->ops->reg_writel(value, (dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_readl(chip, dev, reg) \
+       ((chip)->ops->reg_readl((dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_writew(chip, dev, reg, value) \
+       ((chip)->ops->reg_writew(value, (dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_readw(chip, dev, reg) \
+       ((chip)->ops->reg_readw((dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_writeb(chip, dev, reg, value) \
+       ((chip)->ops->reg_writeb(value, (dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_readb(chip, dev, reg) \
+       ((chip)->ops->reg_readb((dev)->sd_addr + ICH6_REG_##reg))
+
+#endif /* __SOUND_HDA_PRIV_H */
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
new file mode 100644 (file)
index 0000000..e207909
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * sysfs interface for HD-audio codec
+ *
+ * Copyright (c) 2014 Takashi Iwai <tiwai@suse.de>
+ *
+ * split from hda_hwdep.c
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/mutex.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include <sound/hda_hwdep.h>
+#include <sound/minors.h>
+
+/* hint string pair */
+struct hda_hint {
+       const char *key;
+       const char *val;        /* contained in the same alloc as key */
+};
+
+#ifdef CONFIG_PM
+static ssize_t power_on_acct_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       snd_hda_update_power_acct(codec);
+       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
+}
+
+static ssize_t power_off_acct_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       snd_hda_update_power_acct(codec);
+       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
+}
+
+static DEVICE_ATTR_RO(power_on_acct);
+static DEVICE_ATTR_RO(power_off_acct);
+#endif /* CONFIG_PM */
+
+#define CODEC_INFO_SHOW(type)                                  \
+static ssize_t type##_show(struct device *dev,                 \
+                          struct device_attribute *attr,       \
+                          char *buf)                           \
+{                                                              \
+       struct hda_codec *codec = dev_get_drvdata(dev);         \
+       return sprintf(buf, "0x%x\n", codec->type);             \
+}
+
+#define CODEC_INFO_STR_SHOW(type)                              \
+static ssize_t type##_show(struct device *dev,                 \
+                            struct device_attribute *attr,     \
+                                       char *buf)              \
+{                                                              \
+       struct hda_codec *codec = dev_get_drvdata(dev);         \
+       return sprintf(buf, "%s\n",                             \
+                      codec->type ? codec->type : "");         \
+}
+
+CODEC_INFO_SHOW(vendor_id);
+CODEC_INFO_SHOW(subsystem_id);
+CODEC_INFO_SHOW(revision_id);
+CODEC_INFO_SHOW(afg);
+CODEC_INFO_SHOW(mfg);
+CODEC_INFO_STR_SHOW(vendor_name);
+CODEC_INFO_STR_SHOW(chip_name);
+CODEC_INFO_STR_SHOW(modelname);
+
+static ssize_t pin_configs_show(struct hda_codec *codec,
+                               struct snd_array *list,
+                               char *buf)
+{
+       int i, len = 0;
+       mutex_lock(&codec->user_mutex);
+       for (i = 0; i < list->used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(list, i);
+               len += sprintf(buf + len, "0x%02x 0x%08x\n",
+                              pin->nid, pin->cfg);
+       }
+       mutex_unlock(&codec->user_mutex);
+       return len;
+}
+
+static ssize_t init_pin_configs_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       return pin_configs_show(codec, &codec->init_pins, buf);
+}
+
+static ssize_t driver_pin_configs_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       return pin_configs_show(codec, &codec->driver_pins, buf);
+}
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+
+/*
+ * sysfs interface
+ */
+
+static int clear_codec(struct hda_codec *codec)
+{
+       int err;
+
+       err = snd_hda_codec_reset(codec);
+       if (err < 0) {
+               codec_err(codec, "The codec is being used, can't free.\n");
+               return err;
+       }
+       snd_hda_sysfs_clear(codec);
+       return 0;
+}
+
+static int reconfig_codec(struct hda_codec *codec)
+{
+       int err;
+
+       snd_hda_power_up(codec);
+       codec_info(codec, "hda-codec: reconfiguring\n");
+       err = snd_hda_codec_reset(codec);
+       if (err < 0) {
+               codec_err(codec,
+                          "The codec is being used, can't reconfigure.\n");
+               goto error;
+       }
+       err = snd_hda_codec_configure(codec);
+       if (err < 0)
+               goto error;
+       /* rebuild PCMs */
+       err = snd_hda_codec_build_pcms(codec);
+       if (err < 0)
+               goto error;
+       /* rebuild mixers */
+       err = snd_hda_codec_build_controls(codec);
+       if (err < 0)
+               goto error;
+       err = snd_card_register(codec->bus->card);
+ error:
+       snd_hda_power_down(codec);
+       return err;
+}
+
+/*
+ * allocate a string at most len chars, and remove the trailing EOL
+ */
+static char *kstrndup_noeol(const char *src, size_t len)
+{
+       char *s = kstrndup(src, len, GFP_KERNEL);
+       char *p;
+       if (!s)
+               return NULL;
+       p = strchr(s, '\n');
+       if (p)
+               *p = 0;
+       return s;
+}
+
+#define CODEC_INFO_STORE(type)                                 \
+static ssize_t type##_store(struct device *dev,                        \
+                           struct device_attribute *attr,      \
+                           const char *buf, size_t count)      \
+{                                                              \
+       struct hda_codec *codec = dev_get_drvdata(dev);         \
+       unsigned long val;                                      \
+       int err = kstrtoul(buf, 0, &val);                       \
+       if (err < 0)                                            \
+               return err;                                     \
+       codec->type = val;                                      \
+       return count;                                           \
+}
+
+#define CODEC_INFO_STR_STORE(type)                             \
+static ssize_t type##_store(struct device *dev,                        \
+                           struct device_attribute *attr,      \
+                           const char *buf, size_t count)      \
+{                                                              \
+       struct hda_codec *codec = dev_get_drvdata(dev);         \
+       char *s = kstrndup_noeol(buf, 64);                      \
+       if (!s)                                                 \
+               return -ENOMEM;                                 \
+       kfree(codec->type);                                     \
+       codec->type = s;                                        \
+       return count;                                           \
+}
+
+CODEC_INFO_STORE(vendor_id);
+CODEC_INFO_STORE(subsystem_id);
+CODEC_INFO_STORE(revision_id);
+CODEC_INFO_STR_STORE(vendor_name);
+CODEC_INFO_STR_STORE(chip_name);
+CODEC_INFO_STR_STORE(modelname);
+
+#define CODEC_ACTION_STORE(type)                               \
+static ssize_t type##_store(struct device *dev,                        \
+                           struct device_attribute *attr,      \
+                           const char *buf, size_t count)      \
+{                                                              \
+       struct hda_codec *codec = dev_get_drvdata(dev);         \
+       int err = 0;                                            \
+       if (*buf)                                               \
+               err = type##_codec(codec);                      \
+       return err < 0 ? err : count;                           \
+}
+
+CODEC_ACTION_STORE(reconfig);
+CODEC_ACTION_STORE(clear);
+
+static ssize_t init_verbs_show(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       int i, len = 0;
+       mutex_lock(&codec->user_mutex);
+       for (i = 0; i < codec->init_verbs.used; i++) {
+               struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "0x%02x 0x%03x 0x%04x\n",
+                               v->nid, v->verb, v->param);
+       }
+       mutex_unlock(&codec->user_mutex);
+       return len;
+}
+
+static int parse_init_verbs(struct hda_codec *codec, const char *buf)
+{
+       struct hda_verb *v;
+       int nid, verb, param;
+
+       if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
+               return -EINVAL;
+       if (!nid || !verb)
+               return -EINVAL;
+       mutex_lock(&codec->user_mutex);
+       v = snd_array_new(&codec->init_verbs);
+       if (!v) {
+               mutex_unlock(&codec->user_mutex);
+               return -ENOMEM;
+       }
+       v->nid = nid;
+       v->verb = verb;
+       v->param = param;
+       mutex_unlock(&codec->user_mutex);
+       return 0;
+}
+
+static ssize_t init_verbs_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       int err = parse_init_verbs(codec, buf);
+       if (err < 0)
+               return err;
+       return count;
+}
+
+static ssize_t hints_show(struct device *dev,
+                         struct device_attribute *attr,
+                         char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       int i, len = 0;
+       mutex_lock(&codec->user_mutex);
+       for (i = 0; i < codec->hints.used; i++) {
+               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "%s = %s\n", hint->key, hint->val);
+       }
+       mutex_unlock(&codec->user_mutex);
+       return len;
+}
+
+static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
+{
+       int i;
+
+       for (i = 0; i < codec->hints.used; i++) {
+               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+               if (!strcmp(hint->key, key))
+                       return hint;
+       }
+       return NULL;
+}
+
+static void remove_trail_spaces(char *str)
+{
+       char *p;
+       if (!*str)
+               return;
+       p = str + strlen(str) - 1;
+       for (; isspace(*p); p--) {
+               *p = 0;
+               if (p == str)
+                       return;
+       }
+}
+
+#define MAX_HINTS      1024
+
+static int parse_hints(struct hda_codec *codec, const char *buf)
+{
+       char *key, *val;
+       struct hda_hint *hint;
+       int err = 0;
+
+       buf = skip_spaces(buf);
+       if (!*buf || *buf == '#' || *buf == '\n')
+               return 0;
+       if (*buf == '=')
+               return -EINVAL;
+       key = kstrndup_noeol(buf, 1024);
+       if (!key)
+               return -ENOMEM;
+       /* extract key and val */
+       val = strchr(key, '=');
+       if (!val) {
+               kfree(key);
+               return -EINVAL;
+       }
+       *val++ = 0;
+       val = skip_spaces(val);
+       remove_trail_spaces(key);
+       remove_trail_spaces(val);
+       mutex_lock(&codec->user_mutex);
+       hint = get_hint(codec, key);
+       if (hint) {
+               /* replace */
+               kfree(hint->key);
+               hint->key = key;
+               hint->val = val;
+               goto unlock;
+       }
+       /* allocate a new hint entry */
+       if (codec->hints.used >= MAX_HINTS)
+               hint = NULL;
+       else
+               hint = snd_array_new(&codec->hints);
+       if (hint) {
+               hint->key = key;
+               hint->val = val;
+       } else {
+               err = -ENOMEM;
+       }
+ unlock:
+       mutex_unlock(&codec->user_mutex);
+       if (err)
+               kfree(key);
+       return err;
+}
+
+static ssize_t hints_store(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       int err = parse_hints(codec, buf);
+       if (err < 0)
+               return err;
+       return count;
+}
+
+static ssize_t user_pin_configs_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       return pin_configs_show(codec, &codec->user_pins, buf);
+}
+
+#define MAX_PIN_CONFIGS                32
+
+static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
+{
+       int nid, cfg, err;
+
+       if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
+               return -EINVAL;
+       if (!nid)
+               return -EINVAL;
+       mutex_lock(&codec->user_mutex);
+       err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
+       mutex_unlock(&codec->user_mutex);
+       return err;
+}
+
+static ssize_t user_pin_configs_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct hda_codec *codec = dev_get_drvdata(dev);
+       int err = parse_user_pin_configs(codec, buf);
+       if (err < 0)
+               return err;
+       return count;
+}
+
+/* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
+static DEVICE_ATTR_RW(init_verbs);
+static DEVICE_ATTR_RW(hints);
+static DEVICE_ATTR_RW(user_pin_configs);
+static DEVICE_ATTR_WO(reconfig);
+static DEVICE_ATTR_WO(clear);
+
+/*
+ * Look for hint string
+ */
+const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
+{
+       struct hda_hint *hint = get_hint(codec, key);
+       return hint ? hint->val : NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_hint);
+
+int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
+{
+       const char *p;
+       int ret;
+
+       mutex_lock(&codec->user_mutex);
+       p = snd_hda_get_hint(codec, key);
+       if (!p || !*p)
+               ret = -ENOENT;
+       else {
+               switch (toupper(*p)) {
+               case 'T': /* true */
+               case 'Y': /* yes */
+               case '1':
+                       ret = 1;
+                       break;
+               default:
+                       ret = 0;
+                       break;
+               }
+       }
+       mutex_unlock(&codec->user_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
+
+int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
+{
+       const char *p;
+       unsigned long val;
+       int ret;
+
+       mutex_lock(&codec->user_mutex);
+       p = snd_hda_get_hint(codec, key);
+       if (!p)
+               ret = -ENOENT;
+       else if (kstrtoul(p, 0, &val))
+               ret = -EINVAL;
+       else {
+               *valp = val;
+               ret = 0;
+       }
+       mutex_unlock(&codec->user_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
+#endif /* CONFIG_SND_HDA_RECONFIG */
+
+/*
+ * common sysfs attributes
+ */
+#ifdef CONFIG_SND_HDA_RECONFIG
+#define RECONFIG_DEVICE_ATTR(name)     DEVICE_ATTR_RW(name)
+#else
+#define RECONFIG_DEVICE_ATTR(name)     DEVICE_ATTR_RO(name)
+#endif
+static RECONFIG_DEVICE_ATTR(vendor_id);
+static RECONFIG_DEVICE_ATTR(subsystem_id);
+static RECONFIG_DEVICE_ATTR(revision_id);
+static DEVICE_ATTR_RO(afg);
+static DEVICE_ATTR_RO(mfg);
+static RECONFIG_DEVICE_ATTR(vendor_name);
+static RECONFIG_DEVICE_ATTR(chip_name);
+static RECONFIG_DEVICE_ATTR(modelname);
+static DEVICE_ATTR_RO(init_pin_configs);
+static DEVICE_ATTR_RO(driver_pin_configs);
+
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+
+/* parser mode */
+enum {
+       LINE_MODE_NONE,
+       LINE_MODE_CODEC,
+       LINE_MODE_MODEL,
+       LINE_MODE_PINCFG,
+       LINE_MODE_VERB,
+       LINE_MODE_HINT,
+       LINE_MODE_VENDOR_ID,
+       LINE_MODE_SUBSYSTEM_ID,
+       LINE_MODE_REVISION_ID,
+       LINE_MODE_CHIP_NAME,
+       NUM_LINE_MODES,
+};
+
+static inline int strmatch(const char *a, const char *b)
+{
+       return strnicmp(a, b, strlen(b)) == 0;
+}
+
+/* parse the contents after the line "[codec]"
+ * accept only the line with three numbers, and assign the current codec
+ */
+static void parse_codec_mode(char *buf, struct hda_bus *bus,
+                            struct hda_codec **codecp)
+{
+       int vendorid, subid, caddr;
+       struct hda_codec *codec;
+
+       *codecp = NULL;
+       if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
+               list_for_each_entry(codec, &bus->codec_list, list) {
+                       if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
+                           (subid <= 0 || codec->subsystem_id == subid) &&
+                           codec->addr == caddr) {
+                               *codecp = codec;
+                               break;
+                       }
+               }
+       }
+}
+
+/* parse the contents after the other command tags, [pincfg], [verb],
+ * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
+ * just pass to the sysfs helper (only when any codec was specified)
+ */
+static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
+                             struct hda_codec **codecp)
+{
+       parse_user_pin_configs(*codecp, buf);
+}
+
+static void parse_verb_mode(char *buf, struct hda_bus *bus,
+                           struct hda_codec **codecp)
+{
+       parse_init_verbs(*codecp, buf);
+}
+
+static void parse_hint_mode(char *buf, struct hda_bus *bus,
+                           struct hda_codec **codecp)
+{
+       parse_hints(*codecp, buf);
+}
+
+static void parse_model_mode(char *buf, struct hda_bus *bus,
+                            struct hda_codec **codecp)
+{
+       kfree((*codecp)->modelname);
+       (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
+}
+
+static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
+                                struct hda_codec **codecp)
+{
+       kfree((*codecp)->chip_name);
+       (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
+}
+
+#define DEFINE_PARSE_ID_MODE(name) \
+static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
+                                struct hda_codec **codecp) \
+{ \
+       unsigned long val; \
+       if (!kstrtoul(buf, 0, &val)) \
+               (*codecp)->name = val; \
+}
+
+DEFINE_PARSE_ID_MODE(vendor_id);
+DEFINE_PARSE_ID_MODE(subsystem_id);
+DEFINE_PARSE_ID_MODE(revision_id);
+
+
+struct hda_patch_item {
+       const char *tag;
+       const char *alias;
+       void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
+};
+
+static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
+       [LINE_MODE_CODEC] = {
+               .tag = "[codec]",
+               .parser = parse_codec_mode,
+       },
+       [LINE_MODE_MODEL] = {
+               .tag = "[model]",
+               .parser = parse_model_mode,
+       },
+       [LINE_MODE_VERB] = {
+               .tag = "[verb]",
+               .alias = "[init_verbs]",
+               .parser = parse_verb_mode,
+       },
+       [LINE_MODE_PINCFG] = {
+               .tag = "[pincfg]",
+               .alias = "[user_pin_configs]",
+               .parser = parse_pincfg_mode,
+       },
+       [LINE_MODE_HINT] = {
+               .tag = "[hint]",
+               .alias = "[hints]",
+               .parser = parse_hint_mode
+       },
+       [LINE_MODE_VENDOR_ID] = {
+               .tag = "[vendor_id]",
+               .parser = parse_vendor_id_mode,
+       },
+       [LINE_MODE_SUBSYSTEM_ID] = {
+               .tag = "[subsystem_id]",
+               .parser = parse_subsystem_id_mode,
+       },
+       [LINE_MODE_REVISION_ID] = {
+               .tag = "[revision_id]",
+               .parser = parse_revision_id_mode,
+       },
+       [LINE_MODE_CHIP_NAME] = {
+               .tag = "[chip_name]",
+               .parser = parse_chip_name_mode,
+       },
+};
+
+/* check the line starting with '[' -- change the parser mode accodingly */
+static int parse_line_mode(char *buf, struct hda_bus *bus)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
+               if (!patch_items[i].tag)
+                       continue;
+               if (strmatch(buf, patch_items[i].tag))
+                       return i;
+               if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
+                       return i;
+       }
+       return LINE_MODE_NONE;
+}
+
+/* copy one line from the buffer in fw, and update the fields in fw
+ * return zero if it reaches to the end of the buffer, or non-zero
+ * if successfully copied a line
+ *
+ * the spaces at the beginning and the end of the line are stripped
+ */
+static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
+                           const void **fw_data_p)
+{
+       int len;
+       size_t fw_size = *fw_size_p;
+       const char *p = *fw_data_p;
+
+       while (isspace(*p) && fw_size) {
+               p++;
+               fw_size--;
+       }
+       if (!fw_size)
+               return 0;
+
+       for (len = 0; len < fw_size; len++) {
+               if (!*p)
+                       break;
+               if (*p == '\n') {
+                       p++;
+                       len++;
+                       break;
+               }
+               if (len < size)
+                       *buf++ = *p++;
+       }
+       *buf = 0;
+       *fw_size_p = fw_size - len;
+       *fw_data_p = p;
+       remove_trail_spaces(buf);
+       return 1;
+}
+
+/*
+ * load a "patch" firmware file and parse it
+ */
+int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
+{
+       char buf[128];
+       struct hda_codec *codec;
+       int line_mode;
+
+       line_mode = LINE_MODE_NONE;
+       codec = NULL;
+       while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
+               if (!*buf || *buf == '#' || *buf == '\n')
+                       continue;
+               if (*buf == '[')
+                       line_mode = parse_line_mode(buf, bus);
+               else if (patch_items[line_mode].parser &&
+                        (codec || line_mode <= LINE_MODE_CODEC))
+                       patch_items[line_mode].parser(buf, bus, &codec);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_load_patch);
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+
+/*
+ * sysfs entries
+ */
+static struct attribute *hda_dev_attrs[] = {
+       &dev_attr_vendor_id.attr,
+       &dev_attr_subsystem_id.attr,
+       &dev_attr_revision_id.attr,
+       &dev_attr_afg.attr,
+       &dev_attr_mfg.attr,
+       &dev_attr_vendor_name.attr,
+       &dev_attr_chip_name.attr,
+       &dev_attr_modelname.attr,
+       &dev_attr_init_pin_configs.attr,
+       &dev_attr_driver_pin_configs.attr,
+#ifdef CONFIG_PM
+       &dev_attr_power_on_acct.attr,
+       &dev_attr_power_off_acct.attr,
+#endif
+#ifdef CONFIG_SND_HDA_RECONFIG
+       &dev_attr_init_verbs.attr,
+       &dev_attr_hints.attr,
+       &dev_attr_user_pin_configs.attr,
+       &dev_attr_reconfig.attr,
+       &dev_attr_clear.attr,
+#endif
+       NULL
+};
+
+static struct attribute_group hda_dev_attr_group = {
+       .attrs  = hda_dev_attrs,
+};
+
+const struct attribute_group *snd_hda_dev_attr_groups[] = {
+       &hda_dev_attr_group,
+       NULL
+};
+
+void snd_hda_sysfs_init(struct hda_codec *codec)
+{
+       mutex_init(&codec->user_mutex);
+#ifdef CONFIG_SND_HDA_RECONFIG
+       snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
+       snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
+       snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
+#endif
+}
+
+void snd_hda_sysfs_clear(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_HDA_RECONFIG
+       int i;
+
+       /* clear init verbs */
+       snd_array_free(&codec->init_verbs);
+       /* clear hints */
+       for (i = 0; i < codec->hints.used; i++) {
+               struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+               kfree(hint->key); /* we don't need to free hint->val */
+       }
+       snd_array_free(&codec->hints);
+       snd_array_free(&codec->user_pins);
+#endif
+}
index df3652ad15ef36224fdbc121ee1018116bab28c0..40ba06eb44af47651b510c8f7dbad6cd214ce165 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/module.h>
 
 #include <sound/core.h>
@@ -1026,6 +1025,9 @@ static void ad1884_fixup_thinkpad(struct hda_codec *codec,
                spec->gen.keep_eapd_on = 1;
                spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
                spec->eapd_nid = 0x12;
+               /* Analog PC Beeper - allow firmware/ACPI beeps */
+               spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
+               spec->gen.beep_nid = 0; /* no digital beep */
        }
 }
 
@@ -1092,6 +1094,7 @@ static int patch_ad1884(struct hda_codec *codec)
        spec = codec->spec;
 
        spec->gen.mixer_nid = 0x20;
+       spec->gen.mixer_merge_nid = 0x21;
        spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 
index 30b3a4bc06eef1739c64d85e8e3d67c2a6154c38..5e65999e0d8e6a410061fe87fd287bd695b7305e 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include "hda_codec.h"
index 46ecdbb9053f337ee6f1b199d9babdeb043d72d5..092f2bd030bdc51cf93265dab1e7dc93fb6908df 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/firmware.h>
@@ -868,7 +867,7 @@ static int chipio_write_data_multiple(struct hda_codec *codec,
        int status = 0;
 
        if (data == NULL) {
-               snd_printdd(KERN_ERR "chipio_write_data null ptr\n");
+               codec_dbg(codec, "chipio_write_data null ptr\n");
                return -EINVAL;
        }
 
@@ -1407,12 +1406,12 @@ static int dspio_scp(struct hda_codec *codec,
                return -EINVAL;
 
        if (dir == SCP_GET && reply == NULL) {
-               snd_printdd(KERN_ERR "dspio_scp get but has no buffer\n");
+               codec_dbg(codec, "dspio_scp get but has no buffer\n");
                return -EINVAL;
        }
 
        if (reply != NULL && (reply_len == NULL || (*reply_len == 0))) {
-               snd_printdd(KERN_ERR "dspio_scp bad resp buf len parms\n");
+               codec_dbg(codec, "dspio_scp bad resp buf len parms\n");
                return -EINVAL;
        }
 
@@ -1430,7 +1429,7 @@ static int dspio_scp(struct hda_codec *codec,
                                        sizeof(scp_reply), &ret_bytes);
 
        if (status < 0) {
-               snd_printdd(KERN_ERR "dspio_scp: send scp msg failed\n");
+               codec_dbg(codec, "dspio_scp: send scp msg failed\n");
                return status;
        }
 
@@ -1449,17 +1448,17 @@ static int dspio_scp(struct hda_codec *codec,
                                        / sizeof(unsigned int);
 
                if (*reply_len < ret_size*sizeof(unsigned int)) {
-                       snd_printdd(KERN_ERR "reply too long for buf\n");
+                       codec_dbg(codec, "reply too long for buf\n");
                        return -EINVAL;
                } else if (ret_size != reply_data_size) {
-                       snd_printdd(KERN_ERR "RetLen and HdrLen .NE.\n");
+                       codec_dbg(codec, "RetLen and HdrLen .NE.\n");
                        return -EINVAL;
                } else {
                        *reply_len = ret_size*sizeof(unsigned int);
                        memcpy(reply, scp_reply.data, *reply_len);
                }
        } else {
-               snd_printdd(KERN_ERR "reply ill-formed or errflag set\n");
+               codec_dbg(codec, "reply ill-formed or errflag set\n");
                return -EIO;
        }
 
@@ -1489,22 +1488,22 @@ static int dspio_alloc_dma_chan(struct hda_codec *codec, unsigned int *dma_chan)
        int status = 0;
        unsigned int size = sizeof(dma_chan);
 
-       snd_printdd(KERN_INFO "     dspio_alloc_dma_chan() -- begin\n");
+       codec_dbg(codec, "     dspio_alloc_dma_chan() -- begin\n");
        status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN,
                        SCP_GET, NULL, 0, dma_chan, &size);
 
        if (status < 0) {
-               snd_printdd(KERN_INFO "dspio_alloc_dma_chan: SCP Failed\n");
+               codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n");
                return status;
        }
 
        if ((*dma_chan + 1) == 0) {
-               snd_printdd(KERN_INFO "no free dma channels to allocate\n");
+               codec_dbg(codec, "no free dma channels to allocate\n");
                return -EBUSY;
        }
 
-       snd_printdd("dspio_alloc_dma_chan: chan=%d\n", *dma_chan);
-       snd_printdd(KERN_INFO "     dspio_alloc_dma_chan() -- complete\n");
+       codec_dbg(codec, "dspio_alloc_dma_chan: chan=%d\n", *dma_chan);
+       codec_dbg(codec, "     dspio_alloc_dma_chan() -- complete\n");
 
        return status;
 }
@@ -1517,18 +1516,18 @@ static int dspio_free_dma_chan(struct hda_codec *codec, unsigned int dma_chan)
        int status = 0;
        unsigned int dummy = 0;
 
-       snd_printdd(KERN_INFO "     dspio_free_dma_chan() -- begin\n");
-       snd_printdd("dspio_free_dma_chan: chan=%d\n", dma_chan);
+       codec_dbg(codec, "     dspio_free_dma_chan() -- begin\n");
+       codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan);
 
        status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN,
                           SCP_SET, &dma_chan, sizeof(dma_chan), NULL, &dummy);
 
        if (status < 0) {
-               snd_printdd(KERN_INFO "dspio_free_dma_chan: SCP Failed\n");
+               codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n");
                return status;
        }
 
-       snd_printdd(KERN_INFO "     dspio_free_dma_chan() -- complete\n");
+       codec_dbg(codec, "     dspio_free_dma_chan() -- complete\n");
 
        return status;
 }
@@ -1576,14 +1575,14 @@ static int dsp_reset(struct hda_codec *codec)
        unsigned int res;
        int retry = 20;
 
-       snd_printdd("dsp_reset\n");
+       codec_dbg(codec, "dsp_reset\n");
        do {
                res = dspio_send(codec, VENDOR_DSPIO_DSP_INIT, 0);
                retry--;
        } while (res == -EIO && retry);
 
        if (!retry) {
-               snd_printdd("dsp_reset timeout\n");
+               codec_dbg(codec, "dsp_reset timeout\n");
                return -EIO;
        }
 
@@ -1636,39 +1635,39 @@ static int dsp_dma_setup_common(struct hda_codec *codec,
        unsigned int active;
        bool code, yram;
 
-       snd_printdd(KERN_INFO "-- dsp_dma_setup_common() -- Begin ---------\n");
+       codec_dbg(codec, "-- dsp_dma_setup_common() -- Begin ---------\n");
 
        if (dma_chan >= DSPDMAC_DMA_CFG_CHANNEL_COUNT) {
-               snd_printdd(KERN_ERR "dma chan num invalid\n");
+               codec_dbg(codec, "dma chan num invalid\n");
                return -EINVAL;
        }
 
        if (dsp_is_dma_active(codec, dma_chan)) {
-               snd_printdd(KERN_ERR "dma already active\n");
+               codec_dbg(codec, "dma already active\n");
                return -EBUSY;
        }
 
        dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
 
        if (dsp_addx == INVALID_CHIP_ADDRESS) {
-               snd_printdd(KERN_ERR "invalid chip addr\n");
+               codec_dbg(codec, "invalid chip addr\n");
                return -ENXIO;
        }
 
        chnl_prop = DSPDMAC_CHNLPROP_AC_MASK;
        active = 0;
 
-       snd_printdd(KERN_INFO "   dsp_dma_setup_common()    start reg pgm\n");
+       codec_dbg(codec, "   dsp_dma_setup_common()    start reg pgm\n");
 
        if (ovly) {
                status = chipio_read(codec, DSPDMAC_CHNLPROP_INST_OFFSET,
                                     &chnl_prop);
 
                if (status < 0) {
-                       snd_printdd(KERN_ERR "read CHNLPROP Reg fail\n");
+                       codec_dbg(codec, "read CHNLPROP Reg fail\n");
                        return status;
                }
-               snd_printdd(KERN_INFO "dsp_dma_setup_common() Read CHNLPROP\n");
+               codec_dbg(codec, "dsp_dma_setup_common() Read CHNLPROP\n");
        }
 
        if (!code)
@@ -1680,20 +1679,20 @@ static int dsp_dma_setup_common(struct hda_codec *codec,
 
        status = chipio_write(codec, DSPDMAC_CHNLPROP_INST_OFFSET, chnl_prop);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write CHNLPROP Reg fail\n");
+               codec_dbg(codec, "write CHNLPROP Reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "   dsp_dma_setup_common()    Write CHNLPROP\n");
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write CHNLPROP\n");
 
        if (ovly) {
                status = chipio_read(codec, DSPDMAC_ACTIVE_INST_OFFSET,
                                     &active);
 
                if (status < 0) {
-                       snd_printdd(KERN_ERR "read ACTIVE Reg fail\n");
+                       codec_dbg(codec, "read ACTIVE Reg fail\n");
                        return status;
                }
-               snd_printdd(KERN_INFO "dsp_dma_setup_common() Read ACTIVE\n");
+               codec_dbg(codec, "dsp_dma_setup_common() Read ACTIVE\n");
        }
 
        active &= (~(1 << (DSPDMAC_ACTIVE_AAR_LOBIT + dma_chan))) &
@@ -1701,35 +1700,35 @@ static int dsp_dma_setup_common(struct hda_codec *codec,
 
        status = chipio_write(codec, DSPDMAC_ACTIVE_INST_OFFSET, active);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write ACTIVE Reg fail\n");
+               codec_dbg(codec, "write ACTIVE Reg fail\n");
                return status;
        }
 
-       snd_printdd(KERN_INFO "   dsp_dma_setup_common()    Write ACTIVE\n");
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write ACTIVE\n");
 
        status = chipio_write(codec, DSPDMAC_AUDCHSEL_INST_OFFSET(dma_chan),
                              port_map_mask);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write AUDCHSEL Reg fail\n");
+               codec_dbg(codec, "write AUDCHSEL Reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "   dsp_dma_setup_common()    Write AUDCHSEL\n");
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write AUDCHSEL\n");
 
        status = chipio_write(codec, DSPDMAC_IRQCNT_INST_OFFSET(dma_chan),
                        DSPDMAC_IRQCNT_BICNT_MASK | DSPDMAC_IRQCNT_CICNT_MASK);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write IRQCNT Reg fail\n");
+               codec_dbg(codec, "write IRQCNT Reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "   dsp_dma_setup_common()    Write IRQCNT\n");
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write IRQCNT\n");
 
-       snd_printdd(
+       codec_dbg(codec,
                   "ChipA=0x%x,DspA=0x%x,dmaCh=%u, "
                   "CHSEL=0x%x,CHPROP=0x%x,Active=0x%x\n",
                   chip_addx, dsp_addx, dma_chan,
                   port_map_mask, chnl_prop, active);
 
-       snd_printdd(KERN_INFO "-- dsp_dma_setup_common() -- Complete ------\n");
+       codec_dbg(codec, "-- dsp_dma_setup_common() -- Complete ------\n");
 
        return 0;
 }
@@ -1755,20 +1754,20 @@ static int dsp_dma_setup(struct hda_codec *codec,
        const unsigned int max_dma_count = 1 << (DSPDMAC_XFRCNT_BCNT_HIBIT -
                                                DSPDMAC_XFRCNT_BCNT_LOBIT + 1);
 
-       snd_printdd(KERN_INFO "-- dsp_dma_setup() -- Begin ---------\n");
+       codec_dbg(codec, "-- dsp_dma_setup() -- Begin ---------\n");
 
        if (count > max_dma_count) {
-               snd_printdd(KERN_ERR "count too big\n");
+               codec_dbg(codec, "count too big\n");
                return -EINVAL;
        }
 
        dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
        if (dsp_addx == INVALID_CHIP_ADDRESS) {
-               snd_printdd(KERN_ERR "invalid chip addr\n");
+               codec_dbg(codec, "invalid chip addr\n");
                return -ENXIO;
        }
 
-       snd_printdd(KERN_INFO "   dsp_dma_setup()    start reg pgm\n");
+       codec_dbg(codec, "   dsp_dma_setup()    start reg pgm\n");
 
        addr_field = dsp_addx << DSPDMAC_DMACFG_DBADR_LOBIT;
        incr_field   = 0;
@@ -1785,10 +1784,10 @@ static int dsp_dma_setup(struct hda_codec *codec,
        status = chipio_write(codec, DSPDMAC_DMACFG_INST_OFFSET(dma_chan),
                                dma_cfg);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write DMACFG Reg fail\n");
+               codec_dbg(codec, "write DMACFG Reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "   dsp_dma_setup()    Write DMACFG\n");
+       codec_dbg(codec, "   dsp_dma_setup()    Write DMACFG\n");
 
        adr_ofs = (count - 1) << (DSPDMAC_DSPADROFS_BOFS_LOBIT +
                                                        (code ? 0 : 1));
@@ -1796,10 +1795,10 @@ static int dsp_dma_setup(struct hda_codec *codec,
        status = chipio_write(codec, DSPDMAC_DSPADROFS_INST_OFFSET(dma_chan),
                                adr_ofs);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write DSPADROFS Reg fail\n");
+               codec_dbg(codec, "write DSPADROFS Reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "   dsp_dma_setup()    Write DSPADROFS\n");
+       codec_dbg(codec, "   dsp_dma_setup()    Write DSPADROFS\n");
 
        base_cnt = (count - 1) << DSPDMAC_XFRCNT_BCNT_LOBIT;
 
@@ -1810,17 +1809,17 @@ static int dsp_dma_setup(struct hda_codec *codec,
        status = chipio_write(codec,
                                DSPDMAC_XFRCNT_INST_OFFSET(dma_chan), xfr_cnt);
        if (status < 0) {
-               snd_printdd(KERN_ERR "write XFRCNT Reg fail\n");
+               codec_dbg(codec, "write XFRCNT Reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "   dsp_dma_setup()    Write XFRCNT\n");
+       codec_dbg(codec, "   dsp_dma_setup()    Write XFRCNT\n");
 
-       snd_printdd(
+       codec_dbg(codec,
                   "ChipA=0x%x, cnt=0x%x, DMACFG=0x%x, "
                   "ADROFS=0x%x, XFRCNT=0x%x\n",
                   chip_addx, count, dma_cfg, adr_ofs, xfr_cnt);
 
-       snd_printdd(KERN_INFO "-- dsp_dma_setup() -- Complete ---------\n");
+       codec_dbg(codec, "-- dsp_dma_setup() -- Complete ---------\n");
 
        return 0;
 }
@@ -1834,17 +1833,17 @@ static int dsp_dma_start(struct hda_codec *codec,
        unsigned int reg = 0;
        int status = 0;
 
-       snd_printdd(KERN_INFO "-- dsp_dma_start() -- Begin ---------\n");
+       codec_dbg(codec, "-- dsp_dma_start() -- Begin ---------\n");
 
        if (ovly) {
                status = chipio_read(codec,
                                     DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
 
                if (status < 0) {
-                       snd_printdd(KERN_ERR "read CHNLSTART reg fail\n");
+                       codec_dbg(codec, "read CHNLSTART reg fail\n");
                        return status;
                }
-               snd_printdd(KERN_INFO "-- dsp_dma_start()    Read CHNLSTART\n");
+               codec_dbg(codec, "-- dsp_dma_start()    Read CHNLSTART\n");
 
                reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
                                DSPDMAC_CHNLSTART_DIS_MASK);
@@ -1853,10 +1852,10 @@ static int dsp_dma_start(struct hda_codec *codec,
        status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
                        reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_EN_LOBIT)));
        if (status < 0) {
-               snd_printdd(KERN_ERR "write CHNLSTART reg fail\n");
+               codec_dbg(codec, "write CHNLSTART reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "-- dsp_dma_start() -- Complete ---------\n");
+       codec_dbg(codec, "-- dsp_dma_start() -- Complete ---------\n");
 
        return status;
 }
@@ -1870,17 +1869,17 @@ static int dsp_dma_stop(struct hda_codec *codec,
        unsigned int reg = 0;
        int status = 0;
 
-       snd_printdd(KERN_INFO "-- dsp_dma_stop() -- Begin ---------\n");
+       codec_dbg(codec, "-- dsp_dma_stop() -- Begin ---------\n");
 
        if (ovly) {
                status = chipio_read(codec,
                                     DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
 
                if (status < 0) {
-                       snd_printdd(KERN_ERR "read CHNLSTART reg fail\n");
+                       codec_dbg(codec, "read CHNLSTART reg fail\n");
                        return status;
                }
-               snd_printdd(KERN_INFO "-- dsp_dma_stop()    Read CHNLSTART\n");
+               codec_dbg(codec, "-- dsp_dma_stop()    Read CHNLSTART\n");
                reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
                                DSPDMAC_CHNLSTART_DIS_MASK);
        }
@@ -1888,10 +1887,10 @@ static int dsp_dma_stop(struct hda_codec *codec,
        status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
                        reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_DIS_LOBIT)));
        if (status < 0) {
-               snd_printdd(KERN_ERR "write CHNLSTART reg fail\n");
+               codec_dbg(codec, "write CHNLSTART reg fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "-- dsp_dma_stop() -- Complete ---------\n");
+       codec_dbg(codec, "-- dsp_dma_stop() -- Complete ---------\n");
 
        return status;
 }
@@ -1974,17 +1973,17 @@ static int dsp_allocate_ports(struct hda_codec *codec,
 {
        int status;
 
-       snd_printdd(KERN_INFO "     dsp_allocate_ports() -- begin\n");
+       codec_dbg(codec, "     dsp_allocate_ports() -- begin\n");
 
        if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
-               snd_printdd(KERN_ERR "bad rate multiple\n");
+               codec_dbg(codec, "bad rate multiple\n");
                return -EINVAL;
        }
 
        status = dsp_allocate_router_ports(codec, num_chans,
                                           rate_multi, 0, port_map);
 
-       snd_printdd(KERN_INFO "     dsp_allocate_ports() -- complete\n");
+       codec_dbg(codec, "     dsp_allocate_ports() -- complete\n");
 
        return status;
 }
@@ -2001,7 +2000,7 @@ static int dsp_allocate_ports_format(struct hda_codec *codec,
        unsigned int rate_multi = sample_rate_mul / sample_rate_div;
 
        if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
-               snd_printdd(KERN_ERR "bad rate multiple\n");
+               codec_dbg(codec, "bad rate multiple\n");
                return -EINVAL;
        }
 
@@ -2019,14 +2018,14 @@ static int dsp_free_ports(struct hda_codec *codec)
 {
        int status;
 
-       snd_printdd(KERN_INFO "     dsp_free_ports() -- begin\n");
+       codec_dbg(codec, "     dsp_free_ports() -- begin\n");
 
        status = dsp_free_router_ports(codec);
        if (status < 0) {
-               snd_printdd(KERN_ERR "free router ports fail\n");
+               codec_dbg(codec, "free router ports fail\n");
                return status;
        }
-       snd_printdd(KERN_INFO "     dsp_free_ports() -- complete\n");
+       codec_dbg(codec, "     dsp_free_ports() -- complete\n");
 
        return status;
 }
@@ -2092,8 +2091,6 @@ static int dma_set_state(struct dma_engine *dma, enum dma_state state)
 {
        bool cmd;
 
-       snd_printdd("dma_set_state state=%d\n", state);
-
        switch (state) {
        case DMA_STATE_STOP:
                cmd = false;
@@ -2196,7 +2193,7 @@ static int dspxfr_hci_write(struct hda_codec *codec,
        unsigned int count;
 
        if (fls == NULL || fls->chip_addr != g_chip_addr_magic_value) {
-               snd_printdd(KERN_ERR "hci_write invalid params\n");
+               codec_dbg(codec, "hci_write invalid params\n");
                return -EINVAL;
        }
 
@@ -2205,7 +2202,7 @@ static int dspxfr_hci_write(struct hda_codec *codec,
        while (count >= 2) {
                status = chipio_write(codec, data[0], data[1]);
                if (status < 0) {
-                       snd_printdd(KERN_ERR "hci_write chipio failed\n");
+                       codec_dbg(codec, "hci_write chipio failed\n");
                        return status;
                }
                count -= 2;
@@ -2265,12 +2262,12 @@ static int dspxfr_one_seg(struct hda_codec *codec,
        }
 
        if (hci_write && (!fls || is_last(fls))) {
-               snd_printdd("hci_write\n");
+               codec_dbg(codec, "hci_write\n");
                return dspxfr_hci_write(codec, hci_write);
        }
 
        if (fls == NULL || dma_engine == NULL || port_map_mask == 0) {
-               snd_printdd("Invalid Params\n");
+               codec_dbg(codec, "Invalid Params\n");
                return -EINVAL;
        }
 
@@ -2286,7 +2283,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
        if (!UC_RANGE(chip_addx, words_to_write) &&
            !X_RANGE_ALL(chip_addx, words_to_write) &&
            !Y_RANGE_ALL(chip_addx, words_to_write)) {
-               snd_printdd("Invalid chip_addx Params\n");
+               codec_dbg(codec, "Invalid chip_addx Params\n");
                return -EINVAL;
        }
 
@@ -2296,7 +2293,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
        buffer_addx = dma_get_buffer_addr(dma_engine);
 
        if (buffer_addx == NULL) {
-               snd_printdd(KERN_ERR "dma_engine buffer NULL\n");
+               codec_dbg(codec, "dma_engine buffer NULL\n");
                return -EINVAL;
        }
 
@@ -2309,7 +2306,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
                        (num_chans * sample_rate_mul / sample_rate_div));
 
        if (hda_frame_size_words == 0) {
-               snd_printdd(KERN_ERR "frmsz zero\n");
+               codec_dbg(codec, "frmsz zero\n");
                return -EINVAL;
        }
 
@@ -2317,14 +2314,14 @@ static int dspxfr_one_seg(struct hda_codec *codec,
                                (unsigned int)(UC_RANGE(chip_addx, 1) ?
                                65536 : 32768));
        buffer_size_words -= buffer_size_words % hda_frame_size_words;
-       snd_printdd(
+       codec_dbg(codec,
                   "chpadr=0x%08x frmsz=%u nchan=%u "
                   "rate_mul=%u div=%u bufsz=%u\n",
                   chip_addx, hda_frame_size_words, num_chans,
                   sample_rate_mul, sample_rate_div, buffer_size_words);
 
        if (buffer_size_words < hda_frame_size_words) {
-               snd_printdd(KERN_ERR "dspxfr_one_seg:failed\n");
+               codec_dbg(codec, "dspxfr_one_seg:failed\n");
                return -EINVAL;
        }
 
@@ -2338,7 +2335,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
 
        while (words_to_write != 0) {
                run_size_words = min(buffer_size_words, words_to_write);
-               snd_printdd("dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
+               codec_dbg(codec, "dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
                            words_to_write, run_size_words, remainder_words);
                dma_xfer(dma_engine, data, run_size_words*sizeof(u32));
                if (!comm_dma_setup_done) {
@@ -2360,7 +2357,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
                if (status < 0)
                        return status;
                if (!dsp_is_dma_active(codec, dma_chan)) {
-                       snd_printdd(KERN_ERR "dspxfr:DMA did not start\n");
+                       codec_dbg(codec, "dspxfr:DMA did not start\n");
                        return -EIO;
                }
                status = dma_set_state(dma_engine, DMA_STATE_RUN);
@@ -2392,7 +2389,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
                if (dma_active)
                        break;
 
-               snd_printdd(KERN_INFO "+++++ DMA complete\n");
+               codec_dbg(codec, "+++++ DMA complete\n");
                dma_set_state(dma_engine, DMA_STATE_STOP);
                status = dma_reset(dma_engine);
 
@@ -2466,7 +2463,7 @@ static int dspxfr_image(struct hda_codec *codec,
                                        hda_format, &response);
 
        if (status < 0) {
-               snd_printdd(KERN_ERR "set converter format fail\n");
+               codec_dbg(codec, "set converter format fail\n");
                goto exit;
        }
 
@@ -2481,7 +2478,7 @@ static int dspxfr_image(struct hda_codec *codec,
        if (ovly) {
                status = dspio_alloc_dma_chan(codec, &dma_chan);
                if (status < 0) {
-                       snd_printdd(KERN_ERR "alloc dmachan fail\n");
+                       codec_dbg(codec, "alloc dmachan fail\n");
                        dma_chan = INVALID_DMA_CHANNEL;
                        goto exit;
                }
@@ -2491,7 +2488,7 @@ static int dspxfr_image(struct hda_codec *codec,
        status = dsp_allocate_ports_format(codec, hda_format,
                                        &port_map_mask);
        if (status < 0) {
-               snd_printdd(KERN_ERR "alloc ports fail\n");
+               codec_dbg(codec, "alloc ports fail\n");
                goto exit;
        }
 
@@ -2499,13 +2496,13 @@ static int dspxfr_image(struct hda_codec *codec,
        status = codec_set_converter_stream_channel(codec,
                        WIDGET_CHIP_CTRL, stream_id, 0, &response);
        if (status < 0) {
-               snd_printdd(KERN_ERR "set stream chan fail\n");
+               codec_dbg(codec, "set stream chan fail\n");
                goto exit;
        }
 
        while ((fls_data != NULL) && !is_last(fls_data)) {
                if (!is_valid(fls_data)) {
-                       snd_printdd(KERN_ERR "FLS check fail\n");
+                       codec_dbg(codec, "FLS check fail\n");
                        status = -EINVAL;
                        goto exit;
                }
@@ -2548,7 +2545,7 @@ exit:
  */
 static void dspload_post_setup(struct hda_codec *codec)
 {
-       snd_printdd(KERN_INFO "---- dspload_post_setup ------\n");
+       codec_dbg(codec, "---- dspload_post_setup ------\n");
 
        /*set DSP speaker to 2.0 configuration*/
        chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
@@ -2586,7 +2583,7 @@ static int dspload_image(struct hda_codec *codec,
        unsigned int sample_rate;
        unsigned short channels;
 
-       snd_printdd(KERN_INFO "---- dspload_image begin ------\n");
+       codec_dbg(codec, "---- dspload_image begin ------\n");
        if (router_chans == 0) {
                if (!ovly)
                        router_chans = DMA_TRANSFER_FRAME_SIZE_NWORDS;
@@ -2603,27 +2600,27 @@ static int dspload_image(struct hda_codec *codec,
        }
 
        do {
-               snd_printdd(KERN_INFO "Ready to program DMA\n");
+               codec_dbg(codec, "Ready to program DMA\n");
                if (!ovly)
                        status = dsp_reset(codec);
 
                if (status < 0)
                        break;
 
-               snd_printdd(KERN_INFO "dsp_reset() complete\n");
+               codec_dbg(codec, "dsp_reset() complete\n");
                status = dspxfr_image(codec, fls, reloc, sample_rate, channels,
                                      ovly);
 
                if (status < 0)
                        break;
 
-               snd_printdd(KERN_INFO "dspxfr_image() complete\n");
+               codec_dbg(codec, "dspxfr_image() complete\n");
                if (autostart && !ovly) {
                        dspload_post_setup(codec);
                        status = dsp_set_run_state(codec);
                }
 
-               snd_printdd(KERN_INFO "LOAD FINISHED\n");
+               codec_dbg(codec, "LOAD FINISHED\n");
        } while (0);
 
        return status;
@@ -3132,7 +3129,7 @@ static int ca0132_select_out(struct hda_codec *codec)
        unsigned int tmp;
        int err;
 
-       snd_printdd(KERN_INFO "ca0132_select_out\n");
+       codec_dbg(codec, "ca0132_select_out\n");
 
        snd_hda_power_up(codec);
 
@@ -3150,7 +3147,7 @@ static int ca0132_select_out(struct hda_codec *codec)
                spec->cur_out_type = SPEAKER_OUT;
 
        if (spec->cur_out_type == SPEAKER_OUT) {
-               snd_printdd(KERN_INFO "ca0132_select_out speaker\n");
+               codec_dbg(codec, "ca0132_select_out speaker\n");
                /*speaker out config*/
                tmp = FLOAT_ONE;
                err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
@@ -3183,7 +3180,7 @@ static int ca0132_select_out(struct hda_codec *codec)
                snd_hda_set_pin_ctl(codec, spec->out_pins[0],
                                    pin_ctl | PIN_OUT);
        } else {
-               snd_printdd(KERN_INFO "ca0132_select_out hp\n");
+               codec_dbg(codec, "ca0132_select_out hp\n");
                /*headphone out config*/
                tmp = FLOAT_ZERO;
                err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
@@ -3288,7 +3285,7 @@ static int ca0132_select_mic(struct hda_codec *codec)
        int jack_present;
        int auto_jack;
 
-       snd_printdd(KERN_INFO "ca0132_select_mic\n");
+       codec_dbg(codec, "ca0132_select_mic\n");
 
        snd_hda_power_up(codec);
 
@@ -3410,7 +3407,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
                        val = 0;
        }
 
-       snd_printdd(KERN_INFO "ca0132_effect_set: nid=0x%x, val=%ld\n",
+       codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n",
                    nid, val);
 
        on = (val == 0) ? FLOAT_ZERO : FLOAT_ONE;
@@ -3432,7 +3429,7 @@ static int ca0132_pe_switch_set(struct hda_codec *codec)
        hda_nid_t nid;
        int i, ret = 0;
 
-       snd_printdd(KERN_INFO "ca0132_pe_switch_set: val=%ld\n",
+       codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
                    spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
 
        i = OUT_EFFECT_START_NID - EFFECT_START_NID;
@@ -3478,7 +3475,7 @@ static int ca0132_cvoice_switch_set(struct hda_codec *codec)
        int i, ret = 0;
        unsigned int oldval;
 
-       snd_printdd(KERN_INFO "ca0132_cvoice_switch_set: val=%ld\n",
+       codec_dbg(codec, "ca0132_cvoice_switch_set: val=%ld\n",
                    spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]);
 
        i = IN_EFFECT_START_NID - EFFECT_START_NID;
@@ -3608,7 +3605,7 @@ static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol,
        if (sel >= items)
                return 0;
 
-       snd_printdd(KERN_INFO "ca0132_voicefx_put: sel=%d, preset=%s\n",
+       codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n",
                    sel, ca0132_voicefx_presets[sel].name);
 
        /*
@@ -3679,7 +3676,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int changed = 1;
 
-       snd_printdd(KERN_INFO "ca0132_switch_put: nid=0x%x, val=%ld\n",
+       codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n",
                    nid, *valp);
 
        snd_hda_power_up(codec);
@@ -4142,7 +4139,7 @@ static void ca0132_set_dmic(struct hda_codec *codec, int enable)
        u8 val;
        unsigned int oldval;
 
-       snd_printdd(KERN_INFO "ca0132_set_dmic: enable=%d\n", enable);
+       codec_dbg(codec, "ca0132_set_dmic: enable=%d\n", enable);
 
        oldval = stop_mic1(codec);
        ca0132_set_vipsource(codec, 0);
@@ -4250,7 +4247,7 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
        int i;
        hda_nid_t nid;
 
-       snd_printdd(KERN_INFO "ca0132_refresh_widget_caps.\n");
+       codec_dbg(codec, "ca0132_refresh_widget_caps.\n");
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++)
                codec->wcaps[i] = snd_hda_param_read(codec, nid,
@@ -4394,7 +4391,7 @@ static void ca0132_process_dsp_response(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
 
-       snd_printdd(KERN_INFO "ca0132_process_dsp_response\n");
+       codec_dbg(codec, "ca0132_process_dsp_response\n");
        if (spec->wait_scp) {
                if (dspio_get_response_data(codec) >= 0)
                        spec->wait_scp = 0;
@@ -4413,7 +4410,7 @@ static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
                res = snd_hda_jack_get_action(codec,
                                (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f);
 
-               snd_printdd(KERN_INFO "snd_hda_jack_get_action: 0x%x\n", res);
+               codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res);
 
                switch (res) {
                case UNSOL_TAG_HP:
@@ -4658,7 +4655,7 @@ static int patch_ca0132(struct hda_codec *codec)
        struct ca0132_spec *spec;
        int err;
 
-       snd_printdd("patch_ca0132\n");
+       codec_dbg(codec, "patch_ca0132\n");
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
index fc492ac24caa917c9d3670a37f83cb1d3e0bca95..387f0b55188914d3081444d1b573ea15ad1bab2c 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/tlv.h>
index 9c6ce73b03c5585994ee4099106a70dbe7cca51c..061ea5965dd5dc17b6af0fa32f69c658831e335c 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -32,6 +31,9 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
+#undef ENABLE_CMI_STATIC_QUIRKS
+
+#ifdef ENABLE_CMI_STATIC_QUIRKS
 #define NUM_PINS       11
 
 
@@ -45,10 +47,12 @@ enum {
        CMI_AUTO,       /* let driver guess it */
        CMI_MODELS
 };
+#endif /* ENABLE_CMI_STATIC_QUIRKS */
 
 struct cmi_spec {
        struct hda_gen_spec gen;
 
+#ifdef ENABLE_CMI_STATIC_QUIRKS
        /* below are only for static models */
 
        int board_config;
@@ -81,8 +85,10 @@ struct cmi_spec {
 
        /* multichannel pins */
        struct hda_verb multi_init[9];  /* 2 verbs for each pin + terminator */
+#endif /* ENABLE_CMI_STATIC_QUIRKS */
 };
 
+#ifdef ENABLE_CMI_STATIC_QUIRKS
 /*
  * input MUX
  */
@@ -566,6 +572,7 @@ static const struct hda_codec_ops cmi9880_patch_ops = {
        .init = cmi9880_init,
        .free = cmi9880_free,
 };
+#endif /* ENABLE_CMI_STATIC_QUIRKS */
 
 /*
  * stuff for auto-parser
@@ -588,15 +595,20 @@ static int cmi_parse_auto_config(struct hda_codec *codec)
 
        err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_hda_gen_parse_auto_config(codec, cfg);
        if (err < 0)
-               return err;
+               goto error;
 
        codec->patch_ops = cmi_auto_patch_ops;
        return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
 }
 
+
 static int patch_cmi9880(struct hda_codec *codec)
 {
        struct cmi_spec *spec;
@@ -606,23 +618,18 @@ static int patch_cmi9880(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+#ifdef ENABLE_CMI_STATIC_QUIRKS
        spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
                                                        cmi9880_models,
                                                        cmi9880_cfg_tbl);
        if (spec->board_config < 0) {
-               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+               codec_dbg(codec, "%s: BIOS auto-probing.\n",
                            codec->chip_name);
                spec->board_config = CMI_AUTO; /* try everything */
        }
 
-       if (spec->board_config == CMI_AUTO) {
-               int err = cmi_parse_auto_config(codec);
-               if (err < 0) {
-                       snd_hda_gen_free(codec);
-                       return err;
-               }
-               return 0;
-       }
+       if (spec->board_config == CMI_AUTO)
+               return cmi_parse_auto_config(codec);
 
        /* copy default DAC NIDs */
        memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
@@ -669,6 +676,9 @@ static int patch_cmi9880(struct hda_codec *codec)
        codec->patch_ops = cmi9880_patch_ops;
 
        return 0;
+#else
+       return cmi_parse_auto_config(codec);
+#endif
 }
 
 /*
index bcf91bea33179ce50b9485fd1db59caf1349b64c..1dc7e974f3b1cd554988eb2d2be26ca889aafab8 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
@@ -35,7 +34,7 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
-#define ENABLE_CXT_STATIC_QUIRKS
+#undef ENABLE_CXT_STATIC_QUIRKS
 
 #define CXT_PIN_DIR_IN              0x00
 #define CXT_PIN_DIR_OUT             0x01
@@ -68,6 +67,12 @@ struct conexant_spec {
 
        unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
 
+       /* OPLC XO specific */
+       bool recording;
+       bool dc_enable;
+       unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
+       struct nid_path *dc_mode_path;
+
 #ifdef ENABLE_CXT_STATIC_QUIRKS
        const struct snd_kcontrol_new *mixers[5];
        int num_mixers;
@@ -123,19 +128,6 @@ struct conexant_spec {
        unsigned int hp_laptop:1;
        unsigned int asus:1;
 
-       unsigned int ext_mic_present;
-       unsigned int recording;
-       void (*capture_prepare)(struct hda_codec *codec);
-       void (*capture_cleanup)(struct hda_codec *codec);
-
-       /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
-        * through the microphone jack.
-        * When the user enables this through a mixer switch, both internal and
-        * external microphones are disabled. Gain is fixed at 0dB. In this mode,
-        * we also allow the bias to be configured through a separate mixer
-        * control. */
-       unsigned int dc_enable;
-       unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
        unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
 #endif /* ENABLE_CXT_STATIC_QUIRKS */
 };
@@ -253,8 +245,6 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct snd_pcm_substream *substream)
 {
        struct conexant_spec *spec = codec->spec;
-       if (spec->capture_prepare)
-               spec->capture_prepare(codec);
        snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
                                   stream_tag, 0, format);
        return 0;
@@ -266,8 +256,6 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 {
        struct conexant_spec *spec = codec->spec;
        snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
-       if (spec->capture_cleanup)
-               spec->capture_cleanup(codec);
        return 0;
 }
 
@@ -457,9 +445,7 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
-       struct conexant_spec *spec = codec->spec;
-       snd_hda_detach_beep_device(codec);
-       kfree(spec);
+       kfree(codec->spec);
 }
 
 static const struct snd_kcontrol_new cxt_capture_mixers[] = {
@@ -673,14 +659,6 @@ static const struct hda_input_mux cxt5045_capture_source_benq = {
        }
 };
 
-static const struct hda_input_mux cxt5045_capture_source_hp530 = {
-       .num_items = 2,
-       .items = {
-               { "Mic",          0x1 },
-               { "Internal Mic", 0x2 },
-       }
-};
-
 /* turn on/off EAPD (+ mute HP) as a master switch */
 static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
@@ -796,28 +774,6 @@ static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
        {}
 };
 
-static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
-       HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .info = cxt_eapd_info,
-               .get = cxt_eapd_get,
-               .put = cxt5045_hp_master_sw_put,
-               .private_value = 0x10,
-       },
-
-       {}
-};
-
 static const struct hda_verb cxt5045_init_verbs[] = {
        /* Line in, Mic */
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -1000,7 +956,6 @@ enum {
        CXT5045_LAPTOP_MICSENSE,
        CXT5045_LAPTOP_HPMICSENSE,
        CXT5045_BENQ,
-       CXT5045_LAPTOP_HP530,
 #ifdef CONFIG_SND_DEBUG
        CXT5045_TEST,
 #endif
@@ -1013,7 +968,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
        [CXT5045_LAPTOP_MICSENSE]       = "laptop-micsense",
        [CXT5045_LAPTOP_HPMICSENSE]     = "laptop-hpmicsense",
        [CXT5045_BENQ]                  = "benq",
-       [CXT5045_LAPTOP_HP530]          = "laptop-hp530",
 #ifdef CONFIG_SND_DEBUG
        [CXT5045_TEST]          = "test",
 #endif
@@ -1021,8 +975,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
 };
 
 static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
-       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
@@ -1113,14 +1065,6 @@ static int patch_cxt5045(struct hda_codec *codec)
                spec->num_mixers = 2;
                codec->patch_ops.init = cxt5045_init;
                break;
-       case CXT5045_LAPTOP_HP530:
-               codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
-               spec->input_mux = &cxt5045_capture_source_hp530;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
-               spec->mixers[0] = cxt5045_mixers_hp530;
-               codec->patch_ops.init = cxt5045_init;
-               break;
 #ifdef CONFIG_SND_DEBUG
        case CXT5045_TEST:
                spec->input_mux = &cxt5045_test_capture_source;
@@ -1940,11 +1884,6 @@ static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
 static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
 static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
 
-/* OLPC's microphone port is DC coupled for use with external sensors,
- * therefore we use a 50% mic bias in order to center the input signal with
- * the DC input range of the codec. */
-#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
-
 static const struct hda_channel_mode cxt5066_modes[1] = {
        { 2, NULL },
 };
@@ -1959,7 +1898,8 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
        struct conexant_spec *spec = codec->spec;
        unsigned int pinctl;
 
-       snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
+       codec_dbg(codec,
+                 "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
                    spec->hp_present, spec->cur_eapd);
 
        /* Port A (HP) */
@@ -1997,88 +1937,6 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static const struct hda_input_mux cxt5066_olpc_dc_bias = {
-       .num_items = 3,
-       .items = {
-               { "Off", PIN_IN },
-               { "50%", PIN_VREF50 },
-               { "80%", PIN_VREF80 },
-       },
-};
-
-static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       /* Even though port F is the DC input, the bias is controlled on port B.
-        * we also leave that port as an active input (but unselected) in DC mode
-        * just in case that is necessary to make the bias setting take effect. */
-       return snd_hda_set_pin_ctl_cache(codec, 0x1a,
-               cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
-}
-
-/* OLPC defers mic widget control until when capture is started because the
- * microphone LED comes on as soon as these settings are put in place. if we
- * did this before recording, it would give the false indication that recording
- * is happening when it is not. */
-static void cxt5066_olpc_select_mic(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       if (!spec->recording)
-               return;
-
-       if (spec->dc_enable) {
-               /* in DC mode we ignore presence detection and just use the jack
-                * through our special DC port */
-               const struct hda_verb enable_dc_mode[] = {
-                       /* disble internal mic, port C */
-                       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-                       /* enable DC capture, port F */
-                       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-                       {},
-               };
-
-               snd_hda_sequence_write(codec, enable_dc_mode);
-               /* port B input disabled (and bias set) through the following call */
-               cxt5066_set_olpc_dc_bias(codec);
-               return;
-       }
-
-       /* disable DC (port F) */
-       snd_hda_set_pin_ctl(codec, 0x1e, 0);
-
-       /* external mic, port B */
-       snd_hda_set_pin_ctl(codec, 0x1a,
-               spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
-
-       /* internal mic, port C */
-       snd_hda_set_pin_ctl(codec, 0x1b,
-               spec->ext_mic_present ? 0 : PIN_VREF80);
-}
-
-/* toggle input of built-in and mic jack appropriately */
-static void cxt5066_olpc_automic(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       unsigned int present;
-
-       if (spec->dc_enable) /* don't do presence detection in DC mode */
-               return;
-
-       present = snd_hda_codec_read(codec, 0x1a, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       if (present)
-               snd_printdd("CXT5066: external microphone detected\n");
-       else
-               snd_printdd("CXT5066: external microphone absent\n");
-
-       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
-               present ? 0 : 1);
-       spec->ext_mic_present = !!present;
-
-       cxt5066_olpc_select_mic(codec);
-}
-
 /* toggle input of built-in digital mic and mic jack appropriately */
 static void cxt5066_vostro_automic(struct hda_codec *codec)
 {
@@ -2110,10 +1968,10 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
 
        present = snd_hda_jack_detect(codec, 0x1a);
        if (present) {
-               snd_printdd("CXT5066: external microphone detected\n");
+               codec_dbg(codec, "CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
        } else {
-               snd_printdd("CXT5066: external microphone absent\n");
+               codec_dbg(codec, "CXT5066: external microphone absent\n");
                snd_hda_sequence_write(codec, ext_mic_absent);
        }
 }
@@ -2138,10 +1996,10 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
 
        present = snd_hda_jack_detect(codec, 0x1b);
        if (present) {
-               snd_printdd("CXT5066: external microphone detected\n");
+               codec_dbg(codec, "CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
        } else {
-               snd_printdd("CXT5066: external microphone absent\n");
+               codec_dbg(codec, "CXT5066: external microphone absent\n");
                snd_hda_sequence_write(codec, ext_mic_absent);
        }
 }
@@ -2153,7 +2011,7 @@ static void cxt5066_asus_automic(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_jack_detect(codec, 0x1b);
-       snd_printdd("CXT5066: external microphone present=%d\n", present);
+       codec_dbg(codec, "CXT5066: external microphone present=%d\n", present);
        snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
                            present ? 1 : 0);
 }
@@ -2165,7 +2023,7 @@ static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_jack_detect(codec, 0x1b);
-       snd_printdd("CXT5066: external microphone present=%d\n", present);
+       codec_dbg(codec, "CXT5066: external microphone present=%d\n", present);
        snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
                            present ? 1 : 3);
 }
@@ -2204,13 +2062,13 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
        ext_present = snd_hda_jack_detect(codec, 0x1b);
        dock_present = snd_hda_jack_detect(codec, 0x1a);
        if (ext_present) {
-               snd_printdd("CXT5066: external microphone detected\n");
+               codec_dbg(codec, "CXT5066: external microphone detected\n");
                snd_hda_sequence_write(codec, ext_mic_present);
        } else if (dock_present) {
-               snd_printdd("CXT5066: dock microphone detected\n");
+               codec_dbg(codec, "CXT5066: dock microphone detected\n");
                snd_hda_sequence_write(codec, dock_mic_present);
        } else {
-               snd_printdd("CXT5066: external microphone absent\n");
+               codec_dbg(codec, "CXT5066: external microphone absent\n");
                snd_hda_sequence_write(codec, ext_mic_absent);
        }
 }
@@ -2229,7 +2087,7 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
 
        spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
        spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
-       snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
+       codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n",
                portA, portD, spec->hp_present);
        cxt5066_update_speaker(codec);
 }
@@ -2251,27 +2109,10 @@ static void cxt5066_automic(struct hda_codec *codec)
                cxt5066_asus_automic(codec);
 }
 
-/* unsolicited event for jack sensing */
-static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct conexant_spec *spec = codec->spec;
-       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
-       switch (res >> 26) {
-       case CONEXANT_HP_EVENT:
-               cxt5066_hp_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
-               /* ignore mic events in DC mode; we're always using the jack */
-               if (!spec->dc_enable)
-                       cxt5066_olpc_automic(codec);
-               break;
-       }
-}
-
 /* unsolicited event for jack sensing */
 static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
+       codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26);
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5066_hp_automute(codec);
@@ -2338,124 +2179,10 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
                idx = imux->num_items - 1;
 
        spec->mic_boost = idx;
-       if (!spec->dc_enable)
-               cxt5066_set_mic_boost(codec);
-       return 1;
-}
-
-static void cxt5066_enable_dc(struct hda_codec *codec)
-{
-       const struct hda_verb enable_dc_mode[] = {
-               /* disable gain */
-               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-               /* switch to DC input */
-               {0x17, AC_VERB_SET_CONNECT_SEL, 3},
-               {}
-       };
-
-       /* configure as input source */
-       snd_hda_sequence_write(codec, enable_dc_mode);
-       cxt5066_olpc_select_mic(codec); /* also sets configured bias */
-}
-
-static void cxt5066_disable_dc(struct hda_codec *codec)
-{
-       /* reconfigure input source */
        cxt5066_set_mic_boost(codec);
-       /* automic also selects the right mic if we're recording */
-       cxt5066_olpc_automic(codec);
-}
-
-static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       ucontrol->value.integer.value[0] = spec->dc_enable;
-       return 0;
-}
-
-static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       int dc_enable = !!ucontrol->value.integer.value[0];
-
-       if (dc_enable == spec->dc_enable)
-               return 0;
-
-       spec->dc_enable = dc_enable;
-       if (dc_enable)
-               cxt5066_enable_dc(codec);
-       else
-               cxt5066_disable_dc(codec);
-
-       return 1;
-}
-
-static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
-                                          struct snd_ctl_elem_info *uinfo)
-{
-       return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
-}
-
-static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
-       return 0;
-}
-
-static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
-       unsigned int idx;
-
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-
-       spec->dc_input_bias = idx;
-       if (spec->dc_enable)
-               cxt5066_set_olpc_dc_bias(codec);
        return 1;
 }
 
-static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       /* mark as recording and configure the microphone widget so that the
-        * recording LED comes on. */
-       spec->recording = 1;
-       cxt5066_olpc_select_mic(codec);
-}
-
-static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       const struct hda_verb disable_mics[] = {
-               /* disable external mic, port B */
-               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-               /* disble internal mic, port C */
-               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-               /* disable DC capture, port F */
-               {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-               {},
-       };
-
-       snd_hda_sequence_write(codec, disable_mics);
-       spec->recording = 0;
-}
-
 static void conexant_check_dig_outs(struct hda_codec *codec,
                                    const hda_nid_t *dig_pins,
                                    int num_pins)
@@ -2506,43 +2233,6 @@ static const struct snd_kcontrol_new cxt5066_mixer_master[] = {
        {}
 };
 
-static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Volume",
-               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                                 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-                                 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_volume_info,
-               .get = snd_hda_mixer_amp_volume_get,
-               .put = snd_hda_mixer_amp_volume_put,
-               .tlv = { .c = snd_hda_mixer_amp_tlv },
-               /* offset by 28 volume steps to limit minimum gain to -46dB */
-               .private_value =
-                       HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
-       },
-       {}
-};
-
-static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DC Mode Enable Switch",
-               .info = snd_ctl_boolean_mono_info,
-               .get = cxt5066_olpc_dc_get,
-               .put = cxt5066_olpc_dc_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DC Input Bias Enum",
-               .info = cxt5066_olpc_dc_bias_enum_info,
-               .get = cxt5066_olpc_dc_bias_enum_get,
-               .put = cxt5066_olpc_dc_bias_enum_put,
-       },
-       {}
-};
-
 static const struct snd_kcontrol_new cxt5066_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2633,67 +2323,6 @@ static const struct hda_verb cxt5066_init_verbs[] = {
        { } /* end */
 };
 
-static const struct hda_verb cxt5066_init_verbs_olpc[] = {
-       /* Port A: headphones */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
-
-       /* Port B: external microphone */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port C: internal microphone */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port D: unused */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port E: unused, but has primary EAPD */
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
-
-       /* Port F: external DC input through microphone port */
-       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Port G: internal speakers */
-       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
-
-       /* DAC1 */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* DAC2: unused */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-
-       /* Disable digital microphone port */
-       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* Audio input selectors */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-
-       /* Disable SPDIF */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
-       /* enable unsolicited events for Port A and B */
-       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
-       { } /* end */
-};
-
 static const struct hda_verb cxt5066_init_verbs_vostro[] = {
        /* Port A: headphones */
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2879,7 +2508,7 @@ static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
 /* initialize jack-sensing, too */
 static int cxt5066_init(struct hda_codec *codec)
 {
-       snd_printdd("CXT5066: init\n");
+       codec_dbg(codec, "CXT5066: init\n");
        conexant_init(codec);
        if (codec->patch_ops.unsol_event) {
                cxt5066_hp_automute(codec);
@@ -2889,25 +2518,9 @@ static int cxt5066_init(struct hda_codec *codec)
        return 0;
 }
 
-static int cxt5066_olpc_init(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       snd_printdd("CXT5066: init\n");
-       conexant_init(codec);
-       cxt5066_hp_automute(codec);
-       if (!spec->dc_enable) {
-               cxt5066_set_mic_boost(codec);
-               cxt5066_olpc_automic(codec);
-       } else {
-               cxt5066_enable_dc(codec);
-       }
-       return 0;
-}
-
 enum {
        CXT5066_LAPTOP,         /* Laptops w/ EAPD support */
        CXT5066_DELL_LAPTOP,    /* Dell Laptop */
-       CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
        CXT5066_DELL_VOSTRO,    /* Dell Vostro 1015i */
        CXT5066_IDEAPAD,        /* Lenovo IdeaPad U150 */
        CXT5066_THINKPAD,       /* Lenovo ThinkPad T410s, others? */
@@ -2920,7 +2533,6 @@ enum {
 static const char * const cxt5066_models[CXT5066_MODELS] = {
        [CXT5066_LAPTOP]        = "laptop",
        [CXT5066_DELL_LAPTOP]   = "dell-laptop",
-       [CXT5066_OLPC_XO_1_5]   = "olpc-xo-1_5",
        [CXT5066_DELL_VOSTRO]   = "dell-vostro",
        [CXT5066_IDEAPAD]       = "ideapad",
        [CXT5066_THINKPAD]      = "thinkpad",
@@ -2941,10 +2553,8 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
        SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
                      CXT5066_LAPTOP),
-       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
        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),
@@ -3030,32 +2640,11 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->mic_boost = 3; /* default 30dB gain */
                break;
 
-       case CXT5066_OLPC_XO_1_5:
-               codec->patch_ops.init = cxt5066_olpc_init;
-               codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
-               spec->init_verbs[0] = cxt5066_init_verbs_olpc;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
-               spec->port_d_mode = 0;
-               spec->mic_boost = 3; /* default 30dB gain */
-
-               /* no S/PDIF out */
-               spec->multiout.dig_out_nid = 0;
-
-               /* input source automatically selected */
-               spec->input_mux = NULL;
-
-               /* our capture hooks which allow us to turn on the microphone LED
-                * at the right time */
-               spec->capture_prepare = cxt5066_olpc_capture_prepare;
-               spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
-               break;
        case CXT5066_DELL_VOSTRO:
                codec->patch_ops.init = cxt5066_init;
                codec->patch_ops.unsol_event = cxt5066_unsol_event;
                spec->init_verbs[0] = cxt5066_init_verbs_vostro;
-               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
                spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
                spec->port_d_mode = 0;
@@ -3207,11 +2796,7 @@ static int cx_auto_init(struct hda_codec *codec)
        return 0;
 }
 
-static void cx_auto_free(struct hda_codec *codec)
-{
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
-       snd_hda_gen_free(codec);
-}
+#define cx_auto_free   snd_hda_gen_free
 
 static const struct hda_codec_ops cx_auto_patch_ops = {
        .build_controls = cx_auto_build_controls,
@@ -3238,6 +2823,11 @@ enum {
        CXT_FIXUP_HEADPHONE_MIC,
        CXT_FIXUP_GPIO1,
        CXT_FIXUP_THINKPAD_ACPI,
+       CXT_FIXUP_OLPC_XO,
+       CXT_FIXUP_CAP_MIX_AMP,
+       CXT_FIXUP_TOSHIBA_P105,
+       CXT_FIXUP_HP_530,
+       CXT_FIXUP_CAP_MIX_AMP_5047,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -3316,6 +2906,288 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec,
        }
 }
 
+/* OPLC XO 1.5 fixup */
+
+/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
+ * through the microphone jack.
+ * When the user enables this through a mixer switch, both internal and
+ * external microphones are disabled. Gain is fixed at 0dB. In this mode,
+ * we also allow the bias to be configured through a separate mixer
+ * control. */
+
+#define update_mic_pin(codec, nid, val)                                        \
+       snd_hda_codec_update_cache(codec, nid, 0,                       \
+                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
+
+static const struct hda_input_mux olpc_xo_dc_bias = {
+       .num_items = 3,
+       .items = {
+               { "Off", PIN_IN },
+               { "50%", PIN_VREF50 },
+               { "80%", PIN_VREF80 },
+       },
+};
+
+static void olpc_xo_update_mic_boost(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int ch, val;
+
+       for (ch = 0; ch < 2; ch++) {
+               val = AC_AMP_SET_OUTPUT |
+                       (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
+               if (!spec->dc_enable)
+                       val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
+               snd_hda_codec_write(codec, 0x17, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, val);
+       }
+}
+
+static void olpc_xo_update_mic_pins(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int cur_input, val;
+       struct nid_path *path;
+
+       cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
+
+       /* Set up mic pins for port-B, C and F dynamically as the recording
+        * LED is turned on/off by these pin controls
+        */
+       if (!spec->dc_enable) {
+               /* disable DC bias path and pin for port F */
+               update_mic_pin(codec, 0x1e, 0);
+               snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
+
+               /* update port B (ext mic) and C (int mic) */
+               /* OLPC defers mic widget control until when capture is
+                * started because the microphone LED comes on as soon as
+                * these settings are put in place. if we did this before
+                * recording, it would give the false indication that
+                * recording is happening when it is not.
+                */
+               update_mic_pin(codec, 0x1a, spec->recording ?
+                              snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
+               update_mic_pin(codec, 0x1b, spec->recording ?
+                              snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
+               /* enable normal mic path */
+               path = snd_hda_get_path_from_idx(codec, cur_input);
+               if (path)
+                       snd_hda_activate_path(codec, path, true, false);
+       } else {
+               /* disable normal mic path */
+               path = snd_hda_get_path_from_idx(codec, cur_input);
+               if (path)
+                       snd_hda_activate_path(codec, path, false, false);
+
+               /* Even though port F is the DC input, the bias is controlled
+                * on port B.  We also leave that port as an active input (but
+                * unselected) in DC mode just in case that is necessary to
+                * make the bias setting take effect.
+                */
+               if (spec->recording)
+                       val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
+               else
+                       val = 0;
+               update_mic_pin(codec, 0x1a, val);
+               update_mic_pin(codec, 0x1b, 0);
+               /* enable DC bias path and pin */
+               update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
+               snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
+       }
+}
+
+/* mic_autoswitch hook */
+static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)
+{
+       struct conexant_spec *spec = codec->spec;
+       int saved_cached_write = codec->cached_write;
+
+       codec->cached_write = 1;
+       /* in DC mode, we don't handle automic */
+       if (!spec->dc_enable)
+               snd_hda_gen_mic_autoswitch(codec, jack);
+       olpc_xo_update_mic_pins(codec);
+       snd_hda_codec_flush_cache(codec);
+       codec->cached_write = saved_cached_write;
+       if (spec->dc_enable)
+               olpc_xo_update_mic_boost(codec);
+}
+
+/* pcm_capture hook */
+static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
+                                struct hda_codec *codec,
+                                struct snd_pcm_substream *substream,
+                                int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       /* toggle spec->recording flag and update mic pins accordingly
+        * for turning on/off LED
+        */
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               spec->recording = 1;
+               olpc_xo_update_mic_pins(codec);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               spec->recording = 0;
+               olpc_xo_update_mic_pins(codec);
+               break;
+       }
+}
+
+static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.integer.value[0] = spec->dc_enable;
+       return 0;
+}
+
+static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int dc_enable = !!ucontrol->value.integer.value[0];
+
+       if (dc_enable == spec->dc_enable)
+               return 0;
+
+       spec->dc_enable = dc_enable;
+       olpc_xo_update_mic_pins(codec);
+       olpc_xo_update_mic_boost(codec);
+       return 1;
+}
+
+static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
+       return 0;
+}
+
+static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
+}
+
+static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = &olpc_xo_dc_bias;
+       unsigned int idx;
+
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (spec->dc_input_bias == idx)
+               return 0;
+
+       spec->dc_input_bias = idx;
+       if (spec->dc_enable)
+               olpc_xo_update_mic_pins(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new olpc_xo_mixers[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Mode Enable Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = olpc_xo_dc_mode_get,
+               .put = olpc_xo_dc_mode_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Input Bias Enum",
+               .info = olpc_xo_dc_bias_enum_info,
+               .get = olpc_xo_dc_bias_enum_get,
+               .put = olpc_xo_dc_bias_enum_put,
+       },
+       {}
+};
+
+/* overriding mic boost put callback; update mic boost volume only when
+ * DC mode is disabled
+ */
+static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+       if (ret > 0 && spec->dc_enable)
+               olpc_xo_update_mic_boost(codec);
+       return ret;
+}
+
+static void cxt_fixup_olpc_xo(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+       int i;
+
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+
+       spec->gen.mic_autoswitch_hook = olpc_xo_automic;
+       spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
+       spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
+
+       snd_hda_add_new_ctls(codec, olpc_xo_mixers);
+
+       /* OLPC's microphone port is DC coupled for use with external sensors,
+        * therefore we use a 50% mic bias in order to center the input signal
+        * with the DC input range of the codec.
+        */
+       snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
+
+       /* override mic boost control */
+       for (i = 0; i < spec->gen.kctls.used; i++) {
+               struct snd_kcontrol_new *kctl =
+                       snd_array_elem(&spec->gen.kctls, i);
+               if (!strcmp(kctl->name, "Mic Boost Volume")) {
+                       kctl->put = olpc_xo_mic_boost_put;
+                       break;
+               }
+       }
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x2b steps with 0dB offset 0x14)
+ */
+static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+                                 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x1e steps with 0 dB offset 0x17)
+ */
+static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
+                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+}
 
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
@@ -3401,6 +3273,68 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = hda_fixup_thinkpad_acpi,
        },
+       [CXT_FIXUP_OLPC_XO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_olpc_xo,
+       },
+       [CXT_FIXUP_CAP_MIX_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_cap_mix_amp,
+       },
+       [CXT_FIXUP_TOSHIBA_P105] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x10, 0x961701f0 }, /* speaker/hp */
+                       { 0x12, 0x02a1901e }, /* ext mic */
+                       { 0x14, 0x95a70110 }, /* int mic */
+                       {}
+               },
+       },
+       [CXT_FIXUP_HP_530] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x90a60160 }, /* int mic */
+                       {}
+               },
+               .chained = true,
+               .chain_id = CXT_FIXUP_CAP_MIX_AMP,
+       },
+       [CXT_FIXUP_CAP_MIX_AMP_5047] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_cap_mix_amp_5047,
+       },
+};
+
+static const struct snd_pci_quirk cxt5045_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
+       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
+       /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
+        * really bad sound over 0dB on NID 0x17.
+        */
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
+       {}
+};
+
+static const struct hda_model_fixup cxt5045_fixup_models[] = {
+       { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
+       { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
+       { .id = CXT_FIXUP_HP_530, .name = "hp-530" },
+       {}
+};
+
+static const struct snd_pci_quirk cxt5047_fixups[] = {
+       /* HP laptops have really bad sound over 0 dB on NID 0x10.
+        */
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
+       {}
+};
+
+static const struct hda_model_fixup cxt5047_fixup_models[] = {
+       { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
+       {}
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3408,10 +3342,16 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
        {}
 };
 
+static const struct hda_model_fixup cxt5051_fixup_models[] = {
+       { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
+       {}
+};
+
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
+       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@@ -3428,6 +3368,17 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        {}
 };
 
+static const struct hda_model_fixup cxt5066_fixup_models[] = {
+       { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
+       { .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
+       { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
+       { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
+       { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
+       { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
+       { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
+       {}
+};
+
 /* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
  * can be created (bko#42825)
  */
@@ -3449,8 +3400,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
        struct conexant_spec *spec;
        int err;
 
-       printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-              codec->chip_name);
+       codec_info(codec, "%s: BIOS auto-probing.\n", codec->chip_name);
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
@@ -3467,19 +3417,28 @@ static int patch_conexant_auto(struct hda_codec *codec)
        switch (codec->vendor_id) {
        case 0x14f15045:
                codec->single_adc_amp = 1;
+               spec->gen.mixer_nid = 0x17;
+               spec->gen.add_stereo_mix_input = 1;
+               snd_hda_pick_fixup(codec, cxt5045_fixup_models,
+                                  cxt5045_fixups, cxt_fixups);
                break;
        case 0x14f15047:
                codec->pin_amp_workaround = 1;
                spec->gen.mixer_nid = 0x19;
+               spec->gen.add_stereo_mix_input = 1;
+               snd_hda_pick_fixup(codec, cxt5047_fixup_models,
+                                  cxt5047_fixups, cxt_fixups);
                break;
        case 0x14f15051:
                add_cx5051_fake_mutes(codec);
                codec->pin_amp_workaround = 1;
-               snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
+               snd_hda_pick_fixup(codec, cxt5051_fixup_models,
+                                  cxt5051_fixups, cxt_fixups);
                break;
        default:
                codec->pin_amp_workaround = 1;
-               snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
+               snd_hda_pick_fixup(codec, cxt5066_fixup_models,
+                                  cxt5066_fixups, cxt_fixups);
                break;
        }
 
@@ -3513,7 +3472,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
         * Better to make reset, then.
         */
        if (!codec->bus->sync_write) {
-               snd_printd("hda_codec: "
+               codec_info(codec,
                           "Enable sync_write for stable communication\n");
                codec->bus->sync_write = 1;
                codec->bus->allow_bus_reset = 1;
index 5ef95034d041410be9bd453ed555de99d4bb0374..0cb5b89cd0c8b3e81dd57a0bcdaa471d67d018c1 100644 (file)
@@ -68,6 +68,7 @@ struct hdmi_spec_per_pin {
        hda_nid_t pin_nid;
        int num_mux_nids;
        hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+       int mux_idx;
        hda_nid_t cvt_nid;
 
        struct hda_codec *codec;
@@ -353,40 +354,43 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
 #define get_pcm_rec(spec, idx) \
        ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
 
-static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
+static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
 {
+       struct hdmi_spec *spec = codec->spec;
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
                if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
                        return pin_idx;
 
-       snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
+       codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid);
        return -EINVAL;
 }
 
-static int hinfo_to_pin_index(struct hdmi_spec *spec,
+static int hinfo_to_pin_index(struct hda_codec *codec,
                              struct hda_pcm_stream *hinfo)
 {
+       struct hdmi_spec *spec = codec->spec;
        int pin_idx;
 
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
                if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
                        return pin_idx;
 
-       snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
+       codec_warn(codec, "HDMI: hinfo %p not registered\n", hinfo);
        return -EINVAL;
 }
 
-static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
+static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
 {
+       struct hdmi_spec *spec = codec->spec;
        int cvt_idx;
 
        for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
                if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
                        return cvt_idx;
 
-       snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
+       codec_warn(codec, "HDMI: cvt nid %d not registered\n", cvt_nid);
        return -EINVAL;
 }
 
@@ -706,7 +710,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
 
        for (i = 0; i < 8; i++) {
                channel = spec->ops.pin_get_slot_channel(codec, pin_nid, i);
-               printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
+               codec_dbg(codec, "HDMI: ASP channel %d => slot %d\n",
                                                channel, i);
        }
 #endif
@@ -755,8 +759,7 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
                int channel = (slotsetup & 0xf0) >> 4;
                err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, channel);
                if (err) {
-                       snd_printdd(KERN_NOTICE
-                                   "HDMI: channel mapping failed\n");
+                       codec_dbg(codec, "HDMI: channel mapping failed\n");
                        break;
                }
        }
@@ -967,12 +970,12 @@ static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
        int size;
 
        size = snd_hdmi_get_eld_size(codec, pin_nid);
-       printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
+       codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
 
        for (i = 0; i < 8; i++) {
                size = snd_hda_codec_read(codec, pin_nid, 0,
                                                AC_VERB_GET_HDMI_DIP_SIZE, i);
-               printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+               codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
        }
 #endif
 }
@@ -994,12 +997,12 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
                        hdmi_write_dip_byte(codec, pin_nid, 0x0);
                        hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
                        if (pi != i)
-                               snd_printd(KERN_INFO "dip index %d: %d != %d\n",
+                               codec_dbg(codec, "dip index %d: %d != %d\n",
                                                bi, pi, i);
                        if (bi == 0) /* byte index wrapped around */
                                break;
                }
-               snd_printd(KERN_INFO
+               codec_dbg(codec,
                        "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
                        i, size, j);
        }
@@ -1062,6 +1065,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
 {
        union audio_infoframe ai;
 
+       memset(&ai, 0, sizeof(ai));
        if (conn_type == 0) { /* HDMI */
                struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
 
@@ -1080,7 +1084,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
                dp_ai->CC02_CT47        = active_channels - 1;
                dp_ai->CA               = ca;
        } else {
-               snd_printd("HDMI: unknown connection type at pin %d\n",
+               codec_dbg(codec, "HDMI: unknown connection type at pin %d\n",
                            pin_nid);
                return;
        }
@@ -1092,8 +1096,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
         */
        if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
                                        sizeof(ai))) {
-               snd_printdd("hdmi_pin_setup_infoframe: "
-                           "pin=%d channels=%d ca=0x%02x\n",
+               codec_dbg(codec,
+                         "hdmi_pin_setup_infoframe: pin=%d channels=%d ca=0x%02x\n",
                            pin_nid,
                            active_channels, ca);
                hdmi_stop_infoframe_trans(codec, pin_nid);
@@ -1161,7 +1165,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct hdmi_spec *spec = codec->spec;
-       int pin_idx = pin_nid_to_pin_index(spec, jack->nid);
+       int pin_idx = pin_nid_to_pin_index(codec, jack->nid);
        if (pin_idx < 0)
                return;
 
@@ -1180,7 +1184,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
                return;
        jack->jack_dirty = 1;
 
-       _snd_printd(SND_PR_VERBOSE,
+       codec_dbg(codec,
                "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
                codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
                !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
@@ -1195,7 +1199,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
        int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
        int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
 
-       printk(KERN_INFO
+       codec_info(codec,
                "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
                codec->addr,
                tag,
@@ -1217,7 +1221,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
        int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
 
        if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) {
-               snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
+               codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
                return;
        }
 
@@ -1244,7 +1248,7 @@ static void haswell_verify_D0(struct hda_codec *codec,
                msleep(40);
                pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
                pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
-               snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
+               codec_dbg(codec, "Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
        }
 }
 
@@ -1274,8 +1278,8 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
                else
                        new_pinctl |= AC_PINCTL_EPT_NATIVE;
 
-               snd_printdd("hdmi_pin_hbr_setup: "
-                           "NID=0x%x, %spinctl=0x%x\n",
+               codec_dbg(codec,
+                         "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
                            pin_nid,
                            pinctl == new_pinctl ? "" : "new-",
                            new_pinctl);
@@ -1302,7 +1306,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format));
 
        if (err) {
-               snd_printdd("hdmi_setup_stream: HBR is not supported\n");
+               codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
                return err;
        }
 
@@ -1341,6 +1345,8 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
        if (cvt_idx == spec->num_cvts)
                return -ENODEV;
 
+       per_pin->mux_idx = mux_idx;
+
        if (cvt_id)
                *cvt_id = cvt_idx;
        if (mux_id)
@@ -1349,6 +1355,22 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
        return 0;
 }
 
+/* Assure the pin select the right convetor */
+static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
+                       struct hdmi_spec_per_pin *per_pin)
+{
+       hda_nid_t pin_nid = per_pin->pin_nid;
+       int mux_idx, curr;
+
+       mux_idx = per_pin->mux_idx;
+       curr = snd_hda_codec_read(codec, pin_nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+       if (curr != mux_idx)
+               snd_hda_codec_write_cache(codec, pin_nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           mux_idx);
+}
+
 /* Intel HDMI workaround to fix audio routing issue:
  * For some Intel display codecs, pins share the same connection list.
  * So a conveter can be selected by multiple pins and playback on any of these
@@ -1389,7 +1411,8 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
                for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
                        per_cvt = get_cvt(spec, cvt_idx);
                        if (!per_cvt->assigned) {
-                               snd_printdd("choose cvt %d for pin nid %d\n",
+                               codec_dbg(codec,
+                                         "choose cvt %d for pin nid %d\n",
                                        cvt_idx, nid);
                                snd_hda_codec_write_cache(codec, nid, 0,
                                            AC_VERB_SET_CONNECT_SEL,
@@ -1416,7 +1439,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        int err;
 
        /* Validate hinfo */
-       pin_idx = hinfo_to_pin_index(spec, hinfo);
+       pin_idx = hinfo_to_pin_index(codec, hinfo);
        if (snd_BUG_ON(pin_idx < 0))
                return -EINVAL;
        per_pin = get_pin(spec, pin_idx);
@@ -1482,9 +1505,8 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
        hda_nid_t pin_nid = per_pin->pin_nid;
 
        if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
-               snd_printk(KERN_WARNING
-                          "HDMI: pin %d wcaps %#x "
-                          "does not support connection list\n",
+               codec_warn(codec,
+                          "HDMI: pin %d wcaps %#x does not support connection list\n",
                           pin_nid, get_wcaps(codec, pin_nid));
                return -EINVAL;
        }
@@ -1527,7 +1549,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
        else
                eld->eld_valid = false;
 
-       _snd_printd(SND_PR_VERBOSE,
+       codec_dbg(codec,
                "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
                codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid);
 
@@ -1690,7 +1712,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
        nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
        if (!nid || nodes < 0) {
-               snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
+               codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
                return -EINVAL;
        }
 
@@ -1744,12 +1766,25 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 {
        hda_nid_t cvt_nid = hinfo->nid;
        struct hdmi_spec *spec = codec->spec;
-       int pin_idx = hinfo_to_pin_index(spec, hinfo);
+       int pin_idx = hinfo_to_pin_index(codec, hinfo);
        struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        hda_nid_t pin_nid = per_pin->pin_nid;
        bool non_pcm;
        int pinctl;
 
+       if (is_haswell_plus(codec) || is_valleyview(codec)) {
+               /* Verify pin:cvt selections to avoid silent audio after S3.
+                * After S3, the audio driver restores pin:cvt selections
+                * but this can happen before gfx is ready and such selection
+                * is overlooked by HW. Thus multiple pins can share a same
+                * default convertor and mute control will affect each other,
+                * which can cause a resumed audio playback become silent
+                * after S3.
+                */
+               intel_verify_pin_cvt_connect(codec, per_pin);
+               intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx);
+       }
+
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
        mutex_lock(&per_pin->lock);
        per_pin->channels = substream->runtime->channels;
@@ -1788,7 +1823,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
        int pinctl;
 
        if (hinfo->nid) {
-               cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
+               cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
                if (snd_BUG_ON(cvt_idx < 0))
                        return -EINVAL;
                per_cvt = get_cvt(spec, cvt_idx);
@@ -1797,7 +1832,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                per_cvt->assigned = 0;
                hinfo->nid = 0;
 
-               pin_idx = hinfo_to_pin_index(spec, hinfo);
+               pin_idx = hinfo_to_pin_index(codec, hinfo);
                if (snd_BUG_ON(pin_idx < 0))
                        return -EINVAL;
                per_pin = get_pin(spec, pin_idx);
@@ -2211,7 +2246,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
                return;
 
        /* override pins connection list */
-       snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
+       codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid);
        snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
 }
 
@@ -3132,8 +3167,8 @@ static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
                else
                        hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
 
-               snd_printdd("atihdmi_pin_hbr_setup: "
-                               "NID=0x%x, %shbr-ctl=0x%x\n",
+               codec_dbg(codec,
+                         "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
                                pin_nid,
                                hbr_ctl == hbr_ctl_new ? "" : "new-",
                                hbr_ctl_new);
index ec304f3ae3b41d4a8a1295c448ff35e18eb58977..ea2351d119f0a0ff5f10b722995eb0e7b4774688 100644 (file)
@@ -395,6 +395,8 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
                goto do_sku;
        }
 
+       if (!codec->bus->pci)
+               return -1;
        ass = codec->subsystem_id & 0xffff;
        if (ass != codec->bus->pci->subsystem_device && (ass & 1))
                goto do_sku;
@@ -405,8 +407,8 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
        ass = snd_hda_codec_get_pincfg(codec, nid);
 
        if (!(ass & 1)) {
-               printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
-                      codec->chip_name, ass);
+               codec_info(codec, "%s: SKU not ready 0x%08x\n",
+                          codec->chip_name, ass);
                return -1;
        }
 
@@ -430,17 +432,17 @@ do_sku:
        spec->cdefine.swap = (ass & 0x2) >> 1;
        spec->cdefine.override = ass & 0x1;
 
-       snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
+       codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
                   nid, spec->cdefine.sku_cfg);
-       snd_printd("SKU: port_connectivity=0x%x\n",
+       codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
                   spec->cdefine.port_connectivity);
-       snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
-       snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
-       snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
-       snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
-       snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
-       snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
-       snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
+       codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
+       codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
+       codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
+       codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
+       codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
+       codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
+       codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
 
        return 0;
 }
@@ -483,7 +485,8 @@ static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
        }
 
        ass = codec->subsystem_id & 0xffff;
-       if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
+       if (codec->bus->pci &&
+           ass != codec->bus->pci->subsystem_device && (ass & 1))
                goto do_sku;
 
        /* invalid SSID, check the special NID pin defcfg instead */
@@ -499,8 +502,8 @@ static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
        if (codec->vendor_id == 0x10ec0260)
                nid = 0x17;
        ass = snd_hda_codec_get_pincfg(codec, nid);
-       snd_printd("realtek: No valid SSID, "
-                  "checking pincfg 0x%08x for NID 0x%x\n",
+       codec_dbg(codec,
+                 "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
                   ass, nid);
        if (!(ass & 1))
                return 0;
@@ -516,7 +519,7 @@ static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
        if (((ass >> 16) & 0xf) != tmp)
                return 0;
 do_sku:
-       snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+       codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
                   ass & 0xffff, codec->vendor_id);
        /*
         * 0 : override
@@ -574,8 +577,8 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
 {
        if (!alc_subsystem_id(codec, ports)) {
                struct alc_spec *spec = codec->spec;
-               snd_printd("realtek: "
-                          "Enable default setup for auto mode as fallback\n");
+               codec_dbg(codec,
+                         "realtek: Enable default setup for auto mode as fallback\n");
                spec->init_amp = ALC_INIT_DEFAULT;
        }
 }
@@ -845,11 +848,7 @@ static inline void alc_shutup(struct hda_codec *codec)
                snd_hda_shutup_pins(codec);
 }
 
-static void alc_free(struct hda_codec *codec)
-{
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
-       snd_hda_gen_free(codec);
-}
+#define alc_free       snd_hda_gen_free
 
 #ifdef CONFIG_PM
 static void alc_power_eapd(struct hda_codec *codec)
@@ -970,6 +969,8 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
                        return alc_codec_rename(codec, p->name);
        }
 
+       if (!codec->bus->pci)
+               return 0;
        for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
                if (q->codec_vendor_id != codec->vendor_id)
                        continue;
@@ -993,6 +994,7 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
 
 static const struct snd_pci_quirk beep_white_list[] = {
        SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
+       SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
        SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
        SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
        SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
@@ -2786,6 +2788,237 @@ static void alc269_shutup(struct hda_codec *codec)
        snd_hda_shutup_pins(codec);
 }
 
+static void alc282_restore_default_value(struct hda_codec *codec)
+{
+       int val;
+
+       /* Power Down Control */
+       alc_write_coef_idx(codec, 0x03, 0x0002);
+       /* FIFO and filter clock */
+       alc_write_coef_idx(codec, 0x05, 0x0700);
+       /* DMIC control */
+       alc_write_coef_idx(codec, 0x07, 0x0200);
+       /* Analog clock */
+       val = alc_read_coef_idx(codec, 0x06);
+       alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
+       /* JD */
+       val = alc_read_coef_idx(codec, 0x08);
+       alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
+       /* JD offset1 */
+       alc_write_coef_idx(codec, 0x0a, 0xcccc);
+       /* JD offset2 */
+       alc_write_coef_idx(codec, 0x0b, 0xcccc);
+       /* LDO1/2/3, DAC/ADC */
+       alc_write_coef_idx(codec, 0x0e, 0x6e00);
+       /* JD */
+       val = alc_read_coef_idx(codec, 0x0f);
+       alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
+       /* Capless */
+       val = alc_read_coef_idx(codec, 0x10);
+       alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
+       /* Class D test 4 */
+       alc_write_coef_idx(codec, 0x6f, 0x0);
+       /* IO power down directly */
+       val = alc_read_coef_idx(codec, 0x0c);
+       alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
+       /* ANC */
+       alc_write_coef_idx(codec, 0x34, 0xa0c0);
+       /* AGC MUX */
+       val = alc_read_coef_idx(codec, 0x16);
+       alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0);
+       /* DAC simple content protection */
+       val = alc_read_coef_idx(codec, 0x1d);
+       alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
+       /* ADC simple content protection */
+       val = alc_read_coef_idx(codec, 0x1f);
+       alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
+       /* DAC ADC Zero Detection */
+       alc_write_coef_idx(codec, 0x21, 0x8804);
+       /* PLL */
+       alc_write_coef_idx(codec, 0x63, 0x2902);
+       /* capless control 2 */
+       alc_write_coef_idx(codec, 0x68, 0xa080);
+       /* capless control 3 */
+       alc_write_coef_idx(codec, 0x69, 0x3400);
+       /* capless control 4 */
+       alc_write_coef_idx(codec, 0x6a, 0x2f3e);
+       /* capless control 5 */
+       alc_write_coef_idx(codec, 0x6b, 0x0);
+       /* class D test 2 */
+       val = alc_read_coef_idx(codec, 0x6d);
+       alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900);
+       /* class D test 3 */
+       alc_write_coef_idx(codec, 0x6e, 0x110a);
+       /* class D test 5 */
+       val = alc_read_coef_idx(codec, 0x70);
+       alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8);
+       /* class D test 6 */
+       alc_write_coef_idx(codec, 0x71, 0x0014);
+       /* classD OCP */
+       alc_write_coef_idx(codec, 0x72, 0xc2ba);
+       /* classD pure DC test */
+       val = alc_read_coef_idx(codec, 0x77);
+       alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0);
+       /* Class D amp control */
+       alc_write_coef_idx(codec, 0x6c, 0xfc06);
+}
+
+static void alc282_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_pin_sense;
+       int coef78;
+
+       alc282_restore_default_value(codec);
+
+       if (!hp_pin)
+               return;
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       coef78 = alc_read_coef_idx(codec, 0x78);
+
+       /* Index 0x78 Direct Drive HP AMP LPM Control 1 */
+       /* Headphone capless set to high power mode */
+       alc_write_coef_idx(codec, 0x78, 0x9004);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       /* Headphone capless set to normal mode */
+       alc_write_coef_idx(codec, 0x78, coef78);
+}
+
+static void alc282_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_pin_sense;
+       int coef78;
+
+       if (!hp_pin) {
+               alc269_shutup(codec);
+               return;
+       }
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       coef78 = alc_read_coef_idx(codec, 0x78);
+       alc_write_coef_idx(codec, 0x78, 0x9004);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       alc_auto_setup_eapd(codec, false);
+       snd_hda_shutup_pins(codec);
+       alc_write_coef_idx(codec, 0x78, coef78);
+}
+
+static void alc283_restore_default_value(struct hda_codec *codec)
+{
+       int val;
+
+       /* Power Down Control */
+       alc_write_coef_idx(codec, 0x03, 0x0002);
+       /* FIFO and filter clock */
+       alc_write_coef_idx(codec, 0x05, 0x0700);
+       /* DMIC control */
+       alc_write_coef_idx(codec, 0x07, 0x0200);
+       /* Analog clock */
+       val = alc_read_coef_idx(codec, 0x06);
+       alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
+       /* JD */
+       val = alc_read_coef_idx(codec, 0x08);
+       alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
+       /* JD offset1 */
+       alc_write_coef_idx(codec, 0x0a, 0xcccc);
+       /* JD offset2 */
+       alc_write_coef_idx(codec, 0x0b, 0xcccc);
+       /* LDO1/2/3, DAC/ADC */
+       alc_write_coef_idx(codec, 0x0e, 0x6fc0);
+       /* JD */
+       val = alc_read_coef_idx(codec, 0x0f);
+       alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
+       /* Capless */
+       val = alc_read_coef_idx(codec, 0x10);
+       alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
+       /* Class D test 4 */
+       alc_write_coef_idx(codec, 0x3a, 0x0);
+       /* IO power down directly */
+       val = alc_read_coef_idx(codec, 0x0c);
+       alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
+       /* ANC */
+       alc_write_coef_idx(codec, 0x22, 0xa0c0);
+       /* AGC MUX */
+       val = alc_read_coefex_idx(codec, 0x53, 0x01);
+       alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008);
+       /* DAC simple content protection */
+       val = alc_read_coef_idx(codec, 0x1d);
+       alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
+       /* ADC simple content protection */
+       val = alc_read_coef_idx(codec, 0x1f);
+       alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
+       /* DAC ADC Zero Detection */
+       alc_write_coef_idx(codec, 0x21, 0x8804);
+       /* PLL */
+       alc_write_coef_idx(codec, 0x2e, 0x2902);
+       /* capless control 2 */
+       alc_write_coef_idx(codec, 0x33, 0xa080);
+       /* capless control 3 */
+       alc_write_coef_idx(codec, 0x34, 0x3400);
+       /* capless control 4 */
+       alc_write_coef_idx(codec, 0x35, 0x2f3e);
+       /* capless control 5 */
+       alc_write_coef_idx(codec, 0x36, 0x0);
+       /* class D test 2 */
+       val = alc_read_coef_idx(codec, 0x38);
+       alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900);
+       /* class D test 3 */
+       alc_write_coef_idx(codec, 0x39, 0x110a);
+       /* class D test 5 */
+       val = alc_read_coef_idx(codec, 0x3b);
+       alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8);
+       /* class D test 6 */
+       alc_write_coef_idx(codec, 0x3c, 0x0014);
+       /* classD OCP */
+       alc_write_coef_idx(codec, 0x3d, 0xc2ba);
+       /* classD pure DC test */
+       val = alc_read_coef_idx(codec, 0x42);
+       alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0);
+       /* test mode */
+       alc_write_coef_idx(codec, 0x49, 0x0);
+       /* Class D DC enable */
+       val = alc_read_coef_idx(codec, 0x40);
+       alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800);
+       /* DC offset */
+       val = alc_read_coef_idx(codec, 0x42);
+       alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000);
+       /* Class D amp control */
+       alc_write_coef_idx(codec, 0x37, 0xfc06);
+}
+
 static void alc283_init(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -2793,6 +3026,8 @@ static void alc283_init(struct hda_codec *codec)
        bool hp_pin_sense;
        int val;
 
+       alc283_restore_default_value(codec);
+
        if (!hp_pin)
                return;
        hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
@@ -3169,7 +3404,8 @@ static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
                spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
                spec->gen.vmaster_mute_enum = 1;
                codec->power_filter = led_power_filter;
-               snd_printd("Detected mute LED for %x:%d\n", spec->mute_led_nid,
+               codec_dbg(codec,
+                         "Detected mute LED for %x:%d\n", spec->mute_led_nid,
                           spec->mute_led_polarity);
                break;
        }
@@ -3295,7 +3531,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0xb7, 0x802b);
                break;
        }
-       snd_printdd("Headset jack set to unplugged mode.\n");
+       codec_dbg(codec, "Headset jack set to unplugged mode.\n");
 }
 
 
@@ -3338,7 +3574,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
        }
-       snd_printdd("Headset jack set to mic-in mode.\n");
+       codec_dbg(codec, "Headset jack set to mic-in mode.\n");
 }
 
 static void alc_headset_mode_default(struct hda_codec *codec)
@@ -3366,7 +3602,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0xb7, 0x802b);
                break;
        }
-       snd_printdd("Headset jack set to headphone (default) mode.\n");
+       codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
 }
 
 /* Iphone type */
@@ -3395,7 +3631,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0xc3, 0x0000);
                break;
        }
-       snd_printdd("Headset jack set to iPhone-style headset mode.\n");
+       codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
 }
 
 /* Nokia type */
@@ -3424,7 +3660,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
                alc_write_coef_idx(codec, 0xc3, 0x0000);
                break;
        }
-       snd_printdd("Headset jack set to Nokia-style headset mode.\n");
+       codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
 }
 
 static void alc_determine_headset_type(struct hda_codec *codec)
@@ -3466,7 +3702,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                break;
        }
 
-       snd_printdd("Headset jack detected iPhone-style headset: %s\n",
+       codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
                    is_ctia ? "yes" : "no");
        spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
 }
@@ -3592,21 +3828,38 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
                alc_fixup_headset_mode(codec, fix, action);
 }
 
+static void alc255_set_default_jack_type(struct hda_codec *codec)
+{
+       /* Set to iphone type */
+       alc_write_coef_idx(codec, 0x1b, 0x880b);
+       alc_write_coef_idx(codec, 0x45, 0xd089);
+       alc_write_coef_idx(codec, 0x1b, 0x080b);
+       alc_write_coef_idx(codec, 0x46, 0x0004);
+       alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+       msleep(30);
+}
+
 static void alc_fixup_headset_mode_alc255(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* Set to iphone type */
-               alc_write_coef_idx(codec, 0x1b, 0x880b);
-               alc_write_coef_idx(codec, 0x45, 0xd089);
-               alc_write_coef_idx(codec, 0x1b, 0x080b);
-               alc_write_coef_idx(codec, 0x46, 0x0004);
-               alc_write_coef_idx(codec, 0x1b, 0x0c0b);
-               msleep(30);
+               alc255_set_default_jack_type(codec);
        }
        alc_fixup_headset_mode(codec, fix, action);
 }
 
+static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               alc255_set_default_jack_type(codec);
+       } 
+       else
+               alc_fixup_headset_mode(codec, fix, action);
+}
+
 static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
                                        const struct hda_fixup *fix, int action)
 {
@@ -3616,6 +3869,19 @@ static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
        }
 }
 
+static void alc_no_shutup(struct hda_codec *codec)
+{
+}
+
+static void alc_fixup_no_shutup(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->shutup = alc_no_shutup;
+       }
+}
+
 static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -3844,6 +4110,7 @@ enum {
        ALC269_FIXUP_HP_GPIO_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
+       ALC269_FIXUP_NO_SHUTUP,
        ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
        ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
        ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -3873,7 +4140,9 @@ enum {
        ALC290_FIXUP_SUBWOOFER_HSJACK,
        ALC269_FIXUP_THINKPAD_ACPI,
        ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
        ALC255_FIXUP_HEADSET_MODE,
+       ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4020,6 +4289,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_inv_dmic_0x12,
        },
+       [ALC269_FIXUP_NO_SHUTUP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_shutup,
+       },
        [ALC269_FIXUP_LENOVO_DOCK] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -4246,13 +4519,27 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC255_FIXUP_HEADSET_MODE
        },
+       [ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
        [ALC255_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_alc255,
        },
+       [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc255_no_hp_mic,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
@@ -4300,6 +4587,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0629, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x062c, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x062e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0632, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -4312,6 +4602,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_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),
@@ -4404,6 +4696,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -4553,13 +4846,15 @@ static int patch_alc269(struct hda_codec *codec)
                spec->codec_variant = ALC269_TYPE_ALC269VA;
                switch (alc_get_coef0(codec) & 0x00f0) {
                case 0x0010:
-                       if (codec->bus->pci->subsystem_vendor == 0x1025 &&
+                       if (codec->bus->pci &&
+                           codec->bus->pci->subsystem_vendor == 0x1025 &&
                            spec->cdefine.platform_type == 1)
                                err = alc_codec_rename(codec, "ALC271X");
                        spec->codec_variant = ALC269_TYPE_ALC269VB;
                        break;
                case 0x0020:
-                       if (codec->bus->pci->subsystem_vendor == 0x17aa &&
+                       if (codec->bus->pci &&
+                           codec->bus->pci->subsystem_vendor == 0x17aa &&
                            codec->bus->pci->subsystem_device == 0x21f3)
                                err = alc_codec_rename(codec, "ALC3202");
                        spec->codec_variant = ALC269_TYPE_ALC269VC;
@@ -4582,6 +4877,8 @@ static int patch_alc269(struct hda_codec *codec)
                break;
        case 0x10ec0282:
                spec->codec_variant = ALC269_TYPE_ALC282;
+               spec->shutup = alc282_shutup;
+               spec->init_hook = alc282_init;
                break;
        case 0x10ec0233:
        case 0x10ec0283:
@@ -4899,8 +5196,7 @@ static void alc272_fixup_mario(struct hda_codec *codec,
                                      (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
                                      (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
                                      (0 << AC_AMPCAP_MUTE_SHIFT)))
-               printk(KERN_WARNING
-                      "hda_codec: failed to override amp caps for NID 0x2\n");
+               codec_warn(codec, "failed to override amp caps for NID 0x2\n");
 }
 
 static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
@@ -4922,8 +5218,54 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
        }
 }
 
+/* turn on/off mute LED per vmaster hook */
+static void alc662_led_gpio1_mute_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct alc_spec *spec = codec->spec;
+       unsigned int oldval = spec->gpio_led;
+
+       if (enabled)
+               spec->gpio_led &= ~0x01;
+       else
+               spec->gpio_led |= 0x01;
+       if (spec->gpio_led != oldval)
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+}
+
+/* avoid D3 for keeping GPIO up */
+static unsigned int gpio_led_power_filter(struct hda_codec *codec,
+                                         hda_nid_t nid,
+                                         unsigned int power_state)
+{
+       struct alc_spec *spec = codec->spec;
+       if (nid == codec->afg && power_state == AC_PWRST_D3 && spec->gpio_led)
+               return AC_PWRST_D0;
+       return power_state;
+}
+
+static void alc662_fixup_led_gpio1(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
+               {}
+       };
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook;
+               spec->gpio_led = 0;
+               snd_hda_add_verbs(codec, gpio_init);
+               codec->power_filter = gpio_led_power_filter;
+       }
+}
+
 enum {
        ALC662_FIXUP_ASPIRE,
+       ALC662_FIXUP_LED_GPIO1,
        ALC662_FIXUP_IDEAPAD,
        ALC272_FIXUP_MARIO,
        ALC662_FIXUP_CZC_P10T,
@@ -4942,9 +5284,10 @@ enum {
        ALC662_FIXUP_INV_DMIC,
        ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
        ALC668_FIXUP_HEADSET_MODE,
-       ALC662_FIXUP_BASS_CHMAP,
+       ALC662_FIXUP_BASS_MODE4_CHMAP,
+       ALC662_FIXUP_BASS_16,
        ALC662_FIXUP_BASS_1A,
-       ALC662_FIXUP_BASS_1A_CHMAP,
+       ALC662_FIXUP_BASS_CHMAP,
        ALC668_FIXUP_AUTO_MUTE,
 };
 
@@ -4956,12 +5299,18 @@ static const struct hda_fixup alc662_fixups[] = {
                        { }
                }
        },
+       [ALC662_FIXUP_LED_GPIO1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc662_fixup_led_gpio1,
+       },
        [ALC662_FIXUP_IDEAPAD] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
                        { 0x17, 0x99130112 }, /* subwoofer */
                        { }
-               }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_LED_GPIO1,
        },
        [ALC272_FIXUP_MARIO] = {
                .type = HDA_FIXUP_FUNC,
@@ -5126,24 +5475,33 @@ static const struct hda_fixup alc662_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_alc668,
        },
-       [ALC662_FIXUP_BASS_CHMAP] = {
+       [ALC662_FIXUP_BASS_MODE4_CHMAP] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_bass_chmap,
                .chained = true,
                .chain_id = ALC662_FIXUP_ASUS_MODE4
        },
+       [ALC662_FIXUP_BASS_16] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x16, 0x80106111}, /* bass speaker */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_CHMAP,
+       },
        [ALC662_FIXUP_BASS_1A] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
                        {0x1a, 0x80106111}, /* bass speaker */
                        {}
                },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_CHMAP,
        },
-       [ALC662_FIXUP_BASS_1A_CHMAP] = {
+       [ALC662_FIXUP_BASS_CHMAP] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_bass_chmap,
-               .chained = true,
-               .chain_id = ALC662_FIXUP_BASS_1A,
        },
 };
 
@@ -5163,11 +5521,13 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE),
-       SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
-       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP),
-       SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP),
-       SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_CHMAP),
+       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
+       SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+       SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
+       SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
+       SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
        SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
@@ -5308,7 +5668,7 @@ static int patch_alc662(struct hda_codec *codec)
                spec->gen.beep_nid = 0x01;
 
        if ((alc_get_coef0(codec) & (1 << 14)) &&
-           codec->bus->pci->subsystem_vendor == 0x1025 &&
+           codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
            spec->cdefine.platform_type == 1) {
                err = alc_codec_rename(codec, "ALC272X");
                if (err < 0)
index 6679a5095e559ddee57fe068593c31e39a613126..3208ad69583ee5564272d16ce2fd97185351a53c 100644 (file)
@@ -236,7 +236,7 @@ static int si3054_init(struct hda_codec *codec)
        } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
 
        if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
-               snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
+               codec_err(codec, "si3054: cannot initialize. EXT MID = %04x\n", val);
                /* let's pray that this is no fatal error */
                /* return -EACCES; */
        }
@@ -247,7 +247,8 @@ static int si3054_init(struct hda_codec *codec)
        SET_REG(codec, SI3054_LINE_CFG1,0x200);
 
        if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
-               snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n",
+               codec_dbg(codec,
+                         "Link Frame Detect(FDT) is not ready (line status: %04x)\n",
                                GET_REG(codec,SI3054_LINE_STATUS));
        }
 
index 3bc29c9b25296d6ed058eaf552bf71bdba356cab..75515b4940341a8599219f6a3ff2ee741b9f8138 100644 (file)
@@ -296,7 +296,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
 {
        unsigned int gpiostate, gpiomask, gpiodir;
 
-       snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+       codec_dbg(codec, "%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
 
        gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
                                       AC_VERB_GET_GPIO_DATA, 0);
@@ -359,7 +359,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
 {
        int error, pinctl;
 
-       snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref);
+       codec_dbg(codec, "%s, nid %x ctl %x\n", __func__, nid, new_vref);
        pinctl = snd_hda_codec_read(codec, nid, 0,
                                AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 
@@ -2086,9 +2086,12 @@ static void stac92hd83xxx_fixup_hp(struct hda_codec *codec,
        }
 
        if (find_mute_led_cfg(codec, spec->default_polarity))
-               snd_printd("mute LED gpio %d polarity %d\n",
+               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
+
+       /* allow auto-switching of dock line-in */
+       spec->gen.line_in_auto_switch = true;
 }
 
 static void stac92hd83xxx_fixup_hp_zephyr(struct hda_codec *codec,
@@ -3077,7 +3080,7 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
        }
 
        if (find_mute_led_cfg(codec, 1))
-               snd_printd("mute LED gpio %d polarity %d\n",
+               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
 
@@ -4422,8 +4425,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
 
        num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1;
        if (num_dacs < 3 || num_dacs > 5) {
-               printk(KERN_WARNING "hda_codec: Could not determine "
-                      "number of channels defaulting to DAC count\n");
+               codec_warn(codec,
+                          "Could not determine number of channels defaulting to DAC count\n");
                num_dacs = 5;
        }
 
index f84195f3ea31e2f6bac3c1c5f79355e1ec24c0fb..778166259b3e8e72fe039d08fe5e1671d5c6fd94 100644 (file)
@@ -465,14 +465,8 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
 
 static void via_free(struct hda_codec *codec)
 {
-       struct via_spec *spec = codec->spec;
-
-       if (!spec)
-               return;
-
        vt1708_stop_hp_work(codec);
-       snd_hda_gen_spec_free(&spec->gen);
-       kfree(spec);
+       snd_hda_gen_free(codec);
 }
 
 #ifdef CONFIG_PM
index 8fe3b8c18ed4b2c25c00b4963ec766b7671829d9..6ba0b5517c407fdb015a8ca366440b32128a92c6 100644 (file)
@@ -63,7 +63,8 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
                if (!led_set_func)
                        led_set_func = symbol_request(tpacpi_led_set);
                if (!led_set_func) {
-                       snd_printk(KERN_WARNING "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
+                       codec_warn(codec,
+                                  "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
                        return;
                }
 
@@ -75,7 +76,8 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
                }
                if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
                        if (spec->num_adc_nids > 1)
-                               snd_printdd("Skipping micmute LED control due to several ADCs");
+                               codec_dbg(codec,
+                                         "Skipping micmute LED control due to several ADCs");
                        else {
                                spec->cap_sync_hook = update_tpacpi_micmute_led;
                                removefunc = false;
index 55902ec40344d824b17d56d37d047f79281ba294..3b3cf4ac9060ac41b9876e52c94a4151e61cdce5 100644 (file)
@@ -1937,9 +1937,12 @@ static int aureon_add_controls(struct snd_ice1712 *ice)
                snd_ice1712_save_gpio_status(ice);
                id = aureon_cs8415_get(ice, CS8415_ID);
                if (id != 0x41)
-                       snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
+                       dev_info(ice->card->dev,
+                                "No CS8415 chip. Skipping CS8415 controls.\n");
                else if ((id & 0x0F) != 0x01)
-                       snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
+                       dev_info(ice->card->dev,
+                                "Detected unsupported CS8415 rev. (%c)\n",
+                                (char)((id & 0x0F) + 'A' - 1));
                else {
                        for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
                                struct snd_kcontrol *kctl;
index 9e28cc12969b3632357ae4f198634da499864903..ed2144eee38ac872d80e263953733639630169b2 100644 (file)
@@ -425,7 +425,8 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
        if (snd_i2c_sendbytes(ice->cs8427, &reg, 1) != 1)
-               snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg);
+               dev_err(ice->card->dev,
+                       "unable to send register 0x%x byte to CS8427\n", reg);
        snd_i2c_readbytes(ice->cs8427, &reg, 1);
        ucontrol->value.integer.value[0] = (reg & CS8427_UNLOCK) ? 1 : 0;
        return 0;
@@ -575,6 +576,30 @@ static struct snd_ak4xxx_private akm_vx442_priv = {
        .mask_flags = 0,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int snd_ice1712_delta_resume(struct snd_ice1712 *ice)
+{
+       unsigned char akm_backup[AK4XXX_IMAGE_SIZE];
+       /* init codec and restore registers */
+       if (ice->akm_codecs) {
+               memcpy(akm_backup, ice->akm->images, sizeof(akm_backup));
+               snd_akm4xxx_init(ice->akm);
+               memcpy(ice->akm->images, akm_backup, sizeof(akm_backup));
+               snd_akm4xxx_reset(ice->akm, 0);
+       }
+
+       return 0;
+}
+
+static int snd_ice1712_delta_suspend(struct snd_ice1712 *ice)
+{
+       if (ice->akm_codecs) /* reset & mute codec */
+               snd_akm4xxx_reset(ice->akm, 1);
+
+       return 0;
+}
+#endif
+
 static int snd_ice1712_delta_init(struct snd_ice1712 *ice)
 {
        int err;
@@ -621,7 +646,11 @@ static int snd_ice1712_delta_init(struct snd_ice1712 *ice)
                ice->num_total_adcs = 4;
                break;
        }
-
+#ifdef CONFIG_PM_SLEEP
+       ice->pm_resume = snd_ice1712_delta_resume;
+       ice->pm_suspend = snd_ice1712_delta_suspend;
+       ice->pm_suspend_enabled = 1;
+#endif
        /* initialize the SPI clock to high */
        tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
        tmp |= ICE1712_DELTA_AP_CCLK;
@@ -637,7 +666,7 @@ static int snd_ice1712_delta_init(struct snd_ice1712 *ice)
        case ICE1712_SUBDEVICE_VX442:
        case ICE1712_SUBDEVICE_DELTA66E:
                if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
-                       snd_printk(KERN_ERR "unable to create I2C bus\n");
+                       dev_err(ice->card->dev, "unable to create I2C bus\n");
                        return err;
                }
                ice->i2c->private_data = ice;
index bc2e7011c55d7fa184b63197f82ea7d6fab00a95..817a1bc50a60137e5c6674de07ac0c1a1b928ab1 100644 (file)
@@ -163,7 +163,8 @@ static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mas
 
      __error:
        snd_i2c_unlock(ice->i2c);
-       snd_printk(KERN_ERR "AK4524 chip select failed, check cable to the front module\n");
+       dev_err(ice->card->dev,
+               "AK4524 chip select failed, check cable to the front module\n");
        return -EIO;
 }
 
@@ -174,7 +175,7 @@ static void ews88mt_ak4524_lock(struct snd_akm4xxx *ak, int chip)
        unsigned char tmp;
        /* assert AK4524 CS */
        if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)
-               snd_printk(KERN_ERR "fatal error (ews88mt chip select)\n");
+               dev_err(ice->card->dev, "fatal error (ews88mt chip select)\n");
        snd_ice1712_save_gpio_status(ice);
        tmp = ICE1712_EWS88_SERIAL_DATA |
                ICE1712_EWS88_SERIAL_CLOCK |
@@ -456,7 +457,7 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice)
 
        /* create i2c */
        if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
-               snd_printk(KERN_ERR "unable to create I2C bus\n");
+               dev_err(ice->card->dev, "unable to create I2C bus\n");
                return err;
        }
        ice->i2c->private_data = ice;
@@ -469,7 +470,8 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice)
                                            ICE1712_6FIRE_PCF9554_ADDR,
                                            &spec->i2cdevs[EWS_I2C_6FIRE]);
                if (err < 0) {
-                       snd_printk(KERN_ERR "PCF9554 initialization failed\n");
+                       dev_err(ice->card->dev,
+                               "PCF9554 initialization failed\n");
                        return err;
                }
                snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80);
@@ -834,7 +836,7 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg
        byte = 0;
        if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
-               printk(KERN_ERR "cannot read pca\n");
+               dev_err(ice->card->dev, "cannot read pca\n");
                return -EIO;
        }
        snd_i2c_unlock(ice->i2c);
index 28ec872e54c01350369bf47f143db9c2d5da8b8d..291672fc4a99f2428c171c9a57955280776df209 100644 (file)
@@ -394,7 +394,7 @@ int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr)
        err = snd_cs8427_create(ice->i2c, addr,
                (ice->cs8427_timeout * HZ) / 1000, &ice->cs8427);
        if (err < 0) {
-               snd_printk(KERN_ERR "CS8427 initialization failed\n");
+               dev_err(ice->card->dev, "CS8427 initialization failed\n");
                return err;
        }
        ice->spdif.ops.open = open_cs8427;
@@ -467,7 +467,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
                        u16 pbkstatus;
                        struct snd_pcm_substream *substream;
                        pbkstatus = inw(ICEDS(ice, INTSTAT));
-                       /* printk(KERN_DEBUG "pbkstatus = 0x%x\n", pbkstatus); */
+                       /* dev_dbg(ice->card->dev, "pbkstatus = 0x%x\n", pbkstatus); */
                        for (idx = 0; idx < 6; idx++) {
                                if ((pbkstatus & (3 << (idx * 2))) == 0)
                                        continue;
@@ -903,7 +903,8 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm *
        if (rpcm)
                *rpcm = pcm;
 
-       printk(KERN_WARNING "Consumer PCM code does not work well at the moment --jk\n");
+       dev_warn(ice->card->dev,
+                "Consumer PCM code does not work well at the moment --jk\n");
 
        return 0;
 }
@@ -1534,7 +1535,8 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
                ac97.private_free = snd_ice1712_mixer_free_ac97;
                err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
                if (err < 0)
-                       printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
+                       dev_warn(ice->card->dev,
+                                "cannot initialize ac97 for consumer, skipped\n");
                else {
                        err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice));
                        if (err < 0)
@@ -1552,7 +1554,8 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
                ac97.private_free = snd_ice1712_mixer_free_ac97;
                err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
                if (err < 0)
-                       printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
+                       dev_warn(ice->card->dev,
+                                "cannot initialize pro ac97, skipped\n");
                else
                        return 0;
        }
@@ -2332,7 +2335,8 @@ static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
                        pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device);
                        ice->eeprom.subvendor = ((unsigned int)swab16(vendor) << 16) | swab16(device);
                        if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) {
-                               printk(KERN_ERR "ice1712: No valid ID is found\n");
+                               dev_err(ice->card->dev,
+                                       "No valid ID is found\n");
                                return -ENXIO;
                        }
                }
@@ -2340,21 +2344,22 @@ static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
        for (tbl = card_tables; *tbl; tbl++) {
                for (c = *tbl; c->subvendor; c++) {
                        if (modelname && c->model && !strcmp(modelname, c->model)) {
-                               printk(KERN_INFO "ice1712: Using board model %s\n", c->name);
+                               dev_info(ice->card->dev,
+                                        "Using board model %s\n", c->name);
                                ice->eeprom.subvendor = c->subvendor;
                        } else if (c->subvendor != ice->eeprom.subvendor)
                                continue;
                        if (!c->eeprom_size || !c->eeprom_data)
                                goto found;
                        /* if the EEPROM is given by the driver, use it */
-                       snd_printdd("using the defined eeprom..\n");
+                       dev_dbg(ice->card->dev, "using the defined eeprom..\n");
                        ice->eeprom.version = 1;
                        ice->eeprom.size = c->eeprom_size + 6;
                        memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
                        goto read_skipped;
                }
        }
-       printk(KERN_WARNING "ice1712: No matching model found for ID 0x%x\n",
+       dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n",
               ice->eeprom.subvendor);
 
  found:
@@ -2362,12 +2367,13 @@ static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
        if (ice->eeprom.size < 6)
                ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */
        else if (ice->eeprom.size > 32) {
-               snd_printk(KERN_ERR "invalid EEPROM (size = %i)\n", ice->eeprom.size);
+               dev_err(ice->card->dev,
+                       "invalid EEPROM (size = %i)\n", ice->eeprom.size);
                return -EIO;
        }
        ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05);
        if (ice->eeprom.version != 1) {
-               snd_printk(KERN_ERR "invalid EEPROM version %i\n",
+               dev_err(ice->card->dev, "invalid EEPROM version %i\n",
                           ice->eeprom.version);
                /* return -EIO; */
        }
@@ -2428,6 +2434,13 @@ static int snd_ice1712_chip_init(struct snd_ice1712 *ice)
                snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0);
        }
        snd_ice1712_set_pro_rate(ice, 48000, 1);
+       /* unmask used interrupts */
+       outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ?
+             ICE1712_IRQ_MPU2 : 0) |
+            ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ?
+             ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0),
+            ICEREG(ice, IRQMASK));
+       outb(0x00, ICEMT(ice, IRQ));
 
        return 0;
 }
@@ -2553,7 +2566,8 @@ static int snd_ice1712_create(struct snd_card *card,
        /* check, if we can restrict PCI DMA transfers to 28 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 28bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -2589,6 +2603,7 @@ static int snd_ice1712_create(struct snd_card *card,
        ice->pci = pci;
        ice->irq = -1;
        pci_set_master(pci);
+       /* disable legacy emulation */
        pci_write_config_word(ice->pci, 0x40, 0x807f);
        pci_write_config_word(ice->pci, 0x42, 0x0006);
        snd_ice1712_proc_init(ice);
@@ -2609,7 +2624,7 @@ static int snd_ice1712_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, ice)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_ice1712_free(ice);
                return -EIO;
        }
@@ -2625,22 +2640,12 @@ static int snd_ice1712_create(struct snd_card *card,
                return -EIO;
        }
 
-       /* unmask used interrupts */
-       outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ?
-             ICE1712_IRQ_MPU2 : 0) |
-            ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ?
-             ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0),
-            ICEREG(ice, IRQMASK));
-       outb(0x00, ICEMT(ice, IRQ));
-
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
        if (err < 0) {
                snd_ice1712_free(ice);
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_ice1712 = ice;
        return 0;
 }
@@ -2670,7 +2675,8 @@ static int snd_ice1712_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -2809,11 +2815,80 @@ static void snd_ice1712_remove(struct pci_dev *pci)
        snd_card_free(card);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int snd_ice1712_suspend(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct snd_ice1712 *ice = card->private_data;
+
+       if (!ice->pm_suspend_enabled)
+               return 0;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+       snd_pcm_suspend_all(ice->pcm);
+       snd_pcm_suspend_all(ice->pcm_pro);
+       snd_pcm_suspend_all(ice->pcm_ds);
+       snd_ac97_suspend(ice->ac97);
+
+       if (ice->pm_suspend)
+               ice->pm_suspend(ice);
+
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       pci_set_power_state(pci, PCI_D3hot);
+       return 0;
+}
+
+static int snd_ice1712_resume(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct snd_ice1712 *ice = card->private_data;
+
+       if (!ice->pm_suspend_enabled)
+               return 0;
+
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
+
+       if (pci_enable_device(pci) < 0) {
+               snd_card_disconnect(card);
+               return -EIO;
+       }
+
+       pci_set_master(pci);
+
+       if (snd_ice1712_chip_init(ice) < 0) {
+               snd_card_disconnect(card);
+               return -EIO;
+       }
+
+       if (ice->pm_resume)
+               ice->pm_resume(ice);
+
+       if (ice->ac97)
+               snd_ac97_resume(ice->ac97);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(snd_ice1712_pm, snd_ice1712_suspend, snd_ice1712_resume);
+#define SND_VT1712_PM_OPS      &snd_ice1712_pm
+#else
+#define SND_VT1712_PM_OPS      NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static struct pci_driver ice1712_driver = {
        .name = KBUILD_MODNAME,
        .id_table = snd_ice1712_ids,
        .probe = snd_ice1712_probe,
        .remove = snd_ice1712_remove,
+       .driver = {
+               .pm = SND_VT1712_PM_OPS,
+       },
 };
 
 module_pci_driver(ice1712_driver);
index 50047177829172f97c0c6b9302854bdd8b0aca93..5e7948f3efe91d80609543c1b090a48f969251db 100644 (file)
@@ -146,7 +146,7 @@ static unsigned char snd_vt1724_ac97_ready(struct snd_ice1712 *ice)
                        continue;
                return old_cmd;
        }
-       snd_printd(KERN_ERR "snd_vt1724_ac97_ready: timeout\n");
+       dev_dbg(ice->card->dev, "snd_vt1724_ac97_ready: timeout\n");
        return old_cmd;
 }
 
@@ -156,7 +156,7 @@ static int snd_vt1724_ac97_wait_bit(struct snd_ice1712 *ice, unsigned char bit)
        for (tm = 0; tm < 0x10000; tm++)
                if ((inb(ICEMT1724(ice, AC97_CMD)) & bit) == 0)
                        return 0;
-       snd_printd(KERN_ERR "snd_vt1724_ac97_wait_bit: timeout\n");
+       dev_dbg(ice->card->dev, "snd_vt1724_ac97_wait_bit: timeout\n");
        return -EIO;
 }
 
@@ -430,10 +430,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
                spin_lock(&ice->reg_lock);
                if (++timeout > 10) {
                        status = inb(ICEREG1724(ice, IRQSTAT));
-                       printk(KERN_ERR "ice1724: Too long irq loop, "
-                              "status = 0x%x\n", status);
+                       dev_err(ice->card->dev,
+                               "Too long irq loop, status = 0x%x\n", status);
                        if (status & VT1724_IRQ_MPU_TX) {
-                               printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
+                               dev_err(ice->card->dev, "Disabling MPU_TX\n");
                                enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
                        }
                        spin_unlock(&ice->reg_lock);
@@ -801,7 +801,7 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream)
        spin_unlock_irq(&ice->reg_lock);
 
        /*
-       printk(KERN_DEBUG "pro prepare: ch = %d, addr = 0x%x, "
+       dev_dbg(ice->card->dev, "pro prepare: ch = %d, addr = 0x%x, "
               "buffer = 0x%x, period = 0x%x\n",
               substream->runtime->channels,
               (unsigned int)substream->runtime->dma_addr,
@@ -821,13 +821,13 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
 #if 0 /* read PLAYBACK_ADDR */
        ptr = inl(ICEMT1724(ice, PLAYBACK_ADDR));
        if (ptr < substream->runtime->dma_addr) {
-               snd_printd("ice1724: invalid negative ptr\n");
+               dev_dbg(ice->card->dev, "invalid negative ptr\n");
                return 0;
        }
        ptr -= substream->runtime->dma_addr;
        ptr = bytes_to_frames(substream->runtime, ptr);
        if (ptr >= substream->runtime->buffer_size) {
-               snd_printd("ice1724: invalid ptr %d (size=%d)\n",
+               dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n",
                           (int)ptr, (int)substream->runtime->period_size);
                return 0;
        }
@@ -840,7 +840,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
        else if (ptr <= substream->runtime->buffer_size)
                ptr = substream->runtime->buffer_size - ptr;
        else {
-               snd_printd("ice1724: invalid ptr %d (size=%d)\n",
+               dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n",
                           (int)ptr, (int)substream->runtime->buffer_size);
                ptr = 0;
        }
@@ -884,7 +884,7 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr
        else if (ptr <= substream->runtime->buffer_size)
                ptr = substream->runtime->buffer_size - ptr;
        else {
-               snd_printd("ice1724: invalid ptr %d (size=%d)\n",
+               dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n",
                           (int)ptr, (int)substream->runtime->buffer_size);
                ptr = 0;
        }
@@ -1508,7 +1508,8 @@ static int snd_vt1724_ac97_mixer(struct snd_ice1712 *ice)
                ac97.private_data = ice;
                err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
                if (err < 0)
-                       printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
+                       dev_warn(ice->card->dev,
+                                "cannot initialize pro ac97, skipped\n");
                else
                        return 0;
        }
@@ -2271,7 +2272,7 @@ static void wait_i2c_busy(struct snd_ice1712 *ice)
        while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--)
                ;
        if (t == -1)
-               printk(KERN_ERR "ice1724: i2c busy timeout\n");
+               dev_err(ice->card->dev, "i2c busy timeout\n");
 }
 
 unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
@@ -2287,7 +2288,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
        val = inb(ICEREG1724(ice, I2C_DATA));
        mutex_unlock(&ice->i2c_mutex);
        /*
-       printk(KERN_DEBUG "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
+       dev_dbg(ice->card->dev, "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
        */
        return val;
 }
@@ -2298,7 +2299,7 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
        mutex_lock(&ice->i2c_mutex);
        wait_i2c_busy(ice);
        /*
-       printk(KERN_DEBUG "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
+       dev_dbg(ice->card->dev, "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
        */
        outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
        outb(data, ICEREG1724(ice, I2C_DATA));
@@ -2335,7 +2336,8 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
                                ((unsigned int)swab16(vendor) << 16) | swab16(device);
                        if (ice->eeprom.subvendor == 0 ||
                            ice->eeprom.subvendor == (unsigned int)-1) {
-                               printk(KERN_ERR "ice1724: No valid ID is found\n");
+                               dev_err(ice->card->dev,
+                                       "No valid ID is found\n");
                                return -ENXIO;
                        }
                }
@@ -2344,7 +2346,8 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
                for (c = *tbl; c->name; c++) {
                        if (modelname && c->model &&
                            !strcmp(modelname, c->model)) {
-                               printk(KERN_INFO "ice1724: Using board model %s\n",
+                               dev_info(ice->card->dev,
+                                        "Using board model %s\n",
                                       c->name);
                                ice->eeprom.subvendor = c->subvendor;
                        } else if (c->subvendor != ice->eeprom.subvendor)
@@ -2353,14 +2356,14 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
                        if (!c->eeprom_size || !c->eeprom_data)
                                goto found;
                        /* if the EEPROM is given by the driver, use it */
-                       snd_printdd("using the defined eeprom..\n");
+                       dev_dbg(ice->card->dev, "using the defined eeprom..\n");
                        ice->eeprom.version = 2;
                        ice->eeprom.size = c->eeprom_size + 6;
                        memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
                        goto read_skipped;
                }
        }
-       printk(KERN_WARNING "ice1724: No matching model found for ID 0x%x\n",
+       dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n",
               ice->eeprom.subvendor);
 #ifdef CONFIG_PM_SLEEP
        /* assume AC97-only card which can suspend without additional code */
@@ -2372,13 +2375,13 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
        if (ice->eeprom.size < 6)
                ice->eeprom.size = 32;
        else if (ice->eeprom.size > 32) {
-               printk(KERN_ERR "ice1724: Invalid EEPROM (size = %i)\n",
+               dev_err(ice->card->dev, "Invalid EEPROM (size = %i)\n",
                       ice->eeprom.size);
                return -EIO;
        }
        ice->eeprom.version = snd_vt1724_read_i2c(ice, dev, 0x05);
        if (ice->eeprom.version != 1 && ice->eeprom.version != 2)
-               printk(KERN_WARNING "ice1724: Invalid EEPROM version %i\n",
+               dev_warn(ice->card->dev, "Invalid EEPROM version %i\n",
                       ice->eeprom.version);
        size = ice->eeprom.size - 6;
        for (i = 0; i < size; i++)
@@ -2586,7 +2589,7 @@ static int snd_vt1724_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_vt1724_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, ice)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_vt1724_free(ice);
                return -EIO;
        }
@@ -2609,8 +2612,6 @@ static int snd_vt1724_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_ice1712 = ice;
        return 0;
 }
@@ -2638,7 +2639,8 @@ static int snd_vt1724_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
index 8855933e710d7fe54e60ddffe6e509558f9b4589..7a6c0786c55c29f9a104c11298148d9e15d0d3a2 100644 (file)
@@ -244,7 +244,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
        /* AK5385 first, since it requires cold reset affecting both codecs */
        old_gpio = ice->gpio.get_data(ice);
        new_gpio =  (old_gpio & ~GPIO_AK5385A_MASK) | ak5385_pins;
-       /* printk(KERN_DEBUG "JULI - ak5385 set_rate_val: new gpio 0x%x\n",
+       /* dev_dbg(ice->card->dev, "JULI - ak5385 set_rate_val: new gpio 0x%x\n",
                new_gpio); */
        ice->gpio.set_data(ice, new_gpio);
 
@@ -344,7 +344,7 @@ static int juli_mute_put(struct snd_kcontrol *kcontrol,
                        new_gpio =  old_gpio &
                                ~((unsigned int) kcontrol->private_value);
        }
-       /* printk(KERN_DEBUG
+       /* dev_dbg(ice->card->dev,
                "JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, "
                "new_gpio 0x%x\n",
                (unsigned int)ucontrol->value.integer.value[0], old_gpio,
@@ -439,9 +439,9 @@ static void add_slaves(struct snd_card *card,
 {
        for (; *list; list++) {
                struct snd_kcontrol *slave = ctl_find(card, *list);
-               /* printk(KERN_DEBUG "add_slaves - %s\n", *list); */
+               /* dev_dbg(card->dev, "add_slaves - %s\n", *list); */
                if (slave) {
-                       /* printk(KERN_DEBUG "slave %s found\n", *list); */
+                       /* dev_dbg(card->dev, "slave %s found\n", *list); */
                        snd_ctl_add_slave(master, slave);
                }
        }
@@ -536,7 +536,7 @@ static void juli_set_rate(struct snd_ice1712 *ice, unsigned int rate)
 
        old = ice->gpio.get_data(ice);
        new =  (old & ~GPIO_RATE_MASK) | get_gpio_val(rate);
-       /* printk(KERN_DEBUG "JULI - set_rate: old %x, new %x\n",
+       /* dev_dbg(ice->card->dev, "JULI - set_rate: old %x, new %x\n",
                        old & GPIO_RATE_MASK,
                        new & GPIO_RATE_MASK); */
 
@@ -573,7 +573,7 @@ static void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0,
        if (ice->is_spdif_master(ice) && c1) {
                /* only for SPDIF master mode, rate was changed */
                rate = snd_ak4114_external_rate(ak4114);
-               /* printk(KERN_DEBUG "ak4114 - input rate changed to %d\n",
+               /* dev_dbg(ice->card->dev, "ak4114 - input rate changed to %d\n",
                                rate); */
                juli_akm_set_rate_val(ice->akm, rate);
        }
@@ -628,7 +628,7 @@ static int juli_init(struct snd_ice1712 *ice)
 #endif
 
        if (spec->analog) {
-               printk(KERN_INFO "juli@: analog I/O detected\n");
+               dev_info(ice->card->dev, "juli@: analog I/O detected\n");
                ice->num_total_dacs = 2;
                ice->num_total_adcs = 2;
 
index e610339f7601416c972364192011e4f176819727..f3b491aa3e223ce8fc8825e921ebe9e49067afac 100644 (file)
@@ -98,7 +98,7 @@ static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx,
        new = (~mute << 7 & 0x80) | (old & ~0x80);
        change = (new != old);
        if (change)
-               /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/
+               /* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/
                stac9460_put(ice, idx, new);
        return change;
 }
@@ -133,7 +133,7 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        /* due to possible conflicts with stac9460_set_rate_val, mutexing */
        mutex_lock(&spec->mute_mutex);
        /*
-       printk(KERN_DEBUG "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
+       dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
               ucontrol->value.integer.value[0]);
        */
        change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
@@ -187,7 +187,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        if (change) {
                ovol =  (0x7f - nvol) | (tmp & 0x80);
                /*
-               printk(KERN_DEBUG "DAC Volume: reg 0x%02x: 0x%02x\n",
+               dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n",
                       idx, ovol);
                */
                stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
@@ -348,7 +348,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
        for (idx = 0; idx < 7 ; ++idx)
                changed[idx] = stac9460_dac_mute(ice,
                                STAC946X_MASTER_VOLUME + idx, 0);
-       /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+       /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
        stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
        udelay(10);
        /* unmuting - only originally unmuted dacs -
@@ -768,9 +768,10 @@ static int prodigy192_init(struct snd_ice1712 *ice)
                /* from this moment if err = 0 then
                 * spec->ak4114 should not be null
                 */
-               snd_printdd("AK4114 initialized with status %d\n", err);
+               dev_dbg(ice->card->dev,
+                       "AK4114 initialized with status %d\n", err);
        } else
-               snd_printdd("AK4114 not found\n");
+               dev_dbg(ice->card->dev, "AK4114 not found\n");
        if (err < 0)
                return err;
 
index 71c6003ef338a04d5c400b3c0c300d58cf4ddede..2c2df4b74e01420966853324fbeebae6c66b53fa 100644 (file)
@@ -280,7 +280,7 @@ static void qtet_akm_write(struct snd_akm4xxx *ak, int chip,
 
        if (snd_BUG_ON(chip < 0 || chip >= 4))
                return;
-       /*printk(KERN_DEBUG "Writing to AK4620: chip=%d, addr=0x%x,
+       /*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x,
          data=0x%x\n", chip, addr, data);*/
        orig_dir = ice->gpio.get_dir(ice);
        ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL);
@@ -898,7 +898,7 @@ static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate)
        new =  (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate);
        /* switch to internal clock, drop CPLD_SYNC_SEL */
        new &= ~CPLD_SYNC_SEL;
-       /* printk(KERN_DEBUG "QT - set_rate: old %x, new %x\n",
+       /* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n",
           get_cpld(ice), new); */
        set_cpld(ice, new);
 }
@@ -978,7 +978,7 @@ static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0,
                        c1) {
                /* only for SPDIF master mode, rate was changed */
                rate = snd_ak4113_external_rate(ak4113);
-               /* printk(KERN_DEBUG "ak4113 - input rate changed to %d\n",
+               /* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n",
                   rate); */
                qtet_akm_set_rate_val(ice->akm, rate);
        }
index 08d8733604a2ed981d1c5ac32e095c452e56a431..68340d7df76d14cc85bfa534127c60c20db3fada 100644 (file)
@@ -547,7 +547,8 @@ static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int code
        /* access to some forbidden (non existent) ac97 registers will not
         * reset the semaphore. So even if you don't get the semaphore, still
         * continue the access. We don't need the semaphore anyway. */
-       snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
+       dev_err(chip->card->dev,
+               "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
                        igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));
        iagetword(chip, 0);     /* clear semaphore flag */
        /* I don't care about the semaphore */
@@ -562,7 +563,9 @@ static void snd_intel8x0_codec_write(struct snd_ac97 *ac97,
        
        if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {
                if (! chip->in_ac97_init)
-                       snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+                       dev_err(chip->card->dev,
+                               "codec_write %d: semaphore is not ready for register 0x%x\n",
+                               ac97->num, reg);
        }
        iaputword(chip, reg + ac97->num * 0x80, val);
 }
@@ -576,7 +579,9 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
 
        if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {
                if (! chip->in_ac97_init)
-                       snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+                       dev_err(chip->card->dev,
+                               "codec_read %d: semaphore is not ready for register 0x%x\n",
+                               ac97->num, reg);
                res = 0xffff;
        } else {
                res = iagetword(chip, reg + ac97->num * 0x80);
@@ -585,7 +590,9 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
                        iputdword(chip, ICHREG(GLOB_STA), tmp &
                                  ~(chip->codec_ready_bits | ICH_GSCI));
                        if (! chip->in_ac97_init)
-                               snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
+                               dev_err(chip->card->dev,
+                                       "codec_read %d: read timeout for register 0x%x\n",
+                                       ac97->num, reg);
                        res = 0xffff;
                }
        }
@@ -619,7 +626,7 @@ static int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask)
                        return 0;
        }
        if (! chip->in_ac97_init)
-               snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n");
+               dev_warn(chip->card->dev, "AC97 codec ready timeout.\n");
        return -EBUSY;
 }
 
@@ -631,7 +638,7 @@ static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip)
        while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
                udelay(1);
        if (! time && ! chip->in_ac97_init)
-               snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n");
+               dev_warn(chip->card->dev, "ali_codec_semaphore timeout\n");
        return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY);
 }
 
@@ -700,7 +707,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
                        bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
                                                     ichdev->fragsize >> ichdev->pos_shift);
 #if 0
-                       printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
+                       dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n",
                               idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
 #endif
                }
@@ -712,8 +719,8 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
        ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
        ichdev->position = 0;
 #if 0
-       printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
-              "period_size1 = 0x%x\n",
+       dev_dbg(chip->card->dev,
+               "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
               ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
               ichdev->fragsize1);
 #endif
@@ -781,8 +788,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich
                ichdev->lvi_frag %= ichdev->frags;
                ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
 #if 0
-       printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, "
-              "all = 0x%x, 0x%x\n",
+       dev_dbg(chip->card->dev,
+               "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
               ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
               ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
               inl(port + 4), inb(port + ICH_REG_OFF_CR));
@@ -2289,7 +2296,8 @@ static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
                ac97.num = i;
                if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
                        if (err != -EACCES)
-                               snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i);
+                               dev_err(chip->card->dev,
+                                       "Unable to initialize codec #%d\n", i);
                        if (i == 0)
                                goto __err;
                }
@@ -2441,7 +2449,7 @@ static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip)
                        return 0;
                schedule_timeout_uninterruptible(1);
        } while (time_after_eq(end_time, jiffies));
-       snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
+       dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n",
                   igetdword(chip, ICHREG(GLOB_CNT)));
        return -EIO;
 }
@@ -2483,7 +2491,8 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
                } while (time_after_eq(end_time, jiffies));
                if (! status) {
                        /* no codec is found */
-                       snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n",
+                       dev_err(chip->card->dev,
+                               "codec_ready: codec is not ready [0x%x]\n",
                                   igetdword(chip, ICHREG(GLOB_STA)));
                        return -EIO;
                }
@@ -2547,7 +2556,7 @@ static int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing)
                        goto __ok;
                schedule_timeout_uninterruptible(1);
        }
-       snd_printk(KERN_ERR "AC'97 reset failed.\n");
+       dev_err(chip->card->dev, "AC'97 reset failed.\n");
        if (probing)
                return -EIO;
 
@@ -2591,7 +2600,7 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing)
                                break;
                 }
                 if (timeout == 0)
-                        printk(KERN_ERR "intel8x0: reset of registers failed?\n");
+                       dev_err(chip->card->dev, "reset of registers failed?\n");
         }
        /* initialize Buffer Descriptor Lists */
        for (i = 0; i < chip->bdbars_count; i++)
@@ -2692,8 +2701,7 @@ static int intel8x0_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "intel8x0: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2701,8 +2709,8 @@ static int intel8x0_resume(struct device *dev)
        snd_intel8x0_chip_init(chip, 0);
        if (request_irq(pci->irq, snd_intel8x0_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
-                      "disabling device\n", pci->irq);
+               dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+                       pci->irq);
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2779,7 +2787,8 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
       __again:
        subs = chip->pcm[0]->streams[0].substream;
        if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
-               snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
+               dev_warn(chip->card->dev,
+                        "no playback buffer allocated - aborting measure ac97 clock\n");
                return;
        }
        ichdev = &chip->ichd[ICHD_PCMOUT];
@@ -2789,7 +2798,8 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
 
        /* set rate */
        if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) {
-               snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97_bus->clock);
+               dev_err(chip->card->dev, "cannot set ac97 rate: clock = %d\n",
+                       chip->ac97_bus->clock);
                return;
        }
        snd_intel8x0_setup_periods(chip, ichdev);
@@ -2843,7 +2853,8 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
        spin_unlock_irq(&chip->reg_lock);
 
        if (pos == 0) {
-               snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n");
+               dev_err(chip->card->dev,
+                       "measure - unreliable DMA position..\n");
              __retry:
                if (attempt < 3) {
                        msleep(300);
@@ -2857,16 +2868,17 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
        t = stop_time.tv_sec - start_time.tv_sec;
        t *= 1000000;
        t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000;
-       printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
+       dev_info(chip->card->dev,
+                "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
        if (t == 0) {
-               snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n");
+               dev_err(chip->card->dev, "?? calculation error..\n");
                goto __retry;
        }
        pos *= 1000;
        pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
        if (pos < 40000 || pos >= 60000) {
                /* abnormal value. hw problem? */
-               printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
+               dev_info(chip->card->dev, "measured clock %ld rejected\n", pos);
                goto __retry;
        } else if (pos > 40500 && pos < 41500)
                /* first exception - 41000Hz reference clock */
@@ -2878,7 +2890,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
                /* not 48000Hz, tuning the clock.. */
                chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
       __end:
-       printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
+       dev_info(chip->card->dev, "clocking to %d\n", chip->ac97_bus->clock);
        snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
 }
 
@@ -2899,7 +2911,7 @@ static int intel8x0_in_clock_list(struct intel8x0 *chip)
        wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list);
        if (!wl)
                return 0;
-       printk(KERN_INFO "intel8x0: white list rate for %04x:%04x is %i\n",
+       dev_info(chip->card->dev, "white list rate for %04x:%04x is %i\n",
               pci->subsystem_vendor, pci->subsystem_device, wl->value);
        chip->ac97_bus->clock = wl->value;
        return 1;
@@ -3003,7 +3015,7 @@ static int snd_intel8x0_inside_vm(struct pci_dev *pci)
 
 fini:
        if (msg != NULL)
-               printk(KERN_INFO "intel8x0: %s optimization\n", msg);
+               dev_info(&pci->dev, "%s optimization\n", msg);
 
        return result;
 }
@@ -3098,7 +3110,7 @@ static int snd_intel8x0_create(struct snd_card *card,
        else
                chip->addr = pci_iomap(pci, 0, 0);
        if (!chip->addr) {
-               snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+               dev_err(card->dev, "AC'97 space ioremap problem\n");
                snd_intel8x0_free(chip);
                return -EIO;
        }
@@ -3107,7 +3119,7 @@ static int snd_intel8x0_create(struct snd_card *card,
        else
                chip->bmaddr = pci_iomap(pci, 1, 0);
        if (!chip->bmaddr) {
-               snd_printk(KERN_ERR "Controller space ioremap problem\n");
+               dev_err(card->dev, "Controller space ioremap problem\n");
                snd_intel8x0_free(chip);
                return -EIO;
        }
@@ -3152,7 +3164,7 @@ static int snd_intel8x0_create(struct snd_card *card,
                                chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
                                &chip->bdbars) < 0) {
                snd_intel8x0_free(chip);
-               snd_printk(KERN_ERR "intel8x0: cannot allocate buffer descriptors\n");
+               dev_err(card->dev, "cannot allocate buffer descriptors\n");
                return -ENOMEM;
        }
        /* tables must be aligned to 8 bytes here, but the kernel pages
@@ -3206,7 +3218,7 @@ static int snd_intel8x0_create(struct snd_card *card,
        /* request irq after initializaing int_sta_mask, etc */
        if (request_irq(pci->irq, snd_intel8x0_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_intel8x0_free(chip);
                return -EBUSY;
        }
@@ -3217,8 +3229,6 @@ static int snd_intel8x0_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_intel8x0 = chip;
        return 0;
 }
@@ -3265,12 +3275,12 @@ static int check_default_spdif_aclink(struct pci_dev *pci)
        w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
        if (w) {
                if (w->value)
-                       snd_printdd(KERN_INFO
-                                   "intel8x0: Using SPDIF over AC-Link for %s\n",
+                       dev_dbg(&pci->dev,
+                               "Using SPDIF over AC-Link for %s\n",
                                    snd_pci_quirk_name(w));
                else
-                       snd_printdd(KERN_INFO
-                                   "intel8x0: Using integrated SPDIF DMA for %s\n",
+                       dev_dbg(&pci->dev,
+                               "Using integrated SPDIF DMA for %s\n",
                                    snd_pci_quirk_name(w));
                return w->value;
        }
@@ -3285,7 +3295,7 @@ static int snd_intel8x0_probe(struct pci_dev *pci,
        int err;
        struct shortname_table *name;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index 3573c11936656d8f1b003573d559494618c7a694..b54d3e93cab13bfe516ecbf5de6c72113df328a4 100644 (file)
@@ -334,7 +334,8 @@ static int snd_intel8x0m_codec_semaphore(struct intel8x0m *chip, unsigned int co
        /* access to some forbidden (non existent) ac97 registers will not
         * reset the semaphore. So even if you don't get the semaphore, still
         * continue the access. We don't need the semaphore anyway. */
-       snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
+       dev_err(chip->card->dev,
+               "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
                        igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));
        iagetword(chip, 0);     /* clear semaphore flag */
        /* I don't care about the semaphore */
@@ -349,7 +350,9 @@ static void snd_intel8x0m_codec_write(struct snd_ac97 *ac97,
        
        if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) {
                if (! chip->in_ac97_init)
-                       snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+                       dev_err(chip->card->dev,
+                               "codec_write %d: semaphore is not ready for register 0x%x\n",
+                               ac97->num, reg);
        }
        iaputword(chip, reg + ac97->num * 0x80, val);
 }
@@ -363,7 +366,9 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97,
 
        if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) {
                if (! chip->in_ac97_init)
-                       snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+                       dev_err(chip->card->dev,
+                               "codec_read %d: semaphore is not ready for register 0x%x\n",
+                               ac97->num, reg);
                res = 0xffff;
        } else {
                res = iagetword(chip, reg + ac97->num * 0x80);
@@ -372,7 +377,9 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97,
                        iputdword(chip, ICHREG(GLOB_STA),
                                  tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
                        if (! chip->in_ac97_init)
-                               snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
+                               dev_err(chip->card->dev,
+                                       "codec_read %d: read timeout for register 0x%x\n",
+                                       ac97->num, reg);
                        res = 0xffff;
                }
        }
@@ -412,7 +419,7 @@ static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *i
                        bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
                                                     ichdev->fragsize >> chip->pcm_pos_shift);
                        /*
-                       printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
+                       dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n",
                               idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
                        */
                }
@@ -424,8 +431,8 @@ static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *i
        ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
        ichdev->position = 0;
 #if 0
-       printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
-              "period_size1 = 0x%x\n",
+       dev_dbg(chip->card->dev,
+               "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
               ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
               ichdev->fragsize1);
 #endif
@@ -470,8 +477,8 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i
                                                             ichdev->lvi_frag *
                                                             ichdev->fragsize1);
 #if 0
-               printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], "
-                      "prefetch = %i, all = 0x%x, 0x%x\n",
+               dev_dbg(chip->card->dev,
+                       "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
                       ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
                       ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
                       inl(port + 4), inb(port + ICH_REG_OFF_CR));
@@ -850,7 +857,8 @@ static int snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock)
        ac97.pci = chip->pci;
        ac97.num = glob_sta & ICH_SCR ? 1 : 0;
        if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) {
-               snd_printk(KERN_ERR "Unable to initialize codec #%d\n", ac97.num);
+               dev_err(chip->card->dev,
+                       "Unable to initialize codec #%d\n", ac97.num);
                if (ac97.num == 0)
                        goto __err;
                return err;
@@ -901,7 +909,7 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
                        goto __ok;
                schedule_timeout_uninterruptible(1);
        } while (time_after_eq(end_time, jiffies));
-       snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
+       dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n",
                   igetdword(chip, ICHREG(GLOB_CNT)));
        return -EIO;
 
@@ -921,7 +929,8 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
                } while (time_after_eq(end_time, jiffies));
                if (! status) {
                        /* no codec is found */
-                       snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n",
+                       dev_err(chip->card->dev,
+                               "codec_ready: codec is not ready [0x%x]\n",
                                   igetdword(chip, ICHREG(GLOB_STA)));
                        return -EIO;
                }
@@ -1042,16 +1051,15 @@ static int intel8x0m_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "intel8x0m: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
        pci_set_master(pci);
        if (request_irq(pci->irq, snd_intel8x0m_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
-                      "disabling device\n", pci->irq);
+               dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+                       pci->irq);
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -1165,7 +1173,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
        else
                chip->addr = pci_iomap(pci, 0, 0);
        if (!chip->addr) {
-               snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+               dev_err(card->dev, "AC'97 space ioremap problem\n");
                snd_intel8x0m_free(chip);
                return -EIO;
        }
@@ -1174,7 +1182,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
        else
                chip->bmaddr = pci_iomap(pci, 1, 0);
        if (!chip->bmaddr) {
-               snd_printk(KERN_ERR "Controller space ioremap problem\n");
+               dev_err(card->dev, "Controller space ioremap problem\n");
                snd_intel8x0m_free(chip);
                return -EIO;
        }
@@ -1182,7 +1190,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
  port_inited:
        if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_intel8x0m_free(chip);
                return -EBUSY;
        }
@@ -1243,8 +1251,6 @@ static int snd_intel8x0m_create(struct snd_card *card,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_intel8x0m = chip;
        return 0;
 }
@@ -1283,7 +1289,7 @@ static int snd_intel8x0m_probe(struct pci_dev *pci,
        int err;
        struct shortname_table *name;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index 9cf9829555d422a250cff10dd956b23e09dca996..8f36d77f01e5573620c6660d9e8a6b0d3d4810b0 100644 (file)
@@ -2418,8 +2418,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci,
 
         snd_korg1212_proc_init(korg1212);
         
-       snd_card_set_dev(card, &pci->dev);
-
         * rchip = korg1212;
        return 0;
 
@@ -2445,7 +2443,8 @@ snd_korg1212_probe(struct pci_dev *pci,
                dev++;
                return -ENOENT;
        }
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
index 0568540dc8d353995879ba6ab26be56360b164e4..68824cdd137de7bcfc8c80397c59f558970e070b 100644 (file)
@@ -75,7 +75,7 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 static int debug;
 module_param(debug, int, 0644);
 #define verbose_debug(fmt, args...)                    \
-       do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0)
+       do { if (debug > 1) pr_debug(SFX fmt, ##args); } while (0)
 #else
 #define verbose_debug(fmt, args...)
 #endif
@@ -168,7 +168,7 @@ static int rirb_get_response(struct lola *chip, unsigned int *val,
                        verbose_debug("get_response: %x, %x\n",
                                      chip->res, chip->res_ex);
                        if (chip->res_ex & LOLA_RIRB_EX_ERROR) {
-                               printk(KERN_WARNING SFX "RIRB ERROR: "
+                               dev_warn(chip->card->dev, "RIRB ERROR: "
                                       "NID=%x, verb=%x, data=%x, ext=%x\n",
                                       chip->last_cmd_nid,
                                       chip->last_verb, chip->last_data,
@@ -182,9 +182,9 @@ static int rirb_get_response(struct lola *chip, unsigned int *val,
                udelay(20);
                cond_resched();
        }
-       printk(KERN_WARNING SFX "RIRB response error\n");
+       dev_warn(chip->card->dev, "RIRB response error\n");
        if (!chip->polling_mode) {
-               printk(KERN_WARNING SFX "switching to polling mode\n");
+               dev_warn(chip->card->dev, "switching to polling mode\n");
                chip->polling_mode = 1;
                goto again;
        }
@@ -327,7 +327,7 @@ static int reset_controller(struct lola *chip)
                        break;
        } while (time_before(jiffies, end_time));
        if (!gctl) {
-               printk(KERN_ERR SFX "cannot reset controller\n");
+               dev_err(chip->card->dev, "cannot reset controller\n");
                return -EIO;
        }
        return 0;
@@ -452,40 +452,40 @@ static int lola_parse_tree(struct lola *chip)
 
        err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read VENDOR_ID\n");
+               dev_err(chip->card->dev, "Can't read VENDOR_ID\n");
                return err;
        }
        val >>= 16;
        if (val != 0x1369) {
-               printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val);
+               dev_err(chip->card->dev, "Unknown codec vendor 0x%x\n", val);
                return -EINVAL;
        }
 
        err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read FUNCTION_TYPE\n");
+               dev_err(chip->card->dev, "Can't read FUNCTION_TYPE\n");
                return err;
        }
        if (val != 1) {
-               printk(KERN_ERR SFX "Unknown function type %d\n", val);
+               dev_err(chip->card->dev, "Unknown function type %d\n", val);
                return -EINVAL;
        }
 
        err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read SPECCAPS\n");
+               dev_err(chip->card->dev, "Can't read SPECCAPS\n");
                return err;
        }
        chip->lola_caps = val;
        chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps);
        chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps);
-       snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n",
+       dev_dbg(chip->card->dev, "speccaps=0x%x, pins in=%d, out=%d\n",
                    chip->lola_caps,
                    chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
 
        if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT ||
            chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) {
-               printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val);
+               dev_err(chip->card->dev, "Invalid Lola-spec caps 0x%x\n", val);
                return -EINVAL;
        }
 
@@ -586,7 +586,6 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip) {
-               snd_printk(KERN_ERR SFX "cannot allocate chip\n");
                pci_disable_device(pci);
                return -ENOMEM;
        }
@@ -609,7 +608,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
                chip->sample_rate_max = 192000;
                break;
        default:
-               snd_printk(KERN_WARNING SFX
+               dev_warn(chip->card->dev,
                           "Invalid granularity %d, reset to %d\n",
                           chip->granularity, LOLA_GRANULARITY_MAX);
                chip->granularity = LOLA_GRANULARITY_MAX;
@@ -618,7 +617,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
        }
        chip->sample_rate_min = sample_rate_min[dev];
        if (chip->sample_rate_min > chip->sample_rate_max) {
-               snd_printk(KERN_WARNING SFX
+               dev_warn(chip->card->dev,
                           "Invalid sample_rate_min %d, reset to 16000\n",
                           chip->sample_rate_min);
                chip->sample_rate_min = 16000;
@@ -636,7 +635,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
        chip->bar[1].addr = pci_resource_start(pci, 2);
        chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2);
        if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) {
-               snd_printk(KERN_ERR SFX "ioremap error\n");
+               dev_err(chip->card->dev, "ioremap error\n");
                err = -ENXIO;
                goto errout;
        }
@@ -649,7 +648,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
 
        if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+               dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
                err = -EBUSY;
                goto errout;
        }
@@ -660,7 +659,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
        chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff;
        chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff;
        chip->version = (dever >> 24) & 0xff;
-       snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n",
+       dev_dbg(chip->card->dev, "streams in=%d, out=%d, version=0x%x\n",
                    chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams,
                    chip->version);
 
@@ -669,7 +668,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
            chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT ||
            (!chip->pcm[CAPT].num_streams &&
             !chip->pcm[PLAY].num_streams)) {
-               printk(KERN_ERR SFX "invalid DEVER = %x\n", dever);
+               dev_err(chip->card->dev, "invalid DEVER = %x\n", dever);
                err = -EINVAL;
                goto errout;
        }
@@ -680,7 +679,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
 
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
        if (err < 0) {
-               snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+               dev_err(chip->card->dev, "Error creating device [card]!\n");
                goto errout;
        }
 
@@ -717,14 +716,13 @@ static int lola_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
-               snd_printk(KERN_ERR SFX "Error creating card!\n");
+               dev_err(card->dev, "Error creating card!\n");
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        err = lola_create(card, pci, dev, &chip);
        if (err < 0)
                goto out_free;
index eb1d6b97df164f20517222be0173df1e792dce1b..2bef6b412aeee42081d6c33ee827b62fffb6c64c 100644 (file)
@@ -128,21 +128,21 @@ int lola_init_clock_widget(struct lola *chip, int nid)
 
        err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
                return err;
        }
 
        if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
-               snd_printdd("No valid clock widget\n");
+               dev_dbg(chip->card->dev, "No valid clock widget\n");
                return 0;
        }
 
        chip->clock.nid = nid;
        chip->clock.items = val & 0xff;
-       snd_printdd("clock_list nid=%x, entries=%d\n", nid,
+       dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid,
                    chip->clock.items);
        if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
-               printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
+               dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n",
                       chip->clock.items);
                return -EINVAL;
        }
@@ -158,7 +158,7 @@ int lola_init_clock_widget(struct lola *chip, int nid)
                err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
                                      idx, 0, &val, &res_ex);
                if (err < 0) {
-                       printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
+                       dev_err(chip->card->dev, "Can't read CLOCK_LIST\n");
                        return -EINVAL;
                }
 
@@ -223,7 +223,7 @@ int lola_enable_clock_events(struct lola *chip)
        if (err < 0)
                return err;
        if (res) {
-               printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
+               dev_warn(chip->card->dev, "error in enable_clock_events %d\n",
                       res);
                return -EINVAL;
        }
@@ -242,7 +242,7 @@ int lola_set_clock_index(struct lola *chip, unsigned int idx)
        if (err < 0)
                return err;
        if (res) {
-               printk(KERN_WARNING SFX "error in set_clock %d\n", res);
+               dev_warn(chip->card->dev, "error in set_clock %d\n", res);
                return -EINVAL;
        }
        return 0;
index 52c8d6b0f39b9c7b35183f89642a816d8cdd7e58..782f4d8299ae85bd76b52a0b05679ad6add4b75c 100644 (file)
@@ -37,7 +37,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
        pin->nid = nid;
        err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
                return err;
        }
        val &= 0x00f00fff; /* test TYPE and bits 0..11 */
@@ -48,7 +48,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
        else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */
                pin->is_analog = true;
        else {
-               printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid);
+               dev_err(chip->card->dev, "Invalid wcaps 0x%x for 0x%x\n", val, nid);
                return -EINVAL;
        }
 
@@ -62,7 +62,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
        else
                err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't read AMP-caps for 0x%x\n", nid);
                return err;
        }
 
@@ -79,7 +79,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
        err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val,
                              NULL);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't get MAX_LEVEL 0x%x\n", nid);
                return err;
        }
        pin->max_level = val & 0x3ff;   /* 10 bits */
@@ -119,12 +119,12 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
 
        err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
                return err;
        }
 
        if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */
-               snd_printdd("No valid mixer widget\n");
+               dev_dbg(chip->card->dev, "No valid mixer widget\n");
                return 0;
        }
 
@@ -202,7 +202,7 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
         */
        if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
            chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
-               printk(KERN_ERR SFX "Invalid mixer widget size\n");
+               dev_err(chip->card->dev, "Invalid mixer widget size\n");
                return -EINVAL;
        }
 
@@ -213,7 +213,7 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
                (((1U << chip->mixer.dest_phys_outs) - 1)
                 << chip->mixer.dest_phys_out_ofs);
 
-       snd_printdd("Mixer src_mask=%x, dest_mask=%x\n",
+       dev_dbg(chip->card->dev, "Mixer src_mask=%x, dest_mask=%x\n",
                    chip->mixer.src_mask, chip->mixer.dest_mask);
 
        return 0;
@@ -236,7 +236,8 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
            (gain == readw(&chip->mixer.array->src_gain[id])))
                return 0;
 
-       snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
+       dev_dbg(chip->card->dev,
+               "lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
                        id, gain, val);
        writew(gain, &chip->mixer.array->src_gain[id]);
        writel(val, &chip->mixer.array->src_gain_enable);
@@ -409,7 +410,8 @@ static int set_analog_volume(struct lola *chip, int dir,
                return 0;
        if (external_call)
                lola_codec_flush(chip);
-       snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n",
+       dev_dbg(chip->card->dev,
+               "set_analog_volume (dir=%d idx=%d, volume=%d)\n",
                        dir, idx, val);
        err = lola_codec_write(chip, pin->nid,
                               LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
index 5ea85e8b83ab5018029d92504902775170adb018..3bd6985430e824b72e2fd71432ff13afd864a000 100644 (file)
@@ -103,7 +103,7 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
                        return;
                msleep(1);
        }
-       printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
+       dev_warn(chip->card->dev, "SRST not clear (stream %d)\n", str->dsd);
 }
 
 static int lola_stream_wait_for_fifo(struct lola *chip,
@@ -118,7 +118,7 @@ static int lola_stream_wait_for_fifo(struct lola *chip,
                        return 0;
                msleep(1);
        }
-       printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd);
+       dev_warn(chip->card->dev, "FIFO not ready (stream %d)\n", str->dsd);
        return -EIO;
 }
 
@@ -156,7 +156,7 @@ static int lola_sync_wait_for_fifo(struct lola *chip,
                        return 0;
                msleep(1);
        }
-       printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1);
+       dev_warn(chip->card->dev, "FIFO not ready (pending %d)\n", pending - 1);
        return -EIO;
 }
 
@@ -373,7 +373,7 @@ static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
        return 0;
 
  error:
-       snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
+       dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n",
                   str->bufsize, period_bytes);
        return -EINVAL;
 }
@@ -415,7 +415,7 @@ static int lola_set_stream_config(struct lola *chip,
        err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
                              str->format_verb, 0, &val, NULL);
        if (err < 0) {
-               printk(KERN_ERR SFX "Cannot set stream format 0x%x\n",
+               dev_err(chip->card->dev, "Cannot set stream format 0x%x\n",
                       str->format_verb);
                return err;
        }
@@ -427,7 +427,8 @@ static int lola_set_stream_config(struct lola *chip,
                                      LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb,
                                      &val, NULL);
                if (err < 0) {
-                       printk(KERN_ERR SFX "Cannot set stream channel %d\n", i);
+                       dev_err(chip->card->dev,
+                               "Cannot set stream channel %d\n", i);
                        return err;
                }
        }
@@ -651,13 +652,14 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str,
                str->dsd += MAX_STREAM_IN_COUNT;
        err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
                return err;
        }
        if (dir == PLAY) {
                /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */
                if ((val & 0x00f00dff) != 0x00000010) {
-                       printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+                       dev_err(chip->card->dev,
+                               "Invalid wcaps 0x%x for 0x%x\n",
                               val, nid);
                        return -EINVAL;
                }
@@ -666,7 +668,8 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str,
                 * (bug : ignore bit8: Conn list = 0/1)
                 */
                if ((val & 0x00f00cff) != 0x00100010) {
-                       printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+                       dev_err(chip->card->dev,
+                               "Invalid wcaps 0x%x for 0x%x\n",
                               val, nid);
                        return -EINVAL;
                }
@@ -677,14 +680,15 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str,
 
        err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
        if (err < 0) {
-               printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid);
+               dev_err(chip->card->dev, "Can't read FORMATS 0x%x\n", nid);
                return err;
        }
        val &= 3;
        if (val == 3)
                str->can_float = true;
        if (!(val & 1)) {
-               printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid);
+               dev_err(chip->card->dev,
+                       "Invalid formats 0x%x for 0x%x", val, nid);
                return -EINVAL;
        }
        return 0;
index 5fcaaa6da4a811b1bc1ae3e4a6fe431b90b378de..27f60ce8a55c41b5275aeeb014958838800ee21b 100644 (file)
@@ -112,16 +112,16 @@ static int lx_hardware_open(struct lx6464es *chip,
 
        snd_pcm_uframes_t period_size = runtime->period_size;
 
-       snd_printd(LXP "allocating pipe for %d channels\n", channels);
+       dev_dbg(chip->card->dev, "allocating pipe for %d channels\n", channels);
        err = lx_pipe_allocate(chip, 0, is_capture, channels);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "allocating pipe failed\n");
+               dev_err(chip->card->dev, LXP "allocating pipe failed\n");
                return err;
        }
 
        err = lx_set_granularity(chip, period_size);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n",
+               dev_err(chip->card->dev, "setting granularity to %ld failed\n",
                           period_size);
                return err;
        }
@@ -136,24 +136,24 @@ static int lx_hardware_start(struct lx6464es *chip,
        struct snd_pcm_runtime *runtime = substream->runtime;
        int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
-       snd_printd(LXP "setting stream format\n");
+       dev_dbg(chip->card->dev, "setting stream format\n");
        err = lx_stream_set_format(chip, runtime, 0, is_capture);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "setting stream format failed\n");
+               dev_err(chip->card->dev, "setting stream format failed\n");
                return err;
        }
 
-       snd_printd(LXP "starting pipe\n");
+       dev_dbg(chip->card->dev, "starting pipe\n");
        err = lx_pipe_start(chip, 0, is_capture);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "starting pipe failed\n");
+               dev_err(chip->card->dev, "starting pipe failed\n");
                return err;
        }
 
-       snd_printd(LXP "waiting for pipe to start\n");
+       dev_dbg(chip->card->dev, "waiting for pipe to start\n");
        err = lx_pipe_wait_for_start(chip, 0, is_capture);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+               dev_err(chip->card->dev, "waiting for pipe failed\n");
                return err;
        }
 
@@ -167,24 +167,24 @@ static int lx_hardware_stop(struct lx6464es *chip,
        int err = 0;
        int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
-       snd_printd(LXP "pausing pipe\n");
+       dev_dbg(chip->card->dev, "pausing pipe\n");
        err = lx_pipe_pause(chip, 0, is_capture);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "pausing pipe failed\n");
+               dev_err(chip->card->dev, "pausing pipe failed\n");
                return err;
        }
 
-       snd_printd(LXP "waiting for pipe to become idle\n");
+       dev_dbg(chip->card->dev, "waiting for pipe to become idle\n");
        err = lx_pipe_wait_for_idle(chip, 0, is_capture);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+               dev_err(chip->card->dev, "waiting for pipe failed\n");
                return err;
        }
 
-       snd_printd(LXP "stopping pipe\n");
+       dev_dbg(chip->card->dev, "stopping pipe\n");
        err = lx_pipe_stop(chip, 0, is_capture);
        if (err < 0) {
-               snd_printk(LXP "stopping pipe failed\n");
+               dev_err(chip->card->dev, "stopping pipe failed\n");
                return err;
        }
 
@@ -198,10 +198,10 @@ static int lx_hardware_close(struct lx6464es *chip,
        int err = 0;
        int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
-       snd_printd(LXP "releasing pipe\n");
+       dev_dbg(chip->card->dev, "releasing pipe\n");
        err = lx_pipe_release(chip, 0, is_capture);
        if (err < 0) {
-               snd_printk(LXP "releasing pipe failed\n");
+               dev_err(chip->card->dev, "releasing pipe failed\n");
                return err;
        }
 
@@ -216,7 +216,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
        int err = 0;
        int board_rate;
 
-       snd_printdd("->lx_pcm_open\n");
+       dev_dbg(chip->card->dev, "->lx_pcm_open\n");
        mutex_lock(&chip->setup_mutex);
 
        /* copy the struct snd_pcm_hardware struct */
@@ -227,7 +227,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
        err = snd_pcm_hw_constraint_integer(runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
        if (err < 0) {
-               snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+               dev_warn(chip->card->dev, "could not constrain periods\n");
                goto exit;
        }
 #endif
@@ -238,7 +238,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
                                           board_rate, board_rate);
 
        if (err < 0) {
-               snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+               dev_warn(chip->card->dev, "could not constrain periods\n");
                goto exit;
        }
 
@@ -248,7 +248,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
                                           MICROBLAZE_IBL_MIN,
                                           MICROBLAZE_IBL_MAX);
        if (err < 0) {
-               snd_printk(KERN_WARNING LXP
+               dev_warn(chip->card->dev,
                           "could not constrain period size\n");
                goto exit;
        }
@@ -263,14 +263,14 @@ exit:
        runtime->private_data = chip;
 
        mutex_unlock(&chip->setup_mutex);
-       snd_printdd("<-lx_pcm_open, %d\n", err);
+       dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err);
        return err;
 }
 
 static int lx_pcm_close(struct snd_pcm_substream *substream)
 {
        int err = 0;
-       snd_printdd("->lx_pcm_close\n");
+       dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n");
        return err;
 }
 
@@ -285,13 +285,13 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
        struct lx_stream *lx_stream = is_capture ? &chip->capture_stream :
                &chip->playback_stream;
 
-       snd_printdd("->lx_pcm_stream_pointer\n");
+       dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n");
 
        spin_lock_irqsave(&chip->lock, flags);
        pos = lx_stream->frame_pos * substream->runtime->period_size;
        spin_unlock_irqrestore(&chip->lock, flags);
 
-       snd_printdd(LXP "stream_pointer at %ld\n", pos);
+       dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos);
        return pos;
 }
 
@@ -301,37 +301,37 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream)
        int err = 0;
        const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
-       snd_printdd("->lx_pcm_prepare\n");
+       dev_dbg(chip->card->dev, "->lx_pcm_prepare\n");
 
        mutex_lock(&chip->setup_mutex);
 
        if (chip->hardware_running[is_capture]) {
                err = lx_hardware_stop(chip, substream);
                if (err < 0) {
-                       snd_printk(KERN_ERR LXP "failed to stop hardware. "
+                       dev_err(chip->card->dev, "failed to stop hardware. "
                                   "Error code %d\n", err);
                        goto exit;
                }
 
                err = lx_hardware_close(chip, substream);
                if (err < 0) {
-                       snd_printk(KERN_ERR LXP "failed to close hardware. "
+                       dev_err(chip->card->dev, "failed to close hardware. "
                                   "Error code %d\n", err);
                        goto exit;
                }
        }
 
-       snd_printd(LXP "opening hardware\n");
+       dev_dbg(chip->card->dev, "opening hardware\n");
        err = lx_hardware_open(chip, substream);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "failed to open hardware. "
+               dev_err(chip->card->dev, "failed to open hardware. "
                           "Error code %d\n", err);
                goto exit;
        }
 
        err = lx_hardware_start(chip, substream);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "failed to start hardware. "
+               dev_err(chip->card->dev, "failed to start hardware. "
                           "Error code %d\n", err);
                goto exit;
        }
@@ -354,7 +354,7 @@ static int lx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct lx6464es *chip = snd_pcm_substream_chip(substream);
        int err = 0;
 
-       snd_printdd("->lx_pcm_hw_params\n");
+       dev_dbg(chip->card->dev, "->lx_pcm_hw_params\n");
 
        mutex_lock(&chip->setup_mutex);
 
@@ -389,20 +389,20 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
        int err = 0;
        int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 
-       snd_printdd("->lx_pcm_hw_free\n");
+       dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n");
        mutex_lock(&chip->setup_mutex);
 
        if (chip->hardware_running[is_capture]) {
                err = lx_hardware_stop(chip, substream);
                if (err < 0) {
-                       snd_printk(KERN_ERR LXP "failed to stop hardware. "
+                       dev_err(chip->card->dev, "failed to stop hardware. "
                                   "Error code %d\n", err);
                        goto exit;
                }
 
                err = lx_hardware_close(chip, substream);
                if (err < 0) {
-                       snd_printk(KERN_ERR LXP "failed to close hardware. "
+                       dev_err(chip->card->dev, "failed to close hardware. "
                                   "Error code %d\n", err);
                        goto exit;
                }
@@ -446,25 +446,25 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 
                err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed,
                                    size_array);
-               snd_printdd(LXP "starting: needed %d, freed %d\n",
+               dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n",
                            needed, freed);
 
                err = lx_buffer_give(chip, 0, is_capture, period_bytes,
                                     lower_32_bits(buf), upper_32_bits(buf),
                                     &buffer_index);
 
-               snd_printdd(LXP "starting: buffer index %x on 0x%lx (%d bytes)\n",
+               dev_dbg(chip->card->dev, "starting: buffer index %x on 0x%lx (%d bytes)\n",
                            buffer_index, (unsigned long)buf, period_bytes);
                buf += period_bytes;
        }
 
        err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
-       snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed);
+       dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n", needed, freed);
 
-       snd_printd(LXP "starting: starting stream\n");
+       dev_dbg(chip->card->dev, "starting: starting stream\n");
        err = lx_stream_start(chip, 0, is_capture);
        if (err < 0)
-               snd_printk(KERN_ERR LXP "couldn't start stream\n");
+               dev_err(chip->card->dev, "couldn't start stream\n");
        else
                lx_stream->status = LX_STREAM_STATUS_RUNNING;
 
@@ -476,10 +476,10 @@ static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
        const unsigned int is_capture = lx_stream->is_capture;
        int err;
 
-       snd_printd(LXP "stopping: stopping stream\n");
+       dev_dbg(chip->card->dev, "stopping: stopping stream\n");
        err = lx_stream_stop(chip, 0, is_capture);
        if (err < 0)
-               snd_printk(KERN_ERR LXP "couldn't stop stream\n");
+               dev_err(chip->card->dev, "couldn't stop stream\n");
        else
                lx_stream->status = LX_STREAM_STATUS_FREE;
 
@@ -507,7 +507,7 @@ static void lx_trigger_tasklet(unsigned long data)
        struct lx6464es *chip = (struct lx6464es *)data;
        unsigned long flags;
 
-       snd_printdd("->lx_trigger_tasklet\n");
+       dev_dbg(chip->card->dev, "->lx_trigger_tasklet\n");
 
        spin_lock_irqsave(&chip->lock, flags);
        lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream);
@@ -547,14 +547,14 @@ static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct lx_stream *stream = is_capture ? &chip->capture_stream :
                &chip->playback_stream;
 
-       snd_printdd("->lx_pcm_trigger\n");
+       dev_dbg(chip->card->dev, "->lx_pcm_trigger\n");
 
        return lx_pcm_trigger_dispatch(chip, stream, cmd);
 }
 
 static int snd_lx6464es_free(struct lx6464es *chip)
 {
-       snd_printdd("->snd_lx6464es_free\n");
+       dev_dbg(chip->card->dev, "->snd_lx6464es_free\n");
 
        lx_irq_disable(chip);
 
@@ -583,7 +583,7 @@ static int lx_init_xilinx_reset(struct lx6464es *chip)
        int i;
        u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC);
 
-       snd_printdd("->lx_init_xilinx_reset\n");
+       dev_dbg(chip->card->dev, "->lx_init_xilinx_reset\n");
 
        /* activate reset of xilinx */
        plx_reg &= ~CHIPSC_RESET_XILINX;
@@ -603,8 +603,8 @@ static int lx_init_xilinx_reset(struct lx6464es *chip)
                msleep(10);
                reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3);
                if (reg_mbox3) {
-                       snd_printd(LXP "xilinx reset done\n");
-                       snd_printdd(LXP "xilinx took %d loops\n", i);
+                       dev_dbg(chip->card->dev, "xilinx reset done\n");
+                       dev_dbg(chip->card->dev, "xilinx took %d loops\n", i);
                        break;
                }
        }
@@ -624,7 +624,7 @@ static int lx_init_xilinx_test(struct lx6464es *chip)
 {
        u32 reg;
 
-       snd_printdd("->lx_init_xilinx_test\n");
+       dev_dbg(chip->card->dev, "->lx_init_xilinx_test\n");
 
        /* TEST if we have access to Xilinx/MicroBlaze */
        lx_dsp_reg_write(chip, eReg_CSM, 0);
@@ -632,19 +632,19 @@ static int lx_init_xilinx_test(struct lx6464es *chip)
        reg = lx_dsp_reg_read(chip, eReg_CSM);
 
        if (reg) {
-               snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg);
+               dev_err(chip->card->dev, "Problem: Reg_CSM %x.\n", reg);
 
                /* PCI9056_SPACE0_REMAP */
                lx_plx_reg_write(chip, ePLX_PCICR, 1);
 
                reg = lx_dsp_reg_read(chip, eReg_CSM);
                if (reg) {
-                       snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg);
+                       dev_err(chip->card->dev, "Error: Reg_CSM %x.\n", reg);
                        return -EAGAIN; /* seems to be appropriate */
                }
        }
 
-       snd_printd(LXP "Xilinx/MicroBlaze access test successful\n");
+       dev_dbg(chip->card->dev, "Xilinx/MicroBlaze access test successful\n");
 
        return 0;
 }
@@ -661,7 +661,7 @@ static int lx_init_ethersound_config(struct lx6464es *chip)
                (64 << IOCR_OUTPUTS_OFFSET) |
                (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET);
 
-       snd_printdd("->lx_init_ethersound\n");
+       dev_dbg(chip->card->dev, "->lx_init_ethersound\n");
 
        chip->freq_ratio = FREQ_RATIO_SINGLE_MODE;
 
@@ -675,18 +675,18 @@ static int lx_init_ethersound_config(struct lx6464es *chip)
 
        for (i = 0; i != 1000; ++i) {
                if (lx_dsp_reg_read(chip, eReg_CSES) & 4) {
-                       snd_printd(LXP "ethersound initialized after %dms\n",
+                       dev_dbg(chip->card->dev, "ethersound initialized after %dms\n",
                                   i);
                        goto ethersound_initialized;
                }
                msleep(1);
        }
-       snd_printk(KERN_WARNING LXP
+       dev_warn(chip->card->dev,
                   "ethersound could not be initialized after %dms\n", i);
        return -ETIMEDOUT;
 
  ethersound_initialized:
-       snd_printd(LXP "ethersound initialized\n");
+       dev_dbg(chip->card->dev, "ethersound initialized\n");
        return 0;
 }
 
@@ -696,14 +696,14 @@ static int lx_init_get_version_features(struct lx6464es *chip)
 
        int err;
 
-       snd_printdd("->lx_init_get_version_features\n");
+       dev_dbg(chip->card->dev, "->lx_init_get_version_features\n");
 
        err = lx_dsp_get_version(chip, &dsp_version);
 
        if (err == 0) {
                u32 freq;
 
-               snd_printk(LXP "DSP version: V%02d.%02d #%d\n",
+               dev_info(chip->card->dev, "DSP version: V%02d.%02d #%d\n",
                           (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff,
                           dsp_version & 0xff);
 
@@ -718,9 +718,9 @@ static int lx_init_get_version_features(struct lx6464es *chip)
                err = lx_dsp_get_clock_frequency(chip, &freq);
                if (err == 0)
                        chip->board_sample_rate = freq;
-               snd_printd(LXP "actual clock frequency %d\n", freq);
+               dev_dbg(chip->card->dev, "actual clock frequency %d\n", freq);
        } else {
-               snd_printk(KERN_ERR LXP "DSP corrupted \n");
+               dev_err(chip->card->dev, "DSP corrupted \n");
                err = -EAGAIN;
        }
 
@@ -732,7 +732,7 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
        int err = 0;
        u32 snapped_gran = MICROBLAZE_IBL_MIN;
 
-       snd_printdd("->lx_set_granularity\n");
+       dev_dbg(chip->card->dev, "->lx_set_granularity\n");
 
        /* blocksize is a power of 2 */
        while ((snapped_gran < gran) &&
@@ -745,14 +745,14 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
 
        err = lx_dsp_set_granularity(chip, snapped_gran);
        if (err < 0) {
-               snd_printk(KERN_WARNING LXP "could not set granularity\n");
+               dev_warn(chip->card->dev, "could not set granularity\n");
                err = -EAGAIN;
        }
 
        if (snapped_gran != gran)
-               snd_printk(LXP "snapped blocksize to %d\n", snapped_gran);
+               dev_err(chip->card->dev, "snapped blocksize to %d\n", snapped_gran);
 
-       snd_printd(LXP "set blocksize on board %d\n", snapped_gran);
+       dev_dbg(chip->card->dev, "set blocksize on board %d\n", snapped_gran);
        chip->pcm_granularity = snapped_gran;
 
        return err;
@@ -764,19 +764,19 @@ static int lx_init_dsp(struct lx6464es *chip)
        int err;
        int i;
 
-       snd_printdd("->lx_init_dsp\n");
+       dev_dbg(chip->card->dev, "->lx_init_dsp\n");
 
-       snd_printd(LXP "initialize board\n");
+       dev_dbg(chip->card->dev, "initialize board\n");
        err = lx_init_xilinx_reset(chip);
        if (err)
                return err;
 
-       snd_printd(LXP "testing board\n");
+       dev_dbg(chip->card->dev, "testing board\n");
        err = lx_init_xilinx_test(chip);
        if (err)
                return err;
 
-       snd_printd(LXP "initialize ethersound configuration\n");
+       dev_dbg(chip->card->dev, "initialize ethersound configuration\n");
        err = lx_init_ethersound_config(chip);
        if (err)
                return err;
@@ -797,8 +797,9 @@ static int lx_init_dsp(struct lx6464es *chip)
        return -ETIMEDOUT;
 
 mac_ready:
-       snd_printd(LXP "mac address ready read after: %dms\n", i);
-       snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
+       dev_dbg(chip->card->dev, "mac address ready read after: %dms\n", i);
+       dev_info(chip->card->dev,
+                "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
                   chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
                   chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
 
@@ -977,7 +978,7 @@ static int snd_lx6464es_create(struct snd_card *card,
                .dev_free = snd_lx6464es_dev_free,
        };
 
-       snd_printdd("->snd_lx6464es_create\n");
+       dev_dbg(card->dev, "->snd_lx6464es_create\n");
 
        *rchip = NULL;
 
@@ -991,8 +992,8 @@ static int snd_lx6464es_create(struct snd_card *card,
        /* check if we can restrict PCI DMA transfers to 32 bits */
        err = pci_set_dma_mask(pci, DMA_BIT_MASK(32));
        if (err < 0) {
-               snd_printk(KERN_ERR "architecture does not support "
-                          "32bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 32bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -1034,7 +1035,7 @@ static int snd_lx6464es_create(struct snd_card *card,
        err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
                          KBUILD_MODNAME, chip);
        if (err) {
-               snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                goto request_irq_failed;
        }
        chip->irq = pci->irq;
@@ -1045,7 +1046,7 @@ static int snd_lx6464es_create(struct snd_card *card,
 
        err = lx_init_dsp(chip);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "error during DSP initialization\n");
+               dev_err(card->dev, "error during DSP initialization\n");
                return err;
        }
 
@@ -1062,8 +1063,6 @@ static int snd_lx6464es_create(struct snd_card *card,
        if (err < 0)
                return err;
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        return 0;
 
@@ -1090,7 +1089,7 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
        struct lx6464es *chip;
        int err;
 
-       snd_printdd("->snd_lx6464es_probe\n");
+       dev_dbg(&pci->dev, "->snd_lx6464es_probe\n");
 
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
@@ -1099,13 +1098,14 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
        err = snd_lx6464es_create(card, pci, &chip);
        if (err < 0) {
-               snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n");
+               dev_err(card->dev, "error during snd_lx6464es_create\n");
                goto out_free;
        }
 
@@ -1125,7 +1125,7 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
        if (err < 0)
                goto out_free;
 
-       snd_printdd(LXP "initialization successful\n");
+       dev_dbg(chip->card->dev, "initialization successful\n");
        pci_set_drvdata(pci, card);
        dev++;
        return 0;
index 626ecad4dae78bb95fd238f97cc299c4c2b03761..2d8e95e9fbe59c547ad0026a136788e8e4f1d411 100644 (file)
@@ -141,63 +141,6 @@ void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data)
        iowrite32(data, address);
 }
 
-u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr)
-{
-       int index;
-
-       switch (mbox_nr) {
-       case 1:
-               index = ePLX_MBOX1;    break;
-       case 2:
-               index = ePLX_MBOX2;    break;
-       case 3:
-               index = ePLX_MBOX3;    break;
-       case 4:
-               index = ePLX_MBOX4;    break;
-       case 5:
-               index = ePLX_MBOX5;    break;
-       case 6:
-               index = ePLX_MBOX6;    break;
-       case 7:
-               index = ePLX_MBOX7;    break;
-       case 0:                 /* reserved for HF flags */
-               snd_BUG();
-       default:
-               return 0xdeadbeef;
-       }
-
-       return lx_plx_reg_read(chip, index);
-}
-
-int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value)
-{
-       int index = -1;
-
-       switch (mbox_nr) {
-       case 1:
-               index = ePLX_MBOX1;    break;
-       case 3:
-               index = ePLX_MBOX3;    break;
-       case 4:
-               index = ePLX_MBOX4;    break;
-       case 5:
-               index = ePLX_MBOX5;    break;
-       case 6:
-               index = ePLX_MBOX6;    break;
-       case 7:
-               index = ePLX_MBOX7;    break;
-       case 0:                 /* reserved for HF flags */
-       case 2:                 /* reserved for Pipe States
-                                * the DSP keeps an image of it */
-               snd_BUG();
-               return -EBADRQC;
-       }
-
-       lx_plx_reg_write(chip, index, value);
-       return 0;
-}
-
-
 /* rmh */
 
 #ifdef CONFIG_SND_DEBUG
@@ -330,7 +273,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
        int dwloop;
 
        if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
-               snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg);
+               dev_err(chip->card->dev, "PIOSendMessage eReg_CSM %x\n", reg);
                return -EBUSY;
        }
 
@@ -351,7 +294,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
                } else
                        udelay(1);
        }
-       snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! "
+       dev_warn(chip->card->dev, "TIMEOUT lx_message_send_atomic! "
                   "polling failed\n");
 
 polling_successful:
@@ -363,18 +306,18 @@ polling_successful:
                                           rmh->stat_len);
                }
        } else
-               snd_printk(LXP "rmh error: %08x\n", reg);
+               dev_err(chip->card->dev, "rmh error: %08x\n", reg);
 
        /* clear Reg_CSM_MR */
        lx_dsp_reg_write(chip, eReg_CSM, 0);
 
        switch (reg) {
        case ED_DSP_TIMED_OUT:
-               snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n");
+               dev_warn(chip->card->dev, "lx_message_send: dsp timeout\n");
                return -ETIMEDOUT;
 
        case ED_DSP_CRASHED:
-               snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n");
+               dev_warn(chip->card->dev, "lx_message_send: dsp crashed\n");
                return -EAGAIN;
        }
 
@@ -491,33 +434,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
 #define CSES_BROADCAST      0x0002
 #define CSES_UPDATE_LDSV    0x0004
 
-int lx_dsp_es_check_pipeline(struct lx6464es *chip)
-{
-       int i;
-
-       for (i = 0; i != CSES_TIMEOUT; ++i) {
-               /*
-                * le bit CSES_UPDATE_LDSV est ÃƒÂ  1 dés que le macprog
-                * est pret. il re-passe ÃƒÂ  0 lorsque le premier read a
-                * ÃƒÂ©té fait. pour l'instant on retire le test car ce bit
-                * passe a 1 environ 200 ÃƒÂ  400 ms aprés que le registre
-                * confES ÃƒÂ  ÃƒÂ©té ÃƒÂ©crit (kick du xilinx ES).
-                *
-                * On ne teste que le bit CE.
-                * */
-
-               u32 cses = lx_dsp_reg_read(chip, eReg_CSES);
-
-               if ((cses & CSES_CE) == 0)
-                       return 0;
-
-               udelay(1);
-       }
-
-       return -ETIMEDOUT;
-}
-
-
 #define PIPE_INFO_TO_CMD(capture, pipe)                                        \
        ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
 
@@ -542,7 +458,7 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
        spin_unlock_irqrestore(&chip->msg_lock, flags);
 
        if (err != 0)
-               snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n");
+               dev_err(chip->card->dev, "could not allocate pipe\n");
 
        return err;
 }
@@ -604,11 +520,13 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
                }
 
 #if 0
-               snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
+               dev_dbg(chip->card->dev,
+                       "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
                            *r_needed, *r_freed);
                for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
                        for (i = 0; i != chip->rmh.stat_len; ++i)
-                               snd_printdd("  stat[%d]: %x, %x\n", i,
+                               dev_dbg(chip->card->dev,
+                                       "  stat[%d]: %x, %x\n", i,
                                            chip->rmh.stat[i],
                                            chip->rmh.stat[i] & MASK_DATA_SIZE);
                }
@@ -701,8 +619,8 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
        err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */
 
        if (err != 0)
-               snd_printk(KERN_ERR
-                          "lx6464es: could not query pipe's sample count\n");
+               dev_err(chip->card->dev,
+                       "could not query pipe's sample count\n");
        else {
                *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
                                  << 24)     /* hi part */
@@ -728,7 +646,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
        err = lx_message_send_atomic(chip, &chip->rmh);
 
        if (err != 0)
-               snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n");
+               dev_err(chip->card->dev, "could not query pipe's state\n");
        else
                *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
 
@@ -801,7 +719,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
        u32 channels = runtime->channels;
 
        if (runtime->channels != channels)
-               snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d",
+               dev_err(chip->card->dev, "channel count mismatch: %d vs %d",
                           runtime->channels, channels);
 
        spin_lock_irqsave(&chip->msg_lock, flags);
@@ -904,13 +822,16 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
        }
 
        if (err == EB_RBUFFERS_TABLE_OVERFLOW)
-               snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
+               dev_err(chip->card->dev,
+                       "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
 
        if (err == EB_INVALID_STREAM)
-               snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n");
+               dev_err(chip->card->dev,
+                       "lx_buffer_give EB_INVALID_STREAM\n");
 
        if (err == EB_CMD_REFUSED)
-               snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n");
+               dev_err(chip->card->dev,
+                       "lx_buffer_give EB_CMD_REFUSED\n");
 
  done:
        spin_unlock_irqrestore(&chip->msg_lock, flags);
@@ -983,7 +904,8 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
        chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32);        /* hi part */
        chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */
 
-       snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
+       dev_dbg(chip->card->dev,
+               "mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
                   chip->rmh.cmd[2]);
 
        err = lx_message_send_atomic(chip, &chip->rmh);
@@ -1093,7 +1015,7 @@ static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc,
        }
 
        if (irq_async) {
-               /* snd_printd("interrupt: async event pending\n"); */
+               /* dev_dbg(chip->card->dev, "interrupt: async event pending\n"); */
                *r_async_pending = 1;
        }
 
@@ -1139,13 +1061,13 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
        if (eb_pending_in) {
                *r_notified_in_pipe_mask = ((u64)stat[3] << 32)
                        + stat[4];
-               snd_printdd(LXP "interrupt: EOBI pending %llx\n",
+               dev_dbg(chip->card->dev, "interrupt: EOBI pending %llx\n",
                            *r_notified_in_pipe_mask);
        }
        if (eb_pending_out) {
                *r_notified_out_pipe_mask = ((u64)stat[1] << 32)
                        + stat[2];
-               snd_printdd(LXP "interrupt: EOBO pending %llx\n",
+               dev_dbg(chip->card->dev, "interrupt: EOBO pending %llx\n",
                            *r_notified_out_pipe_mask);
        }
 
@@ -1181,17 +1103,19 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
        u32 needed, freed;
        u32 size_array[MAX_STREAM_BUFFER];
 
-       snd_printdd("->lx_interrupt_request_new_buffer\n");
+       dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n");
 
        spin_lock_irqsave(&chip->lock, flags);
 
        err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
-       snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed);
+       dev_dbg(chip->card->dev,
+               "interrupt: needed %d, freed %d\n", needed, freed);
 
        unpack_pointer(buf, &buf_lo, &buf_hi);
        err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi,
                             &buffer_index);
-       snd_printdd(LXP "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n",
+       dev_dbg(chip->card->dev,
+               "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n",
                    buffer_index, (unsigned long)buf, period_bytes);
 
        lx_stream->frame_pos = next_pos;
@@ -1206,11 +1130,11 @@ void lx_tasklet_playback(unsigned long data)
        struct lx_stream *lx_stream = &chip->playback_stream;
        int err;
 
-       snd_printdd("->lx_tasklet_playback\n");
+       dev_dbg(chip->card->dev, "->lx_tasklet_playback\n");
 
        err = lx_interrupt_request_new_buffer(chip, lx_stream);
        if (err < 0)
-               snd_printk(KERN_ERR LXP
+               dev_err(chip->card->dev,
                           "cannot request new buffer for playback\n");
 
        snd_pcm_period_elapsed(lx_stream->stream);
@@ -1222,10 +1146,10 @@ void lx_tasklet_capture(unsigned long data)
        struct lx_stream *lx_stream = &chip->capture_stream;
        int err;
 
-       snd_printdd("->lx_tasklet_capture\n");
+       dev_dbg(chip->card->dev, "->lx_tasklet_capture\n");
        err = lx_interrupt_request_new_buffer(chip, lx_stream);
        if (err < 0)
-               snd_printk(KERN_ERR LXP
+               dev_err(chip->card->dev,
                           "cannot request new buffer for capture\n");
 
        snd_pcm_period_elapsed(lx_stream->stream);
@@ -1240,12 +1164,14 @@ static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip,
        int err = 0;
 
        if (notified_in_pipe_mask) {
-               snd_printdd(LXP "requesting audio transfer for capture\n");
+               dev_dbg(chip->card->dev,
+                       "requesting audio transfer for capture\n");
                tasklet_hi_schedule(&chip->tasklet_capture);
        }
 
        if (notified_out_pipe_mask) {
-               snd_printdd(LXP "requesting audio transfer for playback\n");
+               dev_dbg(chip->card->dev,
+                       "requesting audio transfer for playback\n");
                tasklet_hi_schedule(&chip->tasklet_playback);
        }
 
@@ -1261,11 +1187,12 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
 
        spin_lock(&chip->lock);
 
-       snd_printdd("**************************************************\n");
+       dev_dbg(chip->card->dev,
+               "**************************************************\n");
 
        if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
                spin_unlock(&chip->lock);
-               snd_printdd("IRQ_NONE\n");
+               dev_dbg(chip->card->dev, "IRQ_NONE\n");
                return IRQ_NONE; /* this device did not cause the interrupt */
        }
 
@@ -1274,16 +1201,16 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
 
 #if 0
        if (irqsrc & MASK_SYS_STATUS_EOBI)
-               snd_printdd(LXP "interrupt: EOBI\n");
+               dev_dgg(chip->card->dev, "interrupt: EOBI\n");
 
        if (irqsrc & MASK_SYS_STATUS_EOBO)
-               snd_printdd(LXP "interrupt: EOBO\n");
+               dev_dbg(chip->card->dev, "interrupt: EOBO\n");
 
        if (irqsrc & MASK_SYS_STATUS_URUN)
-               snd_printdd(LXP "interrupt: URUN\n");
+               dev_dbg(chip->card->dev, "interrupt: URUN\n");
 
        if (irqsrc & MASK_SYS_STATUS_ORUN)
-               snd_printdd(LXP "interrupt: ORUN\n");
+               dev_dbg(chip->card->dev, "interrupt: ORUN\n");
 #endif
 
        if (async_pending) {
@@ -1298,7 +1225,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
                                                       &notified_in_pipe_mask,
                                                       &notified_out_pipe_mask);
                if (err)
-                       snd_printk(KERN_ERR LXP
+                       dev_err(chip->card->dev,
                                   "error handling async events\n");
 
                err = lx_interrupt_handle_audio_transfer(chip,
@@ -1306,7 +1233,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
                                                         notified_out_pipe_mask
                        );
                if (err)
-                       snd_printk(KERN_ERR LXP
+                       dev_err(chip->card->dev,
                                   "error during audio transfer\n");
        }
 
@@ -1318,7 +1245,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
                 *
                 * */
 
-               snd_printdd("lx6464es: interrupt requests escmd handling\n");
+               dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
 #endif
        }
 
@@ -1346,12 +1273,12 @@ static void lx_irq_set(struct lx6464es *chip, int enable)
 
 void lx_irq_enable(struct lx6464es *chip)
 {
-       snd_printdd("->lx_irq_enable\n");
+       dev_dbg(chip->card->dev, "->lx_irq_enable\n");
        lx_irq_set(chip, 1);
 }
 
 void lx_irq_disable(struct lx6464es *chip)
 {
-       snd_printdd("->lx_irq_disable\n");
+       dev_dbg(chip->card->dev, "->lx_irq_disable\n");
        lx_irq_set(chip, 0);
 }
index d5417360f51fb8be6a43be6ddef9bd6c2e7ac2e3..0d3ea3e79952a0eeab478949c51ddb90fa5a2aa1 100644 (file)
@@ -1403,7 +1403,7 @@ static int snd_m3_pcm_hw_params(struct snd_pcm_substream *substream,
        /* set buffer address */
        s->buffer_addr = substream->runtime->dma_addr;
        if (s->buffer_addr & 0x3) {
-               snd_printk(KERN_ERR "oh my, not aligned\n");
+               dev_err(substream->pcm->card->dev, "oh my, not aligned\n");
                s->buffer_addr = s->buffer_addr & ~0x3;
        }
        return 0;
@@ -1900,7 +1900,7 @@ static int snd_m3_ac97_wait(struct snd_m3 *chip)
                cpu_relax();
        } while (i-- > 0);
 
-       snd_printk(KERN_ERR "ac97 serial bus busy\n");
+       dev_err(chip->card->dev, "ac97 serial bus busy\n");
        return 1;
 }
 
@@ -2015,7 +2015,8 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
                delay1 += 10;
                delay2 += 100;
 
-               snd_printd("maestro3: retrying codec reset with delays of %d and %d ms\n",
+               dev_dbg(chip->card->dev,
+                       "retrying codec reset with delays of %d and %d ms\n",
                           delay1, delay2);
        }
 
@@ -2194,7 +2195,8 @@ static int snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int in
        address = 0x1100 + ((data_bytes/2) * index);
 
        if ((address + (data_bytes/2)) >= 0x1c00) {
-               snd_printk(KERN_ERR "no memory for %d bytes at ind %d (addr 0x%x)\n",
+               dev_err(chip->card->dev,
+                       "no memory for %d bytes at ind %d (addr 0x%x)\n",
                           data_bytes, index, address);
                return -ENOMEM;
        }
@@ -2439,8 +2441,7 @@ static int m3_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "maestor3: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2553,7 +2554,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        /* check, if we can restrict PCI DMA transfers to 28 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 28bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -2586,9 +2588,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        else {
                quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
                if (quirk) {
-                       snd_printdd(KERN_INFO
-                                   "maestro3: set amp-gpio for '%s'\n",
-                                   snd_pci_quirk_name(quirk));
+                       dev_info(card->dev, "set amp-gpio for '%s'\n",
+                                snd_pci_quirk_name(quirk));
                        chip->amp_gpio = quirk->value;
                } else if (chip->allegro_flag)
                        chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
@@ -2598,9 +2599,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 
        quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
        if (quirk) {
-               snd_printdd(KERN_INFO
-                           "maestro3: enabled irda workaround for '%s'\n",
-                           snd_pci_quirk_name(quirk));
+               dev_info(card->dev, "enabled irda workaround for '%s'\n",
+                        snd_pci_quirk_name(quirk));
                chip->irda_workaround = 1;
        }
        quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
@@ -2652,7 +2652,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 
        if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_m3_free(chip);
                return -ENOMEM;
        }
@@ -2661,7 +2661,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 #ifdef CONFIG_PM_SLEEP
        chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
        if (chip->suspend_mem == NULL)
-               snd_printk(KERN_WARNING "can't allocate apm buffer\n");
+               dev_warn(card->dev, "can't allocate apm buffer\n");
 #endif
 
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
@@ -2685,16 +2685,15 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        if (chip->hv_config & HV_CTRL_ENABLE) {
                err = snd_m3_input_register(chip);
                if (err)
-                       snd_printk(KERN_WARNING "Input device registration "
-                               "failed with error %i", err);
+                       dev_warn(card->dev,
+                                "Input device registration failed with error %i",
+                                err);
        }
 #endif
 
        snd_m3_enable_ints(chip);
        snd_m3_assp_continue(chip);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *chip_ret = chip;
 
        return 0; 
@@ -2721,7 +2720,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -2764,7 +2764,7 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                                  MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
                                  -1, &chip->rmidi);
        if (err < 0)
-               printk(KERN_WARNING "maestro3: no MIDI support.\n");
+               dev_warn(card->dev, "no MIDI support.\n");
 #endif
 
        pci_set_drvdata(pci, card);
index 1e0f6ee193f0a926279e3d3d25a4ea995b78bfdd..a93e7af51eed1138475fbc5b90643ba4703fed1b 100644 (file)
@@ -87,7 +87,8 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
                if(!start) return 0; /* already stopped */
                break;
        default:
-               snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n");
+               dev_err(&mgr->pci->dev,
+                       "error mixart_set_pipe_state called with wrong pipe->status!\n");
                return -EINVAL;      /* function called with wrong pipe status */
        }
 
@@ -102,7 +103,8 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
 
        err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid);
        if(err) {
-               snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
+               dev_err(&mgr->pci->dev,
+                       "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
                return err;
        }
 
@@ -123,7 +125,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
 
        err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
        if (err < 0 || group_state_resp.txx_status != 0) {
-               snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
+               dev_err(&mgr->pci->dev,
+                       "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n",
+                       err, group_state_resp.txx_status);
                return -EINVAL;
        }
 
@@ -134,7 +138,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
 
                err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
                if (err < 0 || group_state_resp.txx_status != 0) {
-                       snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
+                       dev_err(&mgr->pci->dev,
+                               "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n",
+                               err, group_state_resp.txx_status);
                        return -EINVAL;
                }
 
@@ -147,7 +153,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
 
                err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat);
                if (err < 0 || stat != 0) {
-                       snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat);
+                       dev_err(&mgr->pci->dev,
+                               "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n",
+                               err, stat);
                        return -EINVAL;
                }
 
@@ -178,7 +186,9 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
                if(rate == 0)
                        return 0; /* nothing to do */
                else {
-                       snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate);
+                       dev_err(&mgr->pci->dev,
+                               "error mixart_set_clock(%d) called with wrong pipe->status !\n",
+                               rate);
                        return -EINVAL;
                }
        }
@@ -190,7 +200,7 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
        clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
        clock_properties.uid_caller[0] = pipe->group_uid;
 
-       snd_printdd("mixart_set_clock to %d kHz\n", rate);
+       dev_dbg(&mgr->pci->dev, "mixart_set_clock to %d kHz\n", rate);
 
        request.message_id = MSG_CLOCK_SET_PROPERTIES;
        request.uid = mgr->uid_console_manager;
@@ -199,7 +209,9 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
 
        err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp);
        if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) {
-               snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode);
+               dev_err(&mgr->pci->dev,
+                       "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n",
+                       err, clock_prop_resp.status, clock_prop_resp.clock_mode);
                return -EINVAL;
        }
 
@@ -252,7 +264,9 @@ snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture,
                        struct mixart_streaming_group sgroup_resp;
                } *buf;
 
-               snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number);
+               dev_dbg(chip->card->dev,
+                       "add_ref_pipe audio chip(%d) pcm(%d)\n",
+                       chip->chip_idx, pcm_number);
 
                buf = kmalloc(sizeof(*buf), GFP_KERNEL);
                if (!buf)
@@ -302,7 +316,9 @@ snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture,
 
                err = snd_mixart_send_msg(chip->mgr, &request, sizeof(buf->sgroup_resp), &buf->sgroup_resp);
                if((err < 0) || (buf->sgroup_resp.status != 0)) {
-                       snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, buf->sgroup_resp.status);
+                       dev_err(chip->card->dev,
+                               "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n",
+                               err, buf->sgroup_resp.status);
                        kfree(buf);
                        return NULL;
                }
@@ -343,13 +359,14 @@ int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
                /* release the clock */
                err = mixart_set_clock( mgr, pipe, 0);
                if( err < 0 ) {
-                       snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
+                       dev_err(&mgr->pci->dev,
+                               "mixart_set_clock(0) return error!\n");
                }
 
                /* stop the pipe */
                err = mixart_set_pipe_state(mgr, pipe, 0);
                if( err < 0 ) {
-                       snd_printk(KERN_ERR "error stopping pipe!\n");
+                       dev_err(&mgr->pci->dev, "error stopping pipe!\n");
                }
 
                request.message_id = MSG_STREAM_DELETE_GROUP;
@@ -360,7 +377,9 @@ int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
                /* delete the pipe */
                err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
                if ((err < 0) || (delete_resp.status != 0)) {
-                       snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
+                       dev_err(&mgr->pci->dev,
+                               "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n",
+                               err, delete_resp.status);
                }
 
                pipe->group_uid = (struct mixart_uid){0,0};
@@ -414,7 +433,7 @@ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
 
-               snd_printdd("SNDRV_PCM_TRIGGER_START\n");
+               dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_TRIGGER_START\n");
 
                /* START_STREAM */
                if( mixart_set_stream_state(stream, 1) )
@@ -431,19 +450,19 @@ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
 
                stream->status = MIXART_STREAM_STATUS_OPEN;
 
-               snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
+               dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_TRIGGER_STOP\n");
 
                break;
 
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                /* TODO */
                stream->status = MIXART_STREAM_STATUS_PAUSE;
-               snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
+               dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_PAUSE_PUSH\n");
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                /* TODO */
                stream->status = MIXART_STREAM_STATUS_RUNNING;
-               snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
+               dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_PAUSE_RELEASE\n");
                break;
        default:
                return -EINVAL;
@@ -456,7 +475,8 @@ static int mixart_sync_nonblock_events(struct mixart_mgr *mgr)
        unsigned long timeout = jiffies + HZ;
        while (atomic_read(&mgr->msg_processed) > 0) {
                if (time_after(jiffies, timeout)) {
-                       snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
+                       dev_err(&mgr->pci->dev,
+                               "mixart: cannot process nonblock events!\n");
                        return -EBUSY;
                }
                schedule_timeout_uninterruptible(1);
@@ -474,7 +494,7 @@ static int snd_mixart_prepare(struct snd_pcm_substream *subs)
 
        /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
 
-       snd_printdd("snd_mixart_prepare\n");
+       dev_dbg(chip->card->dev, "snd_mixart_prepare\n");
 
        mixart_sync_nonblock_events(chip->mgr);
 
@@ -542,11 +562,13 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form
                stream_param.sample_size = 32;
                break;
        default:
-               snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n");
+               dev_err(chip->card->dev,
+                       "error mixart_set_format() : unknown format\n");
                return -EINVAL;
        }
 
-       snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
+       dev_dbg(chip->card->dev,
+               "set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
                   stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);
 
        /* TODO: what else to configure ? */
@@ -566,7 +588,9 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form
 
        err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
        if((err < 0) || resp.error_code) {
-               snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
+               dev_err(chip->card->dev,
+                       "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n",
+                       err, resp.error_code);
                return -EINVAL;
        }
        return 0;
@@ -627,8 +651,9 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
                bufferinfo[i].available_length = subs->runtime->dma_bytes;
                /* bufferinfo[i].buffer_id  is already defined */
 
-               snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i,
-                               bufferinfo[i].buffer_address,
+               dev_dbg(chip->card->dev,
+                       "snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n",
+                       i, bufferinfo[i].buffer_address,
                                bufferinfo[i].available_length,
                                subs->number);
        }
@@ -714,14 +739,18 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
                pcm_number = MIXART_PCM_DIGITAL;
                runtime->hw = snd_mixart_digital_caps;
        }
-       snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+       dev_dbg(chip->card->dev,
+               "snd_mixart_playback_open C%d/P%d/Sub%d\n",
+               chip->chip_idx, pcm_number, subs->number);
 
        /* get stream info */
        stream = &(chip->playback_stream[pcm_number][subs->number]);
 
        if (stream->status != MIXART_STREAM_STATUS_FREE){
                /* streams in use */
-               snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+               dev_err(chip->card->dev,
+                       "snd_mixart_playback_open C%d/P%d/Sub%d in use\n",
+                       chip->chip_idx, pcm_number, subs->number);
                err = -EBUSY;
                goto _exit_open;
        }
@@ -737,7 +766,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
        /* start the pipe if necessary */
        err = mixart_set_pipe_state(chip->mgr, pipe, 1);
        if( err < 0 ) {
-               snd_printk(KERN_ERR "error starting pipe!\n");
+               dev_err(chip->card->dev, "error starting pipe!\n");
                snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
                err = -EINVAL;
                goto _exit_open;
@@ -792,14 +821,17 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
 
        runtime->hw.channels_min = 2; /* for instance, no mono */
 
-       snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+       dev_dbg(chip->card->dev, "snd_mixart_capture_open C%d/P%d/Sub%d\n",
+               chip->chip_idx, pcm_number, subs->number);
 
        /* get stream info */
        stream = &(chip->capture_stream[pcm_number]);
 
        if (stream->status != MIXART_STREAM_STATUS_FREE){
                /* streams in use */
-               snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+               dev_err(chip->card->dev,
+                       "snd_mixart_capture_open C%d/P%d/Sub%d in use\n",
+                       chip->chip_idx, pcm_number, subs->number);
                err = -EBUSY;
                goto _exit_open;
        }
@@ -815,7 +847,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
        /* start the pipe if necessary */
        err = mixart_set_pipe_state(chip->mgr, pipe, 1);
        if( err < 0 ) {
-               snd_printk(KERN_ERR "error starting pipe!\n");
+               dev_err(chip->card->dev, "error starting pipe!\n");
                snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
                err = -EINVAL;
                goto _exit_open;
@@ -855,7 +887,8 @@ static int snd_mixart_close(struct snd_pcm_substream *subs)
 
        mutex_lock(&mgr->setup_mutex);
 
-       snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
+       dev_dbg(chip->card->dev, "snd_mixart_close C%d/P%d/Sub%d\n",
+               chip->chip_idx, stream->pcm_number, subs->number);
 
        /* sample rate released */
        if(--mgr->ref_count_rate == 0) {
@@ -865,7 +898,9 @@ static int snd_mixart_close(struct snd_pcm_substream *subs)
        /* delete pipe */
        if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {
 
-               snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
+               dev_err(chip->card->dev,
+                       "error snd_mixart_kill_ref_pipe C%dP%d\n",
+                       chip->chip_idx, stream->pcm_number);
        }
 
        stream->pipe      = NULL;
@@ -940,7 +975,8 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip)
        if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
                               MIXART_PLAYBACK_STREAMS,
                               MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
-               snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
+               dev_err(chip->card->dev,
+                       "cannot create the analog pcm %d\n", chip->chip_idx);
                return err;
        }
 
@@ -971,7 +1007,8 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip)
        if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
                               MIXART_PLAYBACK_STREAMS,
                               MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
-               snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
+               dev_err(chip->card->dev,
+                       "cannot create the digital pcm %d\n", chip->chip_idx);
                return err;
        }
 
@@ -1014,7 +1051,7 @@ static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (! chip) {
-               snd_printk(KERN_ERR "cannot allocate chip\n");
+               dev_err(card->dev, "cannot allocate chip\n");
                return -ENOMEM;
        }
 
@@ -1028,8 +1065,6 @@ static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int
        }
 
        mgr->chip[idx] = chip;
-       snd_card_set_dev(card, &mgr->pci->dev);
-
        return 0;
 }
 
@@ -1073,7 +1108,7 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
        /* reset board if some firmware was loaded */
        if(mgr->dsp_loaded) {
                snd_mixart_reset_board(mgr);
-               snd_printdd("reset miXart !\n");
+               dev_dbg(&mgr->pci->dev, "reset miXart !\n");
        }
 
        /* release the i/o ports */
@@ -1234,7 +1269,8 @@ static int snd_mixart_probe(struct pci_dev *pci,
 
        /* check if we can restrict PCI DMA transfers to 32 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+               dev_err(&pci->dev,
+                       "architecture does not support 32bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -1260,7 +1296,7 @@ static int snd_mixart_probe(struct pci_dev *pci,
                mgr->mem[i].phys = pci_resource_start(pci, i);
                mgr->mem[i].virt = pci_ioremap_bar(pci, i);
                if (!mgr->mem[i].virt) {
-                       printk(KERN_ERR "unable to remap resource 0x%lx\n",
+                       dev_err(&pci->dev, "unable to remap resource 0x%lx\n",
                               mgr->mem[i].phys);
                        snd_mixart_free(mgr);
                        return -EBUSY;
@@ -1269,7 +1305,7 @@ static int snd_mixart_probe(struct pci_dev *pci,
 
        if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, mgr)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_mixart_free(mgr);
                return -EBUSY;
        }
@@ -1308,10 +1344,11 @@ static int snd_mixart_probe(struct pci_dev *pci,
                else
                        idx = index[dev] + i;
                snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i);
-               err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
+               err = snd_card_new(&pci->dev, idx, tmpid, THIS_MODULE,
+                                  0, &card);
 
                if (err < 0) {
-                       snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
+                       dev_err(&pci->dev, "cannot allocate the card %d\n", i);
                        snd_mixart_free(mgr);
                        return err;
                }
index 3df0f530f67c0df6626659c8ad45700b670114c1..71f4bdcc4055fbec2aa37317a5a8d2e1c16bc123 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
+#include <linux/pci.h>
 
 #include <asm/io.h>
 #include <sound/core.h>
@@ -94,7 +95,8 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
 
        if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
                err = -EINVAL;
-               snd_printk(KERN_ERR "problem with response size = %d\n", size);
+               dev_err(&mgr->pci->dev,
+                       "problem with response size = %d\n", size);
                goto _clean_exit;
        }
        size -= MSG_DESCRIPTOR_SIZE;
@@ -161,7 +163,7 @@ static int send_msg( struct mixart_mgr *mgr,
        headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
 
        if (tailptr == headptr) {
-               snd_printk(KERN_ERR "error: no message frame available\n");
+               dev_err(&mgr->pci->dev, "error: no message frame available\n");
                return -EBUSY;
        }
 
@@ -265,7 +267,8 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
        if (! timeout) {
                /* error - no ack */
                mutex_unlock(&mgr->msg_mutex);
-               snd_printk(KERN_ERR "error: no response on msg %x\n", msg_frame);
+               dev_err(&mgr->pci->dev,
+                       "error: no response on msg %x\n", msg_frame);
                return -EIO;
        }
 
@@ -278,7 +281,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
        err = get_msg(mgr, &resp, msg_frame);
 
        if( request->message_id != resp.message_id )
-               snd_printk(KERN_ERR "RESPONSE ERROR!\n");
+               dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
 
        mutex_unlock(&mgr->msg_mutex);
        return err;
@@ -321,7 +324,8 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
        if (! timeout) {
                /* error - no ack */
                mutex_unlock(&mgr->msg_mutex);
-               snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
+               dev_err(&mgr->pci->dev,
+                       "error: notification %x not received\n", notif_event);
                return -EIO;
        }
 
@@ -378,7 +382,9 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                        resp.size = sizeof(mixart_msg_data);
                        err = get_msg(mgr, &resp, addr);
                        if( err < 0 ) {
-                               snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg);
+                               dev_err(&mgr->pci->dev,
+                                       "tasklet: error(%d) reading mf %x\n",
+                                       err, msg);
                                break;
                        }
 
@@ -388,10 +394,13 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                        case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
                        case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
                                if(mixart_msg_data[0])
-                                       snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]);
+                                       dev_err(&mgr->pci->dev,
+                                               "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
+                                               mixart_msg_data[0]);
                                break;
                        default:
-                               snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
+                               dev_dbg(&mgr->pci->dev,
+                                       "tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
                                           msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
                                break;
                        }
@@ -401,7 +410,9 @@ void snd_mixart_msg_tasklet(unsigned long arg)
                case MSG_TYPE_COMMAND:
                        /* get_msg() necessary */
                default:
-                       snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg);
+                       dev_err(&mgr->pci->dev,
+                               "tasklet doesn't know what to do with message %x\n",
+                               msg);
                } /* switch type */
 
                /* decrement counter */
@@ -451,7 +462,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                        resp.size = sizeof(mixart_msg_data);
                        err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
                        if( err < 0 ) {
-                               snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
+                               dev_err(&mgr->pci->dev,
+                                       "interrupt: error(%d) reading mf %x\n",
+                                       err, msg);
                                break;
                        }
 
@@ -472,7 +485,8 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                                        struct mixart_stream *stream;
 
                                        if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
-                                               snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
+                                               dev_err(&mgr->pci->dev,
+                                                       "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
                                                           buffer_id, notify->streams[i].sample_pos_low_part);
                                                break;
                                        }
@@ -524,18 +538,22 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                                        }
 #endif
                                        ((char*)mixart_msg_data)[resp.size - 1] = 0;
-                                       snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
+                                       dev_dbg(&mgr->pci->dev,
+                                               "MIXART TRACE : %s\n",
+                                               (char *)mixart_msg_data);
                                }
                                break;
                        }
 
-                       snd_printdd("command %x not handled\n", resp.message_id);
+                       dev_dbg(&mgr->pci->dev, "command %x not handled\n",
+                               resp.message_id);
                        break;
 
                case MSG_TYPE_NOTIFY:
                        if(msg & MSG_CANCEL_NOTIFY_MASK) {
                                msg &= ~MSG_CANCEL_NOTIFY_MASK;
-                               snd_printk(KERN_ERR "canceled notification %x !\n", msg);
+                               dev_err(&mgr->pci->dev,
+                                       "canceled notification %x !\n", msg);
                        }
                        /* no break, continue ! */
                case MSG_TYPE_ANSWER:
@@ -556,7 +574,8 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
                        break;
                case MSG_TYPE_REQUEST:
                default:
-                       snd_printdd("interrupt received request %x\n", msg);
+                       dev_dbg(&mgr->pci->dev,
+                               "interrupt received request %x\n", msg);
                        /* TODO : are there things to do here ? */
                        break;
                } /* switch on msg type */
index ece1f831c16a834c8c0806ea5d5c812bc257f24f..581e1e74863c6471642ea893a4dc77de2419635c 100644 (file)
@@ -165,7 +165,8 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
 
        err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
        if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
-               snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
+               dev_err(&mgr->pci->dev,
+                       "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
                err = -EINVAL;
                goto __error;
        }
@@ -184,7 +185,7 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
                        pipe->uid_left_connector = connector->uid[k];    /* even */
                }
 
-               /* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
+               /* dev_dbg(&mgr->pci->dev, "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
 
                /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
                request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
@@ -194,10 +195,11 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
 
                err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
                if( err < 0 ) {
-                       snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+                       dev_err(&mgr->pci->dev,
+                               "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
                        goto __error;
                }
-               /*snd_printk(KERN_DEBUG "play  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
+               /*dev_dbg(&mgr->pci->dev, "play  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
        }
 
        request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
@@ -207,7 +209,8 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
 
        err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
        if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
-               snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
+               dev_err(&mgr->pci->dev,
+                       "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
                err = -EINVAL;
                goto __error;
        }
@@ -226,7 +229,7 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
                        pipe->uid_left_connector = connector->uid[k];    /* even */
                }
 
-               /* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
+               /* dev_dbg(&mgr->pci->dev, "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
 
                /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
                request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
@@ -236,10 +239,11 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
 
                err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
                if( err < 0 ) {
-                       snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+                       dev_err(&mgr->pci->dev,
+                               "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
                        goto __error;
                }
-               /*snd_printk(KERN_DEBUG "rec  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
+               /*dev_dbg(&mgr->pci->dev, "rec  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
        }
        err = 0;
 
@@ -272,7 +276,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr)
        err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
 
        if( (err < 0) || (console_mgr.error_code != 0) ) {
-               snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
+               dev_dbg(&mgr->pci->dev,
+                       "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n",
+                       console_mgr.error_code);
                return -EINVAL;
        }
 
@@ -286,7 +292,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr)
 
        err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
        if( (err < 0) || ( phys_io.error_code != 0 ) ) {
-               snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
+               dev_err(&mgr->pci->dev,
+                       "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n",
+                       err, phys_io.error_code);
                return -EINVAL;
        }
 
@@ -322,7 +330,7 @@ static int mixart_first_init(struct mixart_mgr *mgr)
        /* this command has no data. response is a 32 bit status */
        err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
        if( (err < 0) || (k != 0) ) {
-               snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
+               dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
                return err == 0 ? -EINVAL : err;
        }
 
@@ -348,7 +356,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
        /* motherboard xilinx status 5 will say that the board is performing a reset */
        if (status_xilinx == 5) {
-               snd_printk(KERN_ERR "miXart is resetting !\n");
+               dev_err(&mgr->pci->dev, "miXart is resetting !\n");
                return -EAGAIN; /* try again later */
        }
 
@@ -357,12 +365,13 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
                /* xilinx already loaded ? */ 
                if (status_xilinx == 4) {
-                       snd_printk(KERN_DEBUG "xilinx is already loaded !\n");
+                       dev_dbg(&mgr->pci->dev, "xilinx is already loaded !\n");
                        return 0;
                }
                /* the status should be 0 == "idle" */
                if (status_xilinx != 0) {
-                       snd_printk(KERN_ERR "xilinx load error ! status = %d\n",
+                       dev_err(&mgr->pci->dev,
+                               "xilinx load error ! status = %d\n",
                                   status_xilinx);
                        return -EIO; /* modprob -r may help ? */
                }
@@ -393,13 +402,14 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
        case MIXART_MOTHERBOARD_ELF_INDEX:
 
                if (status_elf == 4) {
-                       snd_printk(KERN_DEBUG "elf file already loaded !\n");
+                       dev_dbg(&mgr->pci->dev, "elf file already loaded !\n");
                        return 0;
                }
 
                /* the status should be 0 == "idle" */
                if (status_elf != 0) {
-                       snd_printk(KERN_ERR "elf load error ! status = %d\n",
+                       dev_err(&mgr->pci->dev,
+                               "elf load error ! status = %d\n",
                                   status_elf);
                        return -EIO; /* modprob -r may help ? */
                }
@@ -407,7 +417,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                /* wait for xilinx status == 4 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
                if (err < 0) {
-                       snd_printk(KERN_ERR "xilinx was not loaded or "
+                       dev_err(&mgr->pci->dev, "xilinx was not loaded or "
                                   "could not be started\n");
                        return err;
                }
@@ -429,7 +439,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                /* wait for elf status == 4 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
                if (err < 0) {
-                       snd_printk(KERN_ERR "elf could not be started\n");
+                       dev_err(&mgr->pci->dev, "elf could not be started\n");
                        return err;
                }
 
@@ -443,7 +453,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
                /* elf and xilinx should be loaded */
                if (status_elf != 4 || status_xilinx != 4) {
-                       printk(KERN_ERR "xilinx or elf not "
+                       dev_err(&mgr->pci->dev, "xilinx or elf not "
                               "successfully loaded\n");
                        return -EIO; /* modprob -r may help ? */
                }
@@ -451,7 +461,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                /* wait for daughter detection != 0 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
                if (err < 0) {
-                       snd_printk(KERN_ERR "error starting elf file\n");
+                       dev_err(&mgr->pci->dev, "error starting elf file\n");
                        return err;
                }
 
@@ -467,7 +477,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
                /* daughter should be idle */
                if (status_daught != 0) {
-                       printk(KERN_ERR "daughter load error ! status = %d\n",
+                       dev_err(&mgr->pci->dev,
+                               "daughter load error ! status = %d\n",
                               status_daught);
                        return -EIO; /* modprob -r may help ? */
                }
@@ -487,7 +498,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                /* wait for status == 2 */
                err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
                if (err < 0) {
-                       snd_printk(KERN_ERR "daughter board load error\n");
+                       dev_err(&mgr->pci->dev, "daughter board load error\n");
                        return err;
                }
 
@@ -509,7 +520,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
         /* wait for daughter status == 3 */
         err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
         if (err < 0) {
-               snd_printk(KERN_ERR
+               dev_err(&mgr->pci->dev,
                           "daughter board could not be initialised\n");
                return err;
        }
@@ -520,7 +531,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
        /* first communication with embedded */
        err = mixart_first_init(mgr);
         if (err < 0) {
-               snd_printk(KERN_ERR "miXart could not be set up\n");
+               dev_err(&mgr->pci->dev, "miXart could not be set up\n");
                return err;
        }
 
@@ -540,7 +551,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
                        return err;
        }
 
-       snd_printdd("miXart firmware downloaded and successfully set up\n");
+       dev_dbg(&mgr->pci->dev,
+               "miXart firmware downloaded and successfully set up\n");
 
        return 0;
 }
@@ -559,7 +571,8 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
        for (i = 0; i < 3; i++) {
                sprintf(path, "mixart/%s", fw_files[i]);
                if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
-                       snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path);
+                       dev_err(&mgr->pci->dev,
+                               "miXart: can't load firmware %s\n", path);
                        return -ENOENT;
                }
                /* fake hwdep dsp record */
index 3ba6174c3df1d80a6d714ddc836b751bbf917bc5..24a1955b8c2963ad0dfd737868a922fad59c3d71 100644 (file)
@@ -329,7 +329,9 @@ static int mixart_update_analog_audio_level(struct snd_mixart* chip, int is_capt
 
        err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
        if((err<0) || (resp.error_code)) {
-               snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code);
+               dev_dbg(chip->card->dev,
+                       "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n",
+                       chip->chip_idx, is_capture, resp.error_code);
                return -EINVAL;
        }
        return 0;
@@ -762,7 +764,9 @@ int mixart_update_playback_stream_level(struct snd_mixart* chip, int is_aes, int
 
        err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
        if((err<0) || status) {
-               snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+               dev_dbg(chip->card->dev,
+                       "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n",
+                       chip->chip_idx, status);
                return -EINVAL;
        }
        return 0;
@@ -805,7 +809,9 @@ int mixart_update_capture_stream_level(struct snd_mixart* chip, int is_aes)
 
        err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
        if((err<0) || status) {
-               snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+               dev_dbg(chip->card->dev,
+                       "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n",
+                       chip->chip_idx, status);
                return -EINVAL;
        }
        return 0;
@@ -977,7 +983,9 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel)
 
        err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
        if((err<0) || resp) {
-               snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp);
+               dev_dbg(chip->card->dev,
+                       "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n",
+                       chip->chip_idx, resp);
                return -EINVAL;
        }
        return 0;
index fe79fff4c6dc303fd3a5babde6320446979a3f14..ddc60215cc10b3cd2415a30b47830465ff32a1e5 100644 (file)
@@ -318,7 +318,8 @@ snd_nm256_write_buffer(struct nm256 *chip, void *src, int offset, int size)
        offset -= chip->buffer_start;
 #ifdef CONFIG_SND_DEBUG
        if (offset < 0 || offset >= chip->buffer_size) {
-               snd_printk(KERN_ERR "write_buffer invalid offset = %d size = %d\n",
+               dev_err(chip->card->dev,
+                       "write_buffer invalid offset = %d size = %d\n",
                           offset, size);
                return;
        }
@@ -366,7 +367,8 @@ snd_nm256_load_coefficient(struct nm256 *chip, int stream, int number)
                 NM_RECORD_REG_OFFSET : NM_PLAYBACK_REG_OFFSET);
 
        if (snd_nm256_readb(chip, poffset) & 1) {
-               snd_printd("NM256: Engine was enabled while loading coefficients!\n");
+               dev_dbg(chip->card->dev,
+                       "NM256: Engine was enabled while loading coefficients!\n");
                return;
        }
 
@@ -466,7 +468,8 @@ static int snd_nm256_acquire_irq(struct nm256 *chip)
        if (chip->irq < 0) {
                if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED,
                                KBUILD_MODNAME, chip)) {
-                       snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
+                       dev_err(chip->card->dev,
+                               "unable to grab IRQ %d\n", chip->pci->irq);
                        mutex_unlock(&chip->irq_mutex);
                        return -EBUSY;
                }
@@ -1039,7 +1042,7 @@ snd_nm256_interrupt(int irq, void *dev_id)
        if (status & NM_MISC_INT_1) {
                status &= ~NM_MISC_INT_1;
                NM_ACK_INT(chip, NM_MISC_INT_1);
-               snd_printd("NM256: Got misc interrupt #1\n");
+               dev_dbg(chip->card->dev, "NM256: Got misc interrupt #1\n");
                snd_nm256_writew(chip, NM_INT_REG, 0x8000);
                cbyte = snd_nm256_readb(chip, 0x400);
                snd_nm256_writeb(chip, 0x400, cbyte | 2);
@@ -1048,14 +1051,15 @@ snd_nm256_interrupt(int irq, void *dev_id)
        if (status & NM_MISC_INT_2) {
                status &= ~NM_MISC_INT_2;
                NM_ACK_INT(chip, NM_MISC_INT_2);
-               snd_printd("NM256: Got misc interrupt #2\n");
+               dev_dbg(chip->card->dev, "NM256: Got misc interrupt #2\n");
                cbyte = snd_nm256_readb(chip, 0x400);
                snd_nm256_writeb(chip, 0x400, cbyte & ~2);
        }
 
        /* Unknown interrupt. */
        if (status) {
-               snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n",
+               dev_dbg(chip->card->dev,
+                       "NM256: Fire in the hole! Unknown status 0x%x\n",
                           status);
                /* Pray. */
                NM_ACK_INT(chip, status);
@@ -1104,7 +1108,7 @@ snd_nm256_interrupt_zx(int irq, void *dev_id)
        if (status & NM2_MISC_INT_1) {
                status &= ~NM2_MISC_INT_1;
                NM2_ACK_INT(chip, NM2_MISC_INT_1);
-               snd_printd("NM256: Got misc interrupt #1\n");
+               dev_dbg(chip->card->dev, "NM256: Got misc interrupt #1\n");
                cbyte = snd_nm256_readb(chip, 0x400);
                snd_nm256_writeb(chip, 0x400, cbyte | 2);
        }
@@ -1112,14 +1116,15 @@ snd_nm256_interrupt_zx(int irq, void *dev_id)
        if (status & NM2_MISC_INT_2) {
                status &= ~NM2_MISC_INT_2;
                NM2_ACK_INT(chip, NM2_MISC_INT_2);
-               snd_printd("NM256: Got misc interrupt #2\n");
+               dev_dbg(chip->card->dev, "NM256: Got misc interrupt #2\n");
                cbyte = snd_nm256_readb(chip, 0x400);
                snd_nm256_writeb(chip, 0x400, cbyte & ~2);
        }
 
        /* Unknown interrupt. */
        if (status) {
-               snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n",
+               dev_dbg(chip->card->dev,
+                       "NM256: Fire in the hole! Unknown status 0x%x\n",
                           status);
                /* Pray. */
                NM2_ACK_INT(chip, status);
@@ -1245,7 +1250,7 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97,
                        return;
                }
        }
-       snd_printd("nm256: ac97 codec not ready..\n");
+       dev_dbg(chip->card->dev, "nm256: ac97 codec not ready..\n");
 }
 
 /* static resolution table */
@@ -1347,7 +1352,8 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
 
        temp = ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16);
        if (temp == NULL) {
-               snd_printk(KERN_ERR "Unable to scan for card signature in video RAM\n");
+               dev_err(chip->card->dev,
+                       "Unable to scan for card signature in video RAM\n");
                return -EBUSY;
        }
 
@@ -1361,12 +1367,14 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
                if (pointer == 0xffffffff ||
                    pointer < chip->buffer_size ||
                    pointer > chip->buffer_end) {
-                       snd_printk(KERN_ERR "invalid signature found: 0x%x\n", pointer);
+                       dev_err(chip->card->dev,
+                               "invalid signature found: 0x%x\n", pointer);
                        iounmap(temp);
                        return -ENODEV;
                } else {
                        pointer_found = pointer;
-                       printk(KERN_INFO "nm256: found card signature in video RAM: 0x%x\n",
+                       dev_info(chip->card->dev,
+                                "found card signature in video RAM: 0x%x\n",
                               pointer);
                }
        }
@@ -1411,8 +1419,7 @@ static int nm256_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "nm256: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -1520,14 +1527,15 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
        chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE,
                                             card->driver);
        if (chip->res_cport == NULL) {
-               snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n",
+               dev_err(card->dev, "memory region 0x%lx (size 0x%x) busy\n",
                           chip->cport_addr, NM_PORT2_SIZE);
                err = -EBUSY;
                goto __error;
        }
        chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE);
        if (chip->cport == NULL) {
-               snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr);
+               dev_err(card->dev, "unable to map control port %lx\n",
+                       chip->cport_addr);
                err = -ENOMEM;
                goto __error;
        }
@@ -1537,12 +1545,14 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
                pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE);
                if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
                        if (! force_ac97) {
-                               printk(KERN_ERR "nm256: no ac97 is found!\n");
-                               printk(KERN_ERR "  force the driver to load by "
-                                      "passing in the module parameter\n");
-                               printk(KERN_ERR "    force_ac97=1\n");
-                               printk(KERN_ERR "  or try sb16, opl3sa2, or "
-                                      "cs423x drivers instead.\n");
+                               dev_err(card->dev,
+                                       "no ac97 is found!\n");
+                               dev_err(card->dev,
+                                       "force the driver to load by passing in the module parameter\n");
+                               dev_err(card->dev,
+                                       " force_ac97=1\n");
+                               dev_err(card->dev,
+                                       "or try sb16, opl3sa2, or cs423x drivers instead.\n");
                                err = -ENXIO;
                                goto __error;
                        }
@@ -1581,14 +1591,14 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
        chip->buffer_start = chip->buffer_end - chip->buffer_size;
        chip->buffer_addr += chip->buffer_start;
 
-       printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n",
+       dev_info(card->dev, "Mapping port 1 from 0x%x - 0x%x\n",
               chip->buffer_start, chip->buffer_end);
 
        chip->res_buffer = request_mem_region(chip->buffer_addr,
                                              chip->buffer_size,
                                              card->driver);
        if (chip->res_buffer == NULL) {
-               snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n",
+               dev_err(card->dev, "buffer 0x%lx (size 0x%x) busy\n",
                           chip->buffer_addr, chip->buffer_size);
                err = -EBUSY;
                goto __error;
@@ -1596,7 +1606,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
        chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size);
        if (chip->buffer == NULL) {
                err = -ENOMEM;
-               snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr);
+               dev_err(card->dev, "unable to map ring buffer at %lx\n",
+                       chip->buffer_addr);
                goto __error;
        }
 
@@ -1626,8 +1637,6 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
                goto __error;
 
-       snd_card_set_dev(card, &pci->dev);
-
        *chip_ret = chip;
        return 0;
 
@@ -1660,12 +1669,12 @@ static int snd_nm256_probe(struct pci_dev *pci,
 
        q = snd_pci_quirk_lookup(pci, nm256_quirks);
        if (q) {
-               snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n",
+               dev_dbg(&pci->dev, "Enabled quirk for %s.\n",
                            snd_pci_quirk_name(q));
                switch (q->value) {
                case NM_BLACKLISTED:
-                       printk(KERN_INFO "nm256: The device is blacklisted. "
-                              "Loading stopped\n");
+                       dev_info(&pci->dev,
+                                "The device is blacklisted. Loading stopped\n");
                        return -ENODEV;
                case NM_RESET_WORKAROUND_2:
                        reset_workaround_2 = 1;
@@ -1676,7 +1685,7 @@ static int snd_nm256_probe(struct pci_dev *pci,
                }
        }
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -1691,7 +1700,7 @@ static int snd_nm256_probe(struct pci_dev *pci,
                strcpy(card->driver, "NM256XL+");
                break;
        default:
-               snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device);
+               dev_err(&pci->dev, "invalid device id 0x%x\n", pci->device);
                snd_card_free(card);
                return -EINVAL;
        }
@@ -1714,12 +1723,12 @@ static int snd_nm256_probe(struct pci_dev *pci,
        card->private_data = chip;
 
        if (reset_workaround) {
-               snd_printdd(KERN_INFO "nm256: reset_workaround activated\n");
+               dev_dbg(&pci->dev, "reset_workaround activated\n");
                chip->reset_workaround = 1;
        }
 
        if (reset_workaround_2) {
-               snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n");
+               dev_dbg(&pci->dev, "reset_workaround_2 activated\n");
                chip->reset_workaround_2 = 1;
        }
 
index 3274907189febb4b6e3939274417abb58c21ca18..4b8a32c37e3105ef22bce70d881cdbda400ae89a 100644 (file)
@@ -147,7 +147,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
                        return;
                }
        }
-       snd_printk(KERN_ERR "AC'97 write timeout\n");
+       dev_err(chip->card->dev, "AC'97 write timeout\n");
 }
 EXPORT_SYMBOL(oxygen_write_ac97);
 
@@ -179,7 +179,7 @@ u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec,
                        reg ^= 0xffff;
                }
        }
-       snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec);
+       dev_err(chip->card->dev, "AC'97 read timeout on codec %u\n", codec);
        return 0;
 }
 EXPORT_SYMBOL(oxygen_read_ac97);
@@ -208,7 +208,7 @@ static int oxygen_wait_spi(struct oxygen *chip)
                                                OXYGEN_SPI_BUSY) == 0)
                        return 0;
        }
-       snd_printk(KERN_ERR "oxygen: SPI wait timeout\n");
+       dev_err(chip->card->dev, "oxygen: SPI wait timeout\n");
        return -EIO;
 }
 
@@ -288,5 +288,5 @@ void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value)
                      & OXYGEN_EEPROM_BUSY))
                        return;
        }
-       snd_printk(KERN_ERR "EEPROM write timeout\n");
+       dev_err(chip->card->dev, "EEPROM write timeout\n");
 }
index b0cb48adddc790c3f87e7a52cdb0431430e13ce2..b67e306024738e3932001e05306708282967e009 100644 (file)
@@ -313,7 +313,7 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
                oxygen_clear_bits8(chip, OXYGEN_MISC,
                                   OXYGEN_MISC_WRITE_PCI_SUBID);
 
-               snd_printk(KERN_INFO "EEPROM ID restored\n");
+               dev_info(chip->card->dev, "EEPROM ID restored\n");
        }
 }
 
@@ -595,7 +595,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        const struct pci_device_id *pci_id;
        int err;
 
-       err = snd_card_create(index, id, owner, sizeof(*chip), &card);
+       err = snd_card_new(&pci->dev, index, id, owner,
+                          sizeof(*chip), &card);
        if (err < 0)
                return err;
 
@@ -616,13 +617,13 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
 
        err = pci_request_regions(pci, DRIVER);
        if (err < 0) {
-               snd_printk(KERN_ERR "cannot reserve PCI resources\n");
+               dev_err(card->dev, "cannot reserve PCI resources\n");
                goto err_pci_enable;
        }
 
        if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) ||
            pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) {
-               snd_printk(KERN_ERR "invalid PCI I/O range\n");
+               dev_err(card->dev, "invalid PCI I/O range\n");
                err = -ENXIO;
                goto err_pci_regions;
        }
@@ -648,7 +649,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        }
 
        pci_set_master(pci);
-       snd_card_set_dev(card, &pci->dev);
        card->private_free = oxygen_card_free;
 
        configure_pcie_bridge(pci);
@@ -658,7 +658,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
                          KBUILD_MODNAME, chip);
        if (err < 0) {
-               snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
+               dev_err(card->dev, "cannot grab interrupt %d\n", pci->irq);
                goto err_card;
        }
        chip->irq = pci->irq;
@@ -796,7 +796,7 @@ static int oxygen_pci_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               snd_printk(KERN_ERR "cannot reenable device");
+               dev_err(dev, "cannot reenable device");
                snd_card_disconnect(card);
                return -EIO;
        }
index ed6f199f8a38ac3d1412fc8efa4010ba23ecee4d..4cf3200e988b03adf40129af71cfe1c9bb51bb69 100644 (file)
@@ -238,11 +238,21 @@ void set_cs4245_adc_params(struct oxygen *chip,
        cs4245_write_spi(chip, CS4245_MCLK_FREQ);
 }
 
+static inline unsigned int shift_bits(unsigned int value,
+                                     unsigned int shift_from,
+                                     unsigned int shift_to,
+                                     unsigned int mask)
+{
+       if (shift_from < shift_to)
+               return (value << (shift_to - shift_from)) & mask;
+       else
+               return (value >> (shift_from - shift_to)) & mask;
+}
+
 unsigned int adjust_dg_dac_routing(struct oxygen *chip,
                                          unsigned int play_routing)
 {
        struct dg *data = chip->model_data;
-       unsigned int routing = 0;
 
        switch (data->output_sel) {
        case PLAYBACK_DST_HP:
@@ -252,15 +262,23 @@ unsigned int adjust_dg_dac_routing(struct oxygen *chip,
                        OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
                break;
        case PLAYBACK_DST_MULTICH:
-               routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
-                         (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
-                         (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
-                         (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
                oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
                        OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
                break;
        }
-       return routing;
+       return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC1_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC2_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC3_SOURCE_MASK);
 }
 
 void dump_cs4245_registers(struct oxygen *chip,
index 136dac6a396432e687c1915c906e7625249ba846..91d92bc32b75225d75aeb56b1341b8c0a0a328e2 100644 (file)
@@ -120,7 +120,7 @@ void xonar_hdmi_uart_input(struct oxygen *chip)
        if (chip->uart_input_count >= 2 &&
            chip->uart_input[chip->uart_input_count - 2] == 'O' &&
            chip->uart_input[chip->uart_input_count - 1] == 'K') {
-               printk(KERN_DEBUG "message from HDMI chip received:\n");
+               dev_dbg(chip->card->dev, "message from HDMI chip received:\n");
                print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
                                     chip->uart_input, chip->uart_input_count);
                chip->uart_input_count = 0;
index 0ebe7f5916f995a992a227d5ee9fd0755c6c0a87..706b1a42163ff55e8eb4c69d314e6e75de307af9 100644 (file)
@@ -56,9 +56,9 @@ static void xonar_ext_power_gpio_changed(struct oxygen *chip)
        if (has_power != data->has_power) {
                data->has_power = has_power;
                if (has_power) {
-                       snd_printk(KERN_NOTICE "power restored\n");
+                       dev_notice(chip->card->dev, "power restored\n");
                } else {
-                       snd_printk(KERN_CRIT
+                       dev_crit(chip->card->dev,
                                   "Hey! Don't unplug the power cable!\n");
                        /* TODO: stop PCMs */
                }
index d379b284955b23dea2cded6e8efe7e0ba17ccda2..8d09444ff88bd524ef6717e107880e36fa840416 100644 (file)
@@ -284,7 +284,7 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
                        rmh.cmd_len = 3;
                        err = pcxhr_send_msg(mgr, &rmh);
                        if (err < 0) {
-                               snd_printk(KERN_ERR
+                               dev_err(&mgr->pci->dev,
                                           "error CMD_ACCESS_IO_WRITE "
                                           "for PLL register : %x!\n", err);
                                return err;
@@ -357,7 +357,7 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
                        return err;
        }
        /* set the new frequency */
-       snd_printdd("clock register : set %x\n", val);
+       dev_dbg(&mgr->pci->dev, "clock register : set %x\n", val);
        err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK,
                                          val, changed);
        if (err)
@@ -380,7 +380,7 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
                mgr->codec_speed = speed;       /* save new codec speed */
        }
 
-       snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
+       dev_dbg(&mgr->pci->dev, "pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
                    rate, realfreq);
        return 0;
 }
@@ -480,7 +480,7 @@ static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr,
        case REG_STATUS_SYNC_192000 :   rate = 192000; break;
        default: rate = 0;
        }
-       snd_printdd("External clock is at %d Hz\n", rate);
+       dev_dbg(&mgr->pci->dev, "External clock is at %d Hz\n", rate);
        *sample_rate = rate;
        return 0;
 }
@@ -537,8 +537,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
 
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
-               snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n",
-                          err);
+               dev_err(chip->card->dev,
+                       "ERROR pcxhr_set_stream_state err=%x;\n", err);
        stream->status =
          start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
        return err;
@@ -628,7 +628,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
        rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16;
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
-               snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err);
+               dev_err(chip->card->dev,
+                       "ERROR pcxhr_set_format err=%x;\n", err);
        return err;
 }
 
@@ -665,7 +666,7 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
        rmh.cmd_len = 4;
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
-               snd_printk(KERN_ERR
+               dev_err(chip->card->dev,
                           "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
        return err;
 }
@@ -735,11 +736,11 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        }
        if (capture_mask == 0 && playback_mask == 0) {
                mutex_unlock(&mgr->setup_mutex);
-               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n");
+               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n");
                return;
        }
 
-       snd_printdd("pcxhr_trigger_tasklet : "
+       dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
                    "playback_mask=%x capture_mask=%x\n",
                    playback_mask, capture_mask);
 
@@ -747,7 +748,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
                           "error stop pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
@@ -792,7 +793,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
                           "error start pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
@@ -825,7 +826,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        do_gettimeofday(&my_tv2);
-       snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
+       dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
                    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
 }
@@ -902,7 +903,7 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start)
        }
        err = pcxhr_send_msg(mgr, &rmh);
        if (err < 0)
-               snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n",
+               dev_err(&mgr->pci->dev, "error pcxhr_hardware_timer err(%x)\n",
                           err);
        return err;
 }
@@ -916,7 +917,8 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs)
        struct pcxhr_mgr *mgr = chip->mgr;
        int err = 0;
 
-       snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
+       dev_dbg(chip->card->dev,
+               "pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
                    subs->runtime->period_size, subs->runtime->periods,
                    subs->runtime->buffer_size);
 
@@ -1025,11 +1027,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
        runtime->hw = pcxhr_caps;
 
        if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) {
-               snd_printdd("pcxhr_open playback chip%d subs%d\n",
+               dev_dbg(chip->card->dev, "pcxhr_open playback chip%d subs%d\n",
                            chip->chip_idx, subs->number);
                stream = &chip->playback_stream[subs->number];
        } else {
-               snd_printdd("pcxhr_open capture chip%d subs%d\n",
+               dev_dbg(chip->card->dev, "pcxhr_open capture chip%d subs%d\n",
                            chip->chip_idx, subs->number);
                if (mgr->mono_capture)
                        runtime->hw.channels_max = 1;
@@ -1039,7 +1041,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
        }
        if (stream->status != PCXHR_STREAM_STATUS_FREE){
                /* streams in use */
-               snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n",
+               dev_err(chip->card->dev, "pcxhr_open chip%d subs%d in use\n",
                           chip->chip_idx, subs->number);
                mutex_unlock(&mgr->setup_mutex);
                return -EBUSY;
@@ -1105,7 +1107,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
 
        mutex_lock(&mgr->setup_mutex);
 
-       snd_printdd("pcxhr_close chip%d subs%d\n",
+       dev_dbg(chip->card->dev, "pcxhr_close chip%d subs%d\n",
                    chip->chip_idx, subs->number);
 
        /* sample rate released */
@@ -1168,7 +1170,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip)
        if ((err = snd_pcm_new(chip->card, name, 0,
                               chip->nb_streams_play,
                               chip->nb_streams_capt, &pcm)) < 0) {
-               snd_printk(KERN_ERR "cannot create pcm %s\n", name);
+               dev_err(chip->card->dev, "cannot create pcm %s\n", name);
                return err;
        }
        pcm->private_data = chip;
@@ -1214,7 +1216,7 @@ static int pcxhr_create(struct pcxhr_mgr *mgr,
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (! chip) {
-               snd_printk(KERN_ERR "cannot allocate chip\n");
+               dev_err(card->dev, "cannot allocate chip\n");
                return -ENOMEM;
        }
 
@@ -1239,7 +1241,6 @@ static int pcxhr_create(struct pcxhr_mgr *mgr,
        }
 
        mgr->chip[idx] = chip;
-       snd_card_set_dev(card, &mgr->pci->dev);
 
        return 0;
 }
@@ -1488,7 +1489,7 @@ static int pcxhr_free(struct pcxhr_mgr *mgr)
        /* reset board if some firmware was loaded */
        if(mgr->dsp_loaded) {
                pcxhr_reset_board(mgr);
-               snd_printdd("reset pcxhr !\n");
+               dev_dbg(&mgr->pci->dev, "reset pcxhr !\n");
        }
 
        /* release irq  */
@@ -1537,8 +1538,8 @@ static int pcxhr_probe(struct pci_dev *pci,
 
        /* check if we can restrict PCI DMA transfers to 32 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support "
-                          "32bit PCI busmaster DMA\n");
+               dev_err(&pci->dev,
+                       "architecture does not support 32bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -1589,7 +1590,7 @@ static int pcxhr_probe(struct pci_dev *pci,
 
        if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, mgr)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
                pcxhr_free(mgr);
                return -EBUSY;
        }
@@ -1638,10 +1639,11 @@ static int pcxhr_probe(struct pci_dev *pci,
 
                snprintf(tmpid, sizeof(tmpid), "%s-%d",
                         id[dev] ? id[dev] : card_name, i);
-               err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
+               err = snd_card_new(&pci->dev, idx, tmpid, THIS_MODULE,
+                                  0, &card);
 
                if (err < 0) {
-                       snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
+                       dev_err(card->dev, "cannot allocate the card %d\n", i);
                        pcxhr_free(mgr);
                        return err;
                }
index 37b431b9b69d64fabe211123aea0a44ea589544e..df9371918601e7cfc23874a0324bd3f287bbc6ec 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
+#include <linux/pci.h>
 #include <asm/io.h>
 #include <sound/core.h>
 #include "pcxhr.h"
@@ -132,14 +133,14 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
                *read = PCXHR_INPB(mgr, reg);
                if ((*read & mask) == bit) {
                        if (i > 100)
-                               snd_printdd("ATTENTION! check_reg(%x) "
-                                           "loopcount=%d\n",
+                               dev_dbg(&mgr->pci->dev,
+                                       "ATTENTION! check_reg(%x) loopcount=%d\n",
                                            reg, i);
                        return 0;
                }
                i++;
        } while (time_after_eq(end_time, jiffies));
-       snd_printk(KERN_ERR
+       dev_err(&mgr->pci->dev,
                   "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
                   reg, mask, *read);
        return -EIO;
@@ -216,7 +217,7 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
        err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR,  PCXHR_CVR_HI08_HC, 0,
                                  PCXHR_TIMEOUT_DSP, &reg);
        if (err) {
-               snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT CVR\n");
+               dev_err(&mgr->pci->dev, "pcxhr_send_it_dsp : TIMEOUT CVR\n");
                return err;
        }
        if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
@@ -227,7 +228,7 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
                                          PCXHR_TIMEOUT_DSP,
                                          &reg);
                if (err) {
-                       snd_printk(KERN_ERR
+                       dev_err(&mgr->pci->dev,
                                   "pcxhr_send_it_dsp : TIMEOUT HF5\n");
                        return err;
                }
@@ -294,7 +295,7 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
         */
        if(second) {
                if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
-                       snd_printk(KERN_ERR "error loading first xilinx\n");
+                       dev_err(&mgr->pci->dev, "error loading first xilinx\n");
                        return -EINVAL;
                }
                /* activate second xilinx */
@@ -360,7 +361,7 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
                                          PCXHR_ISR_HI08_TRDY,
                                          PCXHR_TIMEOUT_DSP, &dummy);
                if (err) {
-                       snd_printk(KERN_ERR
+                       dev_err(&mgr->pci->dev,
                                   "dsp loading error at position %d\n", i);
                        return err;
                }
@@ -396,7 +397,7 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
                msleep(PCXHR_WAIT_DEFAULT);
                PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
                msleep(PCXHR_WAIT_DEFAULT);
-               snd_printdd("no need to load eeprom boot\n");
+               dev_dbg(&mgr->pci->dev, "no need to load eeprom boot\n");
                return 0;
        }
        PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
@@ -561,9 +562,9 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                                          PCXHR_ISR_HI08_RXDF,
                                          PCXHR_TIMEOUT_DSP, &reg);
                if (err) {
-                       snd_printk(KERN_ERR "ERROR RMH stat: "
-                                  "ISR:RXDF=1 (ISR = %x; i=%d )\n",
-                                  reg, i);
+                       dev_err(&mgr->pci->dev,
+                               "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
+                               reg, i);
                        return err;
                }
                /* read data */
@@ -591,13 +592,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                }
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                if (rmh->cmd_idx < CMD_LAST_INDEX)
-                       snd_printdd("    stat[%d]=%x\n", i, data);
+                       dev_dbg(&mgr->pci->dev, "    stat[%d]=%x\n", i, data);
 #endif
                if (i < max_stat_len)
                        rmh->stat[i] = data;
        }
        if (rmh->stat_len > max_stat_len) {
-               snd_printdd("PCXHR : rmh->stat_len=%x too big\n",
+               dev_dbg(&mgr->pci->dev, "PCXHR : rmh->stat_len=%x too big\n",
                            rmh->stat_len);
                rmh->stat_len = max_stat_len;
        }
@@ -615,7 +616,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                return -EINVAL;
        err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
        if (err) {
-               snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n");
+               dev_err(&mgr->pci->dev,
+                       "pcxhr_send_message : ED_DSP_CRASHED\n");
                return err;
        }
        /* wait for chk bit */
@@ -641,7 +643,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                data &= 0xff7fff;       /* MASK_1_WORD_COMMAND */
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        if (rmh->cmd_idx < CMD_LAST_INDEX)
-               snd_printdd("MSG cmd[0]=%x (%s)\n",
+               dev_dbg(&mgr->pci->dev, "MSG cmd[0]=%x (%s)\n",
                            data, cmd_names[rmh->cmd_idx]);
 #endif
 
@@ -671,7 +673,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                        data = rmh->cmd[i];
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                        if (rmh->cmd_idx < CMD_LAST_INDEX)
-                               snd_printdd("    cmd[%d]=%x\n", i, data);
+                               dev_dbg(&mgr->pci->dev,
+                                       "    cmd[%d]=%x\n", i, data);
 #endif
                        err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
                                                  PCXHR_ISR_HI08_TRDY,
@@ -697,14 +700,15 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                                          PCXHR_ISR_HI08_RXDF,
                                          PCXHR_TIMEOUT_DSP, &reg);
                if (err) {
-                       snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
+                       dev_err(&mgr->pci->dev,
+                               "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
                        return err;
                }
                /* read error code */
                data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
                data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
                data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
-               snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n",
+               dev_err(&mgr->pci->dev, "ERROR RMH(%d): 0x%x\n",
                           rmh->cmd_idx, data);
                err = -EINVAL;
        } else {
@@ -780,7 +784,7 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
         * (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
         */
        start_mask &= 0xffffff;
-       snd_printdd("CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
+       dev_dbg(&mgr->pci->dev, "CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
        return start_mask;
 }
 
@@ -809,7 +813,7 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
                        }
                        err = pcxhr_send_msg(mgr, &rmh);
                        if (err) {
-                               snd_printk(KERN_ERR
+                               dev_err(&mgr->pci->dev,
                                           "error pipe start "
                                           "(CMD_CAN_START_PIPE) err=%x!\n",
                                           err);
@@ -847,7 +851,7 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
                        }
                        err = pcxhr_send_msg(mgr, &rmh);
                        if (err) {
-                               snd_printk(KERN_ERR
+                               dev_err(&mgr->pci->dev,
                                           "error pipe stop "
                                           "(CMD_STOP_PIPE) err=%x!\n", err);
                                return err;
@@ -876,7 +880,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
                                                          1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
                        err = pcxhr_send_msg(mgr, &rmh);
                        if (err) {
-                               snd_printk(KERN_ERR
+                               dev_err(&mgr->pci->dev,
                                           "error pipe start "
                                           "(CMD_CONF_PIPE) err=%x!\n", err);
                                return err;
@@ -889,7 +893,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
        pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
        err = pcxhr_send_msg(mgr, &rmh);
        if (err) {
-               snd_printk(KERN_ERR
+               dev_err(&mgr->pci->dev,
                           "error pipe start (CMD_SEND_IRQA) err=%x!\n",
                           err);
                return err;
@@ -913,7 +917,8 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
                      (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
        /* current pipe state (playback + record) */
        state = pcxhr_pipes_running(mgr);
-       snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n",
+       dev_dbg(&mgr->pci->dev,
+               "pcxhr_set_pipe_state %s (mask %x current %x)\n",
                    start ? "START" : "STOP", audio_mask, state);
        if (start) {
                /* start only pipes that are not yet started */
@@ -944,7 +949,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
                if ((state & audio_mask) == (start ? audio_mask : 0))
                        break;
                if (++i >= MAX_WAIT_FOR_DSP * 100) {
-                       snd_printk(KERN_ERR "error pipe start/stop\n");
+                       dev_err(&mgr->pci->dev, "error pipe start/stop\n");
                        return -EBUSY;
                }
                udelay(10);                     /* wait 10 microseconds */
@@ -956,7 +961,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
        }
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        do_gettimeofday(&my_tv2);
-       snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n",
+       dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n",
                    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
        return 0;
@@ -971,7 +976,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
 
        spin_lock_irqsave(&mgr->msg_lock, flags);
        if ((mgr->io_num_reg_cont & mask) == value) {
-               snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n",
+               dev_dbg(&mgr->pci->dev,
+                       "IO_NUM_REG_CONT mask %x already is set to %x\n",
                            mask, value);
                if (changed)
                        *changed = 0;
@@ -1024,7 +1030,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
                err = ((err >> 12) & 0xfff);
        if (!err)
                return 0;
-       snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
+       dev_dbg(&mgr->pci->dev, "CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
                    err_src_name[err_src],
                    is_capture ? "Record" : "Play", pipe, err);
        if (err == 0xe01)
@@ -1045,20 +1051,24 @@ void pcxhr_msg_tasklet(unsigned long arg)
        int i, j;
 
        if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
-               snd_printdd("TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
+               dev_dbg(&mgr->pci->dev,
+                       "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
        if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
-               snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
+               dev_dbg(&mgr->pci->dev,
+                       "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
        if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
-               snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
+               dev_dbg(&mgr->pci->dev,
+                       "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
        if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
                /* clear events FREQ_CHANGE and TIME_CODE */
                pcxhr_init_rmh(prmh, CMD_TEST_IT);
                err = pcxhr_send_msg(mgr, prmh);
-               snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n",
+               dev_dbg(&mgr->pci->dev, "CMD_TEST_IT : err=%x, stat=%x\n",
                            err, prmh->stat[0]);
        }
        if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
-               snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
+               dev_dbg(&mgr->pci->dev,
+                       "TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
 
                pcxhr_init_rmh(prmh, CMD_ASYNC);
                prmh->cmd[0] |= 1;      /* add SEL_ASYNC_EVENTS */
@@ -1066,7 +1076,7 @@ void pcxhr_msg_tasklet(unsigned long arg)
                prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
                err = pcxhr_send_msg(mgr, prmh);
                if (err)
-                       snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n",
+                       dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n",
                                   err);
                i = 1;
                while (i < prmh->stat_len) {
@@ -1079,7 +1089,8 @@ void pcxhr_msg_tasklet(unsigned long arg)
                        u32 err2;
 
                        if (prmh->stat[i] & 0x800000) { /* if BIT_END */
-                               snd_printdd("TASKLET : End%sPipe %d\n",
+                               dev_dbg(&mgr->pci->dev,
+                                       "TASKLET : End%sPipe %d\n",
                                            is_capture ? "Record" : "Play",
                                            pipe);
                        }
@@ -1136,7 +1147,8 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
        hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24;
        hw_sample_count += (u_int64_t)rmh.stat[1];
 
-       snd_printdd("stream %c%d : abs samples real(%llu) timer(%llu)\n",
+       dev_dbg(&mgr->pci->dev,
+               "stream %c%d : abs samples real(%llu) timer(%llu)\n",
                    stream->pipe->is_capture ? 'C' : 'P',
                    stream->substream->number,
                    hw_sample_count,
@@ -1202,7 +1214,7 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
                                (u_int32_t)(new_sample_count -
                                            stream->timer_abs_periods);
                } else {
-                       snd_printk(KERN_ERR
+                       dev_err(&mgr->pci->dev,
                                   "ERROR new_sample_count too small ??? %ld\n",
                                   (long unsigned int)new_sample_count);
                }
@@ -1247,33 +1259,39 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
                    (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
                        /* handle dsp counter wraparound without resync */
                        int tmp_diff = dsp_time_diff + PCXHR_DSP_TIME_MASK + 1;
-                       snd_printdd("WARNING DSP timestamp old(%d) new(%d)",
+                       dev_dbg(&mgr->pci->dev,
+                               "WARNING DSP timestamp old(%d) new(%d)",
                                    mgr->dsp_time_last, dsp_time_new);
                        if (tmp_diff > 0 && tmp_diff <= (2*mgr->granularity)) {
-                               snd_printdd("-> timestamp wraparound OK: "
+                               dev_dbg(&mgr->pci->dev,
+                                       "-> timestamp wraparound OK: "
                                            "diff=%d\n", tmp_diff);
                                dsp_time_diff = tmp_diff;
                        } else {
-                               snd_printdd("-> resynchronize all streams\n");
+                               dev_dbg(&mgr->pci->dev,
+                                       "-> resynchronize all streams\n");
                                mgr->dsp_time_err++;
                        }
                }
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                if (dsp_time_diff == 0)
-                       snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n",
+                       dev_dbg(&mgr->pci->dev,
+                               "ERROR DSP TIME NO DIFF time(%d)\n",
                                    dsp_time_new);
                else if (dsp_time_diff >= (2*mgr->granularity))
-                       snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
+                       dev_dbg(&mgr->pci->dev,
+                               "ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
                                    mgr->dsp_time_last,
                                    dsp_time_new - mgr->dsp_time_last);
                else if (dsp_time_diff % mgr->granularity)
-                       snd_printdd("ERROR DSP TIME increased by %d\n",
+                       dev_dbg(&mgr->pci->dev,
+                               "ERROR DSP TIME increased by %d\n",
                                    dsp_time_diff);
 #endif
                mgr->dsp_time_last = dsp_time_new;
 
                if (timer_toggle == mgr->timer_toggle) {
-                       snd_printdd("ERROR TIMER TOGGLE\n");
+                       dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
                        mgr->dsp_time_err++;
                }
                mgr->timer_toggle = timer_toggle;
@@ -1308,7 +1326,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
        }
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        if (reg & PCXHR_FATAL_DSP_ERR)
-               snd_printdd("FATAL DSP ERROR : %x\n", reg);
+               dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
 #endif
        spin_unlock(&mgr->lock);
        return IRQ_HANDLED;     /* this device caused the interrupt */
index d995175c1c48c44960071683fd03aff64d260b42..15a8ce5f1f48d84e2a71f1e4557f6fa07bc31279 100644 (file)
@@ -72,7 +72,8 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
        /* test max nb substream per pipe */
        if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
                return -EINVAL;
-       snd_printdd("supported formats : playback=%x capture=%x\n",
+       dev_dbg(&mgr->pci->dev,
+               "supported formats : playback=%x capture=%x\n",
                    rmh.stat[2], rmh.stat[3]);
 
        pcxhr_init_rmh(&rmh, CMD_VERSION);
@@ -84,7 +85,8 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
        err = pcxhr_send_msg(mgr, &rmh);
        if (err)
                return err;
-       snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
+       dev_dbg(&mgr->pci->dev,
+               "PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
                    (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
        mgr->dsp_version = rmh.stat[0];
 
@@ -179,7 +181,7 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
                stream_count = PCXHR_PLAYBACK_STREAMS;
                audio_count = 2;        /* always stereo */
        }
-       snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n",
+       dev_dbg(&mgr->pci->dev, "snd_add_ref_pipe pin(%d) pcm%c0\n",
                    pin, is_capture ? 'c' : 'p');
        pipe->is_capture = is_capture;
        pipe->first_audio = pin;
@@ -194,7 +196,7 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
        }
        err = pcxhr_send_msg(mgr, &rmh);
        if (err < 0) {
-               snd_printk(KERN_ERR "error pipe allocation "
+               dev_err(&mgr->pci->dev, "error pipe allocation "
                           "(CMD_RES_PIPE) err=%x!\n", err);
                return err;
        }
@@ -222,14 +224,14 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
        /* stop one pipe */
        err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
        if (err < 0)
-               snd_printk(KERN_ERR "error stopping pipe!\n");
+               dev_err(&mgr->pci->dev, "error stopping pipe!\n");
        /* release the pipe */
        pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
        pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
                                  0, 0);
        err = pcxhr_send_msg(mgr, &rmh);
        if (err < 0)
-               snd_printk(KERN_ERR "error pipe release "
+               dev_err(&mgr->pci->dev, "error pipe release "
                           "(CMD_FREE_PIPE) err(%x)\n", err);
        pipe->status = PCXHR_PIPE_UNDEFINED;
        return err;
@@ -289,7 +291,8 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
 {
        int err, card_index;
 
-       snd_printdd("loading dsp [%d] size = %Zd\n", index, dsp->size);
+       dev_dbg(&mgr->pci->dev,
+               "loading dsp [%d] size = %Zd\n", index, dsp->size);
 
        switch (index) {
        case PCXHR_FIRMWARE_XLX_INT_INDEX:
@@ -313,19 +316,19 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
                        return err;
                break;  /* continue with first init */
        default:
-               snd_printk(KERN_ERR "wrong file index\n");
+               dev_err(&mgr->pci->dev, "wrong file index\n");
                return -EFAULT;
        } /* end of switch file index*/
 
        /* first communication with embedded */
        err = pcxhr_init_board(mgr);
         if (err < 0) {
-               snd_printk(KERN_ERR "pcxhr could not be set up\n");
+               dev_err(&mgr->pci->dev, "pcxhr could not be set up\n");
                return err;
        }
        err = pcxhr_config_pipes(mgr);
         if (err < 0) {
-               snd_printk(KERN_ERR "pcxhr pipes could not be set up\n");
+               dev_err(&mgr->pci->dev, "pcxhr pipes could not be set up\n");
                return err;
        }
                /* create devices and mixer in accordance with HW options*/
@@ -344,10 +347,11 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
        }
        err = pcxhr_start_pipes(mgr);
         if (err < 0) {
-               snd_printk(KERN_ERR "pcxhr pipes could not be started\n");
+               dev_err(&mgr->pci->dev, "pcxhr pipes could not be started\n");
                return err;
        }
-       snd_printdd("pcxhr firmware downloaded and successfully set up\n");
+       dev_dbg(&mgr->pci->dev,
+               "pcxhr firmware downloaded and successfully set up\n");
 
        return 0;
 }
@@ -382,7 +386,8 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
                        continue;
                sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
                if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
-                       snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n",
+                       dev_err(&mgr->pci->dev,
+                               "pcxhr: can't load firmware %s\n",
                                   path);
                        return -ENOENT;
                }
index 84fe57626ebaa256a8581ea0fe345c453fddd421..6a56e5306a6594f5977fcd43d9dc05f3e2cad062 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
@@ -290,7 +291,8 @@ int hr222_sub_init(struct pcxhr_mgr *mgr)
        reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
        if (reg & PCXHR_STAT_MIC_CAPS)
                mgr->board_has_mic = 1; /* microphone available */
-       snd_printdd("MIC input available = %d\n", mgr->board_has_mic);
+       dev_dbg(&mgr->pci->dev,
+               "MIC input available = %d\n", mgr->board_has_mic);
 
        /* reset codec */
        PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
@@ -405,7 +407,7 @@ int hr222_sub_set_clock(struct pcxhr_mgr *mgr,
 
        hr222_config_akm(mgr, AKM_UNMUTE_CMD);
 
-       snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n",
+       dev_dbg(&mgr->pci->dev, "set_clock to %dHz (realfreq=%d pllreg=%x)\n",
                    rate, realfreq, pllreg);
        return 0;
 }
@@ -431,13 +433,15 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
                reg = PCXHR_STAT_FREQ_UER1_MASK;
 
        } else {
-               snd_printdd("get_external_clock : type %d not supported\n",
+               dev_dbg(&mgr->pci->dev,
+                       "get_external_clock : type %d not supported\n",
                            clock_type);
                return -EINVAL; /* other clocks not supported */
        }
 
        if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) {
-               snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type);
+               dev_dbg(&mgr->pci->dev,
+                       "get_external_clock(%d) = 0 Hz\n", clock_type);
                *sample_rate = 0;
                return 0; /* no external clock locked */
        }
@@ -495,7 +499,7 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
        else
                rate = 0;
 
-       snd_printdd("External clock is at %d Hz (measured %d Hz)\n",
+       dev_dbg(&mgr->pci->dev, "External clock is at %d Hz (measured %d Hz)\n",
                    rate, calc_rate);
        *sample_rate = rate;
        return 0;
@@ -542,7 +546,8 @@ int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable)
 int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
                                    int is_capture, int channel)
 {
-       snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n",
+       dev_dbg(chip->card->dev,
+               "hr222_update_analog_audio_level(%s chan=%d)\n",
                    is_capture ? "capture" : "playback", channel);
        if (is_capture) {
                int level_l, level_r, level_mic;
@@ -642,7 +647,7 @@ int hr222_iec958_capture_byte(struct snd_pcxhr *chip,
                if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask)
                        temp |= 1;
        }
-       snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+       dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n",
                    chip->chip_idx, aes_idx, temp);
        *aes_bits = temp;
        return 0;
@@ -684,7 +689,7 @@ static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level)
 
        PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
 
-       snd_printdd("hr222_micro_boost : set %x\n", boost_mask);
+       dev_dbg(&mgr->pci->dev, "hr222_micro_boost : set %x\n", boost_mask);
 }
 
 static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
@@ -696,7 +701,7 @@ static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
 
        PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
 
-       snd_printdd("hr222_phantom_power : set %d\n", power);
+       dev_dbg(&mgr->pci->dev, "hr222_phantom_power : set %d\n", power);
 }
 
 
index fec049344621ef97f922c395e8ff5693e3c48945..95c9571780d8ca5da2df9b28408fb78c8325db38 100644 (file)
@@ -72,7 +72,8 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip,
        rmh.cmd_len = 3;
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err < 0) {
-               snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)"
+               dev_dbg(chip->card->dev,
+                       "error update_analog_audio_level card(%d)"
                           " is_capture(%d) err(%x)\n",
                           chip->chip_idx, is_capture, err);
                return -EINVAL;
@@ -284,7 +285,7 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx)
 
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err < 0) {
-               snd_printk(KERN_DEBUG "error update_playback_stream_level "
+               dev_dbg(chip->card->dev, "error update_playback_stream_level "
                           "card(%d) err(%x)\n", chip->chip_idx, err);
                return -EINVAL;
        }
@@ -335,7 +336,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip,
 
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err < 0) {
-               snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n",
+               dev_dbg(chip->card->dev,
+                       "error update_audio_level(%d) err=%x\n",
                           chip->chip_idx, err);
                return -EINVAL;
        }
@@ -930,7 +932,7 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip,
                                temp |= 1;
                }
        }
-       snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+       dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n",
                    chip->chip_idx, aes_idx, temp);
        *aes_bits = temp;
        return 0;
@@ -992,7 +994,8 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip,
                        rmh.cmd[0] |= IO_NUM_REG_CUER;
                        rmh.cmd[1] = cmd;
                        rmh.cmd_len = 2;
-                       snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n",
+                       dev_dbg(chip->card->dev,
+                               "write iec958 AES %d byte %d bit %d (cmd %x)\n",
                                    chip->chip_idx, aes_idx, i, cmd);
                        err = pcxhr_send_msg(chip->mgr, &rmh);
                        if (err)
index 56cc891e395e54a17edf0a80b377370b317c628c..b4a8278241b12ffc4d33c82841cccb96a5cafdcf 100644 (file)
@@ -1916,8 +1916,6 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        return 0;
 }
@@ -2086,7 +2084,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        err = snd_riptide_create(card, pci, &chip);
index cc26346ae66bf82d6fc4680b56ed4f136ff832ab..cc2f0c1b6484430e04672c2bc7962f6d8b91535d 100644 (file)
@@ -1349,14 +1349,15 @@ static int snd_rme32_create(struct rme32 *rme32)
 
        rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE);
        if (!rme32->iobase) {
-               snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n",
+               dev_err(rme32->card->dev,
+                       "unable to remap memory region 0x%lx-0x%lx\n",
                           rme32->port, rme32->port + RME32_IO_SIZE - 1);
                return -ENOMEM;
        }
 
        if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, rme32)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(rme32->card->dev, "unable to grab IRQ %d\n", pci->irq);
                return -EBUSY;
        }
        rme32->irq = pci->irq;
@@ -1938,15 +1939,14 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct rme32), &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct rme32), &card);
        if (err < 0)
                return err;
        card->private_free = snd_rme32_card_free;
        rme32 = (struct rme32 *) card->private_data;
        rme32->card = card;
        rme32->pci = pci;
-       snd_card_set_dev(card, &pci->dev);
         if (fullduplex[dev])
                rme32->fullduplex_mode = 1;
        if ((err = snd_rme32_create(rme32)) < 0) {
index 0236363c301f8e12b7f15a218af5fbcdfb06b25c..76169929770dd10b25cc9ef91ecd6f85d2e90d9e 100644 (file)
@@ -240,7 +240,7 @@ struct rme96 {
 
        u8 rev; /* card revision number */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 playback_pointer;
        u32 capture_pointer;
        void *playback_suspend_buffer;
@@ -1570,7 +1570,7 @@ snd_rme96_free(void *private_data)
                pci_release_regions(rme96->pci);
                rme96->port = 0;
        }
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        vfree(rme96->playback_suspend_buffer);
        vfree(rme96->capture_suspend_buffer);
 #endif
@@ -1609,13 +1609,15 @@ snd_rme96_create(struct rme96 *rme96)
 
        rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE);
        if (!rme96->iobase) {
-               snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
+               dev_err(rme96->card->dev,
+                       "unable to remap memory region 0x%lx-0x%lx\n",
+                       rme96->port, rme96->port + RME96_IO_SIZE - 1);
                return -ENOMEM;
        }
 
        if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, rme96)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(rme96->card->dev, "unable to grab IRQ %d\n", pci->irq);
                return -EBUSY;
        }
        rme96->irq = pci->irq;
@@ -2372,13 +2374,12 @@ snd_rme96_create_switches(struct snd_card *card,
  * Card initialisation
  */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
-static int
-snd_rme96_suspend(struct pci_dev *pci,
-                 pm_message_t state)
+static int rme96_suspend(struct device *dev)
 {
-       struct snd_card *card = pci_get_drvdata(pci);
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct snd_card *card = dev_get_drvdata(dev);
        struct rme96 *rme96 = card->private_data;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
@@ -2407,15 +2408,15 @@ snd_rme96_suspend(struct pci_dev *pci,
        return 0;
 }
 
-static int
-snd_rme96_resume(struct pci_dev *pci)
+static int rme96_resume(struct device *dev)
 {
-       struct snd_card *card = pci_get_drvdata(pci);
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct snd_card *card = dev_get_drvdata(dev);
        struct rme96 *rme96 = card->private_data;
 
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2451,7 +2452,11 @@ snd_rme96_resume(struct pci_dev *pci)
        return 0;
 }
 
-#endif
+static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
+#define RME96_PM_OPS   &rme96_pm
+#else
+#define RME96_PM_OPS   NULL
+#endif /* CONFIG_PM_SLEEP */
 
 static void snd_rme96_card_free(struct snd_card *card)
 {
@@ -2475,31 +2480,30 @@ snd_rme96_probe(struct pci_dev *pci,
                dev++;
                return -ENOENT;
        }
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct rme96), &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct rme96), &card);
        if (err < 0)
                return err;
        card->private_free = snd_rme96_card_free;
        rme96 = card->private_data;
        rme96->card = card;
        rme96->pci = pci;
-       snd_card_set_dev(card, &pci->dev);
        if ((err = snd_rme96_create(rme96)) < 0) {
                snd_card_free(card);
                return err;
        }
        
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
        if (!rme96->playback_suspend_buffer) {
-               snd_printk(KERN_ERR
+               dev_err(card->dev,
                           "Failed to allocate playback suspend buffer!\n");
                snd_card_free(card);
                return -ENOMEM;
        }
        rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
        if (!rme96->capture_suspend_buffer) {
-               snd_printk(KERN_ERR
+               dev_err(card->dev,
                           "Failed to allocate capture suspend buffer!\n");
                snd_card_free(card);
                return -ENOMEM;
@@ -2548,10 +2552,9 @@ static struct pci_driver rme96_driver = {
        .id_table = snd_rme96_ids,
        .probe = snd_rme96_probe,
        .remove = snd_rme96_remove,
-#ifdef CONFIG_PM
-       .suspend = snd_rme96_suspend,
-       .resume = snd_rme96_resume,
-#endif
+       .driver = {
+               .pm = RME96_PM_OPS,
+       },
 };
 
 module_pci_driver(rme96_driver);
index bd90c80bb494e7049d830f13a3e6db46395d09cc..4c6f5d1c9882c1e054f0b785995083430cd6be0f 100644 (file)
@@ -675,14 +675,15 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp)
                if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
                                        HDSP_ConfigError)) {
                        if (i) {
-                               snd_printd("Hammerfall-DSP: IO box found after %d ms\n",
+                               dev_dbg(hdsp->card->dev,
+                                       "IO box found after %d ms\n",
                                                (20 * i));
                        }
                        return 0;
                }
                msleep(20);
        }
-       snd_printk(KERN_ERR "Hammerfall-DSP: no IO box connected!\n");
+       dev_err(hdsp->card->dev, "no IO box connected!\n");
        hdsp->state &= ~HDSP_FirmwareLoaded;
        return -EIO;
 }
@@ -699,13 +700,13 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
                if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError)
                        msleep(delay);
                else {
-                       snd_printd("Hammerfall-DSP: iobox found after %ums!\n",
+                       dev_dbg(hdsp->card->dev, "iobox found after %ums!\n",
                                   i * delay);
                        return 0;
                }
        }
 
-       snd_printk("Hammerfall-DSP: no IO box connected!\n");
+       dev_info(hdsp->card->dev, "no IO box connected!\n");
        hdsp->state &= ~HDSP_FirmwareLoaded;
        return -EIO;
 }
@@ -728,13 +729,14 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
 
        if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
 
-               snd_printk ("Hammerfall-DSP: loading firmware\n");
+               dev_info(hdsp->card->dev, "loading firmware\n");
 
                hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
                hdsp_write (hdsp, HDSP_fifoData, 0);
 
                if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
-                       snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
+                       dev_info(hdsp->card->dev,
+                                "timeout waiting for download preparation\n");
                        hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
                        return -EIO;
                }
@@ -744,7 +746,8 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
                for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) {
                        hdsp_write(hdsp, HDSP_fifoData, cache[i]);
                        if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
-                               snd_printk ("Hammerfall-DSP: timeout during firmware loading\n");
+                               dev_info(hdsp->card->dev,
+                                        "timeout during firmware loading\n");
                                hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
                                return -EIO;
                        }
@@ -760,11 +763,12 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
                hdsp->control2_register = 0;
 #endif
                hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
-               snd_printk ("Hammerfall-DSP: finished firmware loading\n");
+               dev_info(hdsp->card->dev, "finished firmware loading\n");
 
        }
        if (hdsp->state & HDSP_InitializationComplete) {
-               snd_printk(KERN_INFO "Hammerfall-DSP: firmware loaded from cache, restoring defaults\n");
+               dev_info(hdsp->card->dev,
+                        "firmware loaded from cache, restoring defaults\n");
                spin_lock_irqsave(&hdsp->lock, flags);
                snd_hdsp_set_defaults(hdsp);
                spin_unlock_irqrestore(&hdsp->lock, flags);
@@ -791,7 +795,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
                hdsp_write (hdsp, HDSP_fifoData, 0);
                if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
                        hdsp->io_type = Multiface;
-                       snd_printk("Hammerfall-DSP: Multiface found\n");
+                       dev_info(hdsp->card->dev, "Multiface found\n");
                        return 0;
                }
 
@@ -799,7 +803,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
                hdsp_write(hdsp, HDSP_fifoData, 0);
                if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
                        hdsp->io_type = Digiface;
-                       snd_printk("Hammerfall-DSP: Digiface found\n");
+                       dev_info(hdsp->card->dev, "Digiface found\n");
                        return 0;
                }
 
@@ -808,7 +812,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
                hdsp_write(hdsp, HDSP_fifoData, 0);
                if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
                        hdsp->io_type = Multiface;
-                       snd_printk("Hammerfall-DSP: Multiface found\n");
+                       dev_info(hdsp->card->dev, "Multiface found\n");
                        return 0;
                }
 
@@ -817,12 +821,12 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
                hdsp_write(hdsp, HDSP_fifoData, 0);
                if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
                        hdsp->io_type = Multiface;
-                       snd_printk("Hammerfall-DSP: Multiface found\n");
+                       dev_info(hdsp->card->dev, "Multiface found\n");
                        return 0;
                }
 
                hdsp->io_type = RPM;
-               snd_printk("Hammerfall-DSP: RPM found\n");
+               dev_info(hdsp->card->dev, "RPM found\n");
                return 0;
        } else {
                /* firmware was already loaded, get iobox type */
@@ -847,20 +851,18 @@ static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
                hdsp->state &= ~HDSP_FirmwareLoaded;
                if (! load_on_demand)
                        return -EIO;
-               snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
+               dev_err(hdsp->card->dev, "firmware not present.\n");
                /* try to load firmware */
                if (! (hdsp->state & HDSP_FirmwareCached)) {
                        if (! hdsp_request_fw_loader(hdsp))
                                return 0;
-                       snd_printk(KERN_ERR
-                                  "Hammerfall-DSP: No firmware loaded nor "
-                                  "cached, please upload firmware.\n");
+                       dev_err(hdsp->card->dev,
+                                  "No firmware loaded nor cached, please upload firmware.\n");
                        return -EIO;
                }
                if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
-                       snd_printk(KERN_ERR
-                                  "Hammerfall-DSP: Firmware loading from "
-                                  "cache failed, please upload manually.\n");
+                       dev_err(hdsp->card->dev,
+                                  "Firmware loading from cache failed, please upload manually.\n");
                        return -EIO;
                }
        }
@@ -888,7 +890,8 @@ static int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout)
                udelay (100);
        }
 
-       snd_printk ("Hammerfall-DSP: wait for FIFO status <= %d failed after %d iterations\n",
+       dev_warn(hdsp->card->dev,
+                "wait for FIFO status <= %d failed after %d iterations\n",
                    count, timeout);
        return -1;
 }
@@ -1005,7 +1008,9 @@ static int hdsp_spdif_sample_rate(struct hdsp *hdsp)
        default:
                break;
        }
-       snd_printk ("Hammerfall-DSP: unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status);
+       dev_warn(hdsp->card->dev,
+                "unknown spdif frequency status; bits = 0x%x, status = 0x%x\n",
+                rate_bits, status);
        return 0;
 }
 
@@ -1139,7 +1144,8 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
        if (!(hdsp->control_register & HDSP_ClockModeMaster)) {
                if (called_internally) {
                        /* request from ctl or card initialization */
-                       snd_printk(KERN_ERR "Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n");
+                       dev_err(hdsp->card->dev,
+                               "device is not running as a clock master: cannot set sample rate.\n");
                        return -1;
                } else {
                        /* hw_param request while in AutoSync mode */
@@ -1147,11 +1153,14 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
                        int spdif_freq = hdsp_spdif_sample_rate(hdsp);
 
                        if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
-                               snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in double speed mode\n");
+                               dev_info(hdsp->card->dev,
+                                        "Detected ADAT in double speed mode\n");
                        else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
-                               snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n");
+                               dev_info(hdsp->card->dev,
+                                        "Detected ADAT in quad speed mode\n");
                        else if (rate != external_freq) {
-                               snd_printk(KERN_INFO "Hammerfall-DSP: No AutoSync source for requested rate\n");
+                               dev_info(hdsp->card->dev,
+                                        "No AutoSync source for requested rate\n");
                                return -1;
                        }
                }
@@ -1223,7 +1232,8 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
        }
 
        if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) {
-               snd_printk ("Hammerfall-DSP: cannot change speed mode (capture PID = %d, playback PID = %d)\n",
+               dev_warn(hdsp->card->dev,
+                        "cannot change speed mode (capture PID = %d, playback PID = %d)\n",
                            hdsp->capture_pid,
                            hdsp->playback_pid);
                return -EBUSY;
@@ -3785,7 +3795,8 @@ static int snd_hdsp_initialize_memory(struct hdsp *hdsp)
            snd_hammerfall_get_buffer(hdsp->pci, &hdsp->playback_dma_buf, HDSP_DMA_AREA_BYTES) < 0) {
                if (hdsp->capture_dma_buf.area)
                        snd_dma_free_pages(&hdsp->capture_dma_buf);
-               printk(KERN_ERR "%s: no buffers available\n", hdsp->card_name);
+               dev_err(hdsp->card->dev,
+                       "%s: no buffers available\n", hdsp->card_name);
                return -ENOMEM;
        }
 
@@ -4747,7 +4758,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                        return err;
 
                if (!(hdsp->state & HDSP_FirmwareLoaded)) {
-                       snd_printk(KERN_ERR "Hammerfall-DSP: firmware needs to be uploaded to the card.\n");
+                       dev_err(hdsp->card->dev,
+                               "firmware needs to be uploaded to the card.\n");
                        return -EINVAL;
                }
 
@@ -4858,7 +4870,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
                        return -EBUSY;
 
-               snd_printk(KERN_INFO "Hammerfall-DSP: initializing firmware upload\n");
+               dev_info(hdsp->card->dev,
+                        "initializing firmware upload\n");
                firmware = (struct hdsp_firmware __user *)argp;
 
                if (get_user(firmware_data, &firmware->firmware_data))
@@ -4893,7 +4906,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                        snd_hdsp_initialize_midi_flush(hdsp);
 
                        if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
-                               snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
+                               dev_err(hdsp->card->dev,
+                                       "error creating alsa devices\n");
                                return err;
                        }
                }
@@ -4983,7 +4997,8 @@ static int snd_hdsp_enable_io (struct hdsp *hdsp)
        int i;
 
        if (hdsp_fifo_wait (hdsp, 0, 100)) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: enable_io fifo_wait failed\n");
+               dev_err(hdsp->card->dev,
+                       "enable_io fifo_wait failed\n");
                return -EIO;
        }
 
@@ -5057,25 +5072,29 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
        int err;
 
        if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: Error creating pcm interface\n");
+               dev_err(card->dev,
+                       "Error creating pcm interface\n");
                return err;
        }
 
 
        if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: Error creating first midi interface\n");
+               dev_err(card->dev,
+                       "Error creating first midi interface\n");
                return err;
        }
 
        if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
                if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) {
-                       snd_printk(KERN_ERR "Hammerfall-DSP: Error creating second midi interface\n");
+                       dev_err(card->dev,
+                               "Error creating second midi interface\n");
                        return err;
                }
        }
 
        if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: Error creating ctl interface\n");
+               dev_err(card->dev,
+                       "Error creating ctl interface\n");
                return err;
        }
 
@@ -5088,7 +5107,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
        hdsp->playback_substream = NULL;
 
        if ((err = snd_hdsp_set_defaults(hdsp)) < 0) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: Error setting default values\n");
+               dev_err(card->dev,
+                       "Error setting default values\n");
                return err;
        }
 
@@ -5098,7 +5118,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
                        hdsp->port, hdsp->irq);
 
                if ((err = snd_card_register(card)) < 0) {
-                       snd_printk(KERN_ERR "Hammerfall-DSP: error registering card\n");
+                       dev_err(card->dev,
+                               "error registering card\n");
                        return err;
                }
                hdsp->state |= HDSP_InitializationComplete;
@@ -5141,16 +5162,19 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
                        fwfile = "digiface_firmware_rev11.bin";
                break;
        default:
-               snd_printk(KERN_ERR "Hammerfall-DSP: invalid io_type %d\n", hdsp->io_type);
+               dev_err(hdsp->card->dev,
+                       "invalid io_type %d\n", hdsp->io_type);
                return -EINVAL;
        }
 
        if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile);
+               dev_err(hdsp->card->dev,
+                       "cannot load firmware %s\n", fwfile);
                return -ENOENT;
        }
        if (fw->size < HDSP_FIRMWARE_SIZE) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n",
+               dev_err(hdsp->card->dev,
+                       "too short firmware size %d (expected %d)\n",
                           (int)fw->size, HDSP_FIRMWARE_SIZE);
                return -EINVAL;
        }
@@ -5167,13 +5191,15 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
                        return err;
 
                if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) {
-                       snd_printk(KERN_ERR "Hammerfall-DSP: error creating hwdep device\n");
+                       dev_err(hdsp->card->dev,
+                               "error creating hwdep device\n");
                        return err;
                }
                snd_hdsp_initialize_channels(hdsp);
                snd_hdsp_initialize_midi_flush(hdsp);
                if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
-                       snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
+                       dev_err(hdsp->card->dev,
+                               "error creating alsa devices\n");
                        return err;
                }
        }
@@ -5249,13 +5275,14 @@ static int snd_hdsp_create(struct snd_card *card,
                return err;
        hdsp->port = pci_resource_start(pci, 0);
        if ((hdsp->iobase = ioremap_nocache(hdsp->port, HDSP_IO_EXTENT)) == NULL) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
+               dev_err(hdsp->card->dev, "unable to remap region 0x%lx-0x%lx\n",
+                       hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
                return -EBUSY;
        }
 
        if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, hdsp)) {
-               snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq);
+               dev_err(hdsp->card->dev, "unable to use IRQ %d\n", pci->irq);
                return -EBUSY;
        }
 
@@ -5281,17 +5308,20 @@ static int snd_hdsp_create(struct snd_card *card,
                                   if userspace is not ready for
                                   firmware upload
                                */
-                               snd_printk(KERN_ERR "Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n");
+                               dev_err(hdsp->card->dev,
+                                       "couldn't get firmware from userspace. try using hdsploader\n");
                        else
                                /* init is complete, we return */
                                return 0;
                        /* we defer initialization */
-                       snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n");
+                       dev_info(hdsp->card->dev,
+                                "card initialization pending : waiting for firmware\n");
                        if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
                                return err;
                        return 0;
                } else {
-                       snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
+                       dev_info(hdsp->card->dev,
+                                "Firmware already present, initializing card.\n");
                        if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
                                hdsp->io_type = RPM;
                        else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
@@ -5375,8 +5405,8 @@ static int snd_hdsp_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct hdsp), &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct hdsp), &card);
        if (err < 0)
                return err;
 
@@ -5384,7 +5414,6 @@ static int snd_hdsp_probe(struct pci_dev *pci,
        card->private_free = snd_hdsp_card_free;
        hdsp->dev = dev;
        hdsp->pci = pci;
-       snd_card_set_dev(card, &pci->dev);
 
        if ((err = snd_hdsp_create(card, hdsp)) < 0) {
                snd_card_free(card);
index e98dc008de0b91e4b7e73f776081893fafa04084..cb82b593473a891a04b4969a9f1d49227c399978 100644 (file)
@@ -1651,9 +1651,8 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
                           just make a warning an remember setting
                           for future master mode switching */
 
-                       snd_printk(KERN_WARNING "HDSPM: "
-                                  "Warning: device is not running "
-                                  "as a clock master.\n");
+                       dev_warn(hdspm->card->dev,
+                                "Warning: device is not running as a clock master.\n");
                        not_set = 1;
                } else {
 
@@ -1664,15 +1663,14 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
                        if (hdspm_autosync_ref(hdspm) ==
                            HDSPM_AUTOSYNC_FROM_NONE) {
 
-                               snd_printk(KERN_WARNING "HDSPM: "
-                                          "Detected no Externel Sync \n");
+                               dev_warn(hdspm->card->dev,
+                                        "Detected no Externel Sync\n");
                                not_set = 1;
 
                        } else if (rate != external_freq) {
 
-                               snd_printk(KERN_WARNING "HDSPM: "
-                                          "Warning: No AutoSync source for "
-                                          "requested rate\n");
+                               dev_warn(hdspm->card->dev,
+                                        "Warning: No AutoSync source for requested rate\n");
                                not_set = 1;
                        }
                }
@@ -1738,13 +1736,11 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
 
        if (current_speed != target_speed
            && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) {
-               snd_printk
-                   (KERN_ERR "HDSPM: "
-                    "cannot change from %s speed to %s speed mode "
-                    "(capture PID = %d, playback PID = %d)\n",
-                    hdspm_speed_names[current_speed],
-                    hdspm_speed_names[target_speed],
-                    hdspm->capture_pid, hdspm->playback_pid);
+               dev_err(hdspm->card->dev,
+                       "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n",
+                       hdspm_speed_names[current_speed],
+                       hdspm_speed_names[target_speed],
+                       hdspm->capture_pid, hdspm->playback_pid);
                return -EBUSY;
        }
 
@@ -5446,7 +5442,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
         *          0         64     ~3998231       ~8191558
         **/
        /*
-          snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n",
+         dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n",
           now-hdspm->last_interrupt, status & 0xFFC0);
           hdspm->last_interrupt = now;
        */
@@ -5583,7 +5579,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
        spin_lock_irq(&hdspm->lock);
        err = hdspm_set_rate(hdspm, params_rate(params), 0);
        if (err < 0) {
-               snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err);
+               dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err);
                spin_unlock_irq(&hdspm->lock);
                _snd_pcm_hw_param_setempty(params,
                                SNDRV_PCM_HW_PARAM_RATE);
@@ -5594,7 +5590,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
        err = hdspm_set_interrupt_interval(hdspm,
                        params_period_size(params));
        if (err < 0) {
-               snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err);
+               dev_info(hdspm->card->dev,
+                        "err on hdspm_set_interrupt_interval: %d\n", err);
                _snd_pcm_hw_param_setempty(params,
                                SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
                return err;
@@ -5610,7 +5607,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
        err =
                snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
        if (err < 0) {
-               snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err);
+               dev_info(hdspm->card->dev,
+                        "err on snd_pcm_lib_malloc_pages: %d\n", err);
                return err;
        }
 
@@ -5624,7 +5622,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
 
                hdspm->playback_buffer =
                        (unsigned char *) substream->runtime->dma_area;
-               snd_printdd("Allocated sample buffer for playback at %p\n",
+               dev_dbg(hdspm->card->dev,
+                       "Allocated sample buffer for playback at %p\n",
                                hdspm->playback_buffer);
        } else {
                hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn,
@@ -5635,18 +5634,21 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
 
                hdspm->capture_buffer =
                        (unsigned char *) substream->runtime->dma_area;
-               snd_printdd("Allocated sample buffer for capture at %p\n",
+               dev_dbg(hdspm->card->dev,
+                       "Allocated sample buffer for capture at %p\n",
                                hdspm->capture_buffer);
        }
 
        /*
-          snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
+          dev_dbg(hdspm->card->dev,
+          "Allocated sample buffer for %s at 0x%08X\n",
           substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
           "playback" : "capture",
           snd_pcm_sgbuf_get_addr(substream, 0));
           */
        /*
-          snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
+          dev_dbg(hdspm->card->dev,
+          "set_hwparams: %s %d Hz, %d channels, bs = %d\n",
           substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
           "playback" : "capture",
           params_rate(params), params_channels(params),
@@ -5667,12 +5669,14 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
        /* Switch to native float format if requested */
        if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
                if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
-                       snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n");
+                       dev_info(hdspm->card->dev,
+                                "Switching to native 32bit LE float format.\n");
 
                hdspm->control_register |= HDSPe_FLOAT_FORMAT;
        } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) {
                if (hdspm->control_register & HDSPe_FLOAT_FORMAT)
-                       snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n");
+                       dev_info(hdspm->card->dev,
+                                "Switching to native 32bit LE integer format.\n");
 
                hdspm->control_register &= ~HDSPe_FLOAT_FORMAT;
        }
@@ -5715,12 +5719,16 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) {
-                       snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel);
+                       dev_info(hdspm->card->dev,
+                                "snd_hdspm_channel_info: output channel out of range (%d)\n",
+                                info->channel);
                        return -EINVAL;
                }
 
                if (hdspm->channel_map_out[info->channel] < 0) {
-                       snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel);
+                       dev_info(hdspm->card->dev,
+                                "snd_hdspm_channel_info: output channel %d mapped out\n",
+                                info->channel);
                        return -EINVAL;
                }
 
@@ -5728,12 +5736,16 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
                        HDSPM_CHANNEL_BUFFER_BYTES;
        } else {
                if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) {
-                       snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel);
+                       dev_info(hdspm->card->dev,
+                                "snd_hdspm_channel_info: input channel out of range (%d)\n",
+                                info->channel);
                        return -EINVAL;
                }
 
                if (hdspm->channel_map_in[info->channel] < 0) {
-                       snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel);
+                       dev_info(hdspm->card->dev,
+                                "snd_hdspm_channel_info: input channel %d mapped out\n",
+                                info->channel);
                        return -EINVAL;
                }
 
@@ -6283,7 +6295,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
 
                s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms));
                if (0 != s) {
-                       /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu
+                       /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu
                         [Levels]\n", sizeof(struct hdspm_peak_rms), s);
                         */
                        return -EFAULT;
@@ -6329,7 +6341,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
                s = copy_to_user(argp, &ltc, sizeof(struct hdspm_ltc));
                if (0 != s) {
                        /*
-                        snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
+                         dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
                        return -EFAULT;
                }
 
@@ -6494,11 +6506,13 @@ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm)
                                                   wanted,
                                                   wanted);
        if (err < 0) {
-               snd_printdd("Could not preallocate %zd Bytes\n", wanted);
+               dev_dbg(hdspm->card->dev,
+                       "Could not preallocate %zd Bytes\n", wanted);
 
                return err;
        } else
-               snd_printdd(" Preallocated %zd Bytes\n", wanted);
+               dev_dbg(hdspm->card->dev,
+                       " Preallocated %zd Bytes\n", wanted);
 
        return 0;
 }
@@ -6559,7 +6573,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
 {
        int err, i;
 
-       snd_printdd("Create card...\n");
+       dev_dbg(card->dev, "Create card...\n");
        err = snd_hdspm_create_pcm(card, hdspm);
        if (err < 0)
                return err;
@@ -6581,7 +6595,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
        if (err < 0)
                return err;
 
-       snd_printdd("proc init...\n");
+       dev_dbg(card->dev, "proc init...\n");
        snd_hdspm_proc_init(hdspm);
 
        hdspm->system_sample_rate = -1;
@@ -6592,23 +6606,23 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
        hdspm->capture_substream = NULL;
        hdspm->playback_substream = NULL;
 
-       snd_printdd("Set defaults...\n");
+       dev_dbg(card->dev, "Set defaults...\n");
        err = snd_hdspm_set_defaults(hdspm);
        if (err < 0)
                return err;
 
-       snd_printdd("Update mixer controls...\n");
+       dev_dbg(card->dev, "Update mixer controls...\n");
        hdspm_update_simple_mixer_controls(hdspm);
 
-       snd_printdd("Initializeing complete ???\n");
+       dev_dbg(card->dev, "Initializeing complete ???\n");
 
        err = snd_card_register(card);
        if (err < 0) {
-               snd_printk(KERN_ERR "HDSPM: error registering card\n");
+               dev_err(card->dev, "error registering card\n");
                return err;
        }
 
-       snd_printdd("... yes now\n");
+       dev_dbg(card->dev, "... yes now\n");
 
        return 0;
 }
@@ -6662,8 +6676,8 @@ static int snd_hdspm_create(struct snd_card *card,
                        hdspm->card_name = "RME MADI";
                        hdspm->midiPorts = 3;
                } else {
-                       snd_printk(KERN_ERR
-                               "HDSPM: unknown firmware revision %x\n",
+                       dev_err(card->dev,
+                               "unknown firmware revision %x\n",
                                hdspm->firmware_rev);
                        return -ENODEV;
                }
@@ -6682,36 +6696,35 @@ static int snd_hdspm_create(struct snd_card *card,
        hdspm->port = pci_resource_start(pci, 0);
        io_extent = pci_resource_len(pci, 0);
 
-       snd_printdd("grabbed memory region 0x%lx-0x%lx\n",
+       dev_dbg(card->dev, "grabbed memory region 0x%lx-0x%lx\n",
                        hdspm->port, hdspm->port + io_extent - 1);
 
        hdspm->iobase = ioremap_nocache(hdspm->port, io_extent);
        if (!hdspm->iobase) {
-               snd_printk(KERN_ERR "HDSPM: "
-                               "unable to remap region 0x%lx-0x%lx\n",
+               dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
                                hdspm->port, hdspm->port + io_extent - 1);
                return -EBUSY;
        }
-       snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n",
+       dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n",
                        (unsigned long)hdspm->iobase, hdspm->port,
                        hdspm->port + io_extent - 1);
 
        if (request_irq(pci->irq, snd_hdspm_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, hdspm)) {
-               snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to use IRQ %d\n", pci->irq);
                return -EBUSY;
        }
 
-       snd_printdd("use IRQ %d\n", pci->irq);
+       dev_dbg(card->dev, "use IRQ %d\n", pci->irq);
 
        hdspm->irq = pci->irq;
 
-       snd_printdd("kmalloc Mixer memory of %zd Bytes\n",
+       dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n",
                        sizeof(struct hdspm_mixer));
        hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL);
        if (!hdspm->mixer) {
-               snd_printk(KERN_ERR "HDSPM: "
-                               "unable to kmalloc Mixer memory of %d Bytes\n",
+               dev_err(card->dev,
+                       "unable to kmalloc Mixer memory of %d Bytes\n",
                                (int)sizeof(struct hdspm_mixer));
                return -ENOMEM;
        }
@@ -6780,14 +6793,14 @@ static int snd_hdspm_create(struct snd_card *card,
                hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
 
                if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
-                       snd_printk(KERN_INFO "HDSPM: AEB input board found\n");
+                       dev_info(card->dev, "AEB input board found\n");
                        hdspm->ss_in_channels += 4;
                        hdspm->ds_in_channels += 4;
                        hdspm->qs_in_channels += 4;
                }
 
                if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
-                       snd_printk(KERN_INFO "HDSPM: AEB output board found\n");
+                       dev_info(card->dev, "AEB output board found\n");
                        hdspm->ss_out_channels += 4;
                        hdspm->ds_out_channels += 4;
                        hdspm->qs_out_channels += 4;
@@ -6854,7 +6867,7 @@ static int snd_hdspm_create(struct snd_card *card,
                        if (NULL != hdspm->tco) {
                                hdspm_tco_write(hdspm);
                        }
-                       snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n");
+                       dev_info(card->dev, "AIO/RayDAT TCO module found\n");
                } else {
                        hdspm->tco = NULL;
                }
@@ -6869,7 +6882,7 @@ static int snd_hdspm_create(struct snd_card *card,
                        if (NULL != hdspm->tco) {
                                hdspm_tco_write(hdspm);
                        }
-                       snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n");
+                       dev_info(card->dev, "MADI/AES TCO module found\n");
                } else {
                        hdspm->tco = NULL;
                }
@@ -6951,7 +6964,7 @@ static int snd_hdspm_create(struct snd_card *card,
                }
        }
 
-       snd_printdd("create alsa devices.\n");
+       dev_dbg(card->dev, "create alsa devices.\n");
        err = snd_hdspm_create_alsa_devices(card, hdspm);
        if (err < 0)
                return err;
@@ -7016,8 +7029,8 @@ static int snd_hdspm_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev],
-                       THIS_MODULE, sizeof(struct hdspm), &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev],
+                          THIS_MODULE, sizeof(struct hdspm), &card);
        if (err < 0)
                return err;
 
@@ -7026,8 +7039,6 @@ static int snd_hdspm_probe(struct pci_dev *pci,
        hdspm->dev = dev;
        hdspm->pci = pci;
 
-       snd_card_set_dev(card, &pci->dev);
-
        err = snd_hdspm_create(card, hdspm);
        if (err < 0) {
                snd_card_free(card);
index 1503ee3585fddee141b5df731055325b6a1292cc..1d9be90f774827fb7f8db9a5d60a4e0138b2ef23 100644 (file)
@@ -394,7 +394,9 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
        if (offset < period_size) {
                if (offset > rme9652->max_jitter) {
                        if (frag)
-                               printk(KERN_ERR "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", status, offset);
+                               dev_err(rme9652->card->dev,
+                                       "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n",
+                                       status, offset);
                } else if (!frag)
                        return 0;
                offset -= rme9652->max_jitter;
@@ -403,7 +405,9 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
        } else {
                if (offset > period_size + rme9652->max_jitter) {
                        if (!frag)
-                               printk(KERN_ERR "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", status, offset);
+                               dev_err(rme9652->card->dev,
+                                       "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n",
+                                       status, offset);
                } else if (frag)
                        return period_size;
                offset -= rme9652->max_jitter;
@@ -769,7 +773,8 @@ static inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s)
                break;
 
        default:
-               snd_printk(KERN_ERR "%s: unknown S/PDIF input rate (bits = 0x%x)\n",
+               dev_err(s->card->dev,
+                       "%s: unknown S/PDIF input rate (bits = 0x%x)\n",
                           s->card_name, rate_bits);
                return 0;
                break;
@@ -1790,7 +1795,8 @@ static int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652)
            snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) {
                if (rme9652->capture_dma_buf.area)
                        snd_dma_free_pages(&rme9652->capture_dma_buf);
-               printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name);
+               dev_err(rme9652->card->dev,
+                       "%s: no buffers available\n", rme9652->card_name);
                return -ENOMEM;
        }
 
@@ -2468,13 +2474,14 @@ static int snd_rme9652_create(struct snd_card *card,
        rme9652->port = pci_resource_start(pci, 0);
        rme9652->iobase = ioremap_nocache(rme9652->port, RME9652_IO_EXTENT);
        if (rme9652->iobase == NULL) {
-               snd_printk(KERN_ERR "unable to remap region 0x%lx-0x%lx\n", rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1);
+               dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
+                       rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1);
                return -EBUSY;
        }
        
        if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, rme9652)) {
-               snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to request IRQ %d\n", pci->irq);
                return -EBUSY;
        }
        rme9652->irq = pci->irq;
@@ -2587,8 +2594,8 @@ static int snd_rme9652_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_rme9652), &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_rme9652), &card);
 
        if (err < 0)
                return err;
@@ -2597,7 +2604,6 @@ static int snd_rme9652_probe(struct pci_dev *pci,
        card->private_free = snd_rme9652_card_free;
        rme9652->dev = dev;
        rme9652->pci = pci;
-       snd_card_set_dev(card, &pci->dev);
 
        if ((err = snd_rme9652_create(card, rme9652, precise_ptr[dev])) < 0) {
                snd_card_free(card);
index e413b4e2c81952101294d993dba70aee9c1a14fb..6b26b93e001d89fa4c80fe3e6e52e1392b1f2c27 100644 (file)
@@ -1404,8 +1404,6 @@ static int sis_chip_create(struct snd_card *card,
        if (rc)
                goto error_out_cleanup;
 
-       snd_card_set_dev(card, &pci->dev);
-
        return 0;
 
 error_out_cleanup:
@@ -1440,7 +1438,8 @@ static int snd_sis7019_probe(struct pci_dev *pci,
        if (!codecs)
                codecs = SIS_PRIMARY_CODEC_PRESENT;
 
-       rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
+       rc = snd_card_new(&pci->dev, index, id, THIS_MODULE,
+                         sizeof(*sis), &card);
        if (rc < 0)
                goto error_out;
 
index 2a46bf98af30f054a20109ada2a17115de05b127..2044dc74207161b6d8951aa7faddcfb3c317f2be 100644 (file)
@@ -273,7 +273,7 @@ static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic,
        outl(count, sonic->dmaa_port + SV_DMA_COUNT0);
        outb(0x18, sonic->dmaa_port + SV_DMA_MODE);
 #if 0
-       printk(KERN_DEBUG "program dmaa: addr = 0x%x, paddr = 0x%x\n",
+       dev_dbg(sonic->card->dev, "program dmaa: addr = 0x%x, paddr = 0x%x\n",
               addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
 #endif
 }
@@ -289,7 +289,7 @@ static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic,
        outl(count, sonic->dmac_port + SV_DMA_COUNT0);
        outb(0x14, sonic->dmac_port + SV_DMA_MODE);
 #if 0
-       printk(KERN_DEBUG "program dmac: addr = 0x%x, paddr = 0x%x\n",
+       dev_dbg(sonic->card->dev, "program dmac: addr = 0x%x, paddr = 0x%x\n",
               addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
 #endif
 }
@@ -357,105 +357,105 @@ static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char
 #if 0
 static void snd_sonicvibes_debug(struct sonicvibes * sonic)
 {
-       printk(KERN_DEBUG
-              "SV REGS:          INDEX = 0x%02x  ", inb(SV_REG(sonic, INDEX)));
-       printk("                 STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS)));
-       printk(KERN_DEBUG
-              "  0x00: left input      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x00));
-       printk("  0x20: synth rate low  = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20));
-       printk(KERN_DEBUG
-              "  0x01: right input     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x01));
-       printk("  0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21));
-       printk(KERN_DEBUG
-              "  0x02: left AUX1       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x02));
-       printk("  0x22: ADC clock       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22));
-       printk(KERN_DEBUG
-              "  0x03: right AUX1      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x03));
-       printk("  0x23: ADC alt rate    = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23));
-       printk(KERN_DEBUG
-              "  0x04: left CD         = 0x%02x  ", snd_sonicvibes_in(sonic, 0x04));
-       printk("  0x24: ADC pll M       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24));
-       printk(KERN_DEBUG
-              "  0x05: right CD        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x05));
-       printk("  0x25: ADC pll N       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25));
-       printk(KERN_DEBUG
-              "  0x06: left line       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x06));
-       printk("  0x26: Synth pll M     = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26));
-       printk(KERN_DEBUG
-              "  0x07: right line      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x07));
-       printk("  0x27: Synth pll N     = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27));
-       printk(KERN_DEBUG
-              "  0x08: MIC             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x08));
-       printk("  0x28: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28));
-       printk(KERN_DEBUG
-              "  0x09: Game port       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x09));
-       printk("  0x29: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x29));
-       printk(KERN_DEBUG
-              "  0x0a: left synth      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0a));
-       printk("  0x2a: MPU401          = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2a));
-       printk(KERN_DEBUG
-              "  0x0b: right synth     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0b));
-       printk("  0x2b: drive ctrl      = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2b));
-       printk(KERN_DEBUG
-              "  0x0c: left AUX2       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0c));
-       printk("  0x2c: SRS space       = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2c));
-       printk(KERN_DEBUG
-              "  0x0d: right AUX2      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0d));
-       printk("  0x2d: SRS center      = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2d));
-       printk(KERN_DEBUG
-              "  0x0e: left analog     = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0e));
-       printk("  0x2e: wave source     = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2e));
-       printk(KERN_DEBUG
-              "  0x0f: right analog    = 0x%02x  ", snd_sonicvibes_in(sonic, 0x0f));
-       printk("  0x2f: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2f));
-       printk(KERN_DEBUG
-              "  0x10: left PCM        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x10));
-       printk("  0x30: analog power    = 0x%02x\n", snd_sonicvibes_in(sonic, 0x30));
-       printk(KERN_DEBUG
-              "  0x11: right PCM       = 0x%02x  ", snd_sonicvibes_in(sonic, 0x11));
-       printk("  0x31: analog power    = 0x%02x\n", snd_sonicvibes_in(sonic, 0x31));
-       printk(KERN_DEBUG
-              "  0x12: DMA data format = 0x%02x  ", snd_sonicvibes_in(sonic, 0x12));
-       printk("  0x32: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x32));
-       printk(KERN_DEBUG
-              "  0x13: P/C enable      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x13));
-       printk("  0x33: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x33));
-       printk(KERN_DEBUG
-              "  0x14: U/D button      = 0x%02x  ", snd_sonicvibes_in(sonic, 0x14));
-       printk("  0x34: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x34));
-       printk(KERN_DEBUG
-              "  0x15: revision        = 0x%02x  ", snd_sonicvibes_in(sonic, 0x15));
-       printk("  0x35: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x35));
-       printk(KERN_DEBUG
-              "  0x16: ADC output ctrl = 0x%02x  ", snd_sonicvibes_in(sonic, 0x16));
-       printk("  0x36: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x36));
-       printk(KERN_DEBUG
-              "  0x17: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x17));
-       printk("  0x37: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x37));
-       printk(KERN_DEBUG
-              "  0x18: DMA A upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x18));
-       printk("  0x38: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x38));
-       printk(KERN_DEBUG
-              "  0x19: DMA A lower cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x19));
-       printk("  0x39: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x39));
-       printk(KERN_DEBUG
-              "  0x1a: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1a));
-       printk("  0x3a: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3a));
-       printk(KERN_DEBUG
-              "  0x1b: ---             = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1b));
-       printk("  0x3b: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3b));
-       printk(KERN_DEBUG
-              "  0x1c: DMA C upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1c));
-       printk("  0x3c: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3c));
-       printk(KERN_DEBUG
-              "  0x1d: DMA C upper cnt = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1d));
-       printk("  0x3d: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3d));
-       printk(KERN_DEBUG
-              "  0x1e: PCM rate low    = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1e));
-       printk("  0x3e: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3e));
-       printk(KERN_DEBUG
-              "  0x1f: PCM rate high   = 0x%02x  ", snd_sonicvibes_in(sonic, 0x1f));
-       printk("  0x3f: ---             = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3f));
+       dev_dbg(sonic->card->dev,
+               "SV REGS:          INDEX = 0x%02x                   STATUS = 0x%02x\n",
+               inb(SV_REG(sonic, INDEX)), inb(SV_REG(sonic, STATUS)));
+       dev_dbg(sonic->card->dev,
+               "  0x00: left input      = 0x%02x    0x20: synth rate low  = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x00), snd_sonicvibes_in(sonic, 0x20));
+       dev_dbg(sonic->card->dev,
+               "  0x01: right input     = 0x%02x    0x21: synth rate high = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x01), snd_sonicvibes_in(sonic, 0x21));
+       dev_dbg(sonic->card->dev,
+               "  0x02: left AUX1       = 0x%02x    0x22: ADC clock       = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x02), snd_sonicvibes_in(sonic, 0x22));
+       dev_dbg(sonic->card->dev,
+               "  0x03: right AUX1      = 0x%02x    0x23: ADC alt rate    = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x03), snd_sonicvibes_in(sonic, 0x23));
+       dev_dbg(sonic->card->dev,
+               "  0x04: left CD         = 0x%02x    0x24: ADC pll M       = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x04), snd_sonicvibes_in(sonic, 0x24));
+       dev_dbg(sonic->card->dev,
+               "  0x05: right CD        = 0x%02x    0x25: ADC pll N       = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x05), snd_sonicvibes_in(sonic, 0x25));
+       dev_dbg(sonic->card->dev,
+               "  0x06: left line       = 0x%02x    0x26: Synth pll M     = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x06), snd_sonicvibes_in(sonic, 0x26));
+       dev_dbg(sonic->card->dev,
+               "  0x07: right line      = 0x%02x    0x27: Synth pll N     = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x07), snd_sonicvibes_in(sonic, 0x27));
+       dev_dbg(sonic->card->dev,
+               "  0x08: MIC             = 0x%02x    0x28: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x08), snd_sonicvibes_in(sonic, 0x28));
+       dev_dbg(sonic->card->dev,
+               "  0x09: Game port       = 0x%02x    0x29: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x09), snd_sonicvibes_in(sonic, 0x29));
+       dev_dbg(sonic->card->dev,
+               "  0x0a: left synth      = 0x%02x    0x2a: MPU401          = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x0a), snd_sonicvibes_in(sonic, 0x2a));
+       dev_dbg(sonic->card->dev,
+               "  0x0b: right synth     = 0x%02x    0x2b: drive ctrl      = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x0b), snd_sonicvibes_in(sonic, 0x2b));
+       dev_dbg(sonic->card->dev,
+               "  0x0c: left AUX2       = 0x%02x    0x2c: SRS space       = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x0c), snd_sonicvibes_in(sonic, 0x2c));
+       dev_dbg(sonic->card->dev,
+               "  0x0d: right AUX2      = 0x%02x    0x2d: SRS center      = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x0d), snd_sonicvibes_in(sonic, 0x2d));
+       dev_dbg(sonic->card->dev,
+               "  0x0e: left analog     = 0x%02x    0x2e: wave source     = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x0e), snd_sonicvibes_in(sonic, 0x2e));
+       dev_dbg(sonic->card->dev,
+               "  0x0f: right analog    = 0x%02x    0x2f: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x0f), snd_sonicvibes_in(sonic, 0x2f));
+       dev_dbg(sonic->card->dev,
+               "  0x10: left PCM        = 0x%02x    0x30: analog power    = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x10), snd_sonicvibes_in(sonic, 0x30));
+       dev_dbg(sonic->card->dev,
+               "  0x11: right PCM       = 0x%02x    0x31: analog power    = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x11), snd_sonicvibes_in(sonic, 0x31));
+       dev_dbg(sonic->card->dev,
+               "  0x12: DMA data format = 0x%02x    0x32: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x12), snd_sonicvibes_in(sonic, 0x32));
+       dev_dbg(sonic->card->dev,
+               "  0x13: P/C enable      = 0x%02x    0x33: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x13), snd_sonicvibes_in(sonic, 0x33));
+       dev_dbg(sonic->card->dev,
+               "  0x14: U/D button      = 0x%02x    0x34: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x14), snd_sonicvibes_in(sonic, 0x34));
+       dev_dbg(sonic->card->dev,
+               "  0x15: revision        = 0x%02x    0x35: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x15), snd_sonicvibes_in(sonic, 0x35));
+       dev_dbg(sonic->card->dev,
+               "  0x16: ADC output ctrl = 0x%02x    0x36: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x16), snd_sonicvibes_in(sonic, 0x36));
+       dev_dbg(sonic->card->dev,
+               "  0x17: ---             = 0x%02x    0x37: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x17), snd_sonicvibes_in(sonic, 0x37));
+       dev_dbg(sonic->card->dev,
+               "  0x18: DMA A upper cnt = 0x%02x    0x38: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x18), snd_sonicvibes_in(sonic, 0x38));
+       dev_dbg(sonic->card->dev,
+               "  0x19: DMA A lower cnt = 0x%02x    0x39: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x19), snd_sonicvibes_in(sonic, 0x39));
+       dev_dbg(sonic->card->dev,
+               "  0x1a: ---             = 0x%02x    0x3a: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x1a), snd_sonicvibes_in(sonic, 0x3a));
+       dev_dbg(sonic->card->dev,
+               "  0x1b: ---             = 0x%02x    0x3b: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x1b), snd_sonicvibes_in(sonic, 0x3b));
+       dev_dbg(sonic->card->dev,
+               "  0x1c: DMA C upper cnt = 0x%02x    0x3c: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x1c), snd_sonicvibes_in(sonic, 0x3c));
+       dev_dbg(sonic->card->dev,
+               "  0x1d: DMA C upper cnt = 0x%02x    0x3d: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x1d), snd_sonicvibes_in(sonic, 0x3d));
+       dev_dbg(sonic->card->dev,
+               "  0x1e: PCM rate low    = 0x%02x    0x3e: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x1e), snd_sonicvibes_in(sonic, 0x3e));
+       dev_dbg(sonic->card->dev,
+               "  0x1f: PCM rate high   = 0x%02x    0x3f: ---             = 0x%02x\n",
+               snd_sonicvibes_in(sonic, 0x1f), snd_sonicvibes_in(sonic, 0x3f));
 }
 
 #endif
@@ -511,8 +511,10 @@ static void snd_sonicvibes_pll(unsigned int rate,
        *res_m = m;
        *res_n = n;
 #if 0
-       printk(KERN_DEBUG "metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
-       printk(KERN_DEBUG "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
+       dev_dbg(sonic->card->dev,
+               "metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
+       dev_dbg(sonic->card->dev,
+               "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
 #endif
 }
 
@@ -624,7 +626,8 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
        if (status == 0xff) {   /* failure */
                outb(sonic->irqmask = ~0, SV_REG(sonic, IRQMASK));
-               snd_printk(KERN_ERR "IRQ failure - interrupts disabled!!\n");
+               dev_err(sonic->card->dev,
+                       "IRQ failure - interrupts disabled!!\n");
                return IRQ_HANDLED;
        }
        if (sonic->pcm) {
@@ -1198,7 +1201,8 @@ static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic)
 
        sonic->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "sonicvibes: cannot allocate memory for gameport\n");
+               dev_err(sonic->card->dev,
+                       "sonicvibes: cannot allocate memory for gameport\n");
                return -ENOMEM;
        }
 
@@ -1267,7 +1271,8 @@ static int snd_sonicvibes_create(struct snd_card *card,
        /* check, if we can restrict PCI DMA transfers to 24 bits */
         if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 24bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                 return -ENXIO;
         }
@@ -1296,7 +1301,7 @@ static int snd_sonicvibes_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, sonic)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_sonicvibes_free(sonic);
                return -EBUSY;
        }
@@ -1310,24 +1315,32 @@ static int snd_sonicvibes_create(struct snd_card *card,
        if (!dmaa) {
                dmaa = dmaio;
                dmaio += 0x10;
-               snd_printk(KERN_INFO "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa);
+               dev_info(card->dev,
+                        "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n",
+                        dmaa);
        }
        if (!dmac) {
                dmac = dmaio;
                dmaio += 0x10;
-               snd_printk(KERN_INFO "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac);
+               dev_info(card->dev,
+                        "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n",
+                        dmac);
        }
        pci_write_config_dword(pci, 0x40, dmaa);
        pci_write_config_dword(pci, 0x48, dmac);
 
        if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) {
                snd_sonicvibes_free(sonic);
-               snd_printk(KERN_ERR "unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1);
+               dev_err(card->dev,
+                       "unable to grab DDMA-A port at 0x%x-0x%x\n",
+                       dmaa, dmaa + 0x10 - 1);
                return -EBUSY;
        }
        if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) {
                snd_sonicvibes_free(sonic);
-               snd_printk(KERN_ERR "unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1);
+               dev_err(card->dev,
+                       "unable to grab DDMA-C port at 0x%x-0x%x\n",
+                       dmac, dmac + 0x10 - 1);
                return -EBUSY;
        }
 
@@ -1392,8 +1405,6 @@ static int snd_sonicvibes_create(struct snd_card *card,
 
        snd_sonicvibes_proc_init(sonic);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rsonic = sonic;
        return 0;
 }
@@ -1459,7 +1470,8 @@ static int snd_sonic_probe(struct pci_dev *pci,
                return -ENOENT;
        }
  
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
        for (idx = 0; idx < 5; idx++) {
index b3b588bc94c37720dd20026589b39ae342a9890d..d852458caf386f651614a375ceac3c0bd27f96cd 100644 (file)
@@ -89,7 +89,8 @@ static int snd_trident_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
index fb0e1586a6f87cc25bbce39a64744e1fea468de5..1272c18a2544364a7d81a1e0d57a10b5c1f36f04 100644 (file)
@@ -69,40 +69,40 @@ static void snd_trident_print_voice_regs(struct snd_trident *trident, int voice)
 {
        unsigned int val, tmp;
 
-       printk(KERN_DEBUG "Trident voice %i:\n", voice);
+       dev_dbg(trident->card->dev, "Trident voice %i:\n", voice);
        outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR));
        val = inl(TRID_REG(trident, CH_LBA));
-       printk(KERN_DEBUG "LBA: 0x%x\n", val);
+       dev_dbg(trident->card->dev, "LBA: 0x%x\n", val);
        val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
-       printk(KERN_DEBUG "GVSel: %i\n", val >> 31);
-       printk(KERN_DEBUG "Pan: 0x%x\n", (val >> 24) & 0x7f);
-       printk(KERN_DEBUG "Vol: 0x%x\n", (val >> 16) & 0xff);
-       printk(KERN_DEBUG "CTRL: 0x%x\n", (val >> 12) & 0x0f);
-       printk(KERN_DEBUG "EC: 0x%x\n", val & 0x0fff);
+       dev_dbg(trident->card->dev, "GVSel: %i\n", val >> 31);
+       dev_dbg(trident->card->dev, "Pan: 0x%x\n", (val >> 24) & 0x7f);
+       dev_dbg(trident->card->dev, "Vol: 0x%x\n", (val >> 16) & 0xff);
+       dev_dbg(trident->card->dev, "CTRL: 0x%x\n", (val >> 12) & 0x0f);
+       dev_dbg(trident->card->dev, "EC: 0x%x\n", val & 0x0fff);
        if (trident->device != TRIDENT_DEVICE_ID_NX) {
                val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS));
-               printk(KERN_DEBUG "CSO: 0x%x\n", val >> 16);
-               printk("Alpha: 0x%x\n", (val >> 4) & 0x0fff);
-               printk(KERN_DEBUG "FMS: 0x%x\n", val & 0x0f);
+               dev_dbg(trident->card->dev, "CSO: 0x%x\n", val >> 16);
+               dev_dbg(trident->card->dev, "Alpha: 0x%x\n", (val >> 4) & 0x0fff);
+               dev_dbg(trident->card->dev, "FMS: 0x%x\n", val & 0x0f);
                val = inl(TRID_REG(trident, CH_DX_ESO_DELTA));
-               printk(KERN_DEBUG "ESO: 0x%x\n", val >> 16);
-               printk(KERN_DEBUG "Delta: 0x%x\n", val & 0xffff);
+               dev_dbg(trident->card->dev, "ESO: 0x%x\n", val >> 16);
+               dev_dbg(trident->card->dev, "Delta: 0x%x\n", val & 0xffff);
                val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));
        } else {                // TRIDENT_DEVICE_ID_NX
                val = inl(TRID_REG(trident, CH_NX_DELTA_CSO));
                tmp = (val >> 24) & 0xff;
-               printk(KERN_DEBUG "CSO: 0x%x\n", val & 0x00ffffff);
+               dev_dbg(trident->card->dev, "CSO: 0x%x\n", val & 0x00ffffff);
                val = inl(TRID_REG(trident, CH_NX_DELTA_ESO));
                tmp |= (val >> 16) & 0xff00;
-               printk(KERN_DEBUG "Delta: 0x%x\n", tmp);
-               printk(KERN_DEBUG "ESO: 0x%x\n", val & 0x00ffffff);
+               dev_dbg(trident->card->dev, "Delta: 0x%x\n", tmp);
+               dev_dbg(trident->card->dev, "ESO: 0x%x\n", val & 0x00ffffff);
                val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL));
-               printk(KERN_DEBUG "Alpha: 0x%x\n", val >> 20);
-               printk(KERN_DEBUG "FMS: 0x%x\n", (val >> 16) & 0x0f);
+               dev_dbg(trident->card->dev, "Alpha: 0x%x\n", val >> 20);
+               dev_dbg(trident->card->dev, "FMS: 0x%x\n", (val >> 16) & 0x0f);
        }
-       printk(KERN_DEBUG "FMC: 0x%x\n", (val >> 14) & 3);
-       printk(KERN_DEBUG "RVol: 0x%x\n", (val >> 7) & 0x7f);
-       printk(KERN_DEBUG "CVol: 0x%x\n", val & 0x7f);
+       dev_dbg(trident->card->dev, "FMC: 0x%x\n", (val >> 14) & 3);
+       dev_dbg(trident->card->dev, "RVol: 0x%x\n", (val >> 7) & 0x7f);
+       dev_dbg(trident->card->dev, "CVol: 0x%x\n", val & 0x7f);
 }
 #endif
 
@@ -156,7 +156,8 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho
        }
 
        if (count == 0 && !trident->ac97_detect) {
-               snd_printk(KERN_ERR "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n",
+               dev_err(trident->card->dev,
+                       "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n",
                           reg, data);
                data = 0;
        }
@@ -497,16 +498,16 @@ void snd_trident_write_voice_regs(struct snd_trident * trident,
        outl(regs[4], TRID_REG(trident, CH_START + 16));
 
 #if 0
-       printk(KERN_DEBUG "written %i channel:\n", voice->number);
-       printk(KERN_DEBUG "  regs[0] = 0x%x/0x%x\n",
+       dev_dbg(trident->card->dev, "written %i channel:\n", voice->number);
+       dev_dbg(trident->card->dev, "  regs[0] = 0x%x/0x%x\n",
               regs[0], inl(TRID_REG(trident, CH_START + 0)));
-       printk(KERN_DEBUG "  regs[1] = 0x%x/0x%x\n",
+       dev_dbg(trident->card->dev, "  regs[1] = 0x%x/0x%x\n",
               regs[1], inl(TRID_REG(trident, CH_START + 4)));
-       printk(KERN_DEBUG "  regs[2] = 0x%x/0x%x\n",
+       dev_dbg(trident->card->dev, "  regs[2] = 0x%x/0x%x\n",
               regs[2], inl(TRID_REG(trident, CH_START + 8)));
-       printk(KERN_DEBUG "  regs[3] = 0x%x/0x%x\n",
+       dev_dbg(trident->card->dev, "  regs[3] = 0x%x/0x%x\n",
               regs[3], inl(TRID_REG(trident, CH_START + 12)));
-       printk(KERN_DEBUG "  regs[4] = 0x%x/0x%x\n",
+       dev_dbg(trident->card->dev, "  regs[4] = 0x%x/0x%x\n",
               regs[4], inl(TRID_REG(trident, CH_START + 16)));
 #endif
 }
@@ -589,7 +590,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident,
                outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2));
                break;
        case TRIDENT_DEVICE_ID_SI7018:
-               /* printk(KERN_DEBUG "voice->Vol = 0x%x\n", voice->Vol); */
+               /* dev_dbg(trident->card->dev, "voice->Vol = 0x%x\n", voice->Vol); */
                outw((voice->CTRL << 12) | voice->Vol,
                     TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
                break;
@@ -3013,13 +3014,15 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device)
                _ac97.num = 1;
                err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec);
                if (err < 0)
-                       snd_printk(KERN_ERR "SI7018: the secondary codec - invalid access\n");
+                       dev_err(trident->card->dev,
+                               "SI7018: the secondary codec - invalid access\n");
 #if 0  // only for my testing purpose --jk
                {
                        struct snd_ac97 *mc97;
                        err = snd_ac97_modem(trident->card, &_ac97, &mc97);
                        if (err < 0)
-                               snd_printk(KERN_ERR "snd_ac97_modem returned error %i\n", err);
+                               dev_err(trident->card->dev,
+                                       "snd_ac97_modem returned error %i\n", err);
                }
 #endif
        }
@@ -3197,7 +3200,8 @@ int snd_trident_create_gameport(struct snd_trident *chip)
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "trident: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                return -ENOMEM;
        }
 
@@ -3270,7 +3274,8 @@ static int snd_trident_sis_reset(struct snd_trident *trident)
                        goto __si7018_ok;
                do_delay(trident);
        } while (time_after_eq(end_time, jiffies));
-       snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));
+       dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n",
+               inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));
        if (r-- > 0) {
                end_time = jiffies + HZ;
                do {
@@ -3367,7 +3372,7 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident)
 
        if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
                                2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) {
-               snd_printk(KERN_ERR "trident: unable to allocate TLB buffer\n");
+               dev_err(trident->card->dev, "unable to allocate TLB buffer\n");
                return -ENOMEM;
        }
        trident->tlb.entries = (unsigned int*)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4);
@@ -3375,13 +3380,14 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident)
        /* allocate shadow TLB page table (virtual addresses) */
        trident->tlb.shadow_entries = vmalloc(SNDRV_TRIDENT_MAX_PAGES*sizeof(unsigned long));
        if (trident->tlb.shadow_entries == NULL) {
-               snd_printk(KERN_ERR "trident: unable to allocate shadow TLB entries\n");
+               dev_err(trident->card->dev,
+                       "unable to allocate shadow TLB entries\n");
                return -ENOMEM;
        }
        /* allocate and setup silent page and initialise TLB entries */
        if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
                                SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) {
-               snd_printk(KERN_ERR "trident: unable to allocate silent page\n");
+               dev_err(trident->card->dev, "unable to allocate silent page\n");
                return -ENOMEM;
        }
        memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE);
@@ -3439,7 +3445,7 @@ static int snd_trident_4d_dx_init(struct snd_trident *trident)
                        goto __dx_ok;
                do_delay(trident);
        } while (time_after_eq(end_time, jiffies));
-       snd_printk(KERN_ERR "AC'97 codec ready error\n");
+       dev_err(trident->card->dev, "AC'97 codec ready error\n");
        return -EIO;
 
  __dx_ok:
@@ -3477,7 +3483,8 @@ static int snd_trident_4d_nx_init(struct snd_trident *trident)
                        goto __nx_ok;
                do_delay(trident);
        } while (time_after_eq(end_time, jiffies));
-       snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)));
+       dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n",
+               inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)));
        return -EIO;
 
  __nx_ok:
@@ -3562,7 +3569,8 @@ int snd_trident_create(struct snd_card *card,
        /* check, if we can restrict PCI DMA transfers to 30 bits */
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(30)) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(30)) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 30bit PCI busmaster DMA\n");
+               dev_err(card->dev,
+                       "architecture does not support 30bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -3600,7 +3608,7 @@ int snd_trident_create(struct snd_card *card,
 
        if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, trident)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_trident_free(trident);
                return -EBUSY;
        }
@@ -3664,7 +3672,6 @@ int snd_trident_create(struct snd_card *card,
        snd_trident_enable_eso(trident);
 
        snd_trident_proc_init(trident);
-       snd_card_set_dev(card, &pci->dev);
        *rtrident = trident;
        return 0;
 }
@@ -3950,8 +3957,7 @@ static int snd_trident_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "trident: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index 5ae6f042c586f61e94127ac91979e5e5c0407df8..95b98f537b67f27b1f7600c59ea2a72f3ce23bd7 100644 (file)
@@ -459,7 +459,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                        unsigned int addr;
 
                        if (idx >= VIA_TABLE_SIZE) {
-                               snd_printk(KERN_ERR "via82xx: too much table size!\n");
+                               dev_err(&pci->dev, "too much table size!\n");
                                return -EINVAL;
                        }
                        addr = snd_pcm_sgbuf_get_addr(substream, ofs);
@@ -474,8 +474,9 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                        } else
                                flag = 0; /* period continues to the next */
                        /*
-                       printk(KERN_DEBUG "via: tbl %d: at %d  size %d "
-                              "(rest %d)\n", idx, ofs, r, rest);
+                       dev_dbg(&pci->dev,
+                               "tbl %d: at %d  size %d (rest %d)\n",
+                               idx, ofs, r, rest);
                        */
                        ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
                        dev->idx_table[idx].offset = ofs;
@@ -528,7 +529,7 @@ static int snd_via82xx_codec_ready(struct via82xx *chip, int secondary)
                if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
                        return val & 0xffff;
        }
-       snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n",
+       dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n",
                   secondary, snd_via82xx_codec_xread(chip));
        return -EIO;
 }
@@ -587,7 +588,8 @@ static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned sho
        xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
        while (1) {
                if (again++ > 3) {
-                       snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n",
+                       dev_err(chip->card->dev,
+                               "codec_read: codec %i is not valid [0x%x]\n",
                                   ac97->num, snd_via82xx_codec_xread(chip));
                        return 0xffff;
                }
@@ -777,7 +779,9 @@ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        ((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\
                                     viadev->lastpos < viadev->bufsize2))
 
-static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx,
+static inline unsigned int calc_linear_pos(struct via82xx *chip,
+                                          struct viadev *viadev,
+                                          unsigned int idx,
                                           unsigned int count)
 {
        unsigned int size, base, res;
@@ -790,7 +794,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
 
        /* check the validity of the calculated position */
        if (size < count) {
-               snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
+               dev_dbg(chip->card->dev,
+                       "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
                           (int)size, (int)count);
                res = viadev->lastpos;
        } else {
@@ -807,9 +812,9 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
                }
                if (check_invalid_pos(viadev, res)) {
 #ifdef POINTER_DEBUG
-                       printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, "
-                              "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, "
-                              "count = 0x%x\n", idx, viadev->tbl_entries,
+                       dev_dbg(chip->card->dev,
+                               "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n",
+                               idx, viadev->tbl_entries,
                               viadev->lastpos, viadev->bufsize2,
                               viadev->idx_table[idx].offset,
                               viadev->idx_table[idx].size, count);
@@ -817,8 +822,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
                        /* count register returns full size when end of buffer is reached */
                        res = base + size;
                        if (check_invalid_pos(viadev, res)) {
-                               snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), "
-                                          "using last valid pointer\n");
+                               dev_dbg(chip->card->dev,
+                                       "invalid via82xx_cur_ptr (2), using last valid pointer\n");
                                res = viadev->lastpos;
                        }
                }
@@ -850,7 +855,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
                idx = 0;
        else /* CURR_PTR holds the address + 8 */
                idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries;
-       res = calc_linear_pos(viadev, idx, count);
+       res = calc_linear_pos(chip, viadev, idx, count);
        viadev->lastpos = res; /* remember the last position */
        spin_unlock(&chip->reg_lock);
 
@@ -889,13 +894,14 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst
                idx = count >> 24;
                if (idx >= viadev->tbl_entries) {
 #ifdef POINTER_DEBUG
-                       printk(KERN_DEBUG "fail: invalid idx = %i/%i\n", idx,
+                       dev_dbg(chip->card->dev,
+                               "fail: invalid idx = %i/%i\n", idx,
                               viadev->tbl_entries);
 #endif
                        res = viadev->lastpos;
                } else {
                        count &= 0xffffff;
-                       res = calc_linear_pos(viadev, idx, count);
+                       res = calc_linear_pos(chip, viadev, idx, count);
                }
        } else {
                res = viadev->hwptr_done;
@@ -1940,14 +1946,15 @@ static int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legac
 
        r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport");
        if (!r) {
-               printk(KERN_WARNING "via82xx: cannot reserve joystick port %#x\n",
+               dev_warn(chip->card->dev, "cannot reserve joystick port %#x\n",
                       JOYSTICK_ADDR);
                return -EBUSY;
        }
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                release_and_free_resource(r);
                return -ENOMEM;
        }
@@ -2016,7 +2023,8 @@ static int snd_via8233_init_misc(struct via82xx *chip)
                strcpy(sid.name, "PCM Playback Volume");
                sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
                if (! snd_ctl_find_id(chip->card, &sid)) {
-                       snd_printd(KERN_INFO "Using DXS as PCM Playback\n");
+                       dev_info(chip->card->dev,
+                                "Using DXS as PCM Playback\n");
                        err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip));
                        if (err < 0)
                                return err;
@@ -2102,8 +2110,9 @@ static int snd_via686_init_misc(struct via82xx *chip)
                                        mpu_port, MPU401_INFO_INTEGRATED |
                                        MPU401_INFO_IRQ_HOOK, -1,
                                        &chip->rmidi) < 0) {
-                       printk(KERN_WARNING "unable to initialize MPU-401"
-                              " at 0x%lx, skipping\n", mpu_port);
+                       dev_warn(chip->card->dev,
+                                "unable to initialize MPU-401 at 0x%lx, skipping\n",
+                                mpu_port);
                        legacy &= ~VIA_FUNC_ENABLE_MIDI;
                } else {
                        legacy &= ~VIA_FUNC_MIDI_IRQMASK;       /* enable MIDI interrupt */
@@ -2203,7 +2212,8 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
        } while (time_before(jiffies, end_time));
 
        if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
-               snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val);
+               dev_err(chip->card->dev,
+                       "AC'97 codec is not ready [0x%x]\n", val);
 
 #if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */
        snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
@@ -2303,8 +2313,7 @@ static int snd_via82xx_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "via82xx: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2417,7 +2426,7 @@ static int snd_via82xx_create(struct snd_card *card,
                        snd_via8233_interrupt : snd_via686_interrupt,
                        IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_via82xx_free(chip);
                return -EBUSY;
        }
@@ -2441,8 +2450,6 @@ static int snd_via82xx_create(struct snd_card *card,
         * We call pci_set_master here because it does not hurt. */
        pci_set_master(pci);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_via = chip;
        return 0;
 }
@@ -2516,7 +2523,7 @@ static int check_dxs_list(struct pci_dev *pci, int revision)
 
        w = snd_pci_quirk_lookup(pci, dxs_whitelist);
        if (w) {
-               snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
+               dev_dbg(&pci->dev, "DXS white list for %s found\n",
                            snd_pci_quirk_name(w));
                return w->value;
        }
@@ -2528,10 +2535,10 @@ static int check_dxs_list(struct pci_dev *pci, int revision)
        /*
         * not detected, try 48k rate only to be sure.
         */
-       printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n");
-       printk(KERN_INFO "         Please try dxs_support=5 option\n");
-       printk(KERN_INFO "         and report if it works on your machine.\n");
-       printk(KERN_INFO "         For more details, read ALSA-Configuration.txt.\n");
+       dev_info(&pci->dev, "Assuming DXS channels with 48k fixed sample rate.\n");
+       dev_info(&pci->dev, "         Please try dxs_support=5 option\n");
+       dev_info(&pci->dev, "         and report if it works on your machine.\n");
+       dev_info(&pci->dev, "         For more details, read ALSA-Configuration.txt.\n");
        return VIA_DXS_48K;
 };
 
@@ -2544,7 +2551,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
        unsigned int i;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -2584,7 +2591,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
                        strcpy(card->driver, "VIA8233");
                break;
        default:
-               snd_printk(KERN_ERR "invalid card type %d\n", card_type);
+               dev_err(card->dev, "invalid card type %d\n", card_type);
                err = -EINVAL;
                goto __error;
        }
index ca190283cbd7745f50d4ec4ffeaf74726ea3afc1..46a0526b1d7902ab81e4a29d7fb2ce1506410f67 100644 (file)
@@ -312,7 +312,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                        unsigned int addr;
 
                        if (idx >= VIA_TABLE_SIZE) {
-                               snd_printk(KERN_ERR "via82xx: too much table size!\n");
+                               dev_err(&pci->dev, "too much table size!\n");
                                return -EINVAL;
                        }
                        addr = snd_pcm_sgbuf_get_addr(substream, ofs);
@@ -329,8 +329,9 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
                        } else
                                flag = 0; /* period continues to the next */
                        /*
-                       printk(KERN_DEBUG "via: tbl %d: at %d  size %d "
-                              "(rest %d)\n", idx, ofs, r, rest);
+                       dev_dbg(&pci->dev,
+                               "tbl %d: at %d  size %d (rest %d)\n",
+                               idx, ofs, r, rest);
                        */
                        ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
                        dev->idx_table[idx].offset = ofs;
@@ -382,7 +383,7 @@ static int snd_via82xx_codec_ready(struct via82xx_modem *chip, int secondary)
                if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
                        return val & 0xffff;
        }
-       snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n",
+       dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n",
                   secondary, snd_via82xx_codec_xread(chip));
        return -EIO;
 }
@@ -443,7 +444,8 @@ static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned sho
        xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
        while (1) {
                if (again++ > 3) {
-                       snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n",
+                       dev_err(chip->card->dev,
+                               "codec_read: codec %i is not valid [0x%x]\n",
                                   ac97->num, snd_via82xx_codec_xread(chip));
                        return 0xffff;
                }
@@ -560,7 +562,9 @@ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        ((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\
                                     viadev->lastpos < viadev->bufsize2))
 
-static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx,
+static inline unsigned int calc_linear_pos(struct via82xx_modem *chip,
+                                          struct viadev *viadev,
+                                          unsigned int idx,
                                           unsigned int count)
 {
        unsigned int size, res;
@@ -570,20 +574,21 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
 
        /* check the validity of the calculated position */
        if (size < count) {
-               snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
+               dev_err(chip->card->dev,
+                       "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
                           (int)size, (int)count);
                res = viadev->lastpos;
        } else if (check_invalid_pos(viadev, res)) {
 #ifdef POINTER_DEBUG
-               printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, "
-                      "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, "
-                      "count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos,
+               dev_dbg(chip->card->dev,
+                       "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n",
+                       idx, viadev->tbl_entries, viadev->lastpos,
                       viadev->bufsize2, viadev->idx_table[idx].offset,
                       viadev->idx_table[idx].size, count);
 #endif
                if (count && size < count) {
-                       snd_printd(KERN_ERR "invalid via82xx_cur_ptr, "
-                                  "using last valid pointer\n");
+                       dev_dbg(chip->card->dev,
+                               "invalid via82xx_cur_ptr, using last valid pointer\n");
                        res = viadev->lastpos;
                } else {
                        if (! count)
@@ -595,8 +600,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
                                 */
                                res = viadev->idx_table[idx].offset + size;
                        if (check_invalid_pos(viadev, res)) {
-                               snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), "
-                                          "using last valid pointer\n");
+                               dev_dbg(chip->card->dev,
+                                       "invalid via82xx_cur_ptr (2), using last valid pointer\n");
                                res = viadev->lastpos;
                        }
                }
@@ -632,7 +637,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
        else /* CURR_PTR holds the address + 8 */
                idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) %
                        viadev->tbl_entries;
-       res = calc_linear_pos(viadev, idx, count);
+       res = calc_linear_pos(chip, viadev, idx, count);
        spin_unlock(&chip->reg_lock);
 
        return bytes_to_frames(substream->runtime, res);
@@ -991,7 +996,8 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
        } while (time_before(jiffies, end_time));
 
        if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
-               snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val);
+               dev_err(chip->card->dev,
+                       "AC'97 codec is not ready [0x%x]\n", val);
 
        snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
                                 VIA_REG_AC97_SECONDARY_VALID |
@@ -1054,8 +1060,7 @@ static int snd_via82xx_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "via82xx-modem: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -1137,7 +1142,7 @@ static int snd_via82xx_create(struct snd_card *card,
        chip->port = pci_resource_start(pci, 0);
        if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_via82xx_free(chip);
                return -EBUSY;
        }
@@ -1161,8 +1166,6 @@ static int snd_via82xx_create(struct snd_card *card,
         * We call pci_set_master here because it does not hurt. */
        pci_set_master(pci);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *r_via = chip;
        return 0;
 }
@@ -1177,7 +1180,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
        unsigned int i;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -1188,7 +1191,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
                sprintf(card->shortname, "VIA 82XX modem");
                break;
        default:
-               snd_printk(KERN_ERR "invalid card type %d\n", card_type);
+               dev_err(card->dev, "invalid card type %d\n", card_type);
                err = -EINVAL;
                goto __error;
        }
index ab8a9b1bfb8e21933290e86be80a4f8a6459313b..ff9074d22607a7a640105d304c784aca644989b1 100644 (file)
@@ -170,7 +170,7 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci,
 
        if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_vx222_free(chip);
                return -EBUSY;
        }
@@ -181,8 +181,6 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci,
                return err;
        }
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = vx;
        return 0;
 }
@@ -204,7 +202,8 @@ static int snd_vx222_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -229,7 +228,7 @@ static int snd_vx222_probe(struct pci_dev *pci,
 
        sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %i",
                card->shortname, vx->port[0], vx->port[1], vx->core.irq);
-       snd_printdd("%s at 0x%lx & 0x%lx, irq %i\n",
+       dev_dbg(card->dev, "%s at 0x%lx & 0x%lx, irq %i\n",
                    card->shortname, vx->port[0], vx->port[1], vx->core.irq);
 
 #ifdef SND_VX_FW_LOADER
@@ -280,8 +279,7 @@ static int snd_vx222_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "vx222: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
index a69e774d0b138f46d373cab95bb78858e04c1f11..2d1570273e99eb6d77bfcf03868c488af4554388 100644 (file)
@@ -108,7 +108,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val)
 {
        outb(val, vx2_reg_addr(chip, offset));
        /*
-       printk(KERN_DEBUG "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+       dev_dbg(chip->card->dev, "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
        */
 }
 
@@ -129,7 +129,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset)
 static void vx2_outl(struct vx_core *chip, int offset, unsigned int val)
 {
        /*
-       printk(KERN_DEBUG "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+       dev_dbg(chip->card->dev, "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
        */
        outl(val, vx2_reg_addr(chip, offset));
 }
@@ -173,7 +173,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
        struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
        unsigned int data;
 
-       snd_printdd("testing xilinx...\n");
+       dev_dbg(_chip->card->dev, "testing xilinx...\n");
        /* This test uses several write/read sequences on TEST0 and TEST1 bits
         * to figure out whever or not the xilinx was correctly loaded
         */
@@ -183,7 +183,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
        vx_inl(chip, ISR);
        data = vx_inl(chip, STATUS);
        if ((data & VX_STATUS_VAL_TEST0_MASK) == VX_STATUS_VAL_TEST0_MASK) {
-               snd_printdd("bad!\n");
+               dev_dbg(_chip->card->dev, "bad!\n");
                return -ENODEV;
        }
 
@@ -192,7 +192,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
        vx_inl(chip, ISR);
        data = vx_inl(chip, STATUS);
        if (! (data & VX_STATUS_VAL_TEST0_MASK)) {
-               snd_printdd("bad! #2\n");
+               dev_dbg(_chip->card->dev, "bad! #2\n");
                return -ENODEV;
        }
 
@@ -203,7 +203,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
                vx_inl(chip, ISR);
                data = vx_inl(chip, STATUS);
                if ((data & VX_STATUS_VAL_TEST1_MASK) == VX_STATUS_VAL_TEST1_MASK) {
-                       snd_printdd("bad! #3\n");
+                       dev_dbg(_chip->card->dev, "bad! #3\n");
                        return -ENODEV;
                }
 
@@ -212,11 +212,11 @@ static int vx2_test_xilinx(struct vx_core *_chip)
                vx_inl(chip, ISR);
                data = vx_inl(chip, STATUS);
                if (! (data & VX_STATUS_VAL_TEST1_MASK)) {
-                       snd_printdd("bad! #4\n");
+                       dev_dbg(_chip->card->dev, "bad! #4\n");
                        return -ENODEV;
                }
        }
-       snd_printdd("ok, xilinx fine.\n");
+       dev_dbg(_chip->card->dev, "ok, xilinx fine.\n");
        return 0;
 }
 
@@ -397,7 +397,8 @@ static int vx2_load_xilinx_binary(struct vx_core *chip, const struct firmware *x
                i = vx_inl(chip, GPIOC);
                if (i & 0x0100)
                        return 0;
-               snd_printk(KERN_ERR "vx222: xilinx test failed after load, GPIOC=0x%x\n", i);
+               dev_err(chip->card->dev,
+                       "xilinx test failed after load, GPIOC=0x%x\n", i);
                return -EINVAL;
        }
 
index e8932b2e4a5dcce73f4a2417933d90cf618079cb..82eed164b27582324ce5dbc40588e32cd07302a4 100644 (file)
@@ -106,7 +106,8 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev,
                                        break;
                        }
                        if (!r) {
-                               printk(KERN_ERR "ymfpci: no gameport ports available\n");
+                               dev_err(chip->card->dev,
+                                       "no gameport ports available\n");
                                return -EBUSY;
                        }
                }
@@ -116,19 +117,22 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev,
                case 0x204: legacy_ctrl2 |= 2 << 6; break;
                case 0x205: legacy_ctrl2 |= 3 << 6; break;
                default:
-                       printk(KERN_ERR "ymfpci: invalid joystick port %#x", io_port);
+                       dev_err(chip->card->dev,
+                               "invalid joystick port %#x", io_port);
                        return -EINVAL;
                }
        }
 
        if (!r && !(r = request_region(io_port, 1, "YMFPCI gameport"))) {
-               printk(KERN_ERR "ymfpci: joystick port %#x is in use.\n", io_port);
+               dev_err(chip->card->dev,
+                       "joystick port %#x is in use.\n", io_port);
                return -EBUSY;
        }
 
        chip->gameport = gp = gameport_allocate_port();
        if (!gp) {
-               printk(KERN_ERR "ymfpci: cannot allocate memory for gameport\n");
+               dev_err(chip->card->dev,
+                       "cannot allocate memory for gameport\n");
                release_and_free_resource(r);
                return -ENOMEM;
        }
@@ -187,7 +191,8 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+                          0, &card);
        if (err < 0)
                return err;
 
@@ -313,7 +318,9 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
                                               MPU401_INFO_INTEGRATED |
                                               MPU401_INFO_IRQ_HOOK,
                                               -1, &chip->rawmidi)) < 0) {
-                       printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
+                       dev_warn(card->dev,
+                                "cannot initialize MPU401 at 0x%lx, skipping...\n",
+                                mpu_port[dev]);
                        legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
                        pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
                }
@@ -323,12 +330,14 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
                                           fm_port[dev],
                                           fm_port[dev] + 2,
                                           OPL3_HW_OPL3, 1, &opl3)) < 0) {
-                       printk(KERN_WARNING "ymfpci: cannot initialize FM OPL3 at 0x%lx, skipping...\n", fm_port[dev]);
+                       dev_warn(card->dev,
+                                "cannot initialize FM OPL3 at 0x%lx, skipping...\n",
+                                fm_port[dev]);
                        legacy_ctrl &= ~YMFPCI_LEGACY_FMEN;
                        pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
                } else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
                        snd_card_free(card);
-                       snd_printk(KERN_ERR "cannot create opl3 hwdep\n");
+                       dev_err(card->dev, "cannot create opl3 hwdep\n");
                        return err;
                }
        }
index d591c154fc58fc4a9aeb3a5407e500b24d7e4996..81c916a5eb96a09ba4f4cb8cec1f75339f9f2dca 100644 (file)
@@ -86,7 +86,9 @@ static int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary)
                        return 0;
                schedule_timeout_uninterruptible(1);
        } while (time_before(jiffies, end_time));
-       snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg));
+       dev_err(chip->card->dev,
+               "codec_ready: codec %i is not ready [0x%x]\n",
+               secondary, snd_ymfpci_readw(chip, reg));
        return -EBUSY;
 }
 
@@ -319,7 +321,7 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
                ypcm->last_pos = pos;
                if (ypcm->period_pos >= ypcm->period_size) {
                        /*
-                       printk(KERN_DEBUG
+                       dev_dbg(chip->card->dev,
                               "done - active_bank = 0x%x, start = 0x%x\n",
                               chip->active_bank,
                               voice->bank[chip->active_bank].start);
@@ -372,7 +374,7 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream
                if (ypcm->period_pos >= ypcm->period_size) {
                        ypcm->period_pos %= ypcm->period_size;
                        /*
-                       printk(KERN_DEBUG
+                       dev_dbg(chip->card->dev,
                               "done - active_bank = 0x%x, start = 0x%x\n",
                               chip->active_bank,
                               voice->bank[chip->active_bank].start);
@@ -2067,7 +2069,8 @@ static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
                               &chip->pci->dev);
        if (err >= 0) {
                if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) {
-                       snd_printk(KERN_ERR "DSP microcode has wrong size\n");
+                       dev_err(chip->card->dev,
+                               "DSP microcode has wrong size\n");
                        err = -EINVAL;
                }
        }
@@ -2082,8 +2085,8 @@ static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
                               &chip->pci->dev);
        if (err >= 0) {
                if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) {
-                       snd_printk(KERN_ERR "controller microcode"
-                                  " has wrong size\n");
+                       dev_err(chip->card->dev,
+                               "controller microcode has wrong size\n");
                        err = -EINVAL;
                }
        }
@@ -2360,8 +2363,7 @@ static int snd_ymfpci_resume(struct device *dev)
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "ymfpci: pci_enable_device failed, "
-                      "disabling device\n");
+               dev_err(dev, "pci_enable_device failed, disabling device\n");
                snd_card_disconnect(card);
                return -EIO;
        }
@@ -2433,13 +2435,15 @@ int snd_ymfpci_create(struct snd_card *card,
        chip->src441_used = -1;
 
        if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) {
-               snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
+               dev_err(chip->card->dev,
+                       "unable to grab memory region 0x%lx-0x%lx\n",
+                       chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
                snd_ymfpci_free(chip);
                return -EBUSY;
        }
        if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, chip)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
                snd_ymfpci_free(chip);
                return -EBUSY;
        }
@@ -2453,7 +2457,7 @@ int snd_ymfpci_create(struct snd_card *card,
 
        err = snd_ymfpci_request_firmware(chip);
        if (err < 0) {
-               snd_printk(KERN_ERR "firmware request failed: %d\n", err);
+               dev_err(chip->card->dev, "firmware request failed: %d\n", err);
                snd_ymfpci_free(chip);
                return err;
        }
@@ -2487,8 +2491,6 @@ int snd_ymfpci_create(struct snd_card *card,
 
        snd_ymfpci_proc_init(card, chip);
 
-       snd_card_set_dev(card, &pci->dev);
-
        *rchip = chip;
        return 0;
 }
index 8f489de5c4c6101567263c1deaa1b6bc5c0db080..56bda124cd4acfda66a3865761c2ffa1208009f7 100644 (file)
@@ -112,7 +112,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
                return -ENODEV; /* disabled explicitly */
 
        /* ok, create a card instance */
-       err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+       err = snd_card_new(&link->dev, index[i], id[i], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
                snd_printk(KERN_ERR "pdacf: cannot create a card instance\n");
                return err;
@@ -131,8 +132,6 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
                return err;
        }
 
-       snd_card_set_dev(card, &link->dev);
-
        pdacf->index = i;
        card_list[i] = card;
 
index d4db7ecaa6bf5c1aec13a0fdcbd12778c521af35..786e7e139c9eeae713a57ab334ea08bd1c6ce6f1 100644 (file)
@@ -238,7 +238,6 @@ static int vxpocket_config(struct pcmcia_device *link)
                goto failed;
 
        chip->dev = &link->dev;
-       snd_card_set_dev(chip->card, chip->dev);
 
        if (snd_vxpocket_assign_resources(chip, link->resource[0]->start,
                                                link->irq) < 0)
@@ -307,7 +306,8 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
                return -ENODEV; /* disabled explicitly */
 
        /* ok, create a card instance */
-       err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+       err = snd_card_new(&p_dev->dev, index[i], id[i], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
                snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
                return err;
index 8abb521b4814b413a9423edf48bf2d7e41c08e2e..350a7c8f86dd4ef83b464cb994acdcba0b202727 100644 (file)
@@ -58,7 +58,7 @@ static int snd_pmac_probe(struct platform_device *devptr)
        char *name_ext;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
@@ -122,8 +122,6 @@ static int snd_pmac_probe(struct platform_device *devptr)
        if (enable_beep)
                snd_pmac_attach_beep(chip);
 
-       snd_card_set_dev(card, &devptr->dev);
-
        if ((err = snd_card_register(card)) < 0)
                goto __error;
 
index ebb76f2d90d790175cbb35b93ffa1213f258a299..58f292a87f98fcc7eae969b4676b7feb487e4dfa 100644 (file)
@@ -984,7 +984,8 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
        }
 
        /* create card instance */
-       ret = snd_card_create(index, id, THIS_MODULE, 0, &the_card.card);
+       ret = snd_card_new(&dev->core, index, id, THIS_MODULE,
+                          0, &the_card.card);
        if (ret < 0)
                goto clean_irq;
 
@@ -1052,7 +1053,6 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
        snd_ps3_init_avsetting(&the_card);
 
        /* register the card */
-       snd_card_set_dev(the_card.card, &dev->core);
        ret = snd_card_register(the_card.card);
        if (ret < 0)
                goto clean_dma_map;
index 78a369785a9ecf3b3e8d1a72e6b536e6a8ddb89a..47849eaf266d5c1e2ba17ddd50edf4dda6381d92 100644 (file)
@@ -608,8 +608,8 @@ static int snd_aica_probe(struct platform_device *devptr)
        dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
        if (unlikely(!dreamcastcard))
                return -ENOMEM;
-       err = snd_card_create(index, SND_AICA_DRIVER, THIS_MODULE, 0,
-                             &dreamcastcard->card);
+       err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
+                          THIS_MODULE, 0, &dreamcastcard->card);
        if (unlikely(err < 0)) {
                kfree(dreamcastcard);
                return err;
@@ -624,7 +624,6 @@ static int snd_aica_probe(struct platform_device *devptr)
        err = snd_aicapcmchip(dreamcastcard, 0);
        if (unlikely(err < 0))
                goto freedreamcast;
-       snd_card_set_dev(dreamcastcard->card, &devptr->dev);
        dreamcastcard->timer.data = 0;
        dreamcastcard->channel = NULL;
        /* Add basic controls */
index 7c9422c4fc0f99097c0b3b6197a1dc0ff8165099..d1fb74dabbd11f4fd8019cf79c7ca9c3749c2f88 100644 (file)
@@ -396,7 +396,7 @@ static int snd_sh_dac_probe(struct platform_device *devptr)
        struct snd_card *card;
        int err;
 
-       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
        if (err < 0) {
                        snd_printk(KERN_ERR "cannot allocate the card\n");
                        return err;
index d62ce483a443a5298688f51462e807e6ea1b2cb4..0060b31cc3f3d7ffa9f6538985cf1231d9389685 100644 (file)
@@ -50,6 +50,7 @@ source "sound/soc/pxa/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/sirf/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
index 62a1822e77bf6f42410fd68c6d539c8cf97c922f..5f1df02984f82b15815f92ce0e0639be4a7c6ddb 100644 (file)
@@ -27,6 +27,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)  += sirf/
 obj-$(CONFIG_SND_SOC)  += spear/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
index e634eb78ed03be1c76e2782c1215fd84f208e4da..4789619a52d86dc38b8da2222b11cbda50dd0a8c 100644 (file)
@@ -58,6 +58,6 @@ config SND_AT91_SOC_AFEB9260
        depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
        select SND_ATMEL_SOC_PDC
        select SND_ATMEL_SOC_SSC
-       select SND_SOC_TLV320AIC23
+       select SND_SOC_TLV320AIC23_I2C
        help
          Say Y here to support sound on AFEB9260 board.
index 1ead3c977a51743619b0bb2084ec174b7cf867a8..de433cfd044ce2c2ce6599766e4d7cedef5798b3 100644 (file)
@@ -341,6 +341,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 {
        int id = dai->id;
        struct atmel_ssc_info *ssc_p = &ssc_info[id];
+       struct ssc_device *ssc = ssc_p->ssc;
        struct atmel_pcm_dma_params *dma_params;
        int dir, channels, bits;
        u32 tfmr, rfmr, tcmr, rcmr;
@@ -466,7 +467,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(RCMR_START, start_event)
                        | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
                        | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
-                       | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK);
+                       | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_PIN : SSC_CKS_CLOCK);
 
                rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
                        | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
@@ -481,7 +483,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(TCMR_START, start_event)
                        | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
                        | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
-                       | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+                       | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_CLOCK : SSC_CKS_PIN);
 
                tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
                        | SSC_BF(TFMR_FSDEN, 0)
@@ -550,7 +553,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(RCMR_START, SSC_START_RISING_RF)
                        | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
                        | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
-                       | SSC_BF(RCMR_CKS, SSC_CKS_PIN);
+                       | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_PIN : SSC_CKS_CLOCK);
 
                rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
                        | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
@@ -565,7 +569,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(TCMR_START, SSC_START_RISING_RF)
                        | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
                        | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
-                       | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+                       | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_CLOCK : SSC_CKS_PIN);
 
                tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
                        | SSC_BF(TFMR_FSDEN, 0)
index f15bff1548f8fceb86c3f466201aab13107d9816..174bd546c08b0814bf45a999b307aa9b67e69ad4 100644 (file)
@@ -155,25 +155,14 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       /* Add specific widgets */
-       snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets,
-                                 ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
-       /* Set up specific audio path interconnects */
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
        /* not connected */
        snd_soc_dapm_nc_pin(dapm, "RLINEIN");
        snd_soc_dapm_nc_pin(dapm, "LLINEIN");
 
-#ifdef ENABLE_MIC_INPUT
-       snd_soc_dapm_enable_pin(dapm, "Int Mic");
-#else
-       snd_soc_dapm_nc_pin(dapm, "Int Mic");
+#ifndef ENABLE_MIC_INPUT
+       snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
 #endif
 
-       /* always connected */
-       snd_soc_dapm_enable_pin(dapm, "Ext Spk");
-
        return 0;
 }
 
@@ -194,6 +183,11 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
        .dai_link = &at91sam9g20ek_dai,
        .num_links = 1,
        .set_bias_level = at91sam9g20ek_set_bias_level,
+
+       .dapm_widgets = at91sam9g20ek_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
+       .dapm_routes = intercon,
+       .num_dapm_routes = ARRAY_SIZE(intercon),
 };
 
 static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
index 4544d8eb1452b24638c969ed15432a6f41e98ef8..6347d5910138cbcd5eef0478b0fb53bca9636de6 100644 (file)
@@ -14,7 +14,8 @@ config SND_BF5XX_SOC_SSM2602
        depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S if !BF60x
        select SND_BF6XX_SOC_I2S if BF60x
-       select SND_SOC_SSM2602
+       select SND_SOC_SSM2602_SPI if SPI_MASTER
+       select SND_SOC_SSM2602_I2C if I2C
        help
          Say Y if you want to add support for the Analog Devices
          SSM2602 Audio Codec Add-On Card.
@@ -46,7 +47,8 @@ config SND_SOC_BFIN_EVAL_ADAV80X
        tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
        depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S
-       select SND_SOC_ADAV80X
+       select SND_SOC_ADAV801 if SPI_MASTER
+       select SND_SOC_ADAV803 if I2C
        help
          Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
          EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
@@ -67,7 +69,8 @@ config SND_BF5XX_SOC_AD193X
        tristate "SoC AD193X Audio support for Blackfin"
        depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S
-       select SND_SOC_AD193X
+       select SND_SOC_AD193X_I2C if I2C
+       select SND_SOC_AD193X_SPI if SPI_MASTER
        help
          Say Y if you want to add support for AD193X codec on Blackfin.
          This driver supports AD1936, AD1937, AD1938 and AD1939.
index 06f938deda15bd0d888e7e6140d54f10ec9331b5..5477c54759230e7783af1fd6df7bb1a20bcfb122 100644 (file)
@@ -1,6 +1,6 @@
 config SND_EP93XX_SOC
        tristate "SoC Audio support for the Cirrus Logic EP93xx series"
-       depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC
+       depends on ARCH_EP93XX || COMPILE_TEST
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
@@ -18,7 +18,7 @@ config SND_EP93XX_SOC_SNAPPERCL15
         tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
         depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
         select SND_EP93XX_SOC_I2S
-        select SND_SOC_TLV320AIC23
+        select SND_SOC_TLV320AIC23_I2C
         help
           Say Y or M here if you want to add support for I2S audio on the
           Bluewater Systems Snapper CL15 module.
index 29238a7476dd87e002d7500d0fffb3f37eada3d0..5b68b106cfc2161c95f5c1b1845d8646b152945f 100644 (file)
@@ -65,18 +65,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
-                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-       return 0;
-}
-
 static struct snd_soc_dai_link snappercl15_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "AIC23",
@@ -84,7 +72,6 @@ static struct snd_soc_dai_link snappercl15_dai = {
        .codec_dai_name = "tlv320aic23-hifi",
        .codec_name     = "tlv320aic23-codec.0-001a",
        .platform_name  = "ep93xx-i2s",
-       .init           = snappercl15_tlv320aic23_init,
        .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
                          SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &snappercl15_ops,
@@ -95,6 +82,11 @@ static struct snd_soc_card snd_soc_snappercl15 = {
        .owner          = THIS_MODULE,
        .dai_link       = &snappercl15_dai,
        .num_links      = 1,
+
+       .dapm_widgets           = tlv320aic23_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+       .dapm_routes            = audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(audio_map),
 };
 
 static int snappercl15_probe(struct platform_device *pdev)
index 75d0ad5d2dcb38107934536ba7ef93410025c2f6..b07e17160f94a0453cf080cc487da4874f930673 100644 (file)
@@ -448,38 +448,38 @@ static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
 
 static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
 
-static const struct soc_enum pm860x_hs1_opamp_enum =
-       SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum,
+                           PM860X_HS1_CTRL, 5, pm860x_opamp_texts);
 
-static const struct soc_enum pm860x_hs2_opamp_enum =
-       SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum,
+                           PM860X_HS2_CTRL, 5, pm860x_opamp_texts);
 
-static const struct soc_enum pm860x_hs1_pa_enum =
-       SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum,
+                           PM860X_HS1_CTRL, 3, pm860x_pa_texts);
 
-static const struct soc_enum pm860x_hs2_pa_enum =
-       SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum,
+                           PM860X_HS2_CTRL, 3, pm860x_pa_texts);
 
-static const struct soc_enum pm860x_lo1_opamp_enum =
-       SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum,
+                           PM860X_LO1_CTRL, 5, pm860x_opamp_texts);
 
-static const struct soc_enum pm860x_lo2_opamp_enum =
-       SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum,
+                           PM860X_LO2_CTRL, 5, pm860x_opamp_texts);
 
-static const struct soc_enum pm860x_lo1_pa_enum =
-       SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum,
+                           PM860X_LO1_CTRL, 3, pm860x_pa_texts);
 
-static const struct soc_enum pm860x_lo2_pa_enum =
-       SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum,
+                           PM860X_LO2_CTRL, 3, pm860x_pa_texts);
 
-static const struct soc_enum pm860x_spk_pa_enum =
-       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum,
+                           PM860X_EAR_CTRL_1, 5, pm860x_pa_texts);
 
-static const struct soc_enum pm860x_ear_pa_enum =
-       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum,
+                           PM860X_EAR_CTRL_2, 0, pm860x_pa_texts);
 
-static const struct soc_enum pm860x_spk_ear_opamp_enum =
-       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum,
+                           PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts);
 
 static const struct snd_kcontrol_new pm860x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
@@ -561,8 +561,8 @@ static const char *aif1_text[] = {
        "PCM L", "PCM R",
 };
 
-static const struct soc_enum aif1_enum =
-       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+static SOC_ENUM_SINGLE_DECL(aif1_enum,
+                           PM860X_PCM_IFACE_3, 6, aif1_text);
 
 static const struct snd_kcontrol_new aif1_mux =
        SOC_DAPM_ENUM("PCM Mux", aif1_enum);
@@ -572,8 +572,8 @@ static const char *i2s_din_text[] = {
        "DIN", "DIN1",
 };
 
-static const struct soc_enum i2s_din_enum =
-       SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+static SOC_ENUM_SINGLE_DECL(i2s_din_enum,
+                           PM860X_I2S_IFACE_3, 1, i2s_din_text);
 
 static const struct snd_kcontrol_new i2s_din_mux =
        SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
@@ -583,8 +583,8 @@ static const char *i2s_mic_text[] = {
        "Ex PA", "ADC",
 };
 
-static const struct soc_enum i2s_mic_enum =
-       SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+static SOC_ENUM_SINGLE_DECL(i2s_mic_enum,
+                           PM860X_I2S_IFACE_3, 4, i2s_mic_text);
 
 static const struct snd_kcontrol_new i2s_mic_mux =
        SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
@@ -594,8 +594,8 @@ static const char *adcl_text[] = {
        "ADCR", "ADCL",
 };
 
-static const struct soc_enum adcl_enum =
-       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+static SOC_ENUM_SINGLE_DECL(adcl_enum,
+                           PM860X_PCM_IFACE_3, 4, adcl_text);
 
 static const struct snd_kcontrol_new adcl_mux =
        SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
@@ -605,8 +605,8 @@ static const char *adcr_text[] = {
        "ADCL", "ADCR",
 };
 
-static const struct soc_enum adcr_enum =
-       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+static SOC_ENUM_SINGLE_DECL(adcr_enum,
+                           PM860X_PCM_IFACE_3, 2, adcr_text);
 
 static const struct snd_kcontrol_new adcr_mux =
        SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
@@ -616,8 +616,8 @@ static const char *adcr_ec_text[] = {
        "ADCR", "EC",
 };
 
-static const struct soc_enum adcr_ec_enum =
-       SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+static SOC_ENUM_SINGLE_DECL(adcr_ec_enum,
+                           PM860X_ADC_EN_2, 3, adcr_ec_text);
 
 static const struct snd_kcontrol_new adcr_ec_mux =
        SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
@@ -627,8 +627,8 @@ static const char *ec_text[] = {
        "Left", "Right", "Left + Right",
 };
 
-static const struct soc_enum ec_enum =
-       SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+static SOC_ENUM_SINGLE_DECL(ec_enum,
+                           PM860X_EC_PATH, 1, ec_text);
 
 static const struct snd_kcontrol_new ec_mux =
        SOC_DAPM_ENUM("EC Mux", ec_enum);
@@ -638,36 +638,36 @@ static const char *dac_text[] = {
 };
 
 /* DAC Headset 1 Mux / Mux10 */
-static const struct soc_enum dac_hs1_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_hs1_enum,
+                           PM860X_ANA_INPUT_SEL_1, 0, dac_text);
 
 static const struct snd_kcontrol_new dac_hs1_mux =
        SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
 
 /* DAC Headset 2 Mux / Mux11 */
-static const struct soc_enum dac_hs2_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_hs2_enum,
+                           PM860X_ANA_INPUT_SEL_1, 2, dac_text);
 
 static const struct snd_kcontrol_new dac_hs2_mux =
        SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
 
 /* DAC Lineout 1 Mux / Mux12 */
-static const struct soc_enum dac_lo1_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_lo1_enum,
+                           PM860X_ANA_INPUT_SEL_1, 4, dac_text);
 
 static const struct snd_kcontrol_new dac_lo1_mux =
        SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
 
 /* DAC Lineout 2 Mux / Mux13 */
-static const struct soc_enum dac_lo2_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_lo2_enum,
+                           PM860X_ANA_INPUT_SEL_1, 6, dac_text);
 
 static const struct snd_kcontrol_new dac_lo2_mux =
        SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
 
 /* DAC Spearker Earphone Mux / Mux14 */
-static const struct soc_enum dac_spk_ear_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum,
+                           PM860X_ANA_INPUT_SEL_2, 0, dac_text);
 
 static const struct snd_kcontrol_new dac_spk_ear_mux =
        SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
@@ -677,29 +677,29 @@ static const char *in_text[] = {
        "Digital", "Analog",
 };
 
-static const struct soc_enum hs1_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(hs1_enum,
+                           PM860X_ANA_TO_ANA, 0, in_text);
 
 static const struct snd_kcontrol_new hs1_mux =
        SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
 
 /* Headset 2 Mux / Mux16 */
-static const struct soc_enum hs2_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(hs2_enum,
+                           PM860X_ANA_TO_ANA, 1, in_text);
 
 static const struct snd_kcontrol_new hs2_mux =
        SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
 
 /* Lineout 1 Mux / Mux17 */
-static const struct soc_enum lo1_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(lo1_enum,
+                           PM860X_ANA_TO_ANA, 2, in_text);
 
 static const struct snd_kcontrol_new lo1_mux =
        SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
 
 /* Lineout 2 Mux / Mux18 */
-static const struct soc_enum lo2_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(lo2_enum,
+                           PM860X_ANA_TO_ANA, 3, in_text);
 
 static const struct snd_kcontrol_new lo2_mux =
        SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
@@ -709,8 +709,8 @@ static const char *spk_text[] = {
        "Earpiece", "Speaker",
 };
 
-static const struct soc_enum spk_enum =
-       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+static SOC_ENUM_SINGLE_DECL(spk_enum,
+                           PM860X_ANA_TO_ANA, 6, spk_text);
 
 static const struct snd_kcontrol_new spk_demux =
        SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
@@ -720,8 +720,8 @@ static const char *mic_text[] = {
        "Mic 1", "Mic 2",
 };
 
-static const struct soc_enum mic_enum =
-       SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+static SOC_ENUM_SINGLE_DECL(mic_enum,
+                           PM860X_ADC_ANA_4, 4, mic_text);
 
 static const struct snd_kcontrol_new mic_mux =
        SOC_DAPM_ENUM("MIC Mux", mic_enum);
@@ -1327,7 +1327,9 @@ static int pm860x_probe(struct snd_soc_codec *codec)
 
        pm860x->codec = codec;
 
-       codec->control_data = pm860x->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, pm860x->regmap);
+       if (ret)
+               return ret;
 
        for (i = 0; i < 4; i++) {
                ret = request_threaded_irq(pm860x->irq[i], NULL,
index 983d087aa92aa83125903dc18cd420f57c2009eb..f0e8401378873721f0e69e7fe338fe00afe29fb5 100644 (file)
@@ -8,6 +8,8 @@ config SND_SOC_I2C_AND_SPI
        default y if I2C=y
        default y if SPI_MASTER=y
 
+menu "CODEC drivers"
+
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
        depends on COMPILE_TEST
@@ -16,15 +18,20 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AB8500_CODEC if ABX500_CORE
        select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
        select SND_SOC_AD1836 if SPI_MASTER
-       select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
+       select SND_SOC_AD193X_SPI if SPI_MASTER
+       select SND_SOC_AD193X_I2C if I2C
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
        select SND_SOC_AD73311
        select SND_SOC_ADAU1373 if I2C
-       select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+       select SND_SOC_ADAV801 if SPI_MASTER
+       select SND_SOC_ADAV803 if I2C
+       select SND_SOC_ADAU1977_SPI if SPI_MASTER
+       select SND_SOC_ADAU1977_I2C if I2C
        select SND_SOC_ADAU1701 if I2C
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
+       select SND_SOC_AK4554
        select SND_SOC_AK4641 if I2C
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
@@ -37,6 +44,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CS42L73 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_CS42XX8_I2C if I2C
        select SND_SOC_CX20442 if TTY
        select SND_SOC_DA7210 if I2C
        select SND_SOC_DA7213 if I2C
@@ -59,20 +67,26 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_PCM1681 if I2C
        select SND_SOC_PCM1792A if SPI_MASTER
        select SND_SOC_PCM3008
+       select SND_SOC_PCM512x_I2C if I2C
+       select SND_SOC_PCM512x_SPI if SPI_MASTER
        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_SIRF_AUDIO_CODEC
        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_SSM2602_SPI if SPI_MASTER
+       select SND_SOC_SSM2602_I2C if I2C
        select SND_SOC_STA32X if I2C
        select SND_SOC_STA529 if I2C
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
        select SND_SOC_TAS5086 if I2C
-       select SND_SOC_TLV320AIC23 if I2C
+       select SND_SOC_TLV320AIC23_I2C if I2C
+       select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
        select SND_SOC_TLV320AIC26 if SPI_MASTER
+       select SND_SOC_TLV320AIC31XX if I2C
        select SND_SOC_TLV320AIC32X4 if I2C
        select SND_SOC_TLV320AIC3X if I2C
        select SND_SOC_TPA6130A2 if I2C
@@ -182,6 +196,14 @@ config SND_SOC_AD1836
 config SND_SOC_AD193X
        tristate
 
+config SND_SOC_AD193X_SPI
+       tristate
+       select SND_SOC_AD193X
+
+config SND_SOC_AD193X_I2C
+       tristate
+       select SND_SOC_AD193X
+
 config SND_SOC_AD1980
        tristate
 
@@ -189,41 +211,66 @@ config SND_SOC_AD73311
        tristate
 
 config SND_SOC_ADAU1701
+       tristate "Analog Devices ADAU1701 CODEC"
+       depends on I2C
        select SND_SOC_SIGMADSP
-       tristate
 
 config SND_SOC_ADAU1373
        tristate
 
+config SND_SOC_ADAU1977
+       tristate
+
+config SND_SOC_ADAU1977_SPI
+       tristate
+       select SND_SOC_ADAU1977
+       select REGMAP_SPI
+
+config SND_SOC_ADAU1977_I2C
+       tristate
+       select SND_SOC_ADAU1977
+       select REGMAP_I2C
+
 config SND_SOC_ADAV80X
        tristate
 
+config SND_SOC_ADAV801
+       tristate
+       select SND_SOC_ADAV80X
+
+config SND_SOC_ADAV803
+       tristate
+       select SND_SOC_ADAV80X
+
 config SND_SOC_ADS117X
        tristate
 
 config SND_SOC_AK4104
-       tristate
+       tristate "AKM AK4104 CODEC"
+       depends on SPI_MASTER
 
 config SND_SOC_AK4535
        tristate
 
 config SND_SOC_AK4554
-       tristate
+       tristate "AKM AK4554 CODEC"
 
 config SND_SOC_AK4641
        tristate
 
 config SND_SOC_AK4642
-       tristate
+       tristate "AKM AK4642 CODEC"
+       depends on I2C
 
 config SND_SOC_AK4671
        tristate
 
 config SND_SOC_AK5386
-       tristate
+       tristate "AKM AK5638 CODEC"
 
 config SND_SOC_ALC5623
        tristate
+
 config SND_SOC_ALC5632
        tristate
 
@@ -234,14 +281,17 @@ config SND_SOC_CS42L51
        tristate
 
 config SND_SOC_CS42L52
-       tristate
+       tristate "Cirrus Logic CS42L52 CODEC"
+       depends on I2C
 
 config SND_SOC_CS42L73
-       tristate
+       tristate "Cirrus Logic CS42L73 CODEC"
+       depends on I2C
 
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
-       tristate
+       tristate "Cirrus Logic CS4270 CODEC"
+       depends on I2C
 
 # Cirrus Logic CS4270 Codec VD = 3.3V Errata
 # Select if you are affected by the errata where the part will not function
@@ -252,8 +302,18 @@ config SND_SOC_CS4270_VD33_ERRATA
        depends on SND_SOC_CS4270
 
 config SND_SOC_CS4271
+       tristate "Cirrus Logic CS4271 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_CS42XX8
        tristate
 
+config SND_SOC_CS42XX8_I2C
+       tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
+       depends on I2C
+       select SND_SOC_CS42XX8
+       select REGMAP_I2C
+
 config SND_SOC_CX20442
        tristate
        depends on TTY
@@ -283,6 +343,9 @@ config SND_SOC_BT_SCO
 config SND_SOC_DMIC
        tristate
 
+config SND_SOC_HDMI_CODEC
+       tristate "HDMI stub CODEC"
+
 config SND_SOC_ISABELLE
         tristate
 
@@ -301,18 +364,32 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX9850
        tristate
 
-config SND_SOC_HDMI_CODEC
-       tristate
-
 config SND_SOC_PCM1681
-       tristate
+       tristate "Texas Instruments PCM1681 CODEC"
+       depends on I2C
 
 config SND_SOC_PCM1792A
-       tristate
+       tristate "Texas Instruments PCM1792A CODEC"
+       depends on SPI_MASTER
 
 config SND_SOC_PCM3008
        tristate
 
+config SND_SOC_PCM512x
+       tristate
+
+config SND_SOC_PCM512x_I2C
+       tristate "Texas Instruments PCM512x CODECs - I2C"
+       depends on I2C
+       select SND_SOC_PCM512x
+       select REGMAP_I2C
+
+config SND_SOC_PCM512x_SPI
+       tristate "Texas Instruments PCM512x CODECs - SPI"
+       depends on SPI_MASTER
+       select SND_SOC_PCM512x
+       select REGMAP_SPI
+
 config SND_SOC_RT5631
        tristate
 
@@ -321,7 +398,8 @@ config SND_SOC_RT5640
 
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
-       tristate
+       tristate "Freescale SGTL5000 CODEC"
+       depends on I2C
 
 config SND_SOC_SI476X
        tristate
@@ -330,11 +408,15 @@ config SND_SOC_SIGMADSP
        tristate
        select CRC32
 
+config SND_SOC_SIRF_AUDIO_CODEC
+       tristate "SiRF SoC internal audio codec"
+       select REGMAP_MMIO
+
 config SND_SOC_SN95031
        tristate
 
 config SND_SOC_SPDIF
-       tristate
+       tristate "S/PDIF CODEC"
 
 config SND_SOC_SSM2518
        tristate
@@ -342,6 +424,14 @@ config SND_SOC_SSM2518
 config SND_SOC_SSM2602
        tristate
 
+config SND_SOC_SSM2602_SPI
+       select SND_SOC_SSM2602
+       tristate
+
+config SND_SOC_SSM2602_I2C
+       select SND_SOC_SSM2602
+       tristate
+
 config SND_SOC_STA32X
        tristate
 
@@ -352,20 +442,33 @@ config SND_SOC_STAC9766
        tristate
 
 config SND_SOC_TAS5086
-       tristate
+       tristate "Texas Instruments TAS5086 speaker amplifier"
+       depends on I2C
 
 config SND_SOC_TLV320AIC23
        tristate
 
+config SND_SOC_TLV320AIC23_I2C
+       tristate
+       select SND_SOC_TLV320AIC23
+
+config SND_SOC_TLV320AIC23_SPI
+       tristate
+       select SND_SOC_TLV320AIC23
+
 config SND_SOC_TLV320AIC26
        tristate
        depends on SPI
 
+config SND_SOC_TLV320AIC31XX
+        tristate
+
 config SND_SOC_TLV320AIC32X4
        tristate
 
 config SND_SOC_TLV320AIC3X
-       tristate
+       tristate "Texas Instruments TLV320AIC3x CODECs"
+       depends on I2C
 
 config SND_SOC_TLV320DAC33
        tristate
@@ -414,55 +517,69 @@ config SND_SOC_WM8400
        tristate
 
 config SND_SOC_WM8510
-       tristate
+       tristate "Wolfson Microelectronics WM8510 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8523
-       tristate
+       tristate "Wolfson Microelectronics WM8523 DAC"
+       depends on I2C
 
 config SND_SOC_WM8580
-       tristate
+       tristate "Wolfson Microelectronics WM8523 CODEC"
+       depends on I2C
 
 config SND_SOC_WM8711
-       tristate
+       tristate "Wolfson Microelectronics WM8711 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8727
        tristate
 
 config SND_SOC_WM8728
-       tristate
+       tristate "Wolfson Microelectronics WM8728 DAC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8731
-       tristate
+       tristate "Wolfson Microelectronics WM8731 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8737
-       tristate
+       tristate "Wolfson Microelectronics WM8737 ADC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8741
-       tristate
+       tristate "Wolfson Microelectronics WM8737 DAC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8750
-       tristate
+       tristate "Wolfson Microelectronics WM8750 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8753
-       tristate
+       tristate "Wolfson Microelectronics WM8753 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8770
-       tristate
+       tristate "Wolfson Microelectronics WM8770 CODEC"
+       depends on SPI_MASTER
 
 config SND_SOC_WM8776
-       tristate
+       tristate "Wolfson Microelectronics WM8776 CODEC"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8782
        tristate
 
 config SND_SOC_WM8804
-       tristate
+       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
+       depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8900
        tristate
 
 config SND_SOC_WM8903
-       tristate
+       tristate "Wolfson Microelectronics WM8903 CODEC"
+       depends on I2C
 
 config SND_SOC_WM8904
        tristate
@@ -480,7 +597,8 @@ config SND_SOC_WM8961
        tristate
 
 config SND_SOC_WM8962
-       tristate
+       tristate "Wolfson Microelectronics WM8962 CODEC"
+       depends on I2C
 
 config SND_SOC_WM8971
        tristate
@@ -553,4 +671,7 @@ config SND_SOC_ML26124
        tristate
 
 config SND_SOC_TPA6130A2
-       tristate
+       tristate "Texas Instruments TPA6130A2 headphone amplifier"
+       depends on I2C
+
+endmenu
index bc126764a44d02cb38b50f3ae74900a9ce490da2..3c4d275d064bf8cc921c754a2dc577bdf72f4fe8 100644 (file)
@@ -3,11 +3,18 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
+snd-soc-ad193x-spi-objs := ad193x-spi.o
+snd-soc-ad193x-i2c-objs := ad193x-i2c.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-adau1701-objs := adau1701.o
 snd-soc-adau1373-objs := adau1373.o
+snd-soc-adau1977-objs := adau1977.o
+snd-soc-adau1977-spi-objs := adau1977-spi.o
+snd-soc-adau1977-i2c-objs := adau1977-i2c.o
 snd-soc-adav80x-objs := adav80x.o
+snd-soc-adav801-objs := adav801.o
+snd-soc-adav803-objs := adav803.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
@@ -23,6 +30,8 @@ snd-soc-cs42l52-objs := cs42l52.o
 snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs42xx8-objs := cs42xx8.o
+snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
@@ -46,6 +55,9 @@ snd-soc-hdmi-codec-objs := hdmi.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm512x-objs := pcm512x.o
+snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
+snd-soc-pcm512x-spi-objs := pcm512x-spi.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -53,19 +65,25 @@ 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-sirf-audio-codec-objs := sirf-audio-codec.o
 snd-soc-sn95031-objs := sn95031.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-ssm2602-spi-objs := ssm2602-spi.o
+snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
+snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
+snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
@@ -134,11 +152,18 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC)        += snd-soc-ab8500-codec.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)   += snd-soc-ad193x.o
+obj-$(CONFIG_SND_SOC_AD193X_SPI)       += snd-soc-ad193x-spi.o
+obj-$(CONFIG_SND_SOC_AD193X_I2C)       += snd-soc-ad193x-i2c.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
+obj-$(CONFIG_SND_SOC_ADAU1977)         += snd-soc-adau1977.o
+obj-$(CONFIG_SND_SOC_ADAU1977_SPI)     += snd-soc-adau1977-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1977_I2C)     += snd-soc-adau1977-i2c.o
 obj-$(CONFIG_SND_SOC_ADAU1701)  += snd-soc-adau1701.o
 obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o
+obj-$(CONFIG_SND_SOC_ADAV801)  += snd-soc-adav801.o
+obj-$(CONFIG_SND_SOC_ADAV803)  += snd-soc-adav803.o
 obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
@@ -156,6 +181,8 @@ obj-$(CONFIG_SND_SOC_CS42L52)       += snd-soc-cs42l52.o
 obj-$(CONFIG_SND_SOC_CS42L73)  += snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)   += snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS42XX8)  += snd-soc-cs42xx8.o
+obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)   += snd-soc-da7213.o
@@ -179,6 +206,9 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)  += snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM512x)  += snd-soc-pcm512x.o
+obj-$(CONFIG_SND_SOC_PCM512x_I2C)      += snd-soc-pcm512x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM512x_SPI)      += snd-soc-pcm512x-spi.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
@@ -188,14 +218,19 @@ 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_SSM2602_SPI)      += snd-soc-ssm2602-spi.o
+obj-$(CONFIG_SND_SOC_SSM2602_I2C)      += snd-soc-ssm2602-i2c.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)  += snd-soc-tlv320aic23-i2c.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)  += snd-soc-tlv320aic23-spi.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
-obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TLV320AIC31XX)     += snd-soc-tlv320aic31xx.o
 obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)      += snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)  += snd-soc-twl6040.o
index 77f459868579ad7f90d262f683f32e07ae4506a8..685998dd086e392d592fad5ac0ea9bf35e4ed612 100644 (file)
@@ -40,8 +40,8 @@ struct ad1836_priv {
  */
 static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
 
-static const struct soc_enum ad1836_deemp_enum =
-       SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp);
+static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum,
+                           AD1836_DAC_CTRL1, 8, ad1836_deemp);
 
 #define AD1836_DAC_VOLUME(x) \
        SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c
new file mode 100644 (file)
index 0000000..df3a1a4
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * AD1936/AD1937 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ad193x.h"
+
+static const struct i2c_device_id ad193x_id[] = {
+       { "ad1936", 0 },
+       { "ad1937", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ad193x_id);
+
+static int ad193x_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct regmap_config config;
+
+       config = ad193x_regmap_config;
+       config.val_bits = 8;
+       config.reg_bits = 8;
+
+       return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config));
+}
+
+static int ad193x_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static struct i2c_driver ad193x_i2c_driver = {
+       .driver = {
+               .name = "ad193x",
+       },
+       .probe    = ad193x_i2c_probe,
+       .remove   = ad193x_i2c_remove,
+       .id_table = ad193x_id,
+};
+module_i2c_driver(ad193x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c
new file mode 100644 (file)
index 0000000..390cef9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * AD1938/AD1939 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ad193x.h"
+
+static int ad193x_spi_probe(struct spi_device *spi)
+{
+       struct regmap_config config;
+
+       config = ad193x_regmap_config;
+       config.val_bits = 8;
+       config.reg_bits = 16;
+       config.read_flag_mask = 0x09;
+       config.write_flag_mask = 0x08;
+
+       return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static int ad193x_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static struct spi_driver ad193x_spi_driver = {
+       .driver = {
+               .name   = "ad193x",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad193x_spi_probe,
+       .remove         = ad193x_spi_remove,
+};
+module_spi_driver(ad193x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
index 5a42dca535b77c43f8f63e7131ce09aeb7943e4b..6844d0b2af6889e65501a954eca9ac5061913fe7 100644 (file)
@@ -6,12 +6,10 @@
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -19,6 +17,7 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
+
 #include "ad193x.h"
 
 /* codec private data */
@@ -32,8 +31,8 @@ struct ad193x_priv {
  */
 static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
 
-static const struct soc_enum ad193x_deemp_enum =
-       SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp);
+static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,
+                           ad193x_deemp);
 
 static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
 
@@ -320,17 +319,9 @@ static struct snd_soc_dai_driver ad193x_dai = {
        .ops = &ad193x_dai_ops,
 };
 
-static int ad193x_probe(struct snd_soc_codec *codec)
+static int ad193x_codec_probe(struct snd_soc_codec *codec)
 {
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       codec->control_data = ad193x->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;
-       }
 
        /* default setting for ad193x */
 
@@ -348,11 +339,11 @@ static int ad193x_probe(struct snd_soc_codec *codec)
        regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
        regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
 
-       return ret;
+       return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
-       .probe =        ad193x_probe,
+       .probe = ad193x_codec_probe,
        .controls = ad193x_snd_controls,
        .num_controls = ARRAY_SIZE(ad193x_snd_controls),
        .dapm_widgets = ad193x_dapm_widgets,
@@ -366,140 +357,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)
        return false;
 }
 
-#if defined(CONFIG_SPI_MASTER)
-
-static const struct regmap_config ad193x_spi_regmap_config = {
-       .val_bits = 8,
-       .reg_bits = 16,
-       .read_flag_mask = 0x09,
-       .write_flag_mask = 0x08,
-
+const struct regmap_config ad193x_regmap_config = {
        .max_register = AD193X_NUM_REGS - 1,
        .volatile_reg = adau193x_reg_volatile,
 };
+EXPORT_SYMBOL_GPL(ad193x_regmap_config);
 
-static int ad193x_spi_probe(struct spi_device *spi)
+int ad193x_probe(struct device *dev, struct regmap *regmap)
 {
        struct ad193x_priv *ad193x;
 
-       ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv),
-                             GFP_KERNEL);
-       if (ad193x == NULL)
-               return -ENOMEM;
-
-       ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config);
-       if (IS_ERR(ad193x->regmap))
-               return PTR_ERR(ad193x->regmap);
-
-       spi_set_drvdata(spi, ad193x);
-
-       return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x,
-                       &ad193x_dai, 1);
-}
-
-static int ad193x_spi_remove(struct spi_device *spi)
-{
-       snd_soc_unregister_codec(&spi->dev);
-       return 0;
-}
-
-static struct spi_driver ad193x_spi_driver = {
-       .driver = {
-               .name   = "ad193x",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = ad193x_spi_probe,
-       .remove         = ad193x_spi_remove,
-};
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static const struct regmap_config ad193x_i2c_regmap_config = {
-       .val_bits = 8,
-       .reg_bits = 8,
-
-       .max_register = AD193X_NUM_REGS - 1,
-       .volatile_reg = adau193x_reg_volatile,
-};
-
-static const struct i2c_device_id ad193x_id[] = {
-       { "ad1936", 0 },
-       { "ad1937", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ad193x_id);
-
-static int ad193x_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
-{
-       struct ad193x_priv *ad193x;
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
-       ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),
-                             GFP_KERNEL);
+       ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
        if (ad193x == NULL)
                return -ENOMEM;
 
-       ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config);
-       if (IS_ERR(ad193x->regmap))
-               return PTR_ERR(ad193x->regmap);
-
-       i2c_set_clientdata(client, ad193x);
-
-       return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x,
-                       &ad193x_dai, 1);
-}
-
-static int ad193x_i2c_remove(struct i2c_client *client)
-{
-       snd_soc_unregister_codec(&client->dev);
-       return 0;
-}
-
-static struct i2c_driver ad193x_i2c_driver = {
-       .driver = {
-               .name = "ad193x",
-       },
-       .probe    = ad193x_i2c_probe,
-       .remove   = ad193x_i2c_remove,
-       .id_table = ad193x_id,
-};
-#endif
-
-static int __init ad193x_modinit(void)
-{
-       int ret;
-
-#if IS_ENABLED(CONFIG_I2C)
-       ret =  i2c_add_driver(&ad193x_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
-                               ret);
-       }
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-       ret = spi_register_driver(&ad193x_spi_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n",
-                               ret);
-       }
-#endif
-       return ret;
-}
-module_init(ad193x_modinit);
+       ad193x->regmap = regmap;
 
-static void __exit ad193x_modexit(void)
-{
-#if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&ad193x_spi_driver);
-#endif
+       dev_set_drvdata(dev, ad193x);
 
-#if IS_ENABLED(CONFIG_I2C)
-       i2c_del_driver(&ad193x_i2c_driver);
-#endif
+       return snd_soc_register_codec(dev, &soc_codec_dev_ad193x,
+               &ad193x_dai, 1);
 }
-module_exit(ad193x_modexit);
+EXPORT_SYMBOL_GPL(ad193x_probe);
 
 MODULE_DESCRIPTION("ASoC ad193x driver");
 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
index 47338804999233d2aaf4b6e61b79322a95848d87..ab9a998f15beba416338b9571e64601608fe5fc7 100644 (file)
@@ -9,6 +9,13 @@
 #ifndef __AD193X_H__
 #define __AD193X_H__
 
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config ad193x_regmap_config;
+int ad193x_probe(struct device *dev, struct regmap *regmap);
+
 #define AD193X_PLL_CLK_CTRL0    0x00
 #define AD193X_PLL_POWERDOWN           0x01
 #define AD193X_PLL_INPUT_MASK   0x6
index eb836ed5271f448631ad1268ddd548b69db39c51..877f5737bb6b23bf924ab6b4a48c88f4498a950e 100644 (file)
@@ -345,15 +345,15 @@ static const char *adau1373_fdsp_sel_text[] = {
        "Channel 5",
 };
 
-static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,
        ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,
        ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,
        ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,
        ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,
        ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text);
 
 static const char *adau1373_hpf_cutoff_text[] = {
@@ -362,7 +362,7 @@ static const char *adau1373_hpf_cutoff_text[] = {
        "800Hz",
 };
 
-static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,
        ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text);
 
 static const char *adau1373_bass_lpf_cutoff_text[] = {
@@ -388,14 +388,14 @@ static const unsigned int adau1373_bass_tlv[] = {
        5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0),
 };
 
-static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
        ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text);
 
-static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,
        ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text,
        adau1373_bass_clip_level_values);
 
-static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,
        ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text);
 
 static const char *adau1373_3d_level_text[] = {
@@ -409,9 +409,9 @@ static const char *adau1373_3d_cutoff_text[] = {
        "0.16875 fs", "0.27083 fs"
 };
 
-static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
        ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
        ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text);
 
 static const unsigned int adau1373_3d_tlv[] = {
@@ -427,11 +427,11 @@ static const char *adau1373_lr_mux_text[] = {
        "Stereo",
 };
 
-static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,
        ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,
        ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,
        ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text);
 
 static const struct snd_kcontrol_new adau1373_controls[] = {
@@ -576,8 +576,8 @@ static const char *adau1373_decimator_text[] = {
        "DMIC1",
 };
 
-static const struct soc_enum adau1373_decimator_enum =
-       SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum,
+       adau1373_decimator_text);
 
 static const struct snd_kcontrol_new adau1373_decimator_mux =
        SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum);
@@ -1376,15 +1376,8 @@ static int adau1373_probe(struct snd_soc_codec *codec)
        struct adau1373_platform_data *pdata = codec->dev->platform_data;
        bool lineout_differential = false;
        unsigned int val;
-       int ret;
        int i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-       if (ret) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        if (pdata) {
                if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
                        return -EINVAL;
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
new file mode 100644 (file)
index 0000000..9700e8c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static int adau1977_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       struct regmap_config config;
+
+       config = adau1977_regmap_config;
+       config.val_bits = 8;
+       config.reg_bits = 8;
+
+       return adau1977_probe(&client->dev,
+               devm_regmap_init_i2c(client, &config),
+               id->driver_data, NULL);
+}
+
+static int adau1977_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id adau1977_i2c_ids[] = {
+       { "adau1977", ADAU1977 },
+       { "adau1978", ADAU1978 },
+       { "adau1979", ADAU1978 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
+
+static struct i2c_driver adau1977_i2c_driver = {
+       .driver = {
+               .name = "adau1977",
+               .owner = THIS_MODULE,
+       },
+       .probe = adau1977_i2c_probe,
+       .remove = adau1977_i2c_remove,
+       .id_table = adau1977_i2c_ids,
+};
+module_i2c_driver(adau1977_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c
new file mode 100644 (file)
index 0000000..b05cf5d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static void adau1977_spi_switch_mode(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       /*
+        * To get the device into SPI mode CLATCH has to be pulled low three
+        * times.  Do this by issuing three dummy reads.
+        */
+       spi_w8r8(spi, 0x00);
+       spi_w8r8(spi, 0x00);
+       spi_w8r8(spi, 0x00);
+}
+
+static int adau1977_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct regmap_config config;
+
+       if (!id)
+               return -EINVAL;
+
+       config = adau1977_regmap_config;
+       config.val_bits = 8;
+       config.reg_bits = 16;
+       config.read_flag_mask = 0x1;
+
+       return adau1977_probe(&spi->dev,
+               devm_regmap_init_spi(spi, &config),
+               id->driver_data, adau1977_spi_switch_mode);
+}
+
+static int adau1977_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static const struct spi_device_id adau1977_spi_ids[] = {
+       { "adau1977", ADAU1977 },
+       { "adau1978", ADAU1978 },
+       { "adau1979", ADAU1978 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, adau1977_spi_ids);
+
+static struct spi_driver adau1977_spi_driver = {
+       .driver = {
+               .name = "adau1977",
+               .owner = THIS_MODULE,
+       },
+       .probe = adau1977_spi_probe,
+       .remove = adau1977_spi_remove,
+       .id_table = adau1977_spi_ids,
+};
+module_spi_driver(adau1977_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
new file mode 100644 (file)
index 0000000..fd55da7
--- /dev/null
@@ -0,0 +1,1018 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_data/adau1977.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "adau1977.h"
+
+#define ADAU1977_REG_POWER             0x00
+#define ADAU1977_REG_PLL               0x01
+#define ADAU1977_REG_BOOST             0x02
+#define ADAU1977_REG_MICBIAS           0x03
+#define ADAU1977_REG_BLOCK_POWER_SAI   0x04
+#define ADAU1977_REG_SAI_CTRL0         0x05
+#define ADAU1977_REG_SAI_CTRL1         0x06
+#define ADAU1977_REG_CMAP12            0x07
+#define ADAU1977_REG_CMAP34            0x08
+#define ADAU1977_REG_SAI_OVERTEMP      0x09
+#define ADAU1977_REG_POST_ADC_GAIN(x)  (0x0a + (x))
+#define ADAU1977_REG_MISC_CONTROL      0x0e
+#define ADAU1977_REG_DIAG_CONTROL      0x10
+#define ADAU1977_REG_STATUS(x)         (0x11 + (x))
+#define ADAU1977_REG_DIAG_IRQ1         0x15
+#define ADAU1977_REG_DIAG_IRQ2         0x16
+#define ADAU1977_REG_ADJUST1           0x17
+#define ADAU1977_REG_ADJUST2           0x18
+#define ADAU1977_REG_ADC_CLIP          0x19
+#define ADAU1977_REG_DC_HPF_CAL                0x1a
+
+#define ADAU1977_POWER_RESET                   BIT(7)
+#define ADAU1977_POWER_PWUP                    BIT(0)
+
+#define ADAU1977_PLL_CLK_S                     BIT(4)
+#define ADAU1977_PLL_MCS_MASK                  0x7
+
+#define ADAU1977_MICBIAS_MB_VOLTS_MASK         0xf0
+#define ADAU1977_MICBIAS_MB_VOLTS_OFFSET       4
+
+#define ADAU1977_BLOCK_POWER_SAI_LR_POL                BIT(7)
+#define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE     BIT(6)
+#define ADAU1977_BLOCK_POWER_SAI_LDO_EN                BIT(5)
+
+#define ADAU1977_SAI_CTRL0_FMT_MASK            (0x3 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_I2S             (0x0 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_LJ              (0x1 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT                (0x2 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT                (0x3 << 6)
+
+#define ADAU1977_SAI_CTRL0_SAI_MASK            (0x7 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_I2S             (0x0 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_2           (0x1 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_4           (0x2 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_8           (0x3 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_16          (0x4 << 3)
+
+#define ADAU1977_SAI_CTRL0_FS_MASK             (0x7)
+#define ADAU1977_SAI_CTRL0_FS_8000_12000       (0x0)
+#define ADAU1977_SAI_CTRL0_FS_16000_24000      (0x1)
+#define ADAU1977_SAI_CTRL0_FS_32000_48000      (0x2)
+#define ADAU1977_SAI_CTRL0_FS_64000_96000      (0x3)
+#define ADAU1977_SAI_CTRL0_FS_128000_192000    (0x4)
+
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK     (0x3 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32       (0x0 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24       (0x1 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16       (0x2 << 5)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK     (0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT    (0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT    (0x0 << 4)
+#define ADAU1977_SAI_CTRL1_LRCLK_PULSE         BIT(3)
+#define ADAU1977_SAI_CTRL1_MSB                 BIT(2)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_16         (0x1 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_32         (0x0 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_MASK       (0x1 << 1)
+#define ADAU1977_SAI_CTRL1_MASTER              BIT(0)
+
+#define ADAU1977_SAI_OVERTEMP_DRV_C(x)         BIT(4 + (x))
+#define ADAU1977_SAI_OVERTEMP_DRV_HIZ          BIT(3)
+
+#define ADAU1977_MISC_CONTROL_SUM_MODE_MASK    (0x3 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_1CH     (0x2 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_2CH     (0x1 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_4CH     (0x0 << 6)
+#define ADAU1977_MISC_CONTROL_MMUTE            BIT(4)
+#define ADAU1977_MISC_CONTROL_DC_CAL           BIT(0)
+
+#define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET   4
+#define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET    0
+
+struct adau1977 {
+       struct regmap *regmap;
+       bool right_j;
+       unsigned int sysclk;
+       enum adau1977_sysclk_src sysclk_src;
+       struct gpio_desc *reset_gpio;
+       enum adau1977_type type;
+
+       struct regulator *avdd_reg;
+       struct regulator *dvdd_reg;
+
+       struct snd_pcm_hw_constraint_list constraints;
+
+       struct device *dev;
+       void (*switch_mode)(struct device *dev);
+
+       unsigned int max_master_fs;
+       unsigned int slot_width;
+       bool enabled;
+       bool master;
+};
+
+static const struct reg_default adau1977_reg_defaults[] = {
+       { 0x00, 0x00 },
+       { 0x01, 0x41 },
+       { 0x02, 0x4a },
+       { 0x03, 0x7d },
+       { 0x04, 0x3d },
+       { 0x05, 0x02 },
+       { 0x06, 0x00 },
+       { 0x07, 0x10 },
+       { 0x08, 0x32 },
+       { 0x09, 0xf0 },
+       { 0x0a, 0xa0 },
+       { 0x0b, 0xa0 },
+       { 0x0c, 0xa0 },
+       { 0x0d, 0xa0 },
+       { 0x0e, 0x02 },
+       { 0x10, 0x0f },
+       { 0x15, 0x20 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+       { 0x18, 0x00 },
+       { 0x1a, 0x00 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000);
+
+static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS,
+               3, 0, NULL, 0)
+};
+
+static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI,
+               4, 0, NULL, 0),
+
+       SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0),
+       SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0),
+       SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0),
+       SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0),
+
+       SND_SOC_DAPM_INPUT("AIN1"),
+       SND_SOC_DAPM_INPUT("AIN2"),
+       SND_SOC_DAPM_INPUT("AIN3"),
+       SND_SOC_DAPM_INPUT("AIN4"),
+
+       SND_SOC_DAPM_OUTPUT("VREF"),
+};
+
+static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
+       { "ADC1", NULL, "AIN1" },
+       { "ADC2", NULL, "AIN2" },
+       { "ADC3", NULL, "AIN3" },
+       { "ADC4", NULL, "AIN4" },
+
+       { "ADC1", NULL, "Vref" },
+       { "ADC2", NULL, "Vref" },
+       { "ADC3", NULL, "Vref" },
+       { "ADC4", NULL, "Vref" },
+
+       { "VREF", NULL, "Vref" },
+};
+
+#define ADAU1977_VOLUME(x) \
+       SOC_SINGLE_TLV("ADC" #x " Capture Volume", \
+               ADAU1977_REG_POST_ADC_GAIN((x) - 1), \
+               0, 255, 1, adau1977_adc_gain)
+
+#define ADAU1977_HPF_SWITCH(x) \
+       SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \
+               ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
+
+#define ADAU1977_DC_SUB_SWITCH(x) \
+       SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \
+               ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
+
+static const struct snd_kcontrol_new adau1977_snd_controls[] = {
+       ADAU1977_VOLUME(1),
+       ADAU1977_VOLUME(2),
+       ADAU1977_VOLUME(3),
+       ADAU1977_VOLUME(4),
+
+       ADAU1977_HPF_SWITCH(1),
+       ADAU1977_HPF_SWITCH(2),
+       ADAU1977_HPF_SWITCH(3),
+       ADAU1977_HPF_SWITCH(4),
+
+       ADAU1977_DC_SUB_SWITCH(1),
+       ADAU1977_DC_SUB_SWITCH(2),
+       ADAU1977_DC_SUB_SWITCH(3),
+       ADAU1977_DC_SUB_SWITCH(4),
+};
+
+static int adau1977_reset(struct adau1977 *adau1977)
+{
+       int ret;
+
+       /*
+        * 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(adau1977->regmap, true);
+       ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
+                       ADAU1977_POWER_RESET);
+       regcache_cache_bypass(adau1977->regmap, false);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+/*
+ * Returns the appropriate setting for ths FS field in the CTRL0 register
+ * depending on the rate.
+ */
+static int adau1977_lookup_fs(unsigned int rate)
+{
+       if (rate >= 8000 && rate <= 12000)
+               return ADAU1977_SAI_CTRL0_FS_8000_12000;
+       else if (rate >= 16000 && rate <= 24000)
+               return ADAU1977_SAI_CTRL0_FS_16000_24000;
+       else if (rate >= 32000 && rate <= 48000)
+               return ADAU1977_SAI_CTRL0_FS_32000_48000;
+       else if (rate >= 64000 && rate <= 96000)
+               return ADAU1977_SAI_CTRL0_FS_64000_96000;
+       else if (rate >= 128000 && rate <= 192000)
+               return ADAU1977_SAI_CTRL0_FS_128000_192000;
+       else
+               return -EINVAL;
+}
+
+static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate,
+       unsigned int fs)
+{
+       unsigned int mcs;
+
+       /*
+        * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs
+        * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs
+        * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate)
+        */
+
+       rate *= 512 >> fs;
+
+       if (adau1977->sysclk % rate != 0)
+               return -EINVAL;
+
+       mcs = adau1977->sysclk / rate;
+
+       /* The factors configured by MCS are 1, 2, 3, 4, 6 */
+       if (mcs < 1 || mcs > 6 || mcs == 5)
+               return -EINVAL;
+
+       mcs = mcs - 1;
+       if (mcs == 5)
+               mcs = 4;
+
+       return mcs;
+}
+
+static int adau1977_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 adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+       unsigned int rate = params_rate(params);
+       unsigned int slot_width;
+       unsigned int ctrl0, ctrl0_mask;
+       unsigned int ctrl1;
+       int mcs, fs;
+       int ret;
+
+       fs = adau1977_lookup_fs(rate);
+       if (fs < 0)
+               return fs;
+
+       if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) {
+               mcs = adau1977_lookup_mcs(adau1977, rate, fs);
+               if (mcs < 0)
+                       return mcs;
+       } else {
+               mcs = 0;
+       }
+
+       ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK;
+       ctrl0 = fs;
+
+       if (adau1977->right_j) {
+               switch (params_width(params)) {
+               case 16:
+                       ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT;
+                       break;
+               case 24:
+                       ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK;
+       }
+
+       if (adau1977->master) {
+               switch (params_width(params)) {
+               case 16:
+                       ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT;
+                       slot_width = 16;
+                       break;
+               case 24:
+               case 32:
+                       ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT;
+                       slot_width = 32;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               /* In TDM mode there is a fixed slot width */
+               if (adau1977->slot_width)
+                       slot_width = adau1977->slot_width;
+
+               if (slot_width == 16)
+                       ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16;
+               else
+                       ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32;
+
+               ret = regmap_update_bits(adau1977->regmap,
+                       ADAU1977_REG_SAI_CTRL1,
+                       ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK |
+                       ADAU1977_SAI_CTRL1_BCLKRATE_MASK,
+                       ctrl1);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+                               ctrl0_mask, ctrl0);
+       if (ret < 0)
+               return ret;
+
+       return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+                               ADAU1977_PLL_MCS_MASK, mcs);
+}
+
+static int adau1977_power_disable(struct adau1977 *adau1977)
+{
+       int ret = 0;
+
+       if (!adau1977->enabled)
+               return 0;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+               ADAU1977_POWER_PWUP, 0);
+       if (ret)
+               return ret;
+
+       regcache_mark_dirty(adau1977->regmap);
+
+       if (adau1977->reset_gpio)
+               gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
+
+       regcache_cache_only(adau1977->regmap, true);
+
+       regulator_disable(adau1977->avdd_reg);
+       if (adau1977->dvdd_reg)
+               regulator_disable(adau1977->dvdd_reg);
+
+       adau1977->enabled = false;
+
+       return 0;
+}
+
+static int adau1977_power_enable(struct adau1977 *adau1977)
+{
+       unsigned int val;
+       int ret = 0;
+
+       if (adau1977->enabled)
+               return 0;
+
+       ret = regulator_enable(adau1977->avdd_reg);
+       if (ret)
+               return ret;
+
+       if (adau1977->dvdd_reg) {
+               ret = regulator_enable(adau1977->dvdd_reg);
+               if (ret)
+                       goto err_disable_avdd;
+       }
+
+       if (adau1977->reset_gpio)
+               gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
+
+       regcache_cache_only(adau1977->regmap, false);
+
+       if (adau1977->switch_mode)
+               adau1977->switch_mode(adau1977->dev);
+
+       ret = adau1977_reset(adau1977);
+       if (ret)
+               goto err_disable_dvdd;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+               ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP);
+       if (ret)
+               goto err_disable_dvdd;
+
+       ret = regcache_sync(adau1977->regmap);
+       if (ret)
+               goto err_disable_dvdd;
+
+       /*
+        * The PLL register is not affected by the software reset. It is
+        * possible that the value of the register was changed to the
+        * default value while we were in cache only mode. In this case
+        * regcache_sync will skip over it and we have to manually sync
+        * it.
+        */
+       ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val);
+       if (ret)
+               goto err_disable_dvdd;
+
+       if (val == 0x41) {
+               regcache_cache_bypass(adau1977->regmap, true);
+               ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL,
+                       0x41);
+               if (ret)
+                       goto err_disable_dvdd;
+               regcache_cache_bypass(adau1977->regmap, false);
+       }
+
+       adau1977->enabled = true;
+
+       return ret;
+
+err_disable_dvdd:
+       if (adau1977->dvdd_reg)
+               regulator_disable(adau1977->dvdd_reg);
+err_disable_avdd:
+               regulator_disable(adau1977->avdd_reg);
+       return ret;
+}
+
+static int adau1977_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       struct adau1977 *adau1977 = 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 = adau1977_power_enable(adau1977);
+               break;
+       case SND_SOC_BIAS_OFF:
+               ret = adau1977_power_disable(adau1977);
+               break;
+       }
+
+       if (ret)
+               return ret;
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+       unsigned int rx_mask, int slots, int width)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int ctrl0, ctrl1, drv;
+       unsigned int slot[4];
+       unsigned int i;
+       int ret;
+
+       if (slots == 0) {
+               /* 0 = No fixed slot width */
+               adau1977->slot_width = 0;
+               adau1977->max_master_fs = 192000;
+               return regmap_update_bits(adau1977->regmap,
+                       ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK,
+                       ADAU1977_SAI_CTRL0_SAI_I2S);
+       }
+
+       if (rx_mask == 0 || tx_mask != 0)
+               return -EINVAL;
+
+       drv = 0;
+       for (i = 0; i < 4; i++) {
+               slot[i] = __ffs(rx_mask);
+               drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i);
+               rx_mask &= ~(1 << slot[i]);
+               if (slot[i] >= slots)
+                       return -EINVAL;
+               if (rx_mask == 0)
+                       break;
+       }
+
+       if (rx_mask != 0)
+               return -EINVAL;
+
+       switch (width) {
+       case 16:
+               ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16;
+               break;
+       case 24:
+               /* We can only generate 16 bit or 32 bit wide slots */
+               if (adau1977->master)
+                       return -EINVAL;
+               ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24;
+               break;
+       case 32:
+               ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (slots) {
+       case 2:
+               ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2;
+               break;
+       case 4:
+               ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4;
+               break;
+       case 8:
+               ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8;
+               break;
+       case 16:
+               ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+               ADAU1977_SAI_OVERTEMP_DRV_C(0) |
+               ADAU1977_SAI_OVERTEMP_DRV_C(1) |
+               ADAU1977_SAI_OVERTEMP_DRV_C(2) |
+               ADAU1977_SAI_OVERTEMP_DRV_C(3), drv);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12,
+               (slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+               (slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+       if (ret)
+               return ret;
+
+       ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34,
+               (slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+               (slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+               ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+               ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1);
+       if (ret)
+               return ret;
+
+       adau1977->slot_width = width;
+
+       /* In master mode the maximum bitclock is 24.576 MHz */
+       adau1977->max_master_fs = min(192000, 24576000 / width / slots);
+
+       return 0;
+}
+
+static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int val;
+
+       if (mute)
+               val = ADAU1977_MISC_CONTROL_MMUTE;
+       else
+               val = 0;
+
+       return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL,
+                       ADAU1977_MISC_CONTROL_MMUTE, val);
+}
+
+static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0;
+       bool invert_lrclk;
+       int ret;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               adau1977->master = false;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               ctrl1 |= ADAU1977_SAI_CTRL1_MASTER;
+               adau1977->master = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               invert_lrclk = false;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+               invert_lrclk = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               invert_lrclk = true;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+               invert_lrclk = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       adau1977->right_j = false;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+               invert_lrclk = !invert_lrclk;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+               adau1977->right_j = true;
+               invert_lrclk = !invert_lrclk;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+               ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+               invert_lrclk = false;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+               ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+               invert_lrclk = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (invert_lrclk)
+               block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+               ADAU1977_BLOCK_POWER_SAI_LR_POL |
+               ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+               ADAU1977_SAI_CTRL0_FMT_MASK,
+               ctrl0);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+               ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE,
+               ctrl1);
+}
+
+static int adau1977_startup(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+       u64 formats = 0;
+
+       if (adau1977->slot_width == 16)
+               formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE;
+       else if (adau1977->right_j || adau1977->slot_width == 24)
+               formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE;
+
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+               SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints);
+
+       if (adau1977->master)
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs);
+
+       if (formats != 0)
+               snd_pcm_hw_constraint_mask64(substream->runtime,
+                       SNDRV_PCM_HW_PARAM_FORMAT, formats);
+
+       return 0;
+}
+
+static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int val;
+
+       if (tristate)
+               val = ADAU1977_SAI_OVERTEMP_DRV_HIZ;
+       else
+               val = 0;
+
+       return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+               ADAU1977_SAI_OVERTEMP_DRV_HIZ, val);
+}
+
+static const struct snd_soc_dai_ops adau1977_dai_ops = {
+       .startup        = adau1977_startup,
+       .hw_params      = adau1977_hw_params,
+       .mute_stream    = adau1977_mute,
+       .set_fmt        = adau1977_set_dai_fmt,
+       .set_tdm_slot   = adau1977_set_tdm_slot,
+       .set_tristate   = adau1977_set_tristate,
+};
+
+static struct snd_soc_dai_driver adau1977_dai = {
+       .name = "adau1977-hifi",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 4,
+               .rates = SNDRV_PCM_RATE_KNOT,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+                   SNDRV_PCM_FMTBIT_S32_LE,
+               .sig_bits = 24,
+       },
+       .ops = &adau1977_dai_ops,
+};
+
+static const unsigned int adau1977_rates[] = {
+       8000, 16000, 32000, 64000, 128000,
+       11025, 22050, 44100, 88200, 172400,
+       12000, 24000, 48000, 96000, 192000,
+};
+
+#define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f
+#define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0
+#define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00
+/* All rates >= 32000 */
+#define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c
+
+static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq)
+{
+       unsigned int mcs;
+
+       if (mclk % (base_freq * 128) != 0)
+               return false;
+
+       mcs = mclk / (128 * base_freq);
+       if (mcs < 1 || mcs > 6 || mcs == 5)
+               return false;
+
+       return true;
+}
+
+static int adau1977_set_sysclk(struct snd_soc_codec *codec,
+       int clk_id, int source, unsigned int freq, int dir)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+       unsigned int mask = 0;
+       unsigned int clk_src;
+       unsigned int ret;
+
+       if (dir != SND_SOC_CLOCK_IN)
+               return -EINVAL;
+
+       if (clk_id != ADAU1977_SYSCLK)
+               return -EINVAL;
+
+       switch (source) {
+       case ADAU1977_SYSCLK_SRC_MCLK:
+               clk_src = 0;
+               break;
+       case ADAU1977_SYSCLK_SRC_LRCLK:
+               clk_src = ADAU1977_PLL_CLK_S;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) {
+               if (freq < 4000000 || freq > 36864000)
+                       return -EINVAL;
+
+               if (adau1977_check_sysclk(freq, 32000))
+                       mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000;
+               if (adau1977_check_sysclk(freq, 44100))
+                       mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100;
+               if (adau1977_check_sysclk(freq, 48000))
+                       mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000;
+
+               if (mask == 0)
+                       return -EINVAL;
+       } else if (source == ADAU1977_SYSCLK_SRC_LRCLK) {
+               mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK;
+       }
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+               ADAU1977_PLL_CLK_S, clk_src);
+       if (ret)
+               return ret;
+
+       adau1977->constraints.mask = mask;
+       adau1977->sysclk_src = source;
+       adau1977->sysclk = freq;
+
+       return 0;
+}
+
+static int adau1977_codec_probe(struct snd_soc_codec *codec)
+{
+       struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (adau1977->type) {
+       case ADAU1977:
+               ret = snd_soc_dapm_new_controls(&codec->dapm,
+                       adau1977_micbias_dapm_widgets,
+                       ARRAY_SIZE(adau1977_micbias_dapm_widgets));
+               if (ret < 0)
+                       return ret;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver adau1977_codec_driver = {
+       .probe = adau1977_codec_probe,
+       .set_bias_level = adau1977_set_bias_level,
+       .set_sysclk = adau1977_set_sysclk,
+       .idle_bias_off = true,
+
+       .controls = adau1977_snd_controls,
+       .num_controls = ARRAY_SIZE(adau1977_snd_controls),
+       .dapm_widgets = adau1977_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets),
+       .dapm_routes = adau1977_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes),
+};
+
+static int adau1977_setup_micbias(struct adau1977 *adau1977)
+{
+       struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
+       unsigned int micbias;
+
+       if (pdata) {
+               micbias = pdata->micbias;
+               if (micbias > ADAU1977_MICBIAS_9V0)
+                       return -EINVAL;
+
+       } else {
+               micbias = ADAU1977_MICBIAS_8V5;
+       }
+
+       return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS,
+               ADAU1977_MICBIAS_MB_VOLTS_MASK,
+               micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET);
+}
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+       enum adau1977_type type, void (*switch_mode)(struct device *dev))
+{
+       unsigned int power_off_mask;
+       struct adau1977 *adau1977;
+       int ret;
+
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL);
+       if (adau1977 == NULL)
+               return -ENOMEM;
+
+       adau1977->dev = dev;
+       adau1977->type = type;
+       adau1977->regmap = regmap;
+       adau1977->switch_mode = switch_mode;
+       adau1977->max_master_fs = 192000;
+
+       adau1977->constraints.list = adau1977_rates;
+       adau1977->constraints.count = ARRAY_SIZE(adau1977_rates);
+
+       adau1977->avdd_reg = devm_regulator_get(dev, "AVDD");
+       if (IS_ERR(adau1977->avdd_reg))
+               return PTR_ERR(adau1977->avdd_reg);
+
+       adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD");
+       if (IS_ERR(adau1977->dvdd_reg)) {
+               if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV)
+                       return PTR_ERR(adau1977->dvdd_reg);
+               adau1977->dvdd_reg = NULL;
+       }
+
+       adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(adau1977->reset_gpio)) {
+               ret = PTR_ERR(adau1977->reset_gpio);
+               if (ret != -ENOENT && ret != -ENOSYS)
+                       return PTR_ERR(adau1977->reset_gpio);
+               adau1977->reset_gpio = NULL;
+       }
+
+       dev_set_drvdata(dev, adau1977);
+
+       if (adau1977->reset_gpio) {
+               ret = gpiod_direction_output(adau1977->reset_gpio, 0);
+               if (ret)
+                       return ret;
+               ndelay(100);
+       }
+
+       ret = adau1977_power_enable(adau1977);
+       if (ret)
+               return ret;
+
+       if (type == ADAU1977) {
+               ret = adau1977_setup_micbias(adau1977);
+               if (ret)
+                       goto err_poweroff;
+       }
+
+       if (adau1977->dvdd_reg)
+               power_off_mask = ~0;
+       else
+               power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN;
+
+       ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+                               power_off_mask, 0x00);
+       if (ret)
+               goto err_poweroff;
+
+       ret = adau1977_power_disable(adau1977);
+       if (ret)
+               return ret;
+
+       return snd_soc_register_codec(dev, &adau1977_codec_driver,
+                       &adau1977_dai, 1);
+
+err_poweroff:
+       adau1977_power_disable(adau1977);
+       return ret;
+
+}
+EXPORT_SYMBOL_GPL(adau1977_probe);
+
+static bool adau1977_register_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ADAU1977_REG_STATUS(0):
+       case ADAU1977_REG_STATUS(1):
+       case ADAU1977_REG_STATUS(2):
+       case ADAU1977_REG_STATUS(3):
+       case ADAU1977_REG_ADC_CLIP:
+               return true;
+       }
+
+       return false;
+}
+
+const struct regmap_config adau1977_regmap_config = {
+       .max_register = ADAU1977_REG_DC_HPF_CAL,
+       .volatile_reg = adau1977_register_volatile,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = adau1977_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
+};
+EXPORT_SYMBOL_GPL(adau1977_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h
new file mode 100644 (file)
index 0000000..95e7143
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1977_H__
+#define __SOUND_SOC_CODECS_ADAU1977_H__
+
+#include <linux/regmap.h>
+
+struct device;
+
+enum adau1977_type {
+       ADAU1977,
+       ADAU1978,
+       ADAU1979,
+};
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+       enum adau1977_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1977_regmap_config;
+
+enum adau1977_clk_id {
+       ADAU1977_SYSCLK,
+};
+
+enum adau1977_sysclk_src {
+       ADAU1977_SYSCLK_SRC_MCLK,
+       ADAU1977_SYSCLK_SRC_LRCLK,
+};
+
+#endif
diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c
new file mode 100644 (file)
index 0000000..790fce3
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ADAV801 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+static const struct spi_device_id adav80x_spi_id[] = {
+       { "adav801", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
+
+static int adav80x_spi_probe(struct spi_device *spi)
+{
+       struct regmap_config config;
+
+       config = adav80x_regmap_config;
+       config.read_flag_mask = 0x01;
+
+       return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static int adav80x_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static struct spi_driver adav80x_spi_driver = {
+       .driver = {
+               .name   = "adav801",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = adav80x_spi_probe,
+       .remove         = adav80x_spi_remove,
+       .id_table       = adav80x_spi_id,
+};
+module_spi_driver(adav80x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAV801 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
new file mode 100644 (file)
index 0000000..66d9fce
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * ADAV803 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+static const struct i2c_device_id adav803_id[] = {
+       { "adav803", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adav803_id);
+
+static int adav803_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       return adav80x_bus_probe(&client->dev,
+               devm_regmap_init_i2c(client, &adav80x_regmap_config));
+}
+
+static int adav803_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static struct i2c_driver adav803_driver = {
+       .driver = {
+               .name = "adav803",
+               .owner = THIS_MODULE,
+       },
+       .probe = adav803_probe,
+       .remove = adav803_remove,
+       .id_table = adav803_id,
+};
+module_i2c_driver(adav803_driver);
+
+MODULE_DESCRIPTION("ASoC ADAV803 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
index f78b27a7c461d3e5580dad311fd583f30755a3b4..5062e34ee8dcbdec1849ce83c299409b4ee6d582 100644 (file)
@@ -8,17 +8,15 @@
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
-#include <sound/core.h>
+
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/tlv.h>
 #include <sound/soc.h>
+#include <sound/tlv.h>
 
 #include "adav80x.h"
 
@@ -541,6 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
                              unsigned int freq, int dir)
 {
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        if (dir == SND_SOC_CLOCK_IN) {
                switch (clk_id) {
@@ -573,7 +572,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
                        regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2,
                                iclk_ctrl2);
 
-                       snd_soc_dapm_sync(&codec->dapm);
+                       snd_soc_dapm_sync(dapm);
                }
        } else {
                unsigned int mask;
@@ -600,17 +599,21 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
                        adav80x->sysclk_pd[clk_id] = false;
                }
 
+               snd_soc_dapm_mutex_lock(dapm);
+
                if (adav80x->sysclk_pd[0])
-                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1");
                else
-                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+                       snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1");
 
                if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2])
-                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL2");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2");
                else
-                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
+                       snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2");
 
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_sync_unlocked(dapm);
+
+               snd_soc_dapm_mutex_unlock(dapm);
        }
 
        return 0;
@@ -722,7 +725,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       if (!codec->active || !adav80x->rate)
+       if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
                return 0;
 
        return snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -735,7 +738,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       if (!codec->active)
+       if (!snd_soc_codec_is_active(codec))
                adav80x->rate = 0;
 }
 
@@ -798,15 +801,8 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
 
 static int adav80x_probe(struct snd_soc_codec *codec)
 {
-       int ret;
        struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
 
-       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-       if (ret) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* Force PLLs on for SYSCLK output */
        snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
        snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
@@ -864,39 +860,26 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
        .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
 };
 
-static int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
+int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
 {
        struct adav80x *adav80x;
-       int ret;
 
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL);
+       adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL);
        if (!adav80x)
                return -ENOMEM;
 
-
        dev_set_drvdata(dev, adav80x);
        adav80x->regmap = regmap;
 
-       ret = snd_soc_register_codec(dev, &adav80x_codec_driver,
+       return snd_soc_register_codec(dev, &adav80x_codec_driver,
                adav80x_dais, ARRAY_SIZE(adav80x_dais));
-       if (ret)
-               kfree(adav80x);
-
-       return ret;
-}
-
-static int adav80x_bus_remove(struct device *dev)
-{
-       snd_soc_unregister_codec(dev);
-       kfree(dev_get_drvdata(dev));
-       return 0;
 }
+EXPORT_SYMBOL_GPL(adav80x_bus_probe);
 
-#if defined(CONFIG_SPI_MASTER)
-static const struct regmap_config adav80x_spi_regmap_config = {
+const struct regmap_config adav80x_regmap_config = {
        .val_bits = 8,
        .pad_bits = 1,
        .reg_bits = 7,
@@ -908,105 +891,7 @@ static const struct regmap_config adav80x_spi_regmap_config = {
        .reg_defaults = adav80x_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
 };
-
-static const struct spi_device_id adav80x_spi_id[] = {
-       { "adav801", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
-
-static int adav80x_spi_probe(struct spi_device *spi)
-{
-       return adav80x_bus_probe(&spi->dev,
-               devm_regmap_init_spi(spi, &adav80x_spi_regmap_config));
-}
-
-static int adav80x_spi_remove(struct spi_device *spi)
-{
-       return adav80x_bus_remove(&spi->dev);
-}
-
-static struct spi_driver adav80x_spi_driver = {
-       .driver = {
-               .name   = "adav801",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = adav80x_spi_probe,
-       .remove         = adav80x_spi_remove,
-       .id_table       = adav80x_spi_id,
-};
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-static const struct regmap_config adav80x_i2c_regmap_config = {
-       .val_bits = 8,
-       .pad_bits = 1,
-       .reg_bits = 7,
-
-       .max_register = ADAV80X_PLL_OUTE,
-
-       .cache_type = REGCACHE_RBTREE,
-       .reg_defaults = adav80x_reg_defaults,
-       .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
-};
-
-static const struct i2c_device_id adav80x_i2c_id[] = {
-       { "adav803", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
-
-static int adav80x_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
-{
-       return adav80x_bus_probe(&client->dev,
-               devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config));
-}
-
-static int adav80x_i2c_remove(struct i2c_client *client)
-{
-       return adav80x_bus_remove(&client->dev);
-}
-
-static struct i2c_driver adav80x_i2c_driver = {
-       .driver = {
-               .name = "adav803",
-               .owner = THIS_MODULE,
-       },
-       .probe = adav80x_i2c_probe,
-       .remove = adav80x_i2c_remove,
-       .id_table = adav80x_i2c_id,
-};
-#endif
-
-static int __init adav80x_init(void)
-{
-       int ret = 0;
-
-#if IS_ENABLED(CONFIG_I2C)
-       ret = i2c_add_driver(&adav80x_i2c_driver);
-       if (ret)
-               return ret;
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-       ret = spi_register_driver(&adav80x_spi_driver);
-#endif
-
-       return ret;
-}
-module_init(adav80x_init);
-
-static void __exit adav80x_exit(void)
-{
-#if IS_ENABLED(CONFIG_I2C)
-       i2c_del_driver(&adav80x_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&adav80x_spi_driver);
-#endif
-}
-module_exit(adav80x_exit);
+EXPORT_SYMBOL_GPL(adav80x_regmap_config);
 
 MODULE_DESCRIPTION("ASoC ADAV80x driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
index adb0fc76d4e3337797d95bcddd14d39251679c9e..8a1d7c09dca537de63720233207f5744fbe3793e 100644 (file)
@@ -9,6 +9,13 @@
 #ifndef _ADAV80X_H
 #define _ADAV80X_H
 
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config adav80x_regmap_config;
+int adav80x_bus_probe(struct device *dev, struct regmap *regmap);
+
 enum adav80x_pll_src {
        ADAV80X_PLL_SRC_XIN,
        ADAV80X_PLL_SRC_XTAL,
index b4819dcd4f4dc73f781383681d0ed4198ac2f220..10adf25d4c14f36e64d383d8be3a967387ce1726 100644 (file)
@@ -174,8 +174,6 @@ static int ak4104_probe(struct snd_soc_codec *codec)
        struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = ak4104->regmap;
-
        /* set power-up and non-reset bits */
        ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
index 684fe910669fd884f04e3900c03fc3631773e821..30e297890fec43eca2b01f344efc703aba14cacd 100644 (file)
@@ -388,15 +388,6 @@ static int ak4535_resume(struct snd_soc_codec *codec)
 
 static int ak4535_probe(struct snd_soc_codec *codec)
 {
-       struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       codec->control_data = ak4535->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
        /* power on device */
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
index 94cbe508dd3748723197f7443f5a6ed8524b2b14..868c0e2da1ece12102dc7f6a1ecc2aa6d50a66ab 100644 (file)
@@ -113,14 +113,14 @@ static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
 static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
 
 
-static const struct soc_enum ak4641_mono_out_enum =
-       SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out);
-static const struct soc_enum ak4641_hp_out_enum =
-       SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out);
-static const struct soc_enum ak4641_mic_select_enum =
-       SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select);
-static const struct soc_enum ak4641_mic_or_dac_enum =
-       SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac);
+static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum,
+                           AK4641_SIG1, 6, ak4641_mono_out);
+static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum,
+                           AK4641_MODE2, 2, ak4641_hp_out);
+static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum,
+                           AK4641_MIC, 1, ak4641_mic_select);
+static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum,
+                           AK4641_BTIF, 4, ak4641_mic_or_dac);
 
 static const struct snd_kcontrol_new ak4641_snd_controls[] = {
        SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
@@ -519,14 +519,6 @@ static int ak4641_resume(struct snd_soc_codec *codec)
 
 static int ak4641_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* power on device */
        ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
index 1f646c6e90c6b3ff688e0fd2582fcb1268679bb1..92655cc189ae0ad5791ab3483286de18dbd559b5 100644 (file)
@@ -465,14 +465,6 @@ static int ak4642_resume(struct snd_soc_codec *codec)
 
 static int ak4642_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
index 25bdf6ad4a546c16363381a1a4922c4a334ea48d..998fa0c5a0b93e2d351ec2a2936164748b8c1b91 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include "ak4671.h"
 
 
-/* codec private data */
-struct ak4671_priv {
-       enum snd_soc_control_type control_type;
-};
-
 /* ak4671 register cache & default register settings */
-static const u8 ak4671_reg[AK4671_CACHEREGNUM] = {
-       0x00,   /* AK4671_AD_DA_POWER_MANAGEMENT        (0x00)  */
-       0xf6,   /* AK4671_PLL_MODE_SELECT0              (0x01)  */
-       0x00,   /* AK4671_PLL_MODE_SELECT1              (0x02)  */
-       0x02,   /* AK4671_FORMAT_SELECT                 (0x03)  */
-       0x00,   /* AK4671_MIC_SIGNAL_SELECT             (0x04)  */
-       0x55,   /* AK4671_MIC_AMP_GAIN                  (0x05)  */
-       0x00,   /* AK4671_MIXING_POWER_MANAGEMENT0      (0x06)  */
-       0x00,   /* AK4671_MIXING_POWER_MANAGEMENT1      (0x07)  */
-       0xb5,   /* AK4671_OUTPUT_VOLUME_CONTROL         (0x08)  */
-       0x00,   /* AK4671_LOUT1_SIGNAL_SELECT           (0x09)  */
-       0x00,   /* AK4671_ROUT1_SIGNAL_SELECT           (0x0a)  */
-       0x00,   /* AK4671_LOUT2_SIGNAL_SELECT           (0x0b)  */
-       0x00,   /* AK4671_ROUT2_SIGNAL_SELECT           (0x0c)  */
-       0x00,   /* AK4671_LOUT3_SIGNAL_SELECT           (0x0d)  */
-       0x00,   /* AK4671_ROUT3_SIGNAL_SELECT           (0x0e)  */
-       0x00,   /* AK4671_LOUT1_POWER_MANAGERMENT       (0x0f)  */
-       0x00,   /* AK4671_LOUT2_POWER_MANAGERMENT       (0x10)  */
-       0x80,   /* AK4671_LOUT3_POWER_MANAGERMENT       (0x11)  */
-       0x91,   /* AK4671_LCH_INPUT_VOLUME_CONTROL      (0x12)  */
-       0x91,   /* AK4671_RCH_INPUT_VOLUME_CONTROL      (0x13)  */
-       0xe1,   /* AK4671_ALC_REFERENCE_SELECT          (0x14)  */
-       0x00,   /* AK4671_DIGITAL_MIXING_CONTROL        (0x15)  */
-       0x00,   /* AK4671_ALC_TIMER_SELECT              (0x16)  */
-       0x00,   /* AK4671_ALC_MODE_CONTROL              (0x17)  */
-       0x02,   /* AK4671_MODE_CONTROL1                 (0x18)  */
-       0x01,   /* AK4671_MODE_CONTROL2                 (0x19)  */
-       0x18,   /* AK4671_LCH_OUTPUT_VOLUME_CONTROL     (0x1a)  */
-       0x18,   /* AK4671_RCH_OUTPUT_VOLUME_CONTROL     (0x1b)  */
-       0x00,   /* AK4671_SIDETONE_A_CONTROL            (0x1c)  */
-       0x02,   /* AK4671_DIGITAL_FILTER_SELECT         (0x1d)  */
-       0x00,   /* AK4671_FIL3_COEFFICIENT0             (0x1e)  */
-       0x00,   /* AK4671_FIL3_COEFFICIENT1             (0x1f)  */
-       0x00,   /* AK4671_FIL3_COEFFICIENT2             (0x20)  */
-       0x00,   /* AK4671_FIL3_COEFFICIENT3             (0x21)  */
-       0x00,   /* AK4671_EQ_COEFFICIENT0               (0x22)  */
-       0x00,   /* AK4671_EQ_COEFFICIENT1               (0x23)  */
-       0x00,   /* AK4671_EQ_COEFFICIENT2               (0x24)  */
-       0x00,   /* AK4671_EQ_COEFFICIENT3               (0x25)  */
-       0x00,   /* AK4671_EQ_COEFFICIENT4               (0x26)  */
-       0x00,   /* AK4671_EQ_COEFFICIENT5               (0x27)  */
-       0xa9,   /* AK4671_FIL1_COEFFICIENT0             (0x28)  */
-       0x1f,   /* AK4671_FIL1_COEFFICIENT1             (0x29)  */
-       0xad,   /* AK4671_FIL1_COEFFICIENT2             (0x2a)  */
-       0x20,   /* AK4671_FIL1_COEFFICIENT3             (0x2b)  */
-       0x00,   /* AK4671_FIL2_COEFFICIENT0             (0x2c)  */
-       0x00,   /* AK4671_FIL2_COEFFICIENT1             (0x2d)  */
-       0x00,   /* AK4671_FIL2_COEFFICIENT2             (0x2e)  */
-       0x00,   /* AK4671_FIL2_COEFFICIENT3             (0x2f)  */
-       0x00,   /* AK4671_DIGITAL_FILTER_SELECT2        (0x30)  */
-       0x00,   /* this register not used                       */
-       0x00,   /* AK4671_E1_COEFFICIENT0               (0x32)  */
-       0x00,   /* AK4671_E1_COEFFICIENT1               (0x33)  */
-       0x00,   /* AK4671_E1_COEFFICIENT2               (0x34)  */
-       0x00,   /* AK4671_E1_COEFFICIENT3               (0x35)  */
-       0x00,   /* AK4671_E1_COEFFICIENT4               (0x36)  */
-       0x00,   /* AK4671_E1_COEFFICIENT5               (0x37)  */
-       0x00,   /* AK4671_E2_COEFFICIENT0               (0x38)  */
-       0x00,   /* AK4671_E2_COEFFICIENT1               (0x39)  */
-       0x00,   /* AK4671_E2_COEFFICIENT2               (0x3a)  */
-       0x00,   /* AK4671_E2_COEFFICIENT3               (0x3b)  */
-       0x00,   /* AK4671_E2_COEFFICIENT4               (0x3c)  */
-       0x00,   /* AK4671_E2_COEFFICIENT5               (0x3d)  */
-       0x00,   /* AK4671_E3_COEFFICIENT0               (0x3e)  */
-       0x00,   /* AK4671_E3_COEFFICIENT1               (0x3f)  */
-       0x00,   /* AK4671_E3_COEFFICIENT2               (0x40)  */
-       0x00,   /* AK4671_E3_COEFFICIENT3               (0x41)  */
-       0x00,   /* AK4671_E3_COEFFICIENT4               (0x42)  */
-       0x00,   /* AK4671_E3_COEFFICIENT5               (0x43)  */
-       0x00,   /* AK4671_E4_COEFFICIENT0               (0x44)  */
-       0x00,   /* AK4671_E4_COEFFICIENT1               (0x45)  */
-       0x00,   /* AK4671_E4_COEFFICIENT2               (0x46)  */
-       0x00,   /* AK4671_E4_COEFFICIENT3               (0x47)  */
-       0x00,   /* AK4671_E4_COEFFICIENT4               (0x48)  */
-       0x00,   /* AK4671_E4_COEFFICIENT5               (0x49)  */
-       0x00,   /* AK4671_E5_COEFFICIENT0               (0x4a)  */
-       0x00,   /* AK4671_E5_COEFFICIENT1               (0x4b)  */
-       0x00,   /* AK4671_E5_COEFFICIENT2               (0x4c)  */
-       0x00,   /* AK4671_E5_COEFFICIENT3               (0x4d)  */
-       0x00,   /* AK4671_E5_COEFFICIENT4               (0x4e)  */
-       0x00,   /* AK4671_E5_COEFFICIENT5               (0x4f)  */
-       0x88,   /* AK4671_EQ_CONTROL_250HZ_100HZ        (0x50)  */
-       0x88,   /* AK4671_EQ_CONTROL_3500HZ_1KHZ        (0x51)  */
-       0x08,   /* AK4671_EQ_CONTRO_10KHZ               (0x52)  */
-       0x00,   /* AK4671_PCM_IF_CONTROL0               (0x53)  */
-       0x00,   /* AK4671_PCM_IF_CONTROL1               (0x54)  */
-       0x00,   /* AK4671_PCM_IF_CONTROL2               (0x55)  */
-       0x18,   /* AK4671_DIGITAL_VOLUME_B_CONTROL      (0x56)  */
-       0x18,   /* AK4671_DIGITAL_VOLUME_C_CONTROL      (0x57)  */
-       0x00,   /* AK4671_SIDETONE_VOLUME_CONTROL       (0x58)  */
-       0x00,   /* AK4671_DIGITAL_MIXING_CONTROL2       (0x59)  */
-       0x00,   /* AK4671_SAR_ADC_CONTROL               (0x5a)  */
+static const struct reg_default ak4671_reg_defaults[] = {
+       { 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT        (0x00)  */
+       { 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0              (0x01)  */
+       { 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1              (0x02)  */
+       { 0x03, 0x02 }, /* AK4671_FORMAT_SELECT                 (0x03)  */
+       { 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT             (0x04)  */
+       { 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN                  (0x05)  */
+       { 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0      (0x06)  */
+       { 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1      (0x07)  */
+       { 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL         (0x08)  */
+       { 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT           (0x09)  */
+       { 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT           (0x0a)  */
+       { 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT           (0x0b)  */
+       { 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT           (0x0c)  */
+       { 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT           (0x0d)  */
+       { 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT           (0x0e)  */
+       { 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT       (0x0f)  */
+       { 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT       (0x10)  */
+       { 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT       (0x11)  */
+       { 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL      (0x12)  */
+       { 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL      (0x13)  */
+       { 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT          (0x14)  */
+       { 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL        (0x15)  */
+       { 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT              (0x16)  */
+       { 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL              (0x17)  */
+       { 0x18, 0x02 }, /* AK4671_MODE_CONTROL1                 (0x18)  */
+       { 0x19, 0x01 }, /* AK4671_MODE_CONTROL2                 (0x19)  */
+       { 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL     (0x1a)  */
+       { 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL     (0x1b)  */
+       { 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL            (0x1c)  */
+       { 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT         (0x1d)  */
+       { 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0             (0x1e)  */
+       { 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1             (0x1f)  */
+       { 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2             (0x20)  */
+       { 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3             (0x21)  */
+       { 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0               (0x22)  */
+       { 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1               (0x23)  */
+       { 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2               (0x24)  */
+       { 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3               (0x25)  */
+       { 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4               (0x26)  */
+       { 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5               (0x27)  */
+       { 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0             (0x28)  */
+       { 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1             (0x29)  */
+       { 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2             (0x2a)  */
+       { 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3             (0x2b)  */
+       { 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0             (0x2c)  */
+       { 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1             (0x2d)  */
+       { 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2             (0x2e)  */
+       { 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3             (0x2f)  */
+       { 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2        (0x30)  */
+
+       { 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0               (0x32)  */
+       { 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1               (0x33)  */
+       { 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2               (0x34)  */
+       { 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3               (0x35)  */
+       { 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4               (0x36)  */
+       { 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5               (0x37)  */
+       { 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0               (0x38)  */
+       { 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1               (0x39)  */
+       { 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2               (0x3a)  */
+       { 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3               (0x3b)  */
+       { 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4               (0x3c)  */
+       { 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5               (0x3d)  */
+       { 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0               (0x3e)  */
+       { 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1               (0x3f)  */
+       { 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2               (0x40)  */
+       { 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3               (0x41)  */
+       { 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4               (0x42)  */
+       { 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5               (0x43)  */
+       { 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0               (0x44)  */
+       { 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1               (0x45)  */
+       { 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2               (0x46)  */
+       { 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3               (0x47)  */
+       { 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4               (0x48)  */
+       { 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5               (0x49)  */
+       { 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0               (0x4a)  */
+       { 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1               (0x4b)  */
+       { 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2               (0x4c)  */
+       { 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3               (0x4d)  */
+       { 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4               (0x4e)  */
+       { 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5               (0x4f)  */
+       { 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ        (0x50)  */
+       { 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ        (0x51)  */
+       { 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ               (0x52)  */
+       { 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0               (0x53)  */
+       { 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1               (0x54)  */
+       { 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2               (0x55)  */
+       { 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL      (0x56)  */
+       { 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL      (0x57)  */
+       { 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL       (0x58)  */
+       { 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2       (0x59)  */
+       { 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL               (0x5a)  */
 };
 
 /*
@@ -241,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {
 /* Input MUXs */
 static const char *ak4671_lin_mux_texts[] =
                {"LIN1", "LIN2", "LIN3", "LIN4"};
-static const struct soc_enum ak4671_lin_mux_enum =
-       SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0,
-                       ARRAY_SIZE(ak4671_lin_mux_texts),
-                       ak4671_lin_mux_texts);
+static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum,
+                           AK4671_MIC_SIGNAL_SELECT, 0,
+                           ak4671_lin_mux_texts);
 static const struct snd_kcontrol_new ak4671_lin_mux_control =
        SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);
 
 static const char *ak4671_rin_mux_texts[] =
                {"RIN1", "RIN2", "RIN3", "RIN4"};
-static const struct soc_enum ak4671_rin_mux_enum =
-       SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2,
-                       ARRAY_SIZE(ak4671_rin_mux_texts),
-                       ak4671_rin_mux_texts);
+static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum,
+                           AK4671_MIC_SIGNAL_SELECT, 2,
+                           ak4671_rin_mux_texts);
 static const struct snd_kcontrol_new ak4671_rin_mux_control =
        SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum);
 
@@ -619,21 +613,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
 
 static int ak4671_probe(struct snd_soc_codec *codec)
 {
-       struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
-       snd_soc_add_codec_controls(codec, ak4671_snd_controls,
-                            ARRAY_SIZE(ak4671_snd_controls));
-
-       ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return ret;
+       return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 }
 
 static int ak4671_remove(struct snd_soc_codec *codec)
@@ -646,28 +626,36 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
        .probe = ak4671_probe,
        .remove = ak4671_remove,
        .set_bias_level = ak4671_set_bias_level,
-       .reg_cache_size = AK4671_CACHEREGNUM,
-       .reg_word_size = sizeof(u8),
-       .reg_cache_default = ak4671_reg,
+       .controls = ak4671_snd_controls,
+       .num_controls = ARRAY_SIZE(ak4671_snd_controls),
        .dapm_widgets = ak4671_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
        .dapm_routes = ak4671_intercon,
        .num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
 };
 
+static const struct regmap_config ak4671_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = AK4671_SAR_ADC_CONTROL,
+       .reg_defaults = ak4671_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int ak4671_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
-       struct ak4671_priv *ak4671;
+       struct regmap *regmap;
        int ret;
 
-       ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv),
-                             GFP_KERNEL);
-       if (ak4671 == NULL)
-               return -ENOMEM;
-
-       i2c_set_clientdata(client, ak4671);
-       ak4671->control_type = SND_SOC_I2C;
+       regmap = devm_regmap_init_i2c(client, &ak4671_regmap);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+               return ret;
+       }
 
        ret = snd_soc_register_codec(&client->dev,
                        &soc_codec_dev_ak4671, &ak4671_dai, 1);
index 61cb7ab7552ce5a390fd1306905214a60bdd442e..394a34d3f50a72458aea67bdaebdc887fdd0180d 100644 (file)
 #define AK4671_DIGITAL_MIXING_CONTROL2         0x59
 #define AK4671_SAR_ADC_CONTROL                 0x5a
 
-#define AK4671_CACHEREGNUM                     (AK4671_SAR_ADC_CONTROL + 1)
-
 /* Bitfield Definitions */
 
 /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */
index d3036283482a10814453671ac33f991e46a54b89..09f7e773bafb8721619843c187be4c24b06af73e 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -38,26 +39,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
 
 /* codec private data */
 struct alc5623_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        u8 id;
        unsigned int sysclk;
-       u16 reg_cache[ALC5623_VENDOR_ID2+2];
        unsigned int add_ctrl;
        unsigned int jack_det_ctrl;
 };
 
-static void alc5623_fill_cache(struct snd_soc_codec *codec)
-{
-       int i, step = codec->driver->reg_cache_step;
-       u16 *cache = codec->reg_cache;
-
-       /* not really efficient ... */
-       codec->cache_bypass = 1;
-       for (i = 0 ; i < codec->driver->reg_cache_size ; i += step)
-               cache[i] = snd_soc_read(codec, i);
-       codec->cache_bypass = 0;
-}
-
 static inline int alc5623_reset(struct snd_soc_codec *codec)
 {
        return snd_soc_write(codec, ALC5623_RESET, 0);
@@ -228,32 +216,37 @@ static const char *alc5623_aux_out_input_sel[] = {
                "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
 
 /* auxout output mux */
-static const struct soc_enum alc5623_aux_out_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum,
+                           ALC5623_OUTPUT_MIXER_CTRL, 6,
+                           alc5623_aux_out_input_sel);
 static const struct snd_kcontrol_new alc5623_auxout_mux_controls =
 SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum);
 
 /* speaker output mux */
-static const struct soc_enum alc5623_spkout_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum,
+                           ALC5623_OUTPUT_MIXER_CTRL, 10,
+                           alc5623_spkout_input_sel);
 static const struct snd_kcontrol_new alc5623_spkout_mux_controls =
 SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum);
 
 /* headphone left output mux */
-static const struct soc_enum alc5623_hpl_out_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum,
+                           ALC5623_OUTPUT_MIXER_CTRL, 9,
+                           alc5623_hpl_out_input_sel);
 static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls =
 SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum);
 
 /* headphone right output mux */
-static const struct soc_enum alc5623_hpr_out_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum,
+                           ALC5623_OUTPUT_MIXER_CTRL, 8,
+                           alc5623_hpr_out_input_sel);
 static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls =
 SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum);
 
 /* speaker output N select */
-static const struct soc_enum alc5623_spk_n_sour_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum,
+                           ALC5623_OUTPUT_MIXER_CTRL, 14,
+                           alc5623_spk_n_sour_sel);
 static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls =
 SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum);
 
@@ -338,8 +331,9 @@ SND_SOC_DAPM_VMID("Vmid"),
 };
 
 static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"};
-static const struct soc_enum alc5623_amp_enum =
-       SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names);
+static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum,
+                           ALC5623_OUTPUT_MIXER_CTRL, 13,
+                           alc5623_amp_names);
 static const struct snd_kcontrol_new alc5623_amp_mux_controls =
        SOC_DAPM_ENUM("Route", alc5623_amp_enum);
 
@@ -869,18 +863,28 @@ static struct snd_soc_dai_driver alc5623_dai = {
 
 static int alc5623_suspend(struct snd_soc_codec *codec)
 {
+       struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+
        alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regcache_cache_only(alc5623->regmap, true);
+
        return 0;
 }
 
 static int alc5623_resume(struct snd_soc_codec *codec)
 {
-       int i, step = codec->driver->reg_cache_step;
-       u16 *cache = codec->reg_cache;
+       struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
        /* Sync reg_cache with the hardware */
-       for (i = 2 ; i < codec->driver->reg_cache_size ; i += step)
-               snd_soc_write(codec, i, cache[i]);
+       regcache_cache_only(alc5623->regmap, false);
+       ret = regcache_sync(alc5623->regmap);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to sync register cache: %d\n",
+                       ret);
+               regcache_cache_only(alc5623->regmap, true);
+               return ret;
+       }
 
        alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -900,14 +904,7 @@ static int alc5623_probe(struct snd_soc_codec *codec)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        alc5623_reset(codec);
-       alc5623_fill_cache(codec);
 
        /* power on device */
        alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -980,9 +977,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
        .suspend = alc5623_suspend,
        .resume = alc5623_resume,
        .set_bias_level = alc5623_set_bias_level,
-       .reg_cache_size = ALC5623_VENDOR_ID2+2,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_step = 2,
+};
+
+static const struct regmap_config alc5623_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .reg_stride = 2,
+
+       .max_register = ALC5623_VENDOR_ID2,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 /*
@@ -996,19 +999,32 @@ static int alc5623_i2c_probe(struct i2c_client *client,
 {
        struct alc5623_platform_data *pdata;
        struct alc5623_priv *alc5623;
-       int ret, vid1, vid2;
+       unsigned int vid1, vid2;
+       int ret;
 
-       vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1);
-       if (vid1 < 0) {
-               dev_err(&client->dev, "failed to read I2C\n");
-               return -EIO;
+       alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
+                              GFP_KERNEL);
+       if (alc5623 == NULL)
+               return -ENOMEM;
+
+       alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap);
+       if (IS_ERR(alc5623->regmap)) {
+               ret = PTR_ERR(alc5623->regmap);
+               dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret);
+               return ret;
        }
        vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8);
 
-       vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2);
-       if (vid2 < 0) {
-               dev_err(&client->dev, "failed to read I2C\n");
-               return -EIO;
+       ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret);
+               return ret;
        }
 
        if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
@@ -1021,11 +1037,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
 
        dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2);
 
-       alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
-                              GFP_KERNEL);
-       if (alc5623 == NULL)
-               return -ENOMEM;
-
        pdata = client->dev.platform_data;
        if (pdata) {
                alc5623->add_ctrl = pdata->add_ctrl;
@@ -1048,7 +1059,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
        }
 
        i2c_set_clientdata(client, alc5623);
-       alc5623->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&client->dev,
                &soc_codec_device_alc5623, &alc5623_dai, 1);
index fb001c56cf8d63525d3350f54c96e117454d06bd..ec071a6306ef567fb37b8c97981b64d1b3390f9e 100644 (file)
@@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = {
                "ADC LR", "Voice Stereo Digital"};
 
 /* auxout output mux */
-static const struct soc_enum alc5632_aux_out_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum,
+                           ALC5632_OUTPUT_MIXER_CTRL, 6,
+                           alc5632_aux_out_input_sel);
 static const struct snd_kcontrol_new alc5632_auxout_mux_controls =
 SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum);
 
 /* speaker output mux */
-static const struct soc_enum alc5632_spkout_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum,
+                           ALC5632_OUTPUT_MIXER_CTRL, 10,
+                           alc5632_spkout_input_sel);
 static const struct snd_kcontrol_new alc5632_spkout_mux_controls =
 SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum);
 
 /* headphone left output mux */
-static const struct soc_enum alc5632_hpl_out_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum,
+                           ALC5632_OUTPUT_MIXER_CTRL, 9,
+                           alc5632_hpl_out_input_sel);
 static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls =
 SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum);
 
 /* headphone right output mux */
-static const struct soc_enum alc5632_hpr_out_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum,
+                           ALC5632_OUTPUT_MIXER_CTRL, 8,
+                           alc5632_hpr_out_input_sel);
 static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls =
 SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum);
 
 /* speaker output N select */
-static const struct soc_enum alc5632_spk_n_sour_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum,
+                           ALC5632_OUTPUT_MIXER_CTRL, 14,
+                           alc5632_spk_n_sour_sel);
 static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls =
 SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum);
 
 /* speaker amplifier */
 static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"};
-static const struct soc_enum alc5632_amp_enum =
-       SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names);
+static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum,
+                           ALC5632_OUTPUT_MIXER_CTRL, 13,
+                           alc5632_amp_names);
 static const struct snd_kcontrol_new alc5632_amp_mux_controls =
        SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum);
 
 /* ADC output select */
-static const struct soc_enum alc5632_adcr_func_enum =
-       SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum,
+                           ALC5632_DAC_FUNC_SELECT, 5,
+                           alc5632_adcr_func_sel);
 static const struct snd_kcontrol_new alc5632_adcr_func_controls =
        SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum);
 
 /* I2S out select */
-static const struct soc_enum alc5632_i2s_out_enum =
-       SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum,
+                           ALC5632_I2S_OUT_CTL, 5,
+                           alc5632_i2s_out_sel);
 static const struct snd_kcontrol_new alc5632_i2s_out_controls =
        SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum);
 
@@ -1055,14 +1063,6 @@ static int alc5632_probe(struct snd_soc_codec *codec)
        struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = alc5632->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;
-       }
-
        /* power on device  */
        alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
index e4295fee8f13673f15f9811a9516ba84bb548584..29e198f57d4cd711f56c90fa640c807edbee414a 100644 (file)
 #define ARIZONA_AIF_RX_ENABLES                  0x1A
 #define ARIZONA_AIF_FORCE_WRITE                 0x1B
 
+#define ARIZONA_FLL_VCO_CORNER 141900000
+#define ARIZONA_FLL_MAX_FREF   13500000
+#define ARIZONA_FLL_MIN_FVCO   90000000
+#define ARIZONA_FLL_MAX_FRATIO 16
+#define ARIZONA_FLL_MAX_REFDIV 8
+#define ARIZONA_FLL_MIN_OUTDIV 2
+#define ARIZONA_FLL_MAX_OUTDIV 7
+
 #define arizona_fll_err(_fll, fmt, ...) \
        dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
 #define arizona_fll_warn(_fll, fmt, ...) \
@@ -542,67 +550,76 @@ static const char *arizona_vol_ramp_text[] = {
        "15ms/6dB", "30ms/6dB",
 };
 
-const struct soc_enum arizona_in_vd_ramp =
-       SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
-                       ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
+                    ARIZONA_INPUT_VOLUME_RAMP,
+                    ARIZONA_IN_VD_RAMP_SHIFT,
+                    arizona_vol_ramp_text);
 EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
 
-const struct soc_enum arizona_in_vi_ramp =
-       SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
-                       ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
+                    ARIZONA_INPUT_VOLUME_RAMP,
+                    ARIZONA_IN_VI_RAMP_SHIFT,
+                    arizona_vol_ramp_text);
 EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
 
-const struct soc_enum arizona_out_vd_ramp =
-       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
-                       ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
+                    ARIZONA_OUTPUT_VOLUME_RAMP,
+                    ARIZONA_OUT_VD_RAMP_SHIFT,
+                    arizona_vol_ramp_text);
 EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
 
-const struct soc_enum arizona_out_vi_ramp =
-       SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
-                       ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
+                    ARIZONA_OUTPUT_VOLUME_RAMP,
+                    ARIZONA_OUT_VI_RAMP_SHIFT,
+                    arizona_vol_ramp_text);
 EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
 
 static const char *arizona_lhpf_mode_text[] = {
        "Low-pass", "High-pass"
 };
 
-const struct soc_enum arizona_lhpf1_mode =
-       SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
-                       arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
+                    ARIZONA_HPLPF1_1,
+                    ARIZONA_LHPF1_MODE_SHIFT,
+                    arizona_lhpf_mode_text);
 EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
 
-const struct soc_enum arizona_lhpf2_mode =
-       SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
-                       arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
+                    ARIZONA_HPLPF2_1,
+                    ARIZONA_LHPF2_MODE_SHIFT,
+                    arizona_lhpf_mode_text);
 EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
 
-const struct soc_enum arizona_lhpf3_mode =
-       SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
-                       arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
+                    ARIZONA_HPLPF3_1,
+                    ARIZONA_LHPF3_MODE_SHIFT,
+                    arizona_lhpf_mode_text);
 EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
 
-const struct soc_enum arizona_lhpf4_mode =
-       SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
-                       arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
+                    ARIZONA_HPLPF4_1,
+                    ARIZONA_LHPF4_MODE_SHIFT,
+                    arizona_lhpf_mode_text);
 EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
 
 static const char *arizona_ng_hold_text[] = {
        "30ms", "120ms", "250ms", "500ms",
 };
 
-const struct soc_enum arizona_ng_hold =
-       SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
-                       4, arizona_ng_hold_text);
+SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
+                    ARIZONA_NOISE_GATE_CONTROL,
+                    ARIZONA_NGATE_HOLD_SHIFT,
+                    arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
 static const char * const arizona_in_hpf_cut_text[] = {
        "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
 };
 
-const struct soc_enum arizona_in_hpf_cut_enum =
-       SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
-                       ARRAY_SIZE(arizona_in_hpf_cut_text),
-                       arizona_in_hpf_cut_text);
+SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
+                    ARIZONA_HPF_CONTROL,
+                    ARIZONA_IN_HPF_CUT_SHIFT,
+                    arizona_in_hpf_cut_text);
 EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
 
 static const char * const arizona_in_dmic_osr_text[] = {
@@ -1377,74 +1394,147 @@ struct arizona_fll_cfg {
        int gain;
 };
 
-static int arizona_calc_fll(struct arizona_fll *fll,
-                           struct arizona_fll_cfg *cfg,
-                           unsigned int Fref,
-                           unsigned int Fout)
+static int arizona_validate_fll(struct arizona_fll *fll,
+                               unsigned int Fref,
+                               unsigned int Fout)
 {
-       unsigned int target, div, gcd_fll;
-       int i, ratio;
+       unsigned int Fvco_min;
+
+       if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
+               arizona_fll_err(fll,
+                               "Can't scale %dMHz in to <=13.5MHz\n",
+                               Fref);
+               return -EINVAL;
+       }
 
-       arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
+       Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
+       if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
+               arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
+                               Fout);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int arizona_find_fratio(unsigned int Fref, int *fratio)
+{
+       int i;
+
+       /* Find an appropriate FLL_FRATIO */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       if (fratio)
+                               *fratio = fll_fratios[i].fratio;
+                       return fll_fratios[i].ratio;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int arizona_calc_fratio(struct arizona_fll *fll,
+                              struct arizona_fll_cfg *cfg,
+                              unsigned int target,
+                              unsigned int Fref, bool sync)
+{
+       int init_ratio, ratio;
+       int refdiv, div;
 
-       /* Fref must be <=13.5MHz */
+       /* Fref must be <=13.5MHz, find initial refdiv */
        div = 1;
        cfg->refdiv = 0;
-       while ((Fref / div) > 13500000) {
+       while (Fref > ARIZONA_FLL_MAX_FREF) {
                div *= 2;
+               Fref /= 2;
                cfg->refdiv++;
 
-               if (div > 8) {
-                       arizona_fll_err(fll,
-                                       "Can't scale %dMHz in to <=13.5MHz\n",
-                                       Fref);
+               if (div > ARIZONA_FLL_MAX_REFDIV)
                        return -EINVAL;
+       }
+
+       /* Find an appropriate FLL_FRATIO */
+       init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
+       if (init_ratio < 0) {
+               arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
+                               Fref);
+               return init_ratio;
+       }
+
+       switch (fll->arizona->type) {
+       case WM5110:
+               if (fll->arizona->rev < 3 || sync)
+                       return init_ratio;
+               break;
+       default:
+               return init_ratio;
+       }
+
+       cfg->fratio = init_ratio - 1;
+
+       /* Adjust FRATIO/refdiv to avoid integer mode if possible */
+       refdiv = cfg->refdiv;
+
+       while (div <= ARIZONA_FLL_MAX_REFDIV) {
+               for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
+                    ratio++) {
+                       if (target % (ratio * Fref)) {
+                               cfg->refdiv = refdiv;
+                               cfg->fratio = ratio - 1;
+                               return ratio;
+                       }
                }
+
+               for (ratio = init_ratio - 1; ratio >= 0; ratio--) {
+                       if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) <
+                           Fref)
+                               break;
+
+                       if (target % (ratio * Fref)) {
+                               cfg->refdiv = refdiv;
+                               cfg->fratio = ratio - 1;
+                               return ratio;
+                       }
+               }
+
+               div *= 2;
+               Fref /= 2;
+               refdiv++;
+               init_ratio = arizona_find_fratio(Fref, NULL);
        }
 
-       /* Apply the division for our remaining calculations */
-       Fref /= div;
+       arizona_fll_warn(fll, "Falling back to integer mode operation\n");
+       return cfg->fratio + 1;
+}
+
+static int arizona_calc_fll(struct arizona_fll *fll,
+                           struct arizona_fll_cfg *cfg,
+                           unsigned int Fref, bool sync)
+{
+       unsigned int target, div, gcd_fll;
+       int i, ratio;
+
+       arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
 
        /* Fvco should be over the targt; don't check the upper bound */
-       div = 1;
-       while (Fout * div < 90000000 * fll->vco_mult) {
+       div = ARIZONA_FLL_MIN_OUTDIV;
+       while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
                div++;
-               if (div > 7) {
-                       arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
-                                       Fout);
+               if (div > ARIZONA_FLL_MAX_OUTDIV)
                        return -EINVAL;
-               }
        }
-       target = Fout * div / fll->vco_mult;
+       target = fll->fout * div / fll->vco_mult;
        cfg->outdiv = div;
 
        arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
 
-       /* Find an appropraite FLL_FRATIO and factor it out of the target */
-       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
-               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
-                       cfg->fratio = fll_fratios[i].fratio;
-                       ratio = fll_fratios[i].ratio;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(fll_fratios)) {
-               arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
-                               Fref);
-               return -EINVAL;
-       }
+       /* Find an appropriate FLL_FRATIO and refdiv */
+       ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
+       if (ratio < 0)
+               return ratio;
 
-       for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
-               if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
-                       cfg->gain = fll_gains[i].gain;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(fll_gains)) {
-               arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
-                               Fref);
-               return -EINVAL;
-       }
+       /* Apply the division for our remaining calculations */
+       Fref = Fref / (1 << cfg->refdiv);
 
        cfg->n = target / (ratio * Fref);
 
@@ -1469,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
                cfg->lambda >>= 1;
        }
 
+       for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
+               if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
+                       cfg->gain = fll_gains[i].gain;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_gains)) {
+               arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
+                               Fref);
+               return -EINVAL;
+       }
+
        arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
                        cfg->n, cfg->theta, cfg->lambda);
        arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
@@ -1496,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
                                 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
                                 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
 
-       if (sync)
-               regmap_update_bits_async(arizona->regmap, base + 0x7,
-                                        ARIZONA_FLL1_GAIN_MASK,
-                                        cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
-       else
-               regmap_update_bits_async(arizona->regmap, base + 0x9,
-                                        ARIZONA_FLL1_GAIN_MASK,
-                                        cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+       if (sync) {
+               regmap_update_bits(arizona->regmap, base + 0x7,
+                                  ARIZONA_FLL1_GAIN_MASK,
+                                  cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+       } else {
+               regmap_update_bits(arizona->regmap, base + 0x5,
+                                  ARIZONA_FLL1_OUTDIV_MASK,
+                                  cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+               regmap_update_bits(arizona->regmap, base + 0x9,
+                                  ARIZONA_FLL1_GAIN_MASK,
+                                  cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+       }
 
        regmap_update_bits_async(arizona->regmap, base + 2,
                                 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
@@ -1526,13 +1632,12 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll)
        return reg & ARIZONA_FLL1_ENA;
 }
 
-static void arizona_enable_fll(struct arizona_fll *fll,
-                             struct arizona_fll_cfg *ref,
-                             struct arizona_fll_cfg *sync)
+static void arizona_enable_fll(struct arizona_fll *fll)
 {
        struct arizona *arizona = fll->arizona;
        int ret;
        bool use_sync = false;
+       struct arizona_fll_cfg cfg;
 
        /*
         * If we have both REFCLK and SYNCCLK then enable both,
@@ -1540,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll,
         */
        if (fll->ref_src >= 0 && fll->ref_freq &&
            fll->ref_src != fll->sync_src) {
-               regmap_update_bits_async(arizona->regmap, fll->base + 5,
-                                        ARIZONA_FLL1_OUTDIV_MASK,
-                                        ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+               arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
 
-               arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
+               arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
                                  false);
                if (fll->sync_src >= 0) {
-                       arizona_apply_fll(arizona, fll->base + 0x10, sync,
+                       arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
+
+                       arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
                                          fll->sync_src, true);
                        use_sync = true;
                }
        } else if (fll->sync_src >= 0) {
-               regmap_update_bits_async(arizona->regmap, fll->base + 5,
-                                        ARIZONA_FLL1_OUTDIV_MASK,
-                                        sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+               arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
 
-               arizona_apply_fll(arizona, fll->base, sync,
+               arizona_apply_fll(arizona, fll->base, &cfg,
                                  fll->sync_src, false);
 
                regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
@@ -1618,32 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll)
 int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
                           unsigned int Fref, unsigned int Fout)
 {
-       struct arizona_fll_cfg ref, sync;
        int ret;
 
        if (fll->ref_src == source && fll->ref_freq == Fref)
                return 0;
 
-       if (fll->fout) {
-               if (Fref > 0) {
-                       ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
-                       if (ret != 0)
-                               return ret;
-               }
-
-               if (fll->sync_src >= 0) {
-                       ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
-                                              fll->fout);
-                       if (ret != 0)
-                               return ret;
-               }
+       if (fll->fout && Fref > 0) {
+               ret = arizona_validate_fll(fll, Fref, fll->fout);
+               if (ret != 0)
+                       return ret;
        }
 
        fll->ref_src = source;
        fll->ref_freq = Fref;
 
        if (fll->fout && Fref > 0) {
-               arizona_enable_fll(fll, &ref, &sync);
+               arizona_enable_fll(fll);
        }
 
        return 0;
@@ -1653,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
 int arizona_set_fll(struct arizona_fll *fll, int source,
                    unsigned int Fref, unsigned int Fout)
 {
-       struct arizona_fll_cfg ref, sync;
        int ret;
 
        if (fll->sync_src == source &&
@@ -1662,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
 
        if (Fout) {
                if (fll->ref_src >= 0) {
-                       ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
-                                              Fout);
+                       ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
                        if (ret != 0)
                                return ret;
                }
 
-               ret = arizona_calc_fll(fll, &sync, Fref, Fout);
+               ret = arizona_validate_fll(fll, Fref, Fout);
                if (ret != 0)
                        return ret;
        }
@@ -1678,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
        fll->fout = Fout;
 
        if (Fout) {
-               arizona_enable_fll(fll, &ref, &sync);
+               arizona_enable_fll(fll);
        } else {
                arizona_disable_fll(fll);
        }
index 43737a27d79caff3dda074565d0201493d4fb96e..1e25c7af853bcdb7c40b7c94d4cb2ca6e878b8be 100644 (file)
@@ -138,9 +138,8 @@ static int cq93vc_probe(struct snd_soc_codec *codec)
        struct davinci_vc *davinci_vc = codec->dev->platform_data;
 
        davinci_vc->cq93vc.codec = codec;
-       codec->control_data = davinci_vc->regmap;
 
-       snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP);
+       snd_soc_codec_set_cache_io(codec, davinci_vc->regmap);
 
        /* Off, with power on */
        cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
index 83c835d9fd884b18a87cdbb5420838b8fd9229f0..3920e626494885947853fd856f9d5ed37bc443ed 100644 (file)
@@ -506,15 +506,6 @@ static int cs4270_probe(struct snd_soc_codec *codec)
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       /* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
-        * then do the I2C transactions itself.
-        */
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
-               return ret;
-       }
-
        /* Disable auto-mute.  This feature appears to be buggy.  In some
         * situations, auto-mute will not deactivate when it should, so we want
         * this feature disabled by default.  An application (e.g. alsactl) can
index ce05fd93dc748c3cc8e1405b1d50296f5e9780e3..aef4965750c780ec52bea5d0285fe1142e1ba83d 100644 (file)
@@ -159,7 +159,6 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
 }
 
 struct cs4271_private {
-       /* SND_SOC_I2C or SND_SOC_SPI */
        unsigned int                    mclk;
        bool                            master;
        bool                            deemph;
@@ -540,14 +539,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
        struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
        int ret;
-       int gpio_nreset = -EINVAL;
        bool amutec_eq_bmutec = false;
 
 #ifdef CONFIG_OF
        if (of_match_device(cs4271_dt_ids, codec->dev)) {
-               gpio_nreset = of_get_named_gpio(codec->dev->of_node,
-                                               "reset-gpio", 0);
-
                if (of_get_property(codec->dev->of_node,
                                     "cirrus,amutec-eq-bmutec", NULL))
                        amutec_eq_bmutec = true;
@@ -559,27 +554,19 @@ static int cs4271_probe(struct snd_soc_codec *codec)
 #endif
 
        if (cs4271plat) {
-               if (gpio_is_valid(cs4271plat->gpio_nreset))
-                       gpio_nreset = cs4271plat->gpio_nreset;
-
                amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
                cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
        }
 
-       if (gpio_nreset >= 0)
-               if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset"))
-                       gpio_nreset = -EINVAL;
-       if (gpio_nreset >= 0) {
+       if (gpio_is_valid(cs4271->gpio_nreset)) {
                /* Reset codec */
-               gpio_direction_output(gpio_nreset, 0);
+               gpio_direction_output(cs4271->gpio_nreset, 0);
                udelay(1);
-               gpio_set_value(gpio_nreset, 1);
+               gpio_set_value(cs4271->gpio_nreset, 1);
                /* Give the codec time to wake up */
                udelay(1);
        }
 
-       cs4271->gpio_nreset = gpio_nreset;
-
        ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
                                 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
                                 CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
@@ -625,6 +612,36 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
        .num_dapm_routes        = ARRAY_SIZE(cs4271_dapm_routes),
 };
 
+static int cs4271_common_probe(struct device *dev,
+                              struct cs4271_private **c)
+{
+       struct cs4271_platform_data *cs4271plat = dev->platform_data;
+       struct cs4271_private *cs4271;
+
+       cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
+       if (!cs4271)
+               return -ENOMEM;
+
+       if (of_match_device(cs4271_dt_ids, dev))
+               cs4271->gpio_nreset =
+                       of_get_named_gpio(dev->of_node, "reset-gpio", 0);
+
+       if (cs4271plat)
+               cs4271->gpio_nreset = cs4271plat->gpio_nreset;
+
+       if (gpio_is_valid(cs4271->gpio_nreset)) {
+               int ret;
+
+               ret = devm_gpio_request(dev, cs4271->gpio_nreset,
+                                       "CS4271 Reset");
+               if (ret < 0)
+                       return ret;
+       }
+
+       *c = cs4271;
+       return 0;
+}
+
 #if defined(CONFIG_SPI_MASTER)
 
 static const struct regmap_config cs4271_spi_regmap = {
@@ -644,10 +661,11 @@ static const struct regmap_config cs4271_spi_regmap = {
 static int cs4271_spi_probe(struct spi_device *spi)
 {
        struct cs4271_private *cs4271;
+       int ret;
 
-       cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL);
-       if (!cs4271)
-               return -ENOMEM;
+       ret = cs4271_common_probe(&spi->dev, &cs4271);
+       if (ret < 0)
+               return ret;
 
        spi_set_drvdata(spi, cs4271);
        cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
@@ -698,10 +716,11 @@ static int cs4271_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
        struct cs4271_private *cs4271;
+       int ret;
 
-       cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL);
-       if (!cs4271)
-               return -ENOMEM;
+       ret = cs4271_common_probe(&client->dev, &cs4271);
+       if (ret < 0)
+               return ret;
 
        i2c_set_clientdata(client, cs4271);
        cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
index 6e9ea8379a91272de475985429a21643fbabec22..6c0da2baa154e2a79a1baaf4392efacf4a7694af 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/pcm_params.h>
 #include <sound/pcm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 
 #include "cs42l51.h"
 
@@ -40,7 +41,6 @@ enum master_slave_mode {
 };
 
 struct cs42l51_private {
-       enum snd_soc_control_type control_type;
        unsigned int mclk;
        unsigned int audio_mode;        /* The mode (I2S or left-justified) */
        enum master_slave_mode func;
@@ -52,24 +52,6 @@ struct cs42l51_private {
                SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
                SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
 
-static int cs42l51_fill_cache(struct snd_soc_codec *codec)
-{
-       u8 *cache = codec->reg_cache + 1;
-       struct i2c_client *i2c_client = to_i2c_client(codec->dev);
-       s32 length;
-
-       length = i2c_smbus_read_i2c_block_data(i2c_client,
-                       CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
-       if (length != CS42L51_NUMREGS) {
-               dev_err(&i2c_client->dev,
-                               "I2C read failure, addr=0x%x (ret=%d vs %d)\n",
-                               i2c_client->addr, length, CS42L51_NUMREGS);
-               return -EIO;
-       }
-
-       return 0;
-}
-
 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
@@ -124,9 +106,8 @@ static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
 
 static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
 static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
-/* This is a lie. after -102 db, it stays at -102 */
-/* maybe a range would be better */
-static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
 
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
 static const char *chan_mix[] = {
@@ -135,13 +116,12 @@ static const char *chan_mix[] = {
        "R L",
 };
 
-static const struct soc_enum cs42l51_chan_mix =
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
+static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);
 
 static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
        SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
                        CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
-                       6, 0x19, 0x7F, adc_pcm_tlv),
+                       0, 0x19, 0x7F, adc_pcm_tlv),
        SOC_DOUBLE_R("PCM Playback Switch",
                        CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
        SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
@@ -149,7 +129,7 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
                        0, 0x34, 0xE4, aout_tlv),
        SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
                        CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
-                       6, 0x19, 0x7F, adc_pcm_tlv),
+                       0, 0x19, 0x7F, adc_pcm_tlv),
        SOC_DOUBLE_R("ADC Mixer Switch",
                        CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
        SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
@@ -192,22 +172,22 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
 
 static const char *cs42l51_dac_names[] = {"Direct PCM",
        "DSP PCM", "ADC"};
-static const struct soc_enum cs42l51_dac_mux_enum =
-       SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
+static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum,
+                           CS42L51_DAC_CTL, 6, cs42l51_dac_names);
 static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
        SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
 
 static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
        "MIC Left", "MIC+preamp Left"};
-static const struct soc_enum cs42l51_adcl_mux_enum =
-       SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
+static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum,
+                           CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);
 static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
        SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
 
 static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
        "MIC Right", "MIC+preamp Right"};
-static const struct soc_enum cs42l51_adcr_mux_enum =
-       SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
+static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum,
+                           CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);
 static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
        SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
 
@@ -505,21 +485,8 @@ static struct snd_soc_dai_driver cs42l51_dai = {
 
 static int cs42l51_probe(struct snd_soc_codec *codec)
 {
-       struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
        int ret, reg;
 
-       ret = cs42l51_fill_cache(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to fill register cache\n");
-               return ret;
-       }
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /*
         * DAC configuration
         * - Use signal processor
@@ -538,8 +505,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
 
 static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
        .probe = cs42l51_probe,
-       .reg_cache_size = CS42L51_NUMREGS + 1,
-       .reg_word_size = sizeof(u8),
 
        .controls = cs42l51_snd_controls,
        .num_controls = ARRAY_SIZE(cs42l51_snd_controls),
@@ -549,38 +514,53 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
        .num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
 };
 
+static const struct regmap_config cs42l51_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = CS42L51_CHARGE_FREQ,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
        const struct i2c_device_id *id)
 {
        struct cs42l51_private *cs42l51;
+       struct regmap *regmap;
+       unsigned int val;
        int ret;
 
+       regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               dev_err(&i2c_client->dev, "Failed to create regmap: %d\n",
+                       ret);
+               return ret;
+       }
+
        /* Verify that we have a CS42L51 */
-       ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+       ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
        if (ret < 0) {
                dev_err(&i2c_client->dev, "failed to read I2C\n");
                goto error;
        }
 
-       if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
-           (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
-               dev_err(&i2c_client->dev, "Invalid chip id\n");
+       if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+           (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+               dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val);
                ret = -ENODEV;
                goto error;
        }
 
        dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
-                               ret & 7);
+                val & 7);
 
        cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private),
                               GFP_KERNEL);
-       if (!cs42l51) {
-               dev_err(&i2c_client->dev, "could not allocate codec\n");
+       if (!cs42l51)
                return -ENOMEM;
-       }
 
        i2c_set_clientdata(i2c_client, cs42l51);
-       cs42l51->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c_client->dev,
                        &soc_codec_device_cs42l51, &cs42l51_dai, 1);
@@ -600,10 +580,17 @@ static const struct i2c_device_id cs42l51_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs42l51_id);
 
+static const struct of_device_id cs42l51_of_match[] = {
+       { .compatible = "cirrus,cs42l51", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+
 static struct i2c_driver cs42l51_i2c_driver = {
        .driver = {
                .name = "cs42l51-codec",
                .owner = THIS_MODULE,
+               .of_match_table = cs42l51_of_match,
        },
        .id_table = cs42l51_id,
        .probe = cs42l51_i2c_probe,
index 0bac6d5a4ac8fac7c00e3a909f044a499f11761b..f0ca6bee677159e0bb9a6af0a660bb937b815b7d 100644 (file)
@@ -210,13 +210,11 @@ static const char * const cs42l52_adca_text[] = {
 static const char * const cs42l52_adcb_text[] = {
        "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
 
-static const struct soc_enum adca_enum =
-       SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5,
-               ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text);
+static SOC_ENUM_SINGLE_DECL(adca_enum,
+                           CS42L52_ADC_PGA_A, 5, cs42l52_adca_text);
 
-static const struct soc_enum adcb_enum =
-       SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5,
-               ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text);
+static SOC_ENUM_SINGLE_DECL(adcb_enum,
+                           CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text);
 
 static const struct snd_kcontrol_new adca_mux =
        SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
@@ -229,26 +227,22 @@ static const char * const mic_bias_level_text[] = {
        "0.8 +VA", "0.83 +VA", "0.91 +VA"
 };
 
-static const struct soc_enum mic_bias_level_enum =
-       SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0,
-                       ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
+static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum,
+                           CS42L52_IFACE_CTL2, 0, mic_bias_level_text);
 
 static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
 
-static const struct soc_enum mica_enum =
-       SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
-                       ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+static SOC_ENUM_SINGLE_DECL(mica_enum,
+                           CS42L52_MICA_CTL, 5, cs42l52_mic_text);
 
-static const struct soc_enum micb_enum =
-       SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
-                       ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+static SOC_ENUM_SINGLE_DECL(micb_enum,
+                           CS42L52_MICB_CTL, 5, cs42l52_mic_text);
 
 static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
 
-static const struct soc_enum digital_output_mux_enum =
-       SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6,
-                       ARRAY_SIZE(digital_output_mux_text),
-                       digital_output_mux_text);
+static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum,
+                           CS42L52_ADC_MISC_CTL, 6,
+                           digital_output_mux_text);
 
 static const struct snd_kcontrol_new digital_output_mux =
        SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
@@ -258,18 +252,18 @@ static const char * const hp_gain_num_text[] = {
        "0.7099", "0.8399", "1.000", "1.1430"
 };
 
-static const struct soc_enum hp_gain_enum =
-       SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 5,
-               ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text);
+static SOC_ENUM_SINGLE_DECL(hp_gain_enum,
+                           CS42L52_PB_CTL1, 5,
+                           hp_gain_num_text);
 
 static const char * const beep_pitch_text[] = {
        "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
        "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
 };
 
-static const struct soc_enum beep_pitch_enum =
-       SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4,
-                       ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+static SOC_ENUM_SINGLE_DECL(beep_pitch_enum,
+                           CS42L52_BEEP_FREQ, 4,
+                           beep_pitch_text);
 
 static const char * const beep_ontime_text[] = {
        "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
@@ -277,66 +271,66 @@ static const char * const beep_ontime_text[] = {
        "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
 };
 
-static const struct soc_enum beep_ontime_enum =
-       SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0,
-                       ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+static SOC_ENUM_SINGLE_DECL(beep_ontime_enum,
+                           CS42L52_BEEP_FREQ, 0,
+                           beep_ontime_text);
 
 static const char * const beep_offtime_text[] = {
        "1.23 s", "2.58 s", "3.90 s", "5.20 s",
        "6.60 s", "8.05 s", "9.35 s", "10.80 s"
 };
 
-static const struct soc_enum beep_offtime_enum =
-       SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5,
-                       ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+static SOC_ENUM_SINGLE_DECL(beep_offtime_enum,
+                           CS42L52_BEEP_VOL, 5,
+                           beep_offtime_text);
 
 static const char * const beep_config_text[] = {
        "Off", "Single", "Multiple", "Continuous"
 };
 
-static const struct soc_enum beep_config_enum =
-       SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6,
-                       ARRAY_SIZE(beep_config_text), beep_config_text);
+static SOC_ENUM_SINGLE_DECL(beep_config_enum,
+                           CS42L52_BEEP_TONE_CTL, 6,
+                           beep_config_text);
 
 static const char * const beep_bass_text[] = {
        "50 Hz", "100 Hz", "200 Hz", "250 Hz"
 };
 
-static const struct soc_enum beep_bass_enum =
-       SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1,
-                       ARRAY_SIZE(beep_bass_text), beep_bass_text);
+static SOC_ENUM_SINGLE_DECL(beep_bass_enum,
+                           CS42L52_BEEP_TONE_CTL, 1,
+                           beep_bass_text);
 
 static const char * const beep_treble_text[] = {
        "5 kHz", "7 kHz", "10 kHz", " 15 kHz"
 };
 
-static const struct soc_enum beep_treble_enum =
-       SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3,
-                       ARRAY_SIZE(beep_treble_text), beep_treble_text);
+static SOC_ENUM_SINGLE_DECL(beep_treble_enum,
+                           CS42L52_BEEP_TONE_CTL, 3,
+                           beep_treble_text);
 
 static const char * const ng_threshold_text[] = {
        "-34dB", "-37dB", "-40dB", "-43dB",
        "-46dB", "-52dB", "-58dB", "-64dB"
 };
 
-static const struct soc_enum ng_threshold_enum =
-       SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2,
-               ARRAY_SIZE(ng_threshold_text), ng_threshold_text);
+static SOC_ENUM_SINGLE_DECL(ng_threshold_enum,
+                           CS42L52_NOISE_GATE_CTL, 2,
+                           ng_threshold_text);
 
 static const char * const cs42l52_ng_delay_text[] = {
        "50ms", "100ms", "150ms", "200ms"};
 
-static const struct soc_enum ng_delay_enum =
-       SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0,
-               ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text);
+static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
+                           CS42L52_NOISE_GATE_CTL, 0,
+                           cs42l52_ng_delay_text);
 
 static const char * const cs42l52_ng_type_text[] = {
        "Apply Specific", "Apply All"
 };
 
-static const struct soc_enum ng_type_enum =
-       SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6,
-               ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text);
+static SOC_ENUM_SINGLE_DECL(ng_type_enum,
+                           CS42L52_NOISE_GATE_CTL, 6,
+                           cs42l52_ng_type_text);
 
 static const char * const left_swap_text[] = {
        "Left", "LR 2", "Right"};
@@ -347,7 +341,7 @@ static const char * const right_swap_text[] = {
 static const unsigned int swap_values[] = { 0, 1, 3 };
 
 static const struct soc_enum adca_swap_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1,
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 3,
                              ARRAY_SIZE(left_swap_text),
                              left_swap_text,
                              swap_values);
@@ -356,7 +350,7 @@ static const struct snd_kcontrol_new adca_mixer =
        SOC_DAPM_ENUM("Route", adca_swap_enum);
 
 static const struct soc_enum pcma_swap_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1,
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 3,
                              ARRAY_SIZE(left_swap_text),
                              left_swap_text,
                              swap_values);
@@ -365,7 +359,7 @@ static const struct snd_kcontrol_new pcma_mixer =
        SOC_DAPM_ENUM("Route", pcma_swap_enum);
 
 static const struct soc_enum adcb_swap_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1,
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 3,
                              ARRAY_SIZE(right_swap_text),
                              right_swap_text,
                              swap_values);
@@ -374,7 +368,7 @@ static const struct snd_kcontrol_new adcb_mixer =
        SOC_DAPM_ENUM("Route", adcb_swap_enum);
 
 static const struct soc_enum pcmb_swap_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1,
+       SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 3,
                              ARRAY_SIZE(right_swap_text),
                              right_swap_text,
                              swap_values);
@@ -1115,14 +1109,7 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
 static int cs42l52_probe(struct snd_soc_codec *codec)
 {
        struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
-       int ret;
 
-       codec->control_data = cs42l52->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
        regcache_cache_only(cs42l52->regmap, true);
 
        cs42l52_add_mic_controls(codec);
@@ -1134,7 +1121,7 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
        cs42l52->sysclk = CS42L52_DEFAULT_CLK;
        cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
 
-       return ret;
+       return 0;
 }
 
 static int cs42l52_remove(struct snd_soc_codec *codec)
index 549d5d6a3fef47f0680934c68b36a2c6a48529d0..0ee60a19a26334dcae0484244fcf9d374965fc88 100644 (file)
@@ -278,13 +278,13 @@ static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);
 static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" };
 static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" };
 
-static const struct soc_enum pgaa_enum =
-       SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3,
-               ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text);
+static SOC_ENUM_SINGLE_DECL(pgaa_enum,
+                           CS42L73_ADCIPC, 3,
+                           cs42l73_pgaa_text);
 
-static const struct soc_enum pgab_enum =
-       SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7,
-               ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text);
+static SOC_ENUM_SINGLE_DECL(pgab_enum,
+                           CS42L73_ADCIPC, 7,
+                           cs42l73_pgab_text);
 
 static const struct snd_kcontrol_new pgaa_mux =
        SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum);
@@ -309,9 +309,9 @@ static const struct snd_kcontrol_new input_right_mixer[] = {
 static const char * const cs42l73_ng_delay_text[] = {
        "50ms", "100ms", "150ms", "200ms" };
 
-static const struct soc_enum ng_delay_enum =
-       SOC_ENUM_SINGLE(CS42L73_NGCAB, 0,
-               ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text);
+static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
+                           CS42L73_NGCAB, 0,
+                           cs42l73_ng_delay_text);
 
 static const char * const cs42l73_mono_mix_texts[] = {
        "Left", "Right", "Mono Mix"};
@@ -319,7 +319,7 @@ static const char * const cs42l73_mono_mix_texts[] = {
 static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
 
 static const struct soc_enum spk_asp_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 1,
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,
                              ARRAY_SIZE(cs42l73_mono_mix_texts),
                              cs42l73_mono_mix_texts,
                              cs42l73_mono_mix_values);
@@ -337,7 +337,7 @@ static const struct snd_kcontrol_new spk_xsp_mixer =
        SOC_DAPM_ENUM("Route", spk_xsp_enum);
 
 static const struct soc_enum esl_asp_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 5,
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,
                              ARRAY_SIZE(cs42l73_mono_mix_texts),
                              cs42l73_mono_mix_texts,
                              cs42l73_mono_mix_values);
@@ -346,7 +346,7 @@ static const struct snd_kcontrol_new esl_asp_mixer =
        SOC_DAPM_ENUM("Route", esl_asp_enum);
 
 static const struct soc_enum esl_xsp_enum =
-       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 7,
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,
                              ARRAY_SIZE(cs42l73_mono_mix_texts),
                              cs42l73_mono_mix_texts,
                              cs42l73_mono_mix_values);
@@ -357,19 +357,19 @@ static const struct snd_kcontrol_new esl_xsp_mixer =
 static const char * const cs42l73_ip_swap_text[] = {
        "Stereo", "Mono A", "Mono B", "Swap A-B"};
 
-static const struct soc_enum ip_swap_enum =
-       SOC_ENUM_SINGLE(CS42L73_MIOPC, 6,
-               ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text);
+static SOC_ENUM_SINGLE_DECL(ip_swap_enum,
+                           CS42L73_MIOPC, 6,
+                           cs42l73_ip_swap_text);
 
 static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"};
 
-static const struct soc_enum vsp_output_mux_enum =
-       SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5,
-               ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
+static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum,
+                           CS42L73_MIXERCTL, 5,
+                           cs42l73_spo_mixer_text);
 
-static const struct soc_enum xsp_output_mux_enum =
-       SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4,
-               ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
+static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum,
+                           CS42L73_MIXERCTL, 4,
+                           cs42l73_spo_mixer_text);
 
 static const struct snd_kcontrol_new vsp_output_mux =
        SOC_DAPM_ENUM("Route", vsp_output_mux_enum);
@@ -1108,7 +1108,7 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        return 0;
 }
 
-static u32 cs42l73_asrc_rates[] = {
+static const unsigned int cs42l73_asrc_rates[] = {
        8000, 11025, 12000, 16000, 22050,
        24000, 32000, 44100, 48000
 };
@@ -1241,7 +1241,7 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
                                        0x7F, tristate << 7);
 }
 
-static struct snd_pcm_hw_constraint_list constraints_12_24 = {
+static const struct snd_pcm_hw_constraint_list constraints_12_24 = {
        .count  = ARRAY_SIZE(cs42l73_asrc_rates),
        .list   = cs42l73_asrc_rates,
 };
@@ -1255,9 +1255,6 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
-#define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
-
 
 #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
@@ -1278,14 +1275,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
                        .stream_name = "XSP Playback",
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = CS42L73_RATES,
+                       .rates = SNDRV_PCM_RATE_KNOT,
                        .formats = CS42L73_FORMATS,
                },
                .capture = {
                        .stream_name = "XSP Capture",
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = CS42L73_RATES,
+                       .rates = SNDRV_PCM_RATE_KNOT,
                        .formats = CS42L73_FORMATS,
                },
                .ops = &cs42l73_ops,
@@ -1298,14 +1295,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
                        .stream_name = "ASP Playback",
                        .channels_min = 2,
                        .channels_max = 2,
-                       .rates = CS42L73_RATES,
+                       .rates = SNDRV_PCM_RATE_KNOT,
                        .formats = CS42L73_FORMATS,
                },
                .capture = {
                        .stream_name = "ASP Capture",
                        .channels_min = 2,
                        .channels_max = 2,
-                       .rates = CS42L73_RATES,
+                       .rates = SNDRV_PCM_RATE_KNOT,
                        .formats = CS42L73_FORMATS,
                },
                .ops = &cs42l73_ops,
@@ -1318,14 +1315,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
                        .stream_name = "VSP Playback",
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = CS42L73_RATES,
+                       .rates = SNDRV_PCM_RATE_KNOT,
                        .formats = CS42L73_FORMATS,
                },
                .capture = {
                        .stream_name = "VSP Capture",
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = CS42L73_RATES,
+                       .rates = SNDRV_PCM_RATE_KNOT,
                        .formats = CS42L73_FORMATS,
                },
                .ops = &cs42l73_ops,
@@ -1348,17 +1345,8 @@ static int cs42l73_resume(struct snd_soc_codec *codec)
 
 static int cs42l73_probe(struct snd_soc_codec *codec)
 {
-       int ret;
        struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
 
-       codec->control_data = cs42l73->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Set Charge Pump Frequency */
@@ -1371,7 +1359,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
        cs42l73->mclksel = CS42L73_CLKID_MCLK1;
        cs42l73->mclk = 0;
 
-       return ret;
+       return 0;
 }
 
 static int cs42l73_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
new file mode 100644 (file)
index 0000000..657dce2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.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/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+
+#include "cs42xx8.h"
+
+static int cs42xx8_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       u32 ret = cs42xx8_probe(&i2c->dev,
+                       devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+       if (ret)
+               return ret;
+
+       pm_runtime_enable(&i2c->dev);
+       pm_request_idle(&i2c->dev);
+
+       return 0;
+}
+
+static int cs42xx8_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       pm_runtime_disable(&i2c->dev);
+
+       return 0;
+}
+
+static struct i2c_device_id cs42xx8_i2c_id[] = {
+       {"cs42448", (kernel_ulong_t)&cs42448_data},
+       {"cs42888", (kernel_ulong_t)&cs42888_data},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
+
+static struct i2c_driver cs42xx8_i2c_driver = {
+       .driver = {
+               .name = "cs42xx8",
+               .owner = THIS_MODULE,
+               .pm = &cs42xx8_pm,
+       },
+       .probe = cs42xx8_i2c_probe,
+       .remove = cs42xx8_i2c_remove,
+       .id_table = cs42xx8_i2c_id,
+};
+
+module_i2c_driver(cs42xx8_i2c_driver);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
new file mode 100644 (file)
index 0000000..082299a
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.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/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42xx8.h"
+
+#define CS42XX8_NUM_SUPPLIES 4
+static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
+       "VA",
+       "VD",
+       "VLS",
+       "VLC",
+};
+
+#define CS42XX8_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | \
+                        SNDRV_PCM_FMTBIT_S20_3LE | \
+                        SNDRV_PCM_FMTBIT_S24_LE | \
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct cs42xx8_priv {
+       struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
+       const struct cs42xx8_driver_data *drvdata;
+       struct regmap *regmap;
+       struct clk *clk;
+
+       bool slave_mode;
+       unsigned long sysclk;
+};
+
+/* -127.5dB to 0dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+/* -64dB to 24dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
+
+static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
+static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
+                                       "Soft Ramp", "Soft Ramp on Zero Cross" };
+
+static const struct soc_enum adc1_single_enum =
+       SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
+static const struct soc_enum adc2_single_enum =
+       SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
+static const struct soc_enum adc3_single_enum =
+       SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
+static const struct soc_enum dac_szc_enum =
+       SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
+static const struct soc_enum adc_szc_enum =
+       SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
+
+static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
+                        CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
+       SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
+                        CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
+       SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
+                        CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
+       SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
+                        CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
+       SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
+                          CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
+       SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
+                          CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
+       SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
+       SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
+       SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
+       SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
+       SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
+       SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
+       SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
+       SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
+       SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
+       SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
+       SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
+       SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
+       SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
+       SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
+       SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
+       SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
+};
+
+static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
+       SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
+                          CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
+       SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
+       SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
+       SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
+       SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
+       SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
+
+       SND_SOC_DAPM_OUTPUT("AOUT1L"),
+       SND_SOC_DAPM_OUTPUT("AOUT1R"),
+       SND_SOC_DAPM_OUTPUT("AOUT2L"),
+       SND_SOC_DAPM_OUTPUT("AOUT2R"),
+       SND_SOC_DAPM_OUTPUT("AOUT3L"),
+       SND_SOC_DAPM_OUTPUT("AOUT3R"),
+       SND_SOC_DAPM_OUTPUT("AOUT4L"),
+       SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+       SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
+       SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
+
+       SND_SOC_DAPM_INPUT("AIN1L"),
+       SND_SOC_DAPM_INPUT("AIN1R"),
+       SND_SOC_DAPM_INPUT("AIN2L"),
+       SND_SOC_DAPM_INPUT("AIN2R"),
+
+       SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
+       SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
+
+       SND_SOC_DAPM_INPUT("AIN3L"),
+       SND_SOC_DAPM_INPUT("AIN3R"),
+};
+
+static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
+       /* Playback */
+       { "AOUT1L", NULL, "DAC1" },
+       { "AOUT1R", NULL, "DAC1" },
+       { "DAC1", NULL, "PWR" },
+
+       { "AOUT2L", NULL, "DAC2" },
+       { "AOUT2R", NULL, "DAC2" },
+       { "DAC2", NULL, "PWR" },
+
+       { "AOUT3L", NULL, "DAC3" },
+       { "AOUT3R", NULL, "DAC3" },
+       { "DAC3", NULL, "PWR" },
+
+       { "AOUT4L", NULL, "DAC4" },
+       { "AOUT4R", NULL, "DAC4" },
+       { "DAC4", NULL, "PWR" },
+
+       /* Capture */
+       { "ADC1", NULL, "AIN1L" },
+       { "ADC1", NULL, "AIN1R" },
+       { "ADC1", NULL, "PWR" },
+
+       { "ADC2", NULL, "AIN2L" },
+       { "ADC2", NULL, "AIN2R" },
+       { "ADC2", NULL, "PWR" },
+};
+
+static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
+       /* Capture */
+       { "ADC3", NULL, "AIN3L" },
+       { "ADC3", NULL, "AIN3R" },
+       { "ADC3", NULL, "PWR" },
+};
+
+struct cs42xx8_ratios {
+       unsigned int ratio;
+       unsigned char speed;
+       unsigned char mclk;
+};
+
+static const struct cs42xx8_ratios cs42xx8_ratios[] = {
+       { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
+       { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
+       { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
+       { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
+       { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
+       { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
+       { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
+       { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
+       { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
+};
+
+static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+
+       cs42xx8->sysclk = freq;
+
+       return 0;
+}
+
+static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                              unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+       u32 val;
+
+       /* Set DAI format */
+       switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported dai format\n");
+               return -EINVAL;
+       }
+
+       regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
+                          CS42XX8_INTF_DAC_DIF_MASK |
+                          CS42XX8_INTF_ADC_DIF_MASK, val);
+
+       /* Set master/slave audio interface */
+       switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               cs42xx8->slave_mode = true;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               cs42xx8->slave_mode = false;
+               break;
+       default:
+               dev_err(codec->dev, "unsupported master/slave mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cs42xx8_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 cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+       bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       u32 ratio = cs42xx8->sysclk / params_rate(params);
+       u32 i, fm, val, mask;
+
+       for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
+               if (cs42xx8_ratios[i].ratio == ratio)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(cs42xx8_ratios)) {
+               dev_err(codec->dev, "unsupported sysclk ratio\n");
+               return -EINVAL;
+       }
+
+       mask = CS42XX8_FUNCMOD_MFREQ_MASK;
+       val = cs42xx8_ratios[i].mclk;
+
+       fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
+
+       regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
+                          CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
+                          CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
+
+       return 0;
+}
+
+static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
+                          CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
+       .set_fmt        = cs42xx8_set_dai_fmt,
+       .set_sysclk     = cs42xx8_set_dai_sysclk,
+       .hw_params      = cs42xx8_hw_params,
+       .digital_mute   = cs42xx8_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs42xx8_dai = {
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = CS42XX8_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = CS42XX8_FORMATS,
+       },
+       .ops = &cs42xx8_dai_ops,
+};
+
+static const struct reg_default cs42xx8_reg[] = {
+       { 0x01, 0x01 },   /* Chip I.D. and Revision Register */
+       { 0x02, 0x00 },   /* Power Control */
+       { 0x03, 0xF0 },   /* Functional Mode */
+       { 0x04, 0x46 },   /* Interface Formats */
+       { 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
+       { 0x06, 0x10 },   /* Transition Control */
+       { 0x07, 0x00 },   /* DAC Channel Mute */
+       { 0x08, 0x00 },   /* Volume Control AOUT1 */
+       { 0x09, 0x00 },   /* Volume Control AOUT2 */
+       { 0x0a, 0x00 },   /* Volume Control AOUT3 */
+       { 0x0b, 0x00 },   /* Volume Control AOUT4 */
+       { 0x0c, 0x00 },   /* Volume Control AOUT5 */
+       { 0x0d, 0x00 },   /* Volume Control AOUT6 */
+       { 0x0e, 0x00 },   /* Volume Control AOUT7 */
+       { 0x0f, 0x00 },   /* Volume Control AOUT8 */
+       { 0x10, 0x00 },   /* DAC Channel Invert */
+       { 0x11, 0x00 },   /* Volume Control AIN1 */
+       { 0x12, 0x00 },   /* Volume Control AIN2 */
+       { 0x13, 0x00 },   /* Volume Control AIN3 */
+       { 0x14, 0x00 },   /* Volume Control AIN4 */
+       { 0x15, 0x00 },   /* Volume Control AIN5 */
+       { 0x16, 0x00 },   /* Volume Control AIN6 */
+       { 0x17, 0x00 },   /* ADC Channel Invert */
+       { 0x18, 0x00 },   /* Status Control */
+       { 0x1a, 0x00 },   /* Status Mask */
+       { 0x1b, 0x00 },   /* MUTEC Pin Control */
+};
+
+static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42XX8_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42XX8_CHIPID:
+       case CS42XX8_STATUS:
+               return false;
+       default:
+               return true;
+       }
+}
+
+const struct regmap_config cs42xx8_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = CS42XX8_LASTREG,
+       .reg_defaults = cs42xx8_reg,
+       .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
+       .volatile_reg = cs42xx8_volatile_register,
+       .writeable_reg = cs42xx8_writeable_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
+
+static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
+{
+       struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       switch (cs42xx8->drvdata->num_adcs) {
+       case 3:
+               snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
+                                       ARRAY_SIZE(cs42xx8_adc3_snd_controls));
+               snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
+                                       ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
+                                       ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
+               break;
+       default:
+               break;
+       }
+
+       /* Mute all DAC channels */
+       regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
+
+       return 0;
+}
+
+static const struct snd_soc_codec_driver cs42xx8_driver = {
+       .probe = cs42xx8_codec_probe,
+       .idle_bias_off = true,
+
+       .controls = cs42xx8_snd_controls,
+       .num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
+       .dapm_widgets = cs42xx8_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
+       .dapm_routes = cs42xx8_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
+};
+
+const struct cs42xx8_driver_data cs42448_data = {
+       .name = "cs42448",
+       .num_adcs = 3,
+};
+EXPORT_SYMBOL_GPL(cs42448_data);
+
+const struct cs42xx8_driver_data cs42888_data = {
+       .name = "cs42888",
+       .num_adcs = 2,
+};
+EXPORT_SYMBOL_GPL(cs42888_data);
+
+const struct of_device_id cs42xx8_of_match[] = {
+       { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+       { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+EXPORT_SYMBOL_GPL(cs42xx8_of_match);
+
+int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+{
+       const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
+       struct cs42xx8_priv *cs42xx8;
+       int ret, val, i;
+
+       cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
+       if (cs42xx8 == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, cs42xx8);
+
+       if (of_id)
+               cs42xx8->drvdata = of_id->data;
+
+       if (!cs42xx8->drvdata) {
+               dev_err(dev, "failed to find driver data\n");
+               return -EINVAL;
+       }
+
+       cs42xx8->clk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(cs42xx8->clk)) {
+               dev_err(dev, "failed to get the clock: %ld\n",
+                               PTR_ERR(cs42xx8->clk));
+               return -EINVAL;
+       }
+
+       cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
+
+       for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
+               cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev,
+                       ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
+       if (ret) {
+               dev_err(dev, "failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+                                   cs42xx8->supplies);
+       if (ret) {
+               dev_err(dev, "failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       /* Make sure hardware reset done */
+       msleep(5);
+
+       cs42xx8->regmap = regmap;
+       if (IS_ERR(cs42xx8->regmap)) {
+               ret = PTR_ERR(cs42xx8->regmap);
+               dev_err(dev, "failed to allocate regmap: %d\n", ret);
+               goto err_enable;
+       }
+
+       /*
+        * We haven't marked the chip revision as volatile due to
+        * sharing a register with the right input volume; explicitly
+        * bypass the cache to read it.
+        */
+       regcache_cache_bypass(cs42xx8->regmap, true);
+
+       /* Validate the chip ID */
+       regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
+       if (val < 0) {
+               dev_err(dev, "failed to get device ID: %x", val);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       /* The top four bits of the chip ID should be 0000 */
+       if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) {
+               dev_err(dev, "unmatched chip ID: %d\n",
+                               val & CS42XX8_CHIPID_CHIP_ID_MASK);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       dev_info(dev, "found device, revision %X\n",
+                       val & CS42XX8_CHIPID_REV_ID_MASK);
+
+       regcache_cache_bypass(cs42xx8->regmap, false);
+
+       cs42xx8_dai.name = cs42xx8->drvdata->name;
+
+       /* Each adc supports stereo input */
+       cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
+
+       ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
+       if (ret) {
+               dev_err(dev, "failed to register codec:%d\n", ret);
+               goto err_enable;
+       }
+
+       regcache_cache_only(cs42xx8->regmap, true);
+
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+                              cs42xx8->supplies);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cs42xx8_probe);
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs42xx8_runtime_resume(struct device *dev)
+{
+       struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(cs42xx8->clk);
+       if (ret) {
+               dev_err(dev, "failed to enable mclk: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+                                   cs42xx8->supplies);
+       if (ret) {
+               dev_err(dev, "failed to enable supplies: %d\n", ret);
+               goto err_clk;
+       }
+
+       /* Make sure hardware reset done */
+       msleep(5);
+
+       regcache_cache_only(cs42xx8->regmap, false);
+
+       ret = regcache_sync(cs42xx8->regmap);
+       if (ret) {
+               dev_err(dev, "failed to sync regmap: %d\n", ret);
+               goto err_bulk;
+       }
+
+       return 0;
+
+err_bulk:
+       regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+                              cs42xx8->supplies);
+err_clk:
+       clk_disable_unprepare(cs42xx8->clk);
+
+       return ret;
+}
+
+static int cs42xx8_runtime_suspend(struct device *dev)
+{
+       struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+
+       regcache_cache_only(cs42xx8->regmap, true);
+
+       regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+                              cs42xx8->supplies);
+
+       clk_disable_unprepare(cs42xx8->clk);
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops cs42xx8_pm = {
+       SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(cs42xx8_pm);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
new file mode 100644 (file)
index 0000000..da0b94a
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.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 _CS42XX8_H
+#define _CS42XX8_H
+
+struct cs42xx8_driver_data {
+       char name[32];
+       int num_adcs;
+};
+
+extern const struct dev_pm_ops cs42xx8_pm;
+extern const struct cs42xx8_driver_data cs42448_data;
+extern const struct cs42xx8_driver_data cs42888_data;
+extern const struct regmap_config cs42xx8_regmap_config;
+int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+
+/* CS42888 register map */
+#define CS42XX8_CHIPID                         0x01    /* Chip ID */
+#define CS42XX8_PWRCTL                         0x02    /* Power Control */
+#define CS42XX8_FUNCMOD                                0x03    /* Functional Mode */
+#define CS42XX8_INTF                           0x04    /* Interface Formats */
+#define CS42XX8_ADCCTL                         0x05    /* ADC Control */
+#define CS42XX8_TXCTL                          0x06    /* Transition Control */
+#define CS42XX8_DACMUTE                                0x07    /* DAC Mute Control */
+#define CS42XX8_VOLAOUT1                       0x08    /* Volume Control AOUT1 */
+#define CS42XX8_VOLAOUT2                       0x09    /* Volume Control AOUT2 */
+#define CS42XX8_VOLAOUT3                       0x0A    /* Volume Control AOUT3 */
+#define CS42XX8_VOLAOUT4                       0x0B    /* Volume Control AOUT4 */
+#define CS42XX8_VOLAOUT5                       0x0C    /* Volume Control AOUT5 */
+#define CS42XX8_VOLAOUT6                       0x0D    /* Volume Control AOUT6 */
+#define CS42XX8_VOLAOUT7                       0x0E    /* Volume Control AOUT7 */
+#define CS42XX8_VOLAOUT8                       0x0F    /* Volume Control AOUT8 */
+#define CS42XX8_DACINV                         0x10    /* DAC Channel Invert */
+#define CS42XX8_VOLAIN1                                0x11    /* Volume Control AIN1 */
+#define CS42XX8_VOLAIN2                                0x12    /* Volume Control AIN2 */
+#define CS42XX8_VOLAIN3                                0x13    /* Volume Control AIN3 */
+#define CS42XX8_VOLAIN4                                0x14    /* Volume Control AIN4 */
+#define CS42XX8_VOLAIN5                                0x15    /* Volume Control AIN5 */
+#define CS42XX8_VOLAIN6                                0x16    /* Volume Control AIN6 */
+#define CS42XX8_ADCINV                         0x17    /* ADC Channel Invert */
+#define CS42XX8_STATUSCTL                      0x18    /* Status Control */
+#define CS42XX8_STATUS                         0x19    /* Status */
+#define CS42XX8_STATUSM                                0x1A    /* Status Mask */
+#define CS42XX8_MUTEC                          0x1B    /* MUTEC Pin Control */
+
+#define CS42XX8_FIRSTREG                       CS42XX8_CHIPID
+#define CS42XX8_LASTREG                                CS42XX8_MUTEC
+#define CS42XX8_NUMREGS                                (CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1)
+#define CS42XX8_I2C_INCR                       0x80
+
+/* Chip I.D. and Revision Register (Address 01h) */
+#define CS42XX8_CHIPID_CHIP_ID_MASK            0xF0
+#define CS42XX8_CHIPID_REV_ID_MASK             0x0F
+
+/* Power Control (Address 02h) */
+#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT          7
+#define CS42XX8_PWRCTL_PDN_ADC3_MASK           (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC3                        (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT          6
+#define CS42XX8_PWRCTL_PDN_ADC2_MASK           (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2                        (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT          5
+#define CS42XX8_PWRCTL_PDN_ADC1_MASK           (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1                        (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT          4
+#define CS42XX8_PWRCTL_PDN_DAC4_MASK           (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4                        (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT          3
+#define CS42XX8_PWRCTL_PDN_DAC3_MASK           (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3                        (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT          2
+#define CS42XX8_PWRCTL_PDN_DAC2_MASK           (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2                        (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT          1
+#define CS42XX8_PWRCTL_PDN_DAC1_MASK           (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1                        (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_SHIFT               0
+#define CS42XX8_PWRCTL_PDN_MASK                        (1 << CS42XX8_PWRCTL_PDN_SHIFT)
+#define CS42XX8_PWRCTL_PDN                     (1 << CS42XX8_PWRCTL_PDN_SHIFT)
+
+/* Functional Mode (Address 03h) */
+#define CS42XX8_FUNCMOD_DAC_FM_SHIFT           6
+#define CS42XX8_FUNCMOD_DAC_FM_WIDTH           2
+#define CS42XX8_FUNCMOD_DAC_FM_MASK            (((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_DAC_FM(v)              ((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM_SHIFT           4
+#define CS42XX8_FUNCMOD_ADC_FM_WIDTH           2
+#define CS42XX8_FUNCMOD_ADC_FM_MASK            (((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM(v)              ((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_xC_FM_MASK(x)          ((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK)
+#define CS42XX8_FUNCMOD_xC_FM(x, v)            ((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v))
+#define CS42XX8_FUNCMOD_MFREQ_SHIFT            1
+#define CS42XX8_FUNCMOD_MFREQ_WIDTH            3
+#define CS42XX8_FUNCMOD_MFREQ_MASK             (((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT)
+#define CS42XX8_FUNCMOD_MFREQ_256(s)           ((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_384(s)           ((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_512(s)           ((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_768(s)           ((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_1024(s)          ((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+
+#define CS42XX8_FM_SINGLE                      0
+#define CS42XX8_FM_DOUBLE                      1
+#define CS42XX8_FM_QUAD                                2
+#define CS42XX8_FM_AUTO                                3
+
+/* Interface Formats (Address 04h) */
+#define CS42XX8_INTF_FREEZE_SHIFT              7
+#define CS42XX8_INTF_FREEZE_MASK               (1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_FREEZE                    (1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_AUX_DIF_SHIFT             6
+#define CS42XX8_INTF_AUX_DIF_MASK              (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_AUX_DIF                   (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_SHIFT             3
+#define CS42XX8_INTF_DAC_DIF_WIDTH             3
+#define CS42XX8_INTF_DAC_DIF_MASK              (((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_LEFTJ             (0 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_I2S               (1 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ            (2 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16         (3 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_20                (4 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_24                (6 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_TDM               (7 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_SHIFT             0
+#define CS42XX8_INTF_ADC_DIF_WIDTH             3
+#define CS42XX8_INTF_ADC_DIF_MASK              (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_LEFTJ             (0 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_I2S               (1 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ            (2 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16         (3 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_20                (4 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_24                (6 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_TDM               (7 << CS42XX8_INTF_ADC_DIF_SHIFT)
+
+/* ADC Control & DAC De-Emphasis (Address 05h) */
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT    7
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK     (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE          (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM_SHIFT           5
+#define CS42XX8_ADCCTL_DAC_DEM_MASK            (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM                 (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT       4
+#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK                (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE             (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT       3
+#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK                (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE             (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT       2
+#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK                (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE             (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT          1
+#define CS42XX8_ADCCTL_AIN5_MUX_MASK           (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX                        (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT          0
+#define CS42XX8_ADCCTL_AIN6_MUX_MASK           (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX                        (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+
+/* Transition Control (Address 06h) */
+#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT         7
+#define CS42XX8_TXCTL_DAC_SNGVOL_MASK          (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SNGVOL               (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SHIFT            5
+#define CS42XX8_TXCTL_DAC_SZC_WIDTH            2
+#define CS42XX8_TXCTL_DAC_SZC_MASK             (((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_IC               (0 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_ZC               (1 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SR               (2 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SRZC             (3 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_AMUTE_SHIFT              4
+#define CS42XX8_TXCTL_AMUTE_MASK               (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_AMUTE                    (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT                3
+#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK         (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP              (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT         2
+#define CS42XX8_TXCTL_ADC_SNGVOL_MASK          (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL               (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SHIFT            0
+#define CS42XX8_TXCTL_ADC_SZC_MASK             (((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_IC               (0 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_ZC               (1 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SR               (2 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SRZC             (3 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+
+/* DAC Channel Mute (Address 07h) */
+#define CS42XX8_DACMUTE_AOUT(n)                        (0x1 << n)
+#define CS42XX8_DACMUTE_ALL                    0xff
+
+/* Status Control (Address 18h)*/
+#define CS42XX8_STATUSCTL_INI_SHIFT            2
+#define CS42XX8_STATUSCTL_INI_WIDTH            2
+#define CS42XX8_STATUSCTL_INI_MASK             (((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH      (0 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW       (1 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN       (2 << CS42XX8_STATUSCTL_INI_SHIFT)
+
+/* Status (Address 19h)*/
+#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT       4
+#define CS42XX8_STATUS_DAC_CLK_ERR_MASK                (1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT       3
+#define CS42XX8_STATUS_ADC_CLK_ERR_MASK                (1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_SHIFT         2
+#define CS42XX8_STATUS_ADC3_OVFL_MASK          (1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_SHIFT         1
+#define CS42XX8_STATUS_ADC2_OVFL_MASK          (1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_SHIFT         0
+#define CS42XX8_STATUS_ADC1_OVFL_MASK          (1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT)
+
+/* Status Mask (Address 1Ah) */
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT     4
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK      (1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT     3
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK      (1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT       2
+#define CS42XX8_STATUS_ADC3_OVFL_M_MASK                (1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT       1
+#define CS42XX8_STATUS_ADC2_OVFL_M_MASK                (1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT       0
+#define CS42XX8_STATUS_ADC1_OVFL_M_MASK                (1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT)
+
+/* MUTEC Pin Control (Address 1Bh) */
+#define CS42XX8_MUTEC_MCPOLARITY_SHIFT         1
+#define CS42XX8_MUTEC_MCPOLARITY_MASK          (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW    (0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH   (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT       0
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK                (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE             (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#endif /* _CS42XX8_H */
index e62e294a8033a02ed4e7a90c6c9b41317df79d18..137e8ebc092c5a9f2c1264723211ba7e8405871f 100644 (file)
@@ -307,29 +307,29 @@ static const char * const da7210_hpf_cutoff_txt[] = {
        "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"
 };
 
-static const struct soc_enum da7210_dac_hpf_cutoff =
-       SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff,
+                           DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt);
 
-static const struct soc_enum da7210_adc_hpf_cutoff =
-       SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff,
+                           DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt);
 
 /* ADC and DAC voice (8kHz) high pass cutoff value */
 static const char * const da7210_vf_cutoff_txt[] = {
        "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
 };
 
-static const struct soc_enum da7210_dac_vf_cutoff =
-       SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff,
+                           DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt);
 
-static const struct soc_enum da7210_adc_vf_cutoff =
-       SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff,
+                           DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt);
 
 static const char *da7210_hp_mode_txt[] = {
        "Class H", "Class G"
 };
 
-static const struct soc_enum da7210_hp_mode_sel =
-       SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
+                           DA7210_HP_CFG, 0, da7210_hp_mode_txt);
 
 /* ALC can be enabled only if noise suppression is disabled */
 static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
@@ -1071,17 +1071,9 @@ static struct snd_soc_dai_driver da7210_dai = {
 static int da7210_probe(struct snd_soc_codec *codec)
 {
        struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
-       int ret;
 
        dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
-       codec->control_data = da7210->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        da7210->mclk_rate       = 0;    /* This will be set from set_sysclk() */
        da7210->master          = 0;    /* This will be set from set_fmt() */
 
index 0c77e7ad7423fcf9f7929bfe03d19e4d4427cff1..738fa18a50d2a82c900c49fbc68f3c07c7dd2c07 100644 (file)
@@ -63,30 +63,30 @@ static const char * const da7213_voice_hpf_corner_txt[] = {
        "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
 };
 
-static const struct soc_enum da7213_dac_voice_hpf_corner =
-       SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT,
-                       DA7213_VOICE_HPF_CORNER_MAX,
-                       da7213_voice_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner,
+                           DA7213_DAC_FILTERS1,
+                           DA7213_VOICE_HPF_CORNER_SHIFT,
+                           da7213_voice_hpf_corner_txt);
 
-static const struct soc_enum da7213_adc_voice_hpf_corner =
-       SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT,
-                       DA7213_VOICE_HPF_CORNER_MAX,
-                       da7213_voice_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner,
+                           DA7213_ADC_FILTERS1,
+                           DA7213_VOICE_HPF_CORNER_SHIFT,
+                           da7213_voice_hpf_corner_txt);
 
 /* ADC and DAC high pass filter cutoff value */
 static const char * const da7213_audio_hpf_corner_txt[] = {
        "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
 };
 
-static const struct soc_enum da7213_dac_audio_hpf_corner =
-       SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT,
-                       DA7213_AUDIO_HPF_CORNER_MAX,
-                       da7213_audio_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner,
+                           DA7213_DAC_FILTERS1
+                           , DA7213_AUDIO_HPF_CORNER_SHIFT,
+                           da7213_audio_hpf_corner_txt);
 
-static const struct soc_enum da7213_adc_audio_hpf_corner =
-       SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT,
-                       DA7213_AUDIO_HPF_CORNER_MAX,
-                       da7213_audio_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner,
+                           DA7213_ADC_FILTERS1,
+                           DA7213_AUDIO_HPF_CORNER_SHIFT,
+                           da7213_audio_hpf_corner_txt);
 
 /* Gain ramping rate value */
 static const char * const da7213_gain_ramp_rate_txt[] = {
@@ -94,52 +94,50 @@ static const char * const da7213_gain_ramp_rate_txt[] = {
        "nominal rate / 32"
 };
 
-static const struct soc_enum da7213_gain_ramp_rate =
-       SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT,
-                       DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate,
+                           DA7213_GAIN_RAMP_CTRL,
+                           DA7213_GAIN_RAMP_RATE_SHIFT,
+                           da7213_gain_ramp_rate_txt);
 
 /* DAC noise gate setup time value */
 static const char * const da7213_dac_ng_setup_time_txt[] = {
        "256 samples", "512 samples", "1024 samples", "2048 samples"
 };
 
-static const struct soc_enum da7213_dac_ng_setup_time =
-       SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME,
-                       DA7213_DAC_NG_SETUP_TIME_SHIFT,
-                       DA7213_DAC_NG_SETUP_TIME_MAX,
-                       da7213_dac_ng_setup_time_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time,
+                           DA7213_DAC_NG_SETUP_TIME,
+                           DA7213_DAC_NG_SETUP_TIME_SHIFT,
+                           da7213_dac_ng_setup_time_txt);
 
 /* DAC noise gate rampup rate value */
 static const char * const da7213_dac_ng_rampup_txt[] = {
        "0.02 ms/dB", "0.16 ms/dB"
 };
 
-static const struct soc_enum da7213_dac_ng_rampup_rate =
-       SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME,
-                       DA7213_DAC_NG_RAMPUP_RATE_SHIFT,
-                       DA7213_DAC_NG_RAMP_RATE_MAX,
-                       da7213_dac_ng_rampup_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate,
+                           DA7213_DAC_NG_SETUP_TIME,
+                           DA7213_DAC_NG_RAMPUP_RATE_SHIFT,
+                           da7213_dac_ng_rampup_txt);
 
 /* DAC noise gate rampdown rate value */
 static const char * const da7213_dac_ng_rampdown_txt[] = {
        "0.64 ms/dB", "20.48 ms/dB"
 };
 
-static const struct soc_enum da7213_dac_ng_rampdown_rate =
-       SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME,
-                       DA7213_DAC_NG_RAMPDN_RATE_SHIFT,
-                       DA7213_DAC_NG_RAMP_RATE_MAX,
-                       da7213_dac_ng_rampdown_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate,
+                           DA7213_DAC_NG_SETUP_TIME,
+                           DA7213_DAC_NG_RAMPDN_RATE_SHIFT,
+                           da7213_dac_ng_rampdown_txt);
 
 /* DAC soft mute rate value */
 static const char * const da7213_dac_soft_mute_rate_txt[] = {
        "1", "2", "4", "8", "16", "32", "64"
 };
 
-static const struct soc_enum da7213_dac_soft_mute_rate =
-       SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT,
-                       DA7213_DAC_SOFTMUTE_RATE_MAX,
-                       da7213_dac_soft_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate,
+                           DA7213_DAC_FILTERS5,
+                           DA7213_DAC_SOFTMUTE_RATE_SHIFT,
+                           da7213_dac_soft_mute_rate_txt);
 
 /* ALC Attack Rate select */
 static const char * const da7213_alc_attack_rate_txt[] = {
@@ -147,9 +145,10 @@ static const char * const da7213_alc_attack_rate_txt[] = {
        "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
 };
 
-static const struct soc_enum da7213_alc_attack_rate =
-       SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT,
-                       DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate,
+                           DA7213_ALC_CTRL2,
+                           DA7213_ALC_ATTACK_SHIFT,
+                           da7213_alc_attack_rate_txt);
 
 /* ALC Release Rate select */
 static const char * const da7213_alc_release_rate_txt[] = {
@@ -157,9 +156,10 @@ static const char * const da7213_alc_release_rate_txt[] = {
        "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
 };
 
-static const struct soc_enum da7213_alc_release_rate =
-       SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT,
-                       DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate,
+                           DA7213_ALC_CTRL2,
+                           DA7213_ALC_RELEASE_SHIFT,
+                           da7213_alc_release_rate_txt);
 
 /* ALC Hold Time select */
 static const char * const da7213_alc_hold_time_txt[] = {
@@ -168,22 +168,25 @@ static const char * const da7213_alc_hold_time_txt[] = {
        "253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
 };
 
-static const struct soc_enum da7213_alc_hold_time =
-       SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT,
-                       DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time,
+                           DA7213_ALC_CTRL3,
+                           DA7213_ALC_HOLD_SHIFT,
+                           da7213_alc_hold_time_txt);
 
 /* ALC Input Signal Tracking rate select */
 static const char * const da7213_alc_integ_rate_txt[] = {
        "1/4", "1/16", "1/256", "1/65536"
 };
 
-static const struct soc_enum da7213_alc_integ_attack_rate =
-       SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT,
-                       DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate,
+                           DA7213_ALC_CTRL3,
+                           DA7213_ALC_INTEG_ATTACK_SHIFT,
+                           da7213_alc_integ_rate_txt);
 
-static const struct soc_enum da7213_alc_integ_release_rate =
-       SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT,
-                       DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate,
+                           DA7213_ALC_CTRL3,
+                           DA7213_ALC_INTEG_RELEASE_SHIFT,
+                           da7213_alc_integ_rate_txt);
 
 
 /*
@@ -584,15 +587,17 @@ static const char * const da7213_mic_amp_in_sel_txt[] = {
        "Differential", "MIC_P", "MIC_N"
 };
 
-static const struct soc_enum da7213_mic_1_amp_in_sel =
-       SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT,
-                       DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel,
+                           DA7213_MIC_1_CTRL,
+                           DA7213_MIC_AMP_IN_SEL_SHIFT,
+                           da7213_mic_amp_in_sel_txt);
 static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux =
        SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel);
 
-static const struct soc_enum da7213_mic_2_amp_in_sel =
-       SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT,
-                       DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel,
+                           DA7213_MIC_2_CTRL,
+                           DA7213_MIC_AMP_IN_SEL_SHIFT,
+                           da7213_mic_amp_in_sel_txt);
 static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux =
        SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel);
 
@@ -601,15 +606,17 @@ static const char * const da7213_dai_src_txt[] = {
        "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right"
 };
 
-static const struct soc_enum da7213_dai_l_src =
-       SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT,
-                       DA7213_DAI_SRC_MAX, da7213_dai_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src,
+                           DA7213_DIG_ROUTING_DAI,
+                           DA7213_DAI_L_SRC_SHIFT,
+                           da7213_dai_src_txt);
 static const struct snd_kcontrol_new da7213_dai_l_src_mux =
        SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src);
 
-static const struct soc_enum da7213_dai_r_src =
-       SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT,
-                       DA7213_DAI_SRC_MAX, da7213_dai_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src,
+                           DA7213_DIG_ROUTING_DAI,
+                           DA7213_DAI_R_SRC_SHIFT,
+                           da7213_dai_src_txt);
 static const struct snd_kcontrol_new da7213_dai_r_src_mux =
        SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src);
 
@@ -619,15 +626,17 @@ static const char * const da7213_dac_src_txt[] = {
        "DAI Input Right"
 };
 
-static const struct soc_enum da7213_dac_l_src =
-       SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT,
-                       DA7213_DAC_SRC_MAX, da7213_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src,
+                           DA7213_DIG_ROUTING_DAC,
+                           DA7213_DAC_L_SRC_SHIFT,
+                           da7213_dac_src_txt);
 static const struct snd_kcontrol_new da7213_dac_l_src_mux =
        SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src);
 
-static const struct soc_enum da7213_dac_r_src =
-       SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT,
-                       DA7213_DAC_SRC_MAX, da7213_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src,
+                           DA7213_DIG_ROUTING_DAC,
+                           DA7213_DAC_R_SRC_SHIFT,
+                           da7213_dac_src_txt);
 static const struct snd_kcontrol_new da7213_dac_r_src_mux =
        SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src);
 
@@ -1384,17 +1393,9 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 
 static int da7213_probe(struct snd_soc_codec *codec)
 {
-       int ret;
        struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
        struct da7213_platform_data *pdata = da7213->pdata;
 
-       codec->control_data = da7213->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* Default to using ALC auto offset calibration mode. */
        snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
                            DA7213_ALC_CALIB_MODE_MAN, 0);
index f4d965ebc29e8320469becd09a3ac58a2668e8de..7d168ec71cd70409095ee82fb95ec8a929601f98 100644 (file)
@@ -269,81 +269,65 @@ static const char *da732x_hpf_voice[] = {
        "150Hz", "200Hz", "300Hz", "400Hz"
 };
 
-static const struct soc_enum da732x_dac1_hpf_mode_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
-                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
-
-static const struct soc_enum da732x_dac2_hpf_mode_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
-                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum,
+                           DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
+                           da732x_hpf_mode);
 
-static const struct soc_enum da732x_dac3_hpf_mode_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
-                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum,
+                           DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
+                           da732x_hpf_mode);
 
-static const struct soc_enum da732x_adc1_hpf_mode_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
-                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum,
+                           DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
+                           da732x_hpf_mode);
 
-static const struct soc_enum da732x_adc2_hpf_mode_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
-                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum,
+                           DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
+                           da732x_hpf_mode);
 
-static const struct soc_enum da732x_dac1_hp_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
-                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum,
+                           DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
+                           da732x_hpf_mode);
 
-static const struct soc_enum da732x_dac2_hp_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
-                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum,
+                           DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+                           da732x_hpf_music);
 
-static const struct soc_enum da732x_dac3_hp_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
-                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum,
+                           DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+                           da732x_hpf_music);
 
-static const struct soc_enum da732x_adc1_hp_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
-                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum,
+                           DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
+                           da732x_hpf_music);
 
-static const struct soc_enum da732x_adc2_hp_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
-                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum,
+                           DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+                           da732x_hpf_music);
 
-static const struct soc_enum da732x_dac1_voice_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
-                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum,
+                           DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+                           da732x_hpf_music);
 
-static const struct soc_enum da732x_dac2_voice_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
-                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum,
+                           DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
+                           da732x_hpf_voice);
 
-static const struct soc_enum da732x_dac3_voice_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
-                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum,
+                           DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
+                           da732x_hpf_voice);
 
-static const struct soc_enum da732x_adc1_voice_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
-                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum,
+                           DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
+                           da732x_hpf_voice);
 
-static const struct soc_enum da732x_adc2_voice_filter_enum[] = {
-       SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
-                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum,
+                           DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
+                           da732x_hpf_voice);
 
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
+                           DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
+                           da732x_hpf_voice);
 
 static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
@@ -714,65 +698,65 @@ static const char *enable_text[] = {
 };
 
 /* ADC1LMUX */
-static const struct soc_enum adc1l_enum =
-       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
-                       DA732X_ADCL_MUX_MAX, adcl_text);
+static SOC_ENUM_SINGLE_DECL(adc1l_enum,
+                           DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
+                           adcl_text);
 static const struct snd_kcontrol_new adc1l_mux =
        SOC_DAPM_ENUM("ADC Route", adc1l_enum);
 
 /* ADC1RMUX */
-static const struct soc_enum adc1r_enum =
-       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
-                       DA732X_ADCR_MUX_MAX, adcr_text);
+static SOC_ENUM_SINGLE_DECL(adc1r_enum,
+                           DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
+                           adcr_text);
 static const struct snd_kcontrol_new adc1r_mux =
        SOC_DAPM_ENUM("ADC Route", adc1r_enum);
 
 /* ADC2LMUX */
-static const struct soc_enum adc2l_enum =
-       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
-                       DA732X_ADCL_MUX_MAX, adcl_text);
+static SOC_ENUM_SINGLE_DECL(adc2l_enum,
+                           DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
+                           adcl_text);
 static const struct snd_kcontrol_new adc2l_mux =
        SOC_DAPM_ENUM("ADC Route", adc2l_enum);
 
 /* ADC2RMUX */
-static const struct soc_enum adc2r_enum =
-       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
-                       DA732X_ADCR_MUX_MAX, adcr_text);
+static SOC_ENUM_SINGLE_DECL(adc2r_enum,
+                           DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
+                           adcr_text);
 
 static const struct snd_kcontrol_new adc2r_mux =
        SOC_DAPM_ENUM("ADC Route", adc2r_enum);
 
-static const struct soc_enum da732x_hp_left_output =
-       SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
-                       DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output,
+                           DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
+                           enable_text);
 
 static const struct snd_kcontrol_new hpl_mux =
        SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output);
 
-static const struct soc_enum da732x_hp_right_output =
-       SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
-                       DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output,
+                           DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
+                           enable_text);
 
 static const struct snd_kcontrol_new hpr_mux =
        SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output);
 
-static const struct soc_enum da732x_speaker_output =
-       SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
-                       DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_speaker_output,
+                           DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
+                           enable_text);
 
 static const struct snd_kcontrol_new spk_mux =
        SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output);
 
-static const struct soc_enum da732x_lout4_output =
-       SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
-                       DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_lout4_output,
+                           DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
+                           enable_text);
 
 static const struct snd_kcontrol_new lout4_mux =
        SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output);
 
-static const struct soc_enum da732x_lout2_output =
-       SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
-                       DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_lout2_output,
+                           DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
+                           enable_text);
 
 static const struct snd_kcontrol_new lout2_mux =
        SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output);
@@ -1313,9 +1297,9 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
        msleep(DA732X_WAIT_FOR_STABILIZATION);
 
        /* Check DAC offset sign */
-       sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+       sign[DA732X_HPL_DAC] = (snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
                                DA732X_HP_DAC_OFF_CNTL_COMPO);
-       sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+       sign[DA732X_HPR_DAC] = (snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
                                DA732X_HP_DAC_OFF_CNTL_COMPO);
 
        /* Binary search DAC offset values (both channels at once) */
@@ -1332,10 +1316,10 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
 
                msleep(DA732X_WAIT_FOR_STABILIZATION);
 
-               if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+               if ((snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
                     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])
                        offset[DA732X_HPL_DAC] &= ~step;
-               if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+               if ((snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
                     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])
                        offset[DA732X_HPR_DAC] &= ~step;
 
@@ -1376,9 +1360,9 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
        msleep(DA732X_WAIT_FOR_STABILIZATION);
 
        /* Check output offset sign */
-       sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) &
+       sign[DA732X_HPL_AMP] = snd_soc_read(codec, DA732X_REG_HPL) &
                               DA732X_HP_OUT_COMPO;
-       sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) &
+       sign[DA732X_HPR_AMP] = snd_soc_read(codec, DA732X_REG_HPR) &
                               DA732X_HP_OUT_COMPO;
 
        snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
@@ -1399,10 +1383,10 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
 
                msleep(DA732X_WAIT_FOR_STABILIZATION);
 
-               if ((codec->hw_read(codec, DA732X_REG_HPL) &
+               if ((snd_soc_read(codec, DA732X_REG_HPL) &
                     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])
                        offset[DA732X_HPL_AMP] &= ~step;
-               if ((codec->hw_read(codec, DA732X_REG_HPR) &
+               if ((snd_soc_read(codec, DA732X_REG_HPR) &
                     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])
                        offset[DA732X_HPR_AMP] &= ~step;
 
@@ -1499,8 +1483,8 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 
                        da732x_hp_dc_offset_cancellation(codec);
 
-                       regcache_cache_only(codec->control_data, false);
-                       regcache_sync(codec->control_data);
+                       regcache_cache_only(da732x->regmap, false);
+                       regcache_sync(da732x->regmap);
                } else {
                        snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
                                            DA732X_BIAS_BOOST_MASK,
@@ -1511,7 +1495,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
                }
                break;
        case SND_SOC_BIAS_OFF:
-               regcache_cache_only(codec->control_data, true);
+               regcache_cache_only(da732x->regmap, true);
                da732x_set_charge_pump(codec, DA732X_DISABLE_CP);
                snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
                                    DA732X_BIAS_DIS);
@@ -1528,23 +1512,14 @@ static int da732x_probe(struct snd_soc_codec *codec)
 {
        struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret = 0;
 
        da732x->codec = codec;
 
        dapm->idle_bias_off = false;
 
-       codec->control_data = da732x->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec.\n");
-               goto err;
-       }
-
        da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-err:
-       return ret;
+
+       return 0;
 }
 
 static int da732x_remove(struct snd_soc_codec *codec)
@@ -1566,7 +1541,6 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = {
        .dapm_routes            = da732x_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(da732x_dapm_routes),
        .set_pll                = da732x_set_dai_pll,
-       .reg_cache_size         = ARRAY_SIZE(da732x_reg_cache),
 };
 
 static int da732x_i2c_probe(struct i2c_client *i2c,
index c8ce5475de2293febb046f173c5e5f32367c4f2a..1dceafeec4151b4ae85b629aaa61e0737de73c34 100644 (file)
 #define        DA732X_EQ_OVERALL_VOL_DB_MIN    -1800
 #define        DA732X_EQ_OVERALL_VOL_DB_INC    600
 
-#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \
-       {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext}
-
 enum da732x_sysctl {
        DA732X_SR_8KHZ          = 0x1,
        DA732X_SR_11_025KHZ     = 0x2,
index 422812613a28b1cff117b1adfee2029b69e6049b..4ff06b50fbba78342b596058bfac5a9ce973d097 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -321,22 +323,22 @@ static const char * const da9055_hpf_cutoff_txt[] = {
        "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
 };
 
-static const struct soc_enum da9055_dac_hpf_cutoff =
-       SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff,
+                           DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt);
 
-static const struct soc_enum da9055_adc_hpf_cutoff =
-       SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff,
+                           DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt);
 
 /* ADC and DAC voice mode (8kHz) high pass cutoff value */
 static const char * const da9055_vf_cutoff_txt[] = {
        "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
 };
 
-static const struct soc_enum da9055_dac_vf_cutoff =
-       SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff,
+                           DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt);
 
-static const struct soc_enum da9055_adc_vf_cutoff =
-       SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff,
+                           DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt);
 
 /* Gain ramping rate value */
 static const char * const da9055_gain_ramping_txt[] = {
@@ -344,44 +346,44 @@ static const char * const da9055_gain_ramping_txt[] = {
        "nominal rate / 8"
 };
 
-static const struct soc_enum da9055_gain_ramping_rate =
-       SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate,
+                           DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt);
 
 /* DAC noise gate setup time value */
 static const char * const da9055_dac_ng_setup_time_txt[] = {
        "256 samples", "512 samples", "1024 samples", "2048 samples"
 };
 
-static const struct soc_enum da9055_dac_ng_setup_time =
-       SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4,
-                       da9055_dac_ng_setup_time_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time,
+                           DA9055_DAC_NG_SETUP_TIME, 0,
+                           da9055_dac_ng_setup_time_txt);
 
 /* DAC noise gate rampup rate value */
 static const char * const da9055_dac_ng_rampup_txt[] = {
        "0.02 ms/dB", "0.16 ms/dB"
 };
 
-static const struct soc_enum da9055_dac_ng_rampup_rate =
-       SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2,
-                       da9055_dac_ng_rampup_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate,
+                           DA9055_DAC_NG_SETUP_TIME, 2,
+                           da9055_dac_ng_rampup_txt);
 
 /* DAC noise gate rampdown rate value */
 static const char * const da9055_dac_ng_rampdown_txt[] = {
        "0.64 ms/dB", "20.48 ms/dB"
 };
 
-static const struct soc_enum da9055_dac_ng_rampdown_rate =
-       SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2,
-                       da9055_dac_ng_rampdown_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate,
+                           DA9055_DAC_NG_SETUP_TIME, 3,
+                           da9055_dac_ng_rampdown_txt);
 
 /* DAC soft mute rate value */
 static const char * const da9055_dac_soft_mute_rate_txt[] = {
        "1", "2", "4", "8", "16", "32", "64"
 };
 
-static const struct soc_enum da9055_dac_soft_mute_rate =
-       SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7,
-                       da9055_dac_soft_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate,
+                           DA9055_DAC_FILTERS5, 4,
+                           da9055_dac_soft_mute_rate_txt);
 
 /* DAC routing select */
 static const char * const da9055_dac_src_txt[] = {
@@ -389,40 +391,40 @@ static const char * const da9055_dac_src_txt[] = {
        "AIF input right"
 };
 
-static const struct soc_enum da9055_dac_l_src =
-       SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src,
+                           DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt);
 
-static const struct soc_enum da9055_dac_r_src =
-       SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src,
+                           DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt);
 
 /* MIC PGA Left source select */
 static const char * const da9055_mic_l_src_txt[] = {
        "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L"
 };
 
-static const struct soc_enum da9055_mic_l_src =
-       SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src,
+                           DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt);
 
 /* MIC PGA Right source select */
 static const char * const da9055_mic_r_src_txt[] = {
        "MIC2_R_L", "MIC2_R", "MIC2_L"
 };
 
-static const struct soc_enum da9055_mic_r_src =
-       SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src,
+                           DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt);
 
 /* ALC Input Signal Tracking rate select */
 static const char * const da9055_signal_tracking_rate_txt[] = {
        "1/4", "1/16", "1/256", "1/65536"
 };
 
-static const struct soc_enum da9055_integ_attack_rate =
-       SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4,
-                       da9055_signal_tracking_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate,
+                           DA9055_ALC_CTRL3, 4,
+                           da9055_signal_tracking_rate_txt);
 
-static const struct soc_enum da9055_integ_release_rate =
-       SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4,
-                       da9055_signal_tracking_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate,
+                           DA9055_ALC_CTRL3, 6,
+                           da9055_signal_tracking_rate_txt);
 
 /* ALC Attack Rate select */
 static const char * const da9055_attack_rate_txt[] = {
@@ -430,8 +432,8 @@ static const char * const da9055_attack_rate_txt[] = {
        "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
 };
 
-static const struct soc_enum da9055_attack_rate =
-       SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_attack_rate,
+                           DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt);
 
 /* ALC Release Rate select */
 static const char * const da9055_release_rate_txt[] = {
@@ -439,8 +441,8 @@ static const char * const da9055_release_rate_txt[] = {
        "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
 };
 
-static const struct soc_enum da9055_release_rate =
-       SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_release_rate,
+                           DA9055_ALC_CTRL2, 4, da9055_release_rate_txt);
 
 /* ALC Hold Time select */
 static const char * const da9055_hold_time_txt[] = {
@@ -449,8 +451,8 @@ static const char * const da9055_hold_time_txt[] = {
        "253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
 };
 
-static const struct soc_enum da9055_hold_time =
-       SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_hold_time,
+                           DA9055_ALC_CTRL3, 0, da9055_hold_time_txt);
 
 static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
 {
@@ -1381,16 +1383,8 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
 
 static int da9055_probe(struct snd_soc_codec *codec)
 {
-       int ret;
        struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
 
-       codec->control_data = da9055->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* Enable all Gain Ramps */
        snd_soc_update_bits(codec, DA9055_AUX_L_CTRL,
                            DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
@@ -1536,11 +1530,17 @@ static const struct i2c_device_id da9055_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 
+static const struct of_device_id da9055_of_match[] = {
+       { .compatible = "dlg,da9055-codec", },
+       { }
+};
+
 /* I2C codec control layer */
 static struct i2c_driver da9055_i2c_driver = {
        .driver = {
                .name = "da9055-codec",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(da9055_of_match),
        },
        .probe          = da9055_i2c_probe,
        .remove         = da9055_remove,
index cb736ddc446dc0bc5a387dc3ebc28e4bb0fee9aa..3a89ce66d51d7e1c56b7c655fc0ed984e520e75b 100644 (file)
@@ -918,8 +918,7 @@ static int isabelle_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 snd_soc_codec *codec = dai->codec;
        u16 aif = 0;
        unsigned int fs_val = 0;
 
@@ -1090,23 +1089,7 @@ static struct snd_soc_dai_driver isabelle_dai[] = {
        },
 };
 
-static int isabelle_probe(struct snd_soc_codec *codec)
-{
-       int ret = 0;
-
-       codec->control_data = dev_get_regmap(codec->dev, NULL);
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
-       .probe = isabelle_probe,
        .set_bias_level = isabelle_set_bias_level,
        .controls = isabelle_snd_controls,
        .num_controls = ARRAY_SIZE(isabelle_snd_controls),
index 0e5743ea79dfdf6c4a4191694955883fbede59ca..4f048db9f55f1aa0953f4c971c0425a3178a159c 100644 (file)
@@ -101,8 +101,7 @@ static const char *lm4857_mode[] = {
        "Headphone",
 };
 
-static const struct soc_enum lm4857_mode_enum =
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode);
+static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode);
 
 static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("IN"),
index e19490cfb3a8bde2036e61d877b3a8c407cc510c..275b3f72f3f42db71bd94b7ca2b35f146b134d8a 100644 (file)
@@ -195,33 +195,31 @@ struct lm49453_priv {
 
 static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
 
-static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
-                                 lm49453_mic2mode_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+                           lm49453_mic2mode_text);
 
 static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
 
-static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
-                                 LM49453_P0_DIGITAL_MIC1_CONFIG_REG,
-                                 7, lm49453_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+                           LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7,
+                           lm49453_dmic_cfg_text);
 
-static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
-                                 LM49453_P0_DIGITAL_MIC2_CONFIG_REG,
-                                 7, lm49453_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+                           LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7,
+                           lm49453_dmic_cfg_text);
 
 /* MUX Controls */
 static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
 
 static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
 
-static const struct soc_enum lm49453_adcl_enum =
-       SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
-                       ARRAY_SIZE(lm49453_adcl_mux_text),
-                       lm49453_adcl_mux_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_adcl_enum,
+                           LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+                           lm49453_adcl_mux_text);
 
-static const struct soc_enum lm49453_adcr_enum =
-       SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
-                       ARRAY_SIZE(lm49453_adcr_mux_text),
-                       lm49453_adcr_mux_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_adcr_enum,
+                           LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+                           lm49453_adcr_mux_text);
 
 static const struct snd_kcontrol_new lm49453_adcl_mux_control =
        SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
@@ -1409,22 +1407,6 @@ static int lm49453_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int lm49453_probe(struct snd_soc_codec *codec)
-{
-       struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
-       int ret = 0;
-
-       codec->control_data = lm49453->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
 /* power down chip */
 static int lm49453_remove(struct snd_soc_codec *codec)
 {
@@ -1433,7 +1415,6 @@ static int lm49453_remove(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
-       .probe = lm49453_probe,
        .remove = lm49453_remove,
        .suspend = lm49453_suspend,
        .resume = lm49453_resume,
index 31f91560e9f6df0fb115ea862b712e9863cad9dd..ec481fc428c7c9fcb7a963fbabd1e9f34c1ace7b 100644 (file)
@@ -135,11 +135,6 @@ static int max9768_probe(struct snd_soc_codec *codec)
        struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = max9768->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 2, 6, SND_SOC_REGMAP);
-       if (ret)
-               return ret;
-
        if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {
                ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM);
                if (ret)
index ee660e2d3df3ba0ced0587ee13bab59fc86de6f9..ef7cf89f562342307828eafbe0c7b9094b5546e1 100644 (file)
@@ -597,28 +597,27 @@ static const unsigned int max98088_exmode_values[] = {
        0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
 };
 
-static const struct soc_enum max98088_exmode_enum =
-       SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127,
-                             ARRAY_SIZE(max98088_exmode_texts),
-                             max98088_exmode_texts,
-                             max98088_exmode_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(max98088_exmode_enum,
+                                 M98088_REG_41_SPKDHP, 0, 127,
+                                 max98088_exmode_texts,
+                                 max98088_exmode_values);
 
 static const char *max98088_ex_thresh[] = { /* volts PP */
        "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
-static const struct soc_enum max98088_ex_thresh_enum[] = {
-       SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
-               max98088_ex_thresh),
-};
+static SOC_ENUM_SINGLE_DECL(max98088_ex_thresh_enum,
+                           M98088_REG_42_SPKDHP_THRESH, 0,
+                           max98088_ex_thresh);
 
 static const char *max98088_fltr_mode[] = {"Voice", "Music" };
-static const struct soc_enum max98088_filter_mode_enum[] = {
-       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
-};
+static SOC_ENUM_SINGLE_DECL(max98088_filter_mode_enum,
+                           M98088_REG_18_DAI1_FILTERS, 7,
+                           max98088_fltr_mode);
 
 static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
 
-static const struct soc_enum max98088_extmic_enum =
-       SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text);
+static SOC_ENUM_SINGLE_DECL(max98088_extmic_enum,
+                           M98088_REG_48_CFG_MIC, 0,
+                           max98088_extmic_text);
 
 static const struct snd_kcontrol_new max98088_extmic_mux =
        SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
@@ -626,12 +625,12 @@ static const struct snd_kcontrol_new max98088_extmic_mux =
 static const char *max98088_dai1_fltr[] = {
        "Off", "fc=258/fs=16k", "fc=500/fs=16k",
        "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
-static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
-       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
-};
-static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
-       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
-};
+static SOC_ENUM_SINGLE_DECL(max98088_dai1_dac_filter_enum,
+                           M98088_REG_18_DAI1_FILTERS, 0,
+                           max98088_dai1_fltr);
+static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
+                           M98088_REG_18_DAI1_FILTERS, 4,
+                           max98088_dai1_fltr);
 
 static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
@@ -1849,7 +1848,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
 
        /* Now point the soc_enum to .texts array items */
        max98088->eq_enum.texts = max98088->eq_texts;
-       max98088->eq_enum.max = max98088->eq_textcnt;
+       max98088->eq_enum.items = max98088->eq_textcnt;
 
        ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
        if (ret != 0)
@@ -1915,12 +1914,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
 
        regcache_mark_dirty(max98088->regmap);
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* initialize private data */
 
        max98088->sysclk = (unsigned)-1;
index 9f714ea86613cc6939c62c3a420dc0c2ce07bb17..98c6e104357cbe59416f8d602a24ec63e1b68696 100644 (file)
@@ -513,65 +513,75 @@ static const char *max98090_perf_pwr_text[] =
 static const char *max98090_pwr_perf_text[] =
        { "Low Power", "High Performance" };
 
-static const struct soc_enum max98090_vcmbandgap_enum =
-       SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
-               ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum,
+                           M98090_REG_BIAS_CONTROL,
+                           M98090_VCM_MODE_SHIFT,
+                           max98090_pwr_perf_text);
 
 static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
 
-static const struct soc_enum max98090_osr128_enum =
-       SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
-               ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text);
+static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum,
+                           M98090_REG_ADC_CONTROL,
+                           M98090_OSR128_SHIFT,
+                           max98090_osr128_text);
 
 static const char *max98090_mode_text[] = { "Voice", "Music" };
 
-static const struct soc_enum max98090_mode_enum =
-       SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT,
-               ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98090_mode_enum,
+                           M98090_REG_FILTER_CONFIG,
+                           M98090_MODE_SHIFT,
+                           max98090_mode_text);
 
-static const struct soc_enum max98090_filter_dmic34mode_enum =
-       SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG,
-               M98090_FLT_DMIC34MODE_SHIFT,
-               ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum,
+                           M98090_REG_FILTER_CONFIG,
+                           M98090_FLT_DMIC34MODE_SHIFT,
+                           max98090_mode_text);
 
 static const char *max98090_drcatk_text[] =
        { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
 
-static const struct soc_enum max98090_drcatk_enum =
-       SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
-               ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum,
+                           M98090_REG_DRC_TIMING,
+                           M98090_DRCATK_SHIFT,
+                           max98090_drcatk_text);
 
 static const char *max98090_drcrls_text[] =
        { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
 
-static const struct soc_enum max98090_drcrls_enum =
-       SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
-               ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum,
+                           M98090_REG_DRC_TIMING,
+                           M98090_DRCRLS_SHIFT,
+                           max98090_drcrls_text);
 
 static const char *max98090_alccmp_text[] =
        { "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
 
-static const struct soc_enum max98090_alccmp_enum =
-       SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
-               ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
+static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum,
+                           M98090_REG_DRC_COMPRESSOR,
+                           M98090_DRCCMP_SHIFT,
+                           max98090_alccmp_text);
 
 static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
 
-static const struct soc_enum max98090_drcexp_enum =
-       SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
-               ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum,
+                           M98090_REG_DRC_EXPANDER,
+                           M98090_DRCEXP_SHIFT,
+                           max98090_drcexp_text);
 
-static const struct soc_enum max98090_dac_perfmode_enum =
-       SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT,
-               ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text);
+static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum,
+                           M98090_REG_DAC_CONTROL,
+                           M98090_PERFMODE_SHIFT,
+                           max98090_perf_pwr_text);
 
-static const struct soc_enum max98090_dachp_enum =
-       SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT,
-               ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum,
+                           M98090_REG_DAC_CONTROL,
+                           M98090_DACHP_SHIFT,
+                           max98090_pwr_perf_text);
 
-static const struct soc_enum max98090_adchp_enum =
-       SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT,
-               ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum,
+                           M98090_REG_ADC_CONTROL,
+                           M98090_ADCHP_SHIFT,
+                           max98090_pwr_perf_text);
 
 static const struct snd_kcontrol_new max98090_snd_controls[] = {
        SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum),
@@ -842,39 +852,42 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
 
 static const char *mic1_mux_text[] = { "IN12", "IN56" };
 
-static const struct soc_enum mic1_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT,
-               ARRAY_SIZE(mic1_mux_text), mic1_mux_text);
+static SOC_ENUM_SINGLE_DECL(mic1_mux_enum,
+                           M98090_REG_INPUT_MODE,
+                           M98090_EXTMIC1_SHIFT,
+                           mic1_mux_text);
 
 static const struct snd_kcontrol_new max98090_mic1_mux =
        SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum);
 
 static const char *mic2_mux_text[] = { "IN34", "IN56" };
 
-static const struct soc_enum mic2_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT,
-               ARRAY_SIZE(mic2_mux_text), mic2_mux_text);
+static SOC_ENUM_SINGLE_DECL(mic2_mux_enum,
+                           M98090_REG_INPUT_MODE,
+                           M98090_EXTMIC2_SHIFT,
+                           mic2_mux_text);
 
 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 SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, 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 =
-       SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
-               ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text);
+static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum,
+                           M98090_REG_MIC1_INPUT_LEVEL,
+                           M98090_MIC_PA1EN_SHIFT,
+                           max98090_micpre_text);
 
-static const struct soc_enum max98090_pa2en_enum =
-       SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT,
-               ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text);
+static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum,
+                           M98090_REG_MIC2_INPUT_LEVEL,
+                           M98090_MIC_PA2EN_SHIFT,
+                           max98090_micpre_text);
 
 /* LINEA mixer switch */
 static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = {
@@ -938,13 +951,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = {
 
 static const char *lten_mux_text[] = { "Normal", "Loopthrough" };
 
-static const struct soc_enum ltenl_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT,
-               ARRAY_SIZE(lten_mux_text), lten_mux_text);
+static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum,
+                           M98090_REG_IO_CONFIGURATION,
+                           M98090_LTEN_SHIFT,
+                           lten_mux_text);
 
-static const struct soc_enum ltenr_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT,
-               ARRAY_SIZE(lten_mux_text), lten_mux_text);
+static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum,
+                           M98090_REG_IO_CONFIGURATION,
+                           M98090_LTEN_SHIFT,
+                           lten_mux_text);
 
 static const struct snd_kcontrol_new max98090_ltenl_mux =
        SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum);
@@ -954,13 +969,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux =
 
 static const char *lben_mux_text[] = { "Normal", "Loopback" };
 
-static const struct soc_enum lbenl_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT,
-               ARRAY_SIZE(lben_mux_text), lben_mux_text);
+static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum,
+                           M98090_REG_IO_CONFIGURATION,
+                           M98090_LBEN_SHIFT,
+                           lben_mux_text);
 
-static const struct soc_enum lbenr_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT,
-               ARRAY_SIZE(lben_mux_text), lben_mux_text);
+static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum,
+                           M98090_REG_IO_CONFIGURATION,
+                           M98090_LBEN_SHIFT,
+                           lben_mux_text);
 
 static const struct snd_kcontrol_new max98090_lbenl_mux =
        SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum);
@@ -972,13 +989,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" };
 
 static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" };
 
-static const struct soc_enum stenl_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT,
-               ARRAY_SIZE(stenl_mux_text), stenl_mux_text);
+static SOC_ENUM_SINGLE_DECL(stenl_mux_enum,
+                           M98090_REG_ADC_SIDETONE,
+                           M98090_DSTSL_SHIFT,
+                           stenl_mux_text);
 
-static const struct soc_enum stenr_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT,
-               ARRAY_SIZE(stenr_mux_text), stenr_mux_text);
+static SOC_ENUM_SINGLE_DECL(stenr_mux_enum,
+                           M98090_REG_ADC_SIDETONE,
+                           M98090_DSTSR_SHIFT,
+                           stenr_mux_text);
 
 static const struct snd_kcontrol_new max98090_stenl_mux =
        SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum);
@@ -1086,9 +1105,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = {
 
 static const char *linmod_mux_text[] = { "Left Only", "Left and Right" };
 
-static const struct soc_enum linmod_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT,
-               ARRAY_SIZE(linmod_mux_text), linmod_mux_text);
+static SOC_ENUM_SINGLE_DECL(linmod_mux_enum,
+                           M98090_REG_LOUTR_MIXER,
+                           M98090_LINMOD_SHIFT,
+                           linmod_mux_text);
 
 static const struct snd_kcontrol_new max98090_linmod_mux =
        SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum);
@@ -1098,16 +1118,18 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" };
 /*
  * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable
  */
-static const struct soc_enum mixhplsel_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT,
-               ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text);
+static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum,
+                           M98090_REG_HP_CONTROL,
+                           M98090_MIXHPLSEL_SHIFT,
+                           mixhpsel_mux_text);
 
 static const struct snd_kcontrol_new max98090_mixhplsel_mux =
        SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum);
 
-static const struct soc_enum mixhprsel_mux_enum =
-       SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT,
-               ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text);
+static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum,
+                           M98090_REG_HP_CONTROL,
+                           M98090_MIXHPRSEL_SHIFT,
+                           mixhpsel_mux_text);
 
 static const struct snd_kcontrol_new max98090_mixhprsel_mux =
        SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum);
@@ -2196,14 +2218,6 @@ static int max98090_probe(struct snd_soc_codec *codec)
 
        max98090->codec = codec;
 
-       codec->control_data = max98090->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* Reset the codec, the DSP core, and disable all interrupts */
        max98090_reset(max98090);
 
@@ -2329,7 +2343,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
 
        max98090->devtype = id->driver_data;
        i2c_set_clientdata(i2c, max98090);
-       max98090->control_data = i2c;
        max98090->pdata = i2c->dev.platform_data;
        max98090->irq = i2c->irq;
 
index 7e103f249053d3a377e81d43e146d13fcecc03f7..1a4e2334a7b21d6f581a5cf371ffe6964563f6f2 100644 (file)
@@ -1523,7 +1523,6 @@ struct max98090_priv {
        struct regmap *regmap;
        struct snd_soc_codec *codec;
        enum max98090_type devtype;
-       void *control_data;
        struct max98090_pdata *pdata;
        unsigned int sysclk;
        unsigned int bclk;
index 3ba1170ebb53dcdb05d56e043121d83f3a20cbfe..03f0536e6f6185cf72178fad877484a4eb1dc679 100644 (file)
@@ -560,25 +560,27 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
 }
 
 static const char * const max98095_fltr_mode[] = { "Voice", "Music" };
-static const struct soc_enum max98095_dai1_filter_mode_enum[] = {
-       SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode),
-};
-static const struct soc_enum max98095_dai2_filter_mode_enum[] = {
-       SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode),
-};
+static SOC_ENUM_SINGLE_DECL(max98095_dai1_filter_mode_enum,
+                           M98095_02E_DAI1_FILTERS, 7,
+                           max98095_fltr_mode);
+static SOC_ENUM_SINGLE_DECL(max98095_dai2_filter_mode_enum,
+                           M98095_038_DAI2_FILTERS, 7,
+                           max98095_fltr_mode);
 
 static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" };
 
-static const struct soc_enum max98095_extmic_enum =
-       SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text);
+static SOC_ENUM_SINGLE_DECL(max98095_extmic_enum,
+                           M98095_087_CFG_MIC, 0,
+                           max98095_extmic_text);
 
 static const struct snd_kcontrol_new max98095_extmic_mux =
        SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);
 
 static const char * const max98095_linein_text[] = { "INA", "INB" };
 
-static const struct soc_enum max98095_linein_enum =
-       SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text);
+static SOC_ENUM_SINGLE_DECL(max98095_linein_enum,
+                           M98095_086_CFG_LINE, 6,
+                           max98095_linein_text);
 
 static const struct snd_kcontrol_new max98095_linein_mux =
        SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum);
@@ -586,24 +588,26 @@ static const struct snd_kcontrol_new max98095_linein_mux =
 static const char * const max98095_line_mode_text[] = {
        "Stereo", "Differential"};
 
-static const struct soc_enum max98095_linein_mode_enum =
-       SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98095_linein_mode_enum,
+                           M98095_086_CFG_LINE, 7,
+                           max98095_line_mode_text);
 
-static const struct soc_enum max98095_lineout_mode_enum =
-       SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98095_lineout_mode_enum,
+                           M98095_086_CFG_LINE, 4,
+                           max98095_line_mode_text);
 
 static const char * const max98095_dai_fltr[] = {
        "Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",
        "Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"};
-static const struct soc_enum max98095_dai1_dac_filter_enum[] = {
-       SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr),
-};
-static const struct soc_enum max98095_dai2_dac_filter_enum[] = {
-       SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr),
-};
-static const struct soc_enum max98095_dai3_dac_filter_enum[] = {
-       SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr),
-};
+static SOC_ENUM_SINGLE_DECL(max98095_dai1_dac_filter_enum,
+                           M98095_02E_DAI1_FILTERS, 0,
+                           max98095_dai_fltr);
+static SOC_ENUM_SINGLE_DECL(max98095_dai2_dac_filter_enum,
+                           M98095_038_DAI2_FILTERS, 0,
+                           max98095_dai_fltr);
+static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
+                           M98095_042_DAI3_FILTERS, 0,
+                           max98095_dai_fltr);
 
 static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
@@ -1861,7 +1865,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
 
        /* Now point the soc_enum to .texts array items */
        max98095->eq_enum.texts = max98095->eq_texts;
-       max98095->eq_enum.max = max98095->eq_textcnt;
+       max98095->eq_enum.items = max98095->eq_textcnt;
 
        ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
        if (ret != 0)
@@ -2016,7 +2020,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
 
        /* Now point the soc_enum to .texts array items */
        max98095->bq_enum.texts = max98095->bq_texts;
-       max98095->bq_enum.max = max98095->bq_textcnt;
+       max98095->bq_enum.items = max98095->bq_textcnt;
 
        ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
        if (ret != 0)
@@ -2234,12 +2238,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
        struct i2c_client *client;
        int ret = 0;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* reset the codec, the DSP core, and disable all interrupts */
        max98095_reset(codec);
 
index 82757ebf0301df25ab7d2a15da0d6af5cc5623ce..4fdf5aaa236f65cbb643cd837bd792da0619970d 100644 (file)
@@ -312,14 +312,6 @@ static int max9850_resume(struct snd_soc_codec *codec)
 
 static int max9850_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* enable zero-detect */
        snd_soc_update_bits(codec, MAX9850_GENERAL_PURPOSE, 1, 1);
        /* enable slew-rate control */
index 582c2bbd42cb9eae83346b5fbcd4e497d6101493..2c59b1fb69dc98368035e2c4d05a4db9f1cc167b 100644 (file)
@@ -106,8 +106,7 @@ static int mc13783_pcm_hw_params_dac(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 snd_soc_codec *codec = dai->codec;
        unsigned int rate = params_rate(params);
        int i;
 
@@ -126,8 +125,7 @@ static int mc13783_pcm_hw_params_codec(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 snd_soc_codec *codec = dai->codec;
        unsigned int rate = params_rate(params);
        unsigned int val;
 
@@ -408,8 +406,7 @@ static const char * const adcl_enum_text[] = {
        "MC1L", "RXINL",
 };
 
-static const struct soc_enum adcl_enum =
-       SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);
 
 static const struct snd_kcontrol_new left_input_mux =
        SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
@@ -418,8 +415,7 @@ static const char * const adcr_enum_text[] = {
        "MC1R", "MC2", "RXINR", "TXIN",
 };
 
-static const struct soc_enum adcr_enum =
-       SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);
 
 static const struct snd_kcontrol_new right_input_mux =
        SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
@@ -430,8 +426,8 @@ static const struct snd_kcontrol_new samp_ctl =
 static const char * const speaker_amp_source_text[] = {
        "CODEC", "Right"
 };
-static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
-                                 speaker_amp_source_text);
+static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
+                           speaker_amp_source_text);
 static const struct snd_kcontrol_new speaker_amp_source_mux =
        SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
 
@@ -439,8 +435,8 @@ static const char * const headset_amp_source_text[] = {
        "CODEC", "Mixer"
 };
 
-static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
-                                 headset_amp_source_text);
+static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
+                           headset_amp_source_text);
 static const struct snd_kcontrol_new headset_amp_source_mux =
        SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
 
@@ -580,9 +576,9 @@ static struct snd_soc_dapm_route mc13783_routes[] = {
 static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
                                                "Mono", "Mono Mix"};
 
-static const struct soc_enum mc13783_enum_3d_mixer =
-       SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer),
-                       mc13783_3d_mixer);
+static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer,
+                           MC13783_AUDIO_RX1, 16,
+                           mc13783_3d_mixer);
 
 static struct snd_kcontrol_new mc13783_control_list[] = {
        SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
@@ -614,8 +610,8 @@ static int mc13783_probe(struct snd_soc_codec *codec)
        struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
-       ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP);
+       ret = snd_soc_codec_set_cache_io(codec,
+                       dev_get_regmap(codec->dev->parent, NULL));
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
index 185fa3bc3052c826dd71f74cf0e52b6945aaae2c..e661e8420e3dd25b95179c7413adfea8637cd9e2 100644 (file)
@@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
 static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
                                                  "A-law"};
 
-static const struct soc_enum ml26124_adc_companding_enum
-       = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
+static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum,
+                           ML26124_SAI_TRANS_CTL, 6, ml26124_companding);
 
-static const struct soc_enum ml26124_dac_companding_enum
-       = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
+static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum,
+                           ML26124_SAI_RCV_CTL, 6, ml26124_companding);
 
 static const struct snd_kcontrol_new ml26124_snd_controls[] = {
        SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
@@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
 static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
                                "Digital MIC in", "Analog MIC Differential in"};
 
-static const struct soc_enum ml26124_insel_enum =
-       SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
+static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum,
+                           ML26124_MIC_IF_CTL, 0, ml26124_input_select);
 
 static const struct snd_kcontrol_new ml26124_input_mux_controls =
        SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
@@ -586,16 +586,6 @@ static int ml26124_resume(struct snd_soc_codec *codec)
 
 static int ml26124_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
-       codec->control_data = priv->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* Software Reset */
        snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
        snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
index 73f9c3630e2c8e33a56b089fa3a0d5f16e418dd3..e427544183d7f2ee095913adc0a8ad7104f4ebd4 100644 (file)
@@ -172,16 +172,21 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
        int val = 0, ret;
-       int pcm_format = params_format(params);
 
        priv->rate = params_rate(params);
 
        switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_RIGHT_J:
-               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE)
-                       val = 0x00;
-               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
-                       val = 0x03;
+               switch (params_width(params)) {
+               case 24:
+                       val = 0;
+                       break;
+               case 16:
+                       val = 3;
+                       break;
+               default:
+                       return -EINVAL;
+               }
                break;
        case SND_SOC_DAIFMT_I2S:
                val = 0x04;
index 7146653a8e165c942f7107c5ff305dea785578d9..3a80ba4452dfb944aab405b32af83854c349081f 100644 (file)
@@ -107,24 +107,35 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
        int val = 0, ret;
-       int pcm_format = params_format(params);
 
        priv->rate = params_rate(params);
 
        switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_RIGHT_J:
-               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
-                   pcm_format == SNDRV_PCM_FORMAT_S32_LE)
-                       val = 0x02;
-               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
-                       val = 0x00;
+               switch (params_width(params)) {
+               case 24:
+               case 32:
+                       val = 2;
+                       break;
+               case 16:
+                       val = 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
                break;
        case SND_SOC_DAIFMT_I2S:
-               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
-                   pcm_format == SNDRV_PCM_FORMAT_S32_LE)
-                       val = 0x05;
-               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
-                       val = 0x04;
+               switch (params_width(params)) {
+               case 24:
+               case 32:
+                       val = 5;
+                       break;
+               case 16:
+                       val = 4;
+                       break;
+               default:
+                       return -EINVAL;
+               }
                break;
        default:
                dev_err(codec->dev, "Invalid DAI format\n");
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
new file mode 100644 (file)
index 0000000..4d62230
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:     Mark Brown <broonie@linaro.org>
+ *             Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "pcm512x.h"
+
+static int pcm512x_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return pcm512x_probe(&i2c->dev, regmap);
+}
+
+static int pcm512x_i2c_remove(struct i2c_client *i2c)
+{
+       pcm512x_remove(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id pcm512x_i2c_id[] = {
+       { "pcm5121", },
+       { "pcm5122", },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
+
+static const struct of_device_id pcm512x_of_match[] = {
+       { .compatible = "ti,pcm5121", },
+       { .compatible = "ti,pcm5122", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+
+static struct i2c_driver pcm512x_i2c_driver = {
+       .probe          = pcm512x_i2c_probe,
+       .remove         = pcm512x_i2c_remove,
+       .id_table       = pcm512x_i2c_id,
+       .driver         = {
+               .name   = "pcm512x",
+               .owner  = THIS_MODULE,
+               .of_match_table = pcm512x_of_match,
+               .pm     = &pcm512x_pm_ops,
+       },
+};
+
+module_i2c_driver(pcm512x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C");
+MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
new file mode 100644 (file)
index 0000000..f297058
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:     Mark Brown <broonie@linaro.org>
+ *             Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "pcm512x.h"
+
+static int pcm512x_spi_probe(struct spi_device *spi)
+{
+       struct regmap *regmap;
+       int ret;
+
+       regmap = devm_regmap_init_spi(spi, &pcm512x_regmap);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               return ret;
+       }
+
+       return pcm512x_probe(&spi->dev, regmap);
+}
+
+static int pcm512x_spi_remove(struct spi_device *spi)
+{
+       pcm512x_remove(&spi->dev);
+       return 0;
+}
+
+static const struct spi_device_id pcm512x_spi_id[] = {
+       { "pcm5121", },
+       { "pcm5122", },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
+
+static const struct of_device_id pcm512x_of_match[] = {
+       { .compatible = "ti,pcm5121", },
+       { .compatible = "ti,pcm5122", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+
+static struct spi_driver pcm512x_spi_driver = {
+       .probe          = pcm512x_spi_probe,
+       .remove         = pcm512x_spi_remove,
+       .id_table       = pcm512x_spi_id,
+       .driver = {
+               .name   = "pcm512x",
+               .owner  = THIS_MODULE,
+               .of_match_table = pcm512x_of_match,
+               .pm     = &pcm512x_pm_ops,
+       },
+};
+
+module_spi_driver(pcm512x_spi_driver);
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
new file mode 100644 (file)
index 0000000..4b4c0c7
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:     Mark Brown <broonie@linaro.org>
+ *             Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "pcm512x.h"
+
+#define PCM512x_NUM_SUPPLIES 3
+static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
+       "AVDD",
+       "DVDD",
+       "CPVDD",
+};
+
+struct pcm512x_priv {
+       struct regmap *regmap;
+       struct clk *sclk;
+       struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
+       struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+};
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define PCM512x_REGULATOR_EVENT(n) \
+static int pcm512x_regulator_event_##n(struct notifier_block *nb, \
+                                     unsigned long event, void *data)    \
+{ \
+       struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \
+                                                   supply_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               regcache_mark_dirty(pcm512x->regmap);   \
+               regcache_cache_only(pcm512x->regmap, true);     \
+       } \
+       return 0; \
+}
+
+PCM512x_REGULATOR_EVENT(0)
+PCM512x_REGULATOR_EVENT(1)
+PCM512x_REGULATOR_EVENT(2)
+
+static const struct reg_default pcm512x_reg_defaults[] = {
+       { PCM512x_RESET,             0x00 },
+       { PCM512x_POWER,             0x00 },
+       { PCM512x_MUTE,              0x00 },
+       { PCM512x_DSP,               0x00 },
+       { PCM512x_PLL_REF,           0x00 },
+       { PCM512x_DAC_ROUTING,       0x11 },
+       { PCM512x_DSP_PROGRAM,       0x01 },
+       { PCM512x_CLKDET,            0x00 },
+       { PCM512x_AUTO_MUTE,         0x00 },
+       { PCM512x_ERROR_DETECT,      0x00 },
+       { PCM512x_DIGITAL_VOLUME_1,  0x00 },
+       { PCM512x_DIGITAL_VOLUME_2,  0x30 },
+       { PCM512x_DIGITAL_VOLUME_3,  0x30 },
+       { PCM512x_DIGITAL_MUTE_1,    0x22 },
+       { PCM512x_DIGITAL_MUTE_2,    0x00 },
+       { PCM512x_DIGITAL_MUTE_3,    0x07 },
+       { PCM512x_OUTPUT_AMPLITUDE,  0x00 },
+       { PCM512x_ANALOG_GAIN_CTRL,  0x00 },
+       { PCM512x_UNDERVOLTAGE_PROT, 0x00 },
+       { PCM512x_ANALOG_MUTE_CTRL,  0x00 },
+       { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
+       { PCM512x_VCOM_CTRL_1,       0x00 },
+       { PCM512x_VCOM_CTRL_2,       0x01 },
+};
+
+static bool pcm512x_readable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case PCM512x_RESET:
+       case PCM512x_POWER:
+       case PCM512x_MUTE:
+       case PCM512x_PLL_EN:
+       case PCM512x_SPI_MISO_FUNCTION:
+       case PCM512x_DSP:
+       case PCM512x_GPIO_EN:
+       case PCM512x_BCLK_LRCLK_CFG:
+       case PCM512x_DSP_GPIO_INPUT:
+       case PCM512x_MASTER_MODE:
+       case PCM512x_PLL_REF:
+       case PCM512x_PLL_COEFF_0:
+       case PCM512x_PLL_COEFF_1:
+       case PCM512x_PLL_COEFF_2:
+       case PCM512x_PLL_COEFF_3:
+       case PCM512x_PLL_COEFF_4:
+       case PCM512x_DSP_CLKDIV:
+       case PCM512x_DAC_CLKDIV:
+       case PCM512x_NCP_CLKDIV:
+       case PCM512x_OSR_CLKDIV:
+       case PCM512x_MASTER_CLKDIV_1:
+       case PCM512x_MASTER_CLKDIV_2:
+       case PCM512x_FS_SPEED_MODE:
+       case PCM512x_IDAC_1:
+       case PCM512x_IDAC_2:
+       case PCM512x_ERROR_DETECT:
+       case PCM512x_I2S_1:
+       case PCM512x_I2S_2:
+       case PCM512x_DAC_ROUTING:
+       case PCM512x_DSP_PROGRAM:
+       case PCM512x_CLKDET:
+       case PCM512x_AUTO_MUTE:
+       case PCM512x_DIGITAL_VOLUME_1:
+       case PCM512x_DIGITAL_VOLUME_2:
+       case PCM512x_DIGITAL_VOLUME_3:
+       case PCM512x_DIGITAL_MUTE_1:
+       case PCM512x_DIGITAL_MUTE_2:
+       case PCM512x_DIGITAL_MUTE_3:
+       case PCM512x_GPIO_OUTPUT_1:
+       case PCM512x_GPIO_OUTPUT_2:
+       case PCM512x_GPIO_OUTPUT_3:
+       case PCM512x_GPIO_OUTPUT_4:
+       case PCM512x_GPIO_OUTPUT_5:
+       case PCM512x_GPIO_OUTPUT_6:
+       case PCM512x_GPIO_CONTROL_1:
+       case PCM512x_GPIO_CONTROL_2:
+       case PCM512x_OVERFLOW:
+       case PCM512x_RATE_DET_1:
+       case PCM512x_RATE_DET_2:
+       case PCM512x_RATE_DET_3:
+       case PCM512x_RATE_DET_4:
+       case PCM512x_ANALOG_MUTE_DET:
+       case PCM512x_GPIN:
+       case PCM512x_DIGITAL_MUTE_DET:
+       case PCM512x_OUTPUT_AMPLITUDE:
+       case PCM512x_ANALOG_GAIN_CTRL:
+       case PCM512x_UNDERVOLTAGE_PROT:
+       case PCM512x_ANALOG_MUTE_CTRL:
+       case PCM512x_ANALOG_GAIN_BOOST:
+       case PCM512x_VCOM_CTRL_1:
+       case PCM512x_VCOM_CTRL_2:
+       case PCM512x_CRAM_CTRL:
+               return true;
+       default:
+               /* There are 256 raw register addresses */
+               return reg < 0xff;
+       }
+}
+
+static bool pcm512x_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case PCM512x_PLL_EN:
+       case PCM512x_OVERFLOW:
+       case PCM512x_RATE_DET_1:
+       case PCM512x_RATE_DET_2:
+       case PCM512x_RATE_DET_3:
+       case PCM512x_RATE_DET_4:
+       case PCM512x_ANALOG_MUTE_DET:
+       case PCM512x_GPIN:
+       case PCM512x_DIGITAL_MUTE_DET:
+       case PCM512x_CRAM_CTRL:
+               return true;
+       default:
+               /* There are 256 raw register addresses */
+               return reg < 0xff;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const char * const pcm512x_dsp_program_texts[] = {
+       "FIR interpolation with de-emphasis",
+       "Low latency IIR with de-emphasis",
+       "Fixed process flow",
+       "High attenuation with de-emphasis",
+       "Ringing-less low latency FIR",
+};
+
+static const unsigned int pcm512x_dsp_program_values[] = {
+       1,
+       2,
+       3,
+       5,
+       7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program,
+                                 PCM512x_DSP_PROGRAM, 0, 0x1f,
+                                 pcm512x_dsp_program_texts,
+                                 pcm512x_dsp_program_values);
+
+static const char * const pcm512x_clk_missing_text[] = {
+       "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s"
+};
+
+static const struct soc_enum pcm512x_clk_missing =
+       SOC_ENUM_SINGLE(PCM512x_CLKDET, 0,  8, pcm512x_clk_missing_text);
+
+static const char * const pcm512x_autom_text[] = {
+       "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s"
+};
+
+static const struct soc_enum pcm512x_autom_l =
+       SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8,
+                       pcm512x_autom_text);
+
+static const struct soc_enum pcm512x_autom_r =
+       SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8,
+                       pcm512x_autom_text);
+
+static const char * const pcm512x_ramp_rate_text[] = {
+       "1 sample/update", "2 samples/update", "4 samples/update",
+       "Immediate"
+};
+
+static const struct soc_enum pcm512x_vndf =
+       SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4,
+                       pcm512x_ramp_rate_text);
+
+static const struct soc_enum pcm512x_vnuf =
+       SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4,
+                       pcm512x_ramp_rate_text);
+
+static const struct soc_enum pcm512x_vedf =
+       SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4,
+                       pcm512x_ramp_rate_text);
+
+static const char * const pcm512x_ramp_step_text[] = {
+       "4dB/step", "2dB/step", "1dB/step", "0.5dB/step"
+};
+
+static const struct soc_enum pcm512x_vnds =
+       SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4,
+                       pcm512x_ramp_step_text);
+
+static const struct soc_enum pcm512x_vnus =
+       SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4,
+                       pcm512x_ramp_step_text);
+
+static const struct soc_enum pcm512x_veds =
+       SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
+                       pcm512x_ramp_step_text);
+
+static const struct snd_kcontrol_new pcm512x_controls[] = {
+SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
+                PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
+              PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
+              PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
+SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+          PCM512x_RQMR_SHIFT, 1, 1),
+
+SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
+SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program),
+
+SOC_ENUM("Clock Missing Period", pcm512x_clk_missing),
+SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l),
+SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r),
+SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3,
+          PCM512x_ACTL_SHIFT, 1, 0),
+SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
+          PCM512x_AMLR_SHIFT, 1, 0),
+
+SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf),
+SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds),
+SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
+SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
+SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
+SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
+};
+
+static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_OUTPUT("OUTL"),
+SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
+       { "DACL", NULL, "Playback" },
+       { "DACR", NULL, "Playback" },
+
+       { "OUTL", NULL, "DACL" },
+       { "OUTR", NULL, "DACR" },
+};
+
+static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+                                        PCM512x_RQST, 0);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to remove standby: %d\n",
+                               ret);
+                       return ret;
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+                                        PCM512x_RQST, PCM512x_RQST);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to request standby: %d\n",
+                               ret);
+                       return ret;
+               }
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver pcm512x_dai = {
+       .name = "pcm512x-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                          SNDRV_PCM_FMTBIT_S24_LE |
+                          SNDRV_PCM_FMTBIT_S32_LE
+       },
+};
+
+static struct snd_soc_codec_driver pcm512x_codec_driver = {
+       .set_bias_level = pcm512x_set_bias_level,
+       .idle_bias_off = true,
+
+       .controls = pcm512x_controls,
+       .num_controls = ARRAY_SIZE(pcm512x_controls),
+       .dapm_widgets = pcm512x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets),
+       .dapm_routes = pcm512x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes),
+};
+
+static const struct regmap_range_cfg pcm512x_range = {
+       .name = "Pages", .range_min = PCM512x_VIRT_BASE,
+       .range_max = PCM512x_MAX_REGISTER,
+       .selector_reg = PCM512x_PAGE,
+       .selector_mask = 0xff,
+       .window_start = 0, .window_len = 0x100,
+};
+
+const struct regmap_config pcm512x_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .readable_reg = pcm512x_readable,
+       .volatile_reg = pcm512x_volatile,
+
+       .ranges = &pcm512x_range,
+       .num_ranges = 1,
+
+       .max_register = PCM512x_MAX_REGISTER,
+       .reg_defaults = pcm512x_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(pcm512x_regmap);
+
+int pcm512x_probe(struct device *dev, struct regmap *regmap)
+{
+       struct pcm512x_priv *pcm512x;
+       int i, ret;
+
+       pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL);
+       if (!pcm512x)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, pcm512x);
+       pcm512x->regmap = regmap;
+
+       for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++)
+               pcm512x->supplies[i].supply = pcm512x_supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies),
+                                     pcm512x->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to get supplies: %d\n", ret);
+               return ret;
+       }
+
+       pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0;
+       pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1;
+       pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2;
+
+       for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) {
+               ret = regulator_register_notifier(pcm512x->supplies[i].consumer,
+                                                 &pcm512x->supply_nb[i]);
+               if (ret != 0) {
+                       dev_err(dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
+                                   pcm512x->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       /* Reset the device, verifying I/O in the process for I2C */
+       ret = regmap_write(regmap, PCM512x_RESET,
+                          PCM512x_RSTM | PCM512x_RSTR);
+       if (ret != 0) {
+               dev_err(dev, "Failed to reset device: %d\n", ret);
+               goto err;
+       }
+
+       ret = regmap_write(regmap, PCM512x_RESET, 0);
+       if (ret != 0) {
+               dev_err(dev, "Failed to reset device: %d\n", ret);
+               goto err;
+       }
+
+       pcm512x->sclk = devm_clk_get(dev, NULL);
+       if (IS_ERR(pcm512x->sclk)) {
+               if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_info(dev, "No SCLK, using BCLK: %ld\n",
+                        PTR_ERR(pcm512x->sclk));
+
+               /* Disable reporting of missing SCLK as an error */
+               regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
+                                  PCM512x_IDCH, PCM512x_IDCH);
+
+               /* Switch PLL input to BCLK */
+               regmap_update_bits(regmap, PCM512x_PLL_REF,
+                                  PCM512x_SREF, PCM512x_SREF);
+       } else {
+               ret = clk_prepare_enable(pcm512x->sclk);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* Default to standby mode */
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+                                PCM512x_RQST, PCM512x_RQST);
+       if (ret != 0) {
+               dev_err(dev, "Failed to request standby: %d\n",
+                       ret);
+               goto err_clk;
+       }
+
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_idle(dev);
+
+       ret = snd_soc_register_codec(dev, &pcm512x_codec_driver,
+                                   &pcm512x_dai, 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to register CODEC: %d\n", ret);
+               goto err_pm;
+       }
+
+       return 0;
+
+err_pm:
+       pm_runtime_disable(dev);
+err_clk:
+       if (!IS_ERR(pcm512x->sclk))
+               clk_disable_unprepare(pcm512x->sclk);
+err:
+       regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+                                    pcm512x->supplies);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pcm512x_probe);
+
+void pcm512x_remove(struct device *dev)
+{
+       struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+
+       snd_soc_unregister_codec(dev);
+       pm_runtime_disable(dev);
+       if (!IS_ERR(pcm512x->sclk))
+               clk_disable_unprepare(pcm512x->sclk);
+       regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+                              pcm512x->supplies);
+}
+EXPORT_SYMBOL_GPL(pcm512x_remove);
+
+static int pcm512x_suspend(struct device *dev)
+{
+       struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+                                PCM512x_RQPD, PCM512x_RQPD);
+       if (ret != 0) {
+               dev_err(dev, "Failed to request power down: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+                                    pcm512x->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to disable supplies: %d\n", ret);
+               return ret;
+       }
+
+       if (!IS_ERR(pcm512x->sclk))
+               clk_disable_unprepare(pcm512x->sclk);
+
+       return 0;
+}
+
+static int pcm512x_resume(struct device *dev)
+{
+       struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+       int ret;
+
+       if (!IS_ERR(pcm512x->sclk)) {
+               ret = clk_prepare_enable(pcm512x->sclk);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
+                                   pcm512x->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       regcache_cache_only(pcm512x->regmap, false);
+       ret = regcache_sync(pcm512x->regmap);
+       if (ret != 0) {
+               dev_err(dev, "Failed to sync cache: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+                                PCM512x_RQPD, 0);
+       if (ret != 0) {
+               dev_err(dev, "Failed to remove power down: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+const struct dev_pm_ops pcm512x_pm_ops = {
+       SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm512x_pm_ops);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver");
+MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
new file mode 100644 (file)
index 0000000..6ee76aa
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:     Mark Brown <broonie@linaro.org>
+ *             Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _SND_SOC_PCM512X
+#define _SND_SOC_PCM512X
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define PCM512x_VIRT_BASE 0x100
+#define PCM512x_PAGE_LEN  0x100
+#define PCM512x_PAGE_BASE(n)  (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n))
+
+#define PCM512x_PAGE              0
+
+#define PCM512x_RESET             (PCM512x_PAGE_BASE(0) +   1)
+#define PCM512x_POWER             (PCM512x_PAGE_BASE(0) +   2)
+#define PCM512x_MUTE              (PCM512x_PAGE_BASE(0) +   3)
+#define PCM512x_PLL_EN            (PCM512x_PAGE_BASE(0) +   4)
+#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) +   6)
+#define PCM512x_DSP               (PCM512x_PAGE_BASE(0) +   7)
+#define PCM512x_GPIO_EN           (PCM512x_PAGE_BASE(0) +   8)
+#define PCM512x_BCLK_LRCLK_CFG    (PCM512x_PAGE_BASE(0) +   9)
+#define PCM512x_DSP_GPIO_INPUT    (PCM512x_PAGE_BASE(0) +  10)
+#define PCM512x_MASTER_MODE       (PCM512x_PAGE_BASE(0) +  12)
+#define PCM512x_PLL_REF           (PCM512x_PAGE_BASE(0) +  13)
+#define PCM512x_PLL_COEFF_0       (PCM512x_PAGE_BASE(0) +  20)
+#define PCM512x_PLL_COEFF_1       (PCM512x_PAGE_BASE(0) +  21)
+#define PCM512x_PLL_COEFF_2       (PCM512x_PAGE_BASE(0) +  22)
+#define PCM512x_PLL_COEFF_3       (PCM512x_PAGE_BASE(0) +  23)
+#define PCM512x_PLL_COEFF_4       (PCM512x_PAGE_BASE(0) +  24)
+#define PCM512x_DSP_CLKDIV        (PCM512x_PAGE_BASE(0) +  27)
+#define PCM512x_DAC_CLKDIV        (PCM512x_PAGE_BASE(0) +  28)
+#define PCM512x_NCP_CLKDIV        (PCM512x_PAGE_BASE(0) +  29)
+#define PCM512x_OSR_CLKDIV        (PCM512x_PAGE_BASE(0) +  30)
+#define PCM512x_MASTER_CLKDIV_1   (PCM512x_PAGE_BASE(0) +  32)
+#define PCM512x_MASTER_CLKDIV_2   (PCM512x_PAGE_BASE(0) +  33)
+#define PCM512x_FS_SPEED_MODE     (PCM512x_PAGE_BASE(0) +  34)
+#define PCM512x_IDAC_1            (PCM512x_PAGE_BASE(0) +  35)
+#define PCM512x_IDAC_2            (PCM512x_PAGE_BASE(0) +  36)
+#define PCM512x_ERROR_DETECT      (PCM512x_PAGE_BASE(0) +  37)
+#define PCM512x_I2S_1             (PCM512x_PAGE_BASE(0) +  40)
+#define PCM512x_I2S_2             (PCM512x_PAGE_BASE(0) +  41)
+#define PCM512x_DAC_ROUTING       (PCM512x_PAGE_BASE(0) +  42)
+#define PCM512x_DSP_PROGRAM       (PCM512x_PAGE_BASE(0) +  43)
+#define PCM512x_CLKDET            (PCM512x_PAGE_BASE(0) +  44)
+#define PCM512x_AUTO_MUTE         (PCM512x_PAGE_BASE(0) +  59)
+#define PCM512x_DIGITAL_VOLUME_1  (PCM512x_PAGE_BASE(0) +  60)
+#define PCM512x_DIGITAL_VOLUME_2  (PCM512x_PAGE_BASE(0) +  61)
+#define PCM512x_DIGITAL_VOLUME_3  (PCM512x_PAGE_BASE(0) +  62)
+#define PCM512x_DIGITAL_MUTE_1    (PCM512x_PAGE_BASE(0) +  63)
+#define PCM512x_DIGITAL_MUTE_2    (PCM512x_PAGE_BASE(0) +  64)
+#define PCM512x_DIGITAL_MUTE_3    (PCM512x_PAGE_BASE(0) +  65)
+#define PCM512x_GPIO_OUTPUT_1     (PCM512x_PAGE_BASE(0) +  80)
+#define PCM512x_GPIO_OUTPUT_2     (PCM512x_PAGE_BASE(0) +  81)
+#define PCM512x_GPIO_OUTPUT_3     (PCM512x_PAGE_BASE(0) +  82)
+#define PCM512x_GPIO_OUTPUT_4     (PCM512x_PAGE_BASE(0) +  83)
+#define PCM512x_GPIO_OUTPUT_5     (PCM512x_PAGE_BASE(0) +  84)
+#define PCM512x_GPIO_OUTPUT_6     (PCM512x_PAGE_BASE(0) +  85)
+#define PCM512x_GPIO_CONTROL_1    (PCM512x_PAGE_BASE(0) +  86)
+#define PCM512x_GPIO_CONTROL_2    (PCM512x_PAGE_BASE(0) +  87)
+#define PCM512x_OVERFLOW          (PCM512x_PAGE_BASE(0) +  90)
+#define PCM512x_RATE_DET_1        (PCM512x_PAGE_BASE(0) +  91)
+#define PCM512x_RATE_DET_2        (PCM512x_PAGE_BASE(0) +  92)
+#define PCM512x_RATE_DET_3        (PCM512x_PAGE_BASE(0) +  93)
+#define PCM512x_RATE_DET_4        (PCM512x_PAGE_BASE(0) +  94)
+#define PCM512x_ANALOG_MUTE_DET   (PCM512x_PAGE_BASE(0) + 108)
+#define PCM512x_GPIN              (PCM512x_PAGE_BASE(0) + 119)
+#define PCM512x_DIGITAL_MUTE_DET  (PCM512x_PAGE_BASE(0) + 120)
+
+#define PCM512x_OUTPUT_AMPLITUDE  (PCM512x_PAGE_BASE(1) +   1)
+#define PCM512x_ANALOG_GAIN_CTRL  (PCM512x_PAGE_BASE(1) +   2)
+#define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) +   5)
+#define PCM512x_ANALOG_MUTE_CTRL  (PCM512x_PAGE_BASE(1) +   6)
+#define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) +   7)
+#define PCM512x_VCOM_CTRL_1       (PCM512x_PAGE_BASE(1) +   8)
+#define PCM512x_VCOM_CTRL_2       (PCM512x_PAGE_BASE(1) +   9)
+
+#define PCM512x_CRAM_CTRL         (PCM512x_PAGE_BASE(44) +  1)
+
+#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(44) +  1)
+
+/* Page 0, Register 1 - reset */
+#define PCM512x_RSTR (1 << 0)
+#define PCM512x_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define PCM512x_RQPD       (1 << 0)
+#define PCM512x_RQPD_SHIFT 0
+#define PCM512x_RQST       (1 << 4)
+#define PCM512x_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define PCM512x_RQMR_SHIFT 0
+#define PCM512x_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define PCM512x_PLCE       (1 << 0)
+#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLCK       (1 << 4)
+#define PCM512x_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define PCM512x_SDSL       (1 << 0)
+#define PCM512x_SDSL_SHIFT 0
+#define PCM512x_DEMP       (1 << 4)
+#define PCM512x_DEMP_SHIFT 4
+
+/* Page 0, Register 13 - PLL reference */
+#define PCM512x_SREF (1 << 4)
+
+/* Page 0, Register 37 - Error detection */
+#define PCM512x_IPLK (1 << 0)
+#define PCM512x_DCAS (1 << 1)
+#define PCM512x_IDCM (1 << 2)
+#define PCM512x_IDCH (1 << 3)
+#define PCM512x_IDSK (1 << 4)
+#define PCM512x_IDBK (1 << 5)
+#define PCM512x_IDFS (1 << 6)
+
+/* Page 0, Register 42 - DAC routing */
+#define PCM512x_AUPR_SHIFT 0
+#define PCM512x_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define PCM512x_ATMR_SHIFT 0
+#define PCM512x_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define PCM512x_VNDF_SHIFT 6
+#define PCM512x_VNDS_SHIFT 4
+#define PCM512x_VNUF_SHIFT 2
+#define PCM512x_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define PCM512x_VEDF_SHIFT 6
+#define PCM512x_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define PCM512x_ACTL_SHIFT 2
+#define PCM512x_AMLE_SHIFT 1
+#define PCM512x_AMLR_SHIFT 0
+
+/* Page 1, Register 2 - analog volume control */
+#define PCM512x_RAGN_SHIFT 0
+#define PCM512x_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define PCM512x_AGBR_SHIFT 0
+#define PCM512x_AGBL_SHIFT 4
+
+extern const struct dev_pm_ops pcm512x_pm_ops;
+extern const struct regmap_config pcm512x_regmap;
+
+int pcm512x_probe(struct device *dev, struct regmap *regmap);
+void pcm512x_remove(struct device *dev);
+
+#endif
index 912c9cbc27242eb48229506e86b3295a81967185..d4c229f0233ff34c0e474a26b584606f414e6195 100644 (file)
@@ -210,26 +210,22 @@ static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
 static const char *rt5631_input_mode[] = {
        "Single ended", "Differential"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1,
-       RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode);
+static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1,
+                           RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode);
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1,
-       RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);
+static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1,
+                           RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);
 
 /* MONO Input Type */
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL,
-       RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);
+static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL,
+                           RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);
 
 /* SPK Ratio Gain Control */
 static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x",
                        "1.56x", "1.68x", "1.99x", "2.34x"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
-       RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);
+static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
+                           RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);
 
 static const struct snd_kcontrol_new rt5631_snd_controls[] = {
        /* MIC */
@@ -759,9 +755,8 @@ static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {
 /* Left SPK Volume Input */
 static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL,
-       RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL,
+                           RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);
 
 static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =
        SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum);
@@ -769,9 +764,8 @@ static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =
 /* Left HP Volume Input */
 static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_hpvoll_enum, RT5631_HP_OUT_VOL,
-       RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL,
+                           RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);
 
 static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =
        SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum);
@@ -779,9 +773,8 @@ static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =
 /* Left Out Volume Input */
 static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL,
-       RT5631_L_EN_SHIFT, rt5631_outvoll_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL,
+                           RT5631_L_EN_SHIFT, rt5631_outvoll_sel);
 
 static const struct snd_kcontrol_new rt5631_outvoll_mux_control =
        SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum);
@@ -789,9 +782,8 @@ static const struct snd_kcontrol_new rt5631_outvoll_mux_control =
 /* Right Out Volume Input */
 static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL,
-       RT5631_R_EN_SHIFT, rt5631_outvolr_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL,
+                           RT5631_R_EN_SHIFT, rt5631_outvolr_sel);
 
 static const struct snd_kcontrol_new rt5631_outvolr_mux_control =
        SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum);
@@ -799,9 +791,8 @@ static const struct snd_kcontrol_new rt5631_outvolr_mux_control =
 /* Right HP Volume Input */
 static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_hpvolr_enum, RT5631_HP_OUT_VOL,
-       RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL,
+                           RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);
 
 static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =
        SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum);
@@ -809,9 +800,8 @@ static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =
 /* Right SPK Volume Input */
 static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL,
-       RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL,
+                           RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);
 
 static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =
        SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum);
@@ -820,9 +810,8 @@ static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =
 static const char *rt5631_spol_src_sel[] = {
        "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
-       RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+                           RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);
 
 static const struct snd_kcontrol_new rt5631_spol_mux_control =
        SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum);
@@ -831,9 +820,8 @@ static const struct snd_kcontrol_new rt5631_spol_mux_control =
 static const char *rt5631_spor_src_sel[] = {
        "SPORMIX", "MONOIN_RX", "VDAC", "DACR"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
-       RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+                           RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);
 
 static const struct snd_kcontrol_new rt5631_spor_mux_control =
        SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum);
@@ -841,9 +829,8 @@ static const struct snd_kcontrol_new rt5631_spor_mux_control =
 /* MONO Input */
 static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
-       RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+                           RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);
 
 static const struct snd_kcontrol_new rt5631_mono_mux_control =
        SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum);
@@ -851,9 +838,8 @@ static const struct snd_kcontrol_new rt5631_mono_mux_control =
 /* Left HPO Input */
 static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
-       RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+                           RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);
 
 static const struct snd_kcontrol_new rt5631_hpl_mux_control =
        SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum);
@@ -861,9 +847,8 @@ static const struct snd_kcontrol_new rt5631_hpl_mux_control =
 /* Right HPO Input */
 static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"};
 
-static const SOC_ENUM_SINGLE_DECL(
-       rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
-       RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+                           RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);
 
 static const struct snd_kcontrol_new rt5631_hpr_mux_control =
        SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum);
@@ -1585,15 +1570,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
 {
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
-       int ret;
-
-       codec->control_data = rt5631->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;
-       }
 
        val = rt5631_read_index(codec, RT5631_ADDA_MIXER_INTL_REG3);
        if (val & 0x0002)
index 886924934aa5c7db067f352aafc4113d5ab97c06..0061ae6b671673e43615bcd9ebfeef001df487b2 100644 (file)
@@ -361,25 +361,24 @@ static unsigned int bst_tlv[] = {
 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 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 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 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);
+static 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 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 */
@@ -753,9 +752,8 @@ 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 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);
@@ -764,9 +762,8 @@ 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 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);
@@ -776,9 +773,8 @@ 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 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);
@@ -787,9 +783,8 @@ 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 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);
@@ -798,9 +793,8 @@ 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 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);
@@ -809,9 +803,8 @@ 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 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);
@@ -826,9 +819,9 @@ static int rt5640_dac_l2_values[] = {
        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 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);
@@ -841,9 +834,9 @@ 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 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);
@@ -860,9 +853,10 @@ static int rt5640_dai_iis_map_values[] = {
        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 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);
@@ -872,9 +866,8 @@ 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 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);
@@ -1601,8 +1594,7 @@ static int get_clk_info(int sclk, int rate)
 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 snd_soc_codec *codec = dai->codec;
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        unsigned int val_len = 0, val_clk, mask_clk;
        int dai_sel, pre_div, bclk_ms, frame_size;
@@ -1943,16 +1935,8 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 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);
index 0fcbe90f3ef24520dbbd74092829d892b287ca1c..d3ed1be5a186c50fdaab98e0cf725dce53cb4f32 100644 (file)
@@ -187,8 +187,9 @@ static const char *adc_mux_text[] = {
        "MIC_IN", "LINE_IN"
 };
 
-static const struct soc_enum adc_enum =
-SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(adc_enum,
+                           SGTL5000_CHIP_ANA_CTRL, 2,
+                           adc_mux_text);
 
 static const struct snd_kcontrol_new adc_mux =
 SOC_DAPM_ENUM("Capture Mux", adc_enum);
@@ -198,8 +199,9 @@ static const char *dac_mux_text[] = {
        "DAC", "LINE_IN"
 };
 
-static const struct soc_enum dac_enum =
-SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text);
+static SOC_ENUM_SINGLE_DECL(dac_enum,
+                           SGTL5000_CHIP_ANA_CTRL, 6,
+                           dac_mux_text);
 
 static const struct snd_kcontrol_new dac_mux =
 SOC_DAPM_ENUM("Headphone Mux", dac_enum);
@@ -1350,14 +1352,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
        int ret;
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
-       /* setup i2c data ops */
-       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;
-       }
-
        ret = sgtl5000_enable_regulators(codec);
        if (ret)
                return ret;
index 52e7cb08434bd281354c4a34f520f16c38b0446f..244c097cd9053948d43b13c77fee6d6a8b6c7342 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
 
@@ -209,8 +210,9 @@ out:
 
 static int si476x_codec_probe(struct snd_soc_codec *codec)
 {
-       codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
-       return 0;
+       struct regmap *regmap = dev_get_regmap(codec->dev->parent, NULL);
+
+       return snd_soc_codec_set_cache_io(codec, regmap);
 }
 
 static struct snd_soc_dai_ops si476x_dai_ops = {
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
new file mode 100644 (file)
index 0000000..58e7c1f
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * SiRF audio codec driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio-codec.h"
+
+struct sirf_audio_codec {
+       struct clk *clk;
+       struct regmap *regmap;
+       u32 reg_ctrl0, reg_ctrl1;
+};
+
+static const char * const input_mode_mux[] = {"Single-ended",
+       "Differential"};
+
+static const struct soc_enum input_mode_mux_enum =
+       SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
+
+static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
+       SOC_DAPM_ENUM("Route", input_mode_mux_enum);
+
+static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
+static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
+static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
+       0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
+       0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
+);
+
+static struct snd_kcontrol_new volume_controls_atlas6[] = {
+       SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+                       0x7F, 0, playback_vol_tlv),
+       SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
+                       0x3F, 0, capture_vol_tlv_atlas6),
+};
+
+static struct snd_kcontrol_new volume_controls_prima2[] = {
+       SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+                       0x7F, 0, playback_vol_tlv),
+       SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
+                       0x1F, 0, capture_vol_tlv_prima2),
+};
+
+static struct snd_kcontrol_new left_input_path_controls[] = {
+       SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
+       SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
+};
+
+static struct snd_kcontrol_new right_input_path_controls[] = {
+       SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
+       SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
+};
+
+static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
+       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
+       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
+       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
+       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
+       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
+       SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
+
+/* After enable adc, Delay 200ms to avoid pop noise */
+static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(200);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void enable_and_reset_codec(struct regmap *regmap,
+               u32 codec_enable_bits, u32 codec_reset_bits)
+{
+       regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
+                       codec_enable_bits | codec_reset_bits,
+                       codec_enable_bits | ~codec_reset_bits);
+       msleep(20);
+       regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
+                       codec_reset_bits, codec_reset_bits);
+}
+
+static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
+#define ATLAS6_CODEC_RESET_BITS (1 << 28)
+       struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               enable_and_reset_codec(sirf_audio_codec->regmap,
+                       ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(sirf_audio_codec->regmap,
+                       AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS,
+                       ~ATLAS6_CODEC_ENABLE_BITS);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
+#define PRIMA2_CODEC_RESET_BITS (1 << 26)
+       struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               enable_and_reset_codec(sirf_audio_codec->regmap,
+                       PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(sirf_audio_codec->regmap,
+                       AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS,
+                       ~PRIMA2_CODEC_ENABLE_BITS);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
+       SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
+                       25, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
+                       26, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
+                       27, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
+       SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
+                       23, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
+                       24, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
+                       25, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
+       SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
+                       atlas6_codec_enable_and_reset_event,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
+       SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
+                       prima2_codec_enable_and_reset_event,
+                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
+       SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
+       SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
+                       &left_dac_to_hp_left_amp_switch_control),
+       SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
+                       &left_dac_to_hp_right_amp_switch_control),
+       SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
+                       &right_dac_to_hp_left_amp_switch_control),
+       SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
+                       &right_dac_to_hp_right_amp_switch_control),
+       SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+                       &left_dac_to_speaker_lineout_switch_control),
+       SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+                       &right_dac_to_speaker_lineout_switch_control),
+       SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("HPOUTL"),
+       SND_SOC_DAPM_OUTPUT("HPOUTR"),
+       SND_SOC_DAPM_OUTPUT("SPKOUT"),
+
+       SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
+                       adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
+                       adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
+               &left_input_path_controls[0],
+               ARRAY_SIZE(left_input_path_controls)),
+       SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
+               &right_input_path_controls[0],
+               ARRAY_SIZE(right_input_path_controls)),
+
+       SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
+                       &sirf_audio_codec_input_mode_control),
+       SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
+       SND_SOC_DAPM_INPUT("MICIN1"),
+       SND_SOC_DAPM_INPUT("MICIN2"),
+       SND_SOC_DAPM_INPUT("LINEIN1"),
+       SND_SOC_DAPM_INPUT("LINEIN2"),
+
+       SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
+                       30, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
+       {"SPKOUT", NULL, "Speaker Driver"},
+       {"Speaker Driver", NULL, "Speaker amp driver"},
+       {"Speaker amp driver", NULL, "Left dac to speaker lineout"},
+       {"Speaker amp driver", NULL, "Right dac to speaker lineout"},
+       {"Left dac to speaker lineout", "Switch", "DAC left"},
+       {"Right dac to speaker lineout", "Switch", "DAC right"},
+       {"HPOUTL", NULL, "HP Left Driver"},
+       {"HPOUTR", NULL, "HP Right Driver"},
+       {"HP Left Driver", NULL, "HP amp left driver"},
+       {"HP Right Driver", NULL, "HP amp right driver"},
+       {"HP amp left driver", NULL, "Right dac to hp left amp"},
+       {"HP amp right driver", NULL , "Right dac to hp right amp"},
+       {"HP amp left driver", NULL, "Left dac to hp left amp"},
+       {"HP amp right driver", NULL , "Right dac to hp right amp"},
+       {"Right dac to hp left amp", "Switch", "DAC left"},
+       {"Right dac to hp right amp", "Switch", "DAC right"},
+       {"Left dac to hp left amp", "Switch", "DAC left"},
+       {"Left dac to hp right amp", "Switch", "DAC right"},
+       {"DAC left", NULL, "codecclk"},
+       {"DAC right", NULL, "codecclk"},
+       {"DAC left", NULL, "Playback"},
+       {"DAC right", NULL, "Playback"},
+       {"DAC left", NULL, "HSL Phase Opposite"},
+       {"DAC right", NULL, "HSL Phase Opposite"},
+
+       {"Capture", NULL, "ADC left"},
+       {"Capture", NULL, "ADC right"},
+       {"ADC left", NULL, "codecclk"},
+       {"ADC right", NULL, "codecclk"},
+       {"ADC left", NULL, "Left PGA mixer"},
+       {"ADC right", NULL, "Right PGA mixer"},
+       {"Left PGA mixer", "Line Left Switch", "LINEIN2"},
+       {"Right PGA mixer", "Line Right Switch", "LINEIN1"},
+       {"Left PGA mixer", "Mic Left Switch", "MICIN2"},
+       {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
+       {"Mic input mode mux", "Single-ended", "MICIN1"},
+       {"Mic input mode mux", "Differential", "MICIN1"},
+};
+
+static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
+               int cmd,
+               struct snd_soc_dai *dai)
+{
+       int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       struct snd_soc_codec *codec = dai->codec;
+       u32 val = 0;
+
+       /*
+        * This is a workaround, When stop playback,
+        * need disable HP amp, avoid the current noise.
+        */
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               break;
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (playback)
+                       val = IC_HSLEN | IC_HSREN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (playback)
+               snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+                       IC_HSLEN | IC_HSREN, val);
+       return 0;
+}
+
+struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
+       .trigger = sirf_audio_codec_trigger,
+};
+
+struct snd_soc_dai_driver sirf_audio_codec_dai = {
+       .name = "sirf-audio-codec",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &sirf_audio_codec_dai_ops,
+};
+
+static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       pm_runtime_enable(codec->dev);
+
+       if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
+               snd_soc_dapm_new_controls(dapm,
+                       prima2_output_driver_dapm_widgets,
+                       ARRAY_SIZE(prima2_output_driver_dapm_widgets));
+               snd_soc_dapm_new_controls(dapm,
+                       &prima2_codec_clock_dapm_widget, 1);
+               return snd_soc_add_codec_controls(codec,
+                       volume_controls_prima2,
+                       ARRAY_SIZE(volume_controls_prima2));
+       }
+       if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) {
+               snd_soc_dapm_new_controls(dapm,
+                       atlas6_output_driver_dapm_widgets,
+                       ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
+               snd_soc_dapm_new_controls(dapm,
+                       &atlas6_codec_clock_dapm_widget, 1);
+               return snd_soc_add_codec_controls(codec,
+                       volume_controls_atlas6,
+                       ARRAY_SIZE(volume_controls_atlas6));
+       }
+
+       return -EINVAL;
+}
+
+static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
+{
+       pm_runtime_disable(codec->dev);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
+       .probe = sirf_audio_codec_probe,
+       .remove = sirf_audio_codec_remove,
+       .dapm_widgets = sirf_audio_codec_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
+       .dapm_routes = sirf_audio_codec_map,
+       .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
+       .idle_bias_off = true,
+};
+
+static const struct of_device_id sirf_audio_codec_of_match[] = {
+       { .compatible = "sirf,prima2-audio-codec" },
+       { .compatible = "sirf,atlas6-audio-codec" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
+
+static const struct regmap_config sirf_audio_codec_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = AUDIO_IC_CODEC_CTRL3,
+       .cache_type = REGCACHE_NONE,
+};
+
+static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct sirf_audio_codec *sirf_audio_codec;
+       void __iomem *base;
+       struct resource *mem_res;
+       const struct of_device_id *match;
+
+       match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
+
+       sirf_audio_codec = devm_kzalloc(&pdev->dev,
+               sizeof(struct sirf_audio_codec), GFP_KERNEL);
+       if (!sirf_audio_codec)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, sirf_audio_codec);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, mem_res);
+       if (base == NULL)
+               return -ENOMEM;
+
+       sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                           &sirf_audio_codec_regmap_config);
+       if (IS_ERR(sirf_audio_codec->regmap))
+               return PTR_ERR(sirf_audio_codec->regmap);
+
+       sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(sirf_audio_codec->clk)) {
+               dev_err(&pdev->dev, "Get clock failed.\n");
+               return PTR_ERR(sirf_audio_codec->clk);
+       }
+
+       ret = clk_prepare_enable(sirf_audio_codec->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "Enable clock failed.\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_codec(&(pdev->dev),
+                       &soc_codec_device_sirf_audio_codec,
+                       &sirf_audio_codec_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
+               goto err_clk_put;
+       }
+
+       /*
+        * Always open charge pump, if not, when the charge pump closed the
+        * adc will not stable
+        */
+       regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+               IC_CPFREQ, IC_CPFREQ);
+
+       if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
+               regmap_update_bits(sirf_audio_codec->regmap,
+                               AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
+       return 0;
+
+err_clk_put:
+       clk_disable_unprepare(sirf_audio_codec->clk);
+       return ret;
+}
+
+static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
+{
+       struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(sirf_audio_codec->clk);
+       snd_soc_unregister_codec(&(pdev->dev));
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_audio_codec_suspend(struct device *dev)
+{
+       struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
+
+       regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+               &sirf_audio_codec->reg_ctrl0);
+       regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
+               &sirf_audio_codec->reg_ctrl1);
+       clk_disable_unprepare(sirf_audio_codec->clk);
+
+       return 0;
+}
+
+static int sirf_audio_codec_resume(struct device *dev)
+{
+       struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(sirf_audio_codec->clk);
+       if (ret)
+               return ret;
+
+       regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+               sirf_audio_codec->reg_ctrl0);
+       regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
+               sirf_audio_codec->reg_ctrl1);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
+};
+
+static struct platform_driver sirf_audio_codec_driver = {
+       .driver = {
+               .name = "sirf-audio-codec",
+               .owner = THIS_MODULE,
+               .of_match_table = sirf_audio_codec_of_match,
+               .pm = &sirf_audio_codec_pm_ops,
+       },
+       .probe = sirf_audio_codec_driver_probe,
+       .remove = sirf_audio_codec_driver_remove,
+};
+
+module_platform_driver(sirf_audio_codec_driver);
+
+MODULE_DESCRIPTION("SiRF audio codec driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h
new file mode 100644 (file)
index 0000000..d4c187b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * SiRF inner codec controllers define
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_AUDIO_CODEC_H
+#define _SIRF_AUDIO_CODEC_H
+
+
+#define AUDIO_IC_CODEC_PWR                     (0x00E0)
+#define AUDIO_IC_CODEC_CTRL0                   (0x00E4)
+#define AUDIO_IC_CODEC_CTRL1                   (0x00E8)
+#define AUDIO_IC_CODEC_CTRL2                   (0x00EC)
+#define AUDIO_IC_CODEC_CTRL3                   (0x00F0)
+
+#define MICBIASEN              (1 << 3)
+
+#define IC_RDACEN              (1 << 0)
+#define IC_LDACEN              (1 << 1)
+#define IC_HSREN               (1 << 2)
+#define IC_HSLEN               (1 << 3)
+#define IC_SPEN                        (1 << 4)
+#define IC_CPEN                        (1 << 5)
+
+#define IC_HPRSELR             (1 << 6)
+#define IC_HPLSELR             (1 << 7)
+#define IC_HPRSELL             (1 << 8)
+#define IC_HPLSELL             (1 << 9)
+#define IC_SPSELR              (1 << 10)
+#define IC_SPSELL              (1 << 11)
+
+#define IC_MONOR               (1 << 12)
+#define IC_MONOL               (1 << 13)
+
+#define IC_RXOSRSEL            (1 << 28)
+#define IC_CPFREQ              (1 << 29)
+#define IC_HSINVEN             (1 << 30)
+
+#define IC_MICINREN            (1 << 0)
+#define IC_MICINLEN            (1 << 1)
+#define IC_MICIN1SEL           (1 << 2)
+#define IC_MICIN2SEL           (1 << 3)
+#define IC_MICDIFSEL           (1 << 4)
+#define        IC_LINEIN1SEL           (1 << 5)
+#define        IC_LINEIN2SEL           (1 << 6)
+#define        IC_RADCEN               (1 << 7)
+#define        IC_LADCEN               (1 << 8)
+#define        IC_ALM                  (1 << 9)
+
+#define IC_DIGMICEN             (1 << 22)
+#define IC_DIGMICFREQ           (1 << 23)
+#define IC_ADC14B_12            (1 << 24)
+#define IC_FIRDAC_HSL_EN        (1 << 25)
+#define IC_FIRDAC_HSR_EN        (1 << 26)
+#define IC_FIRDAC_LOUT_EN       (1 << 27)
+#define IC_POR                  (1 << 28)
+#define IC_CODEC_CLK_EN         (1 << 29)
+#define IC_HP_3DB_BOOST         (1 << 30)
+
+#define IC_ADC_LEFT_GAIN_SHIFT 16
+#define IC_ADC_RIGHT_GAIN_SHIFT 10
+#define IC_ADC_GAIN_MASK       0x3F
+#define IC_MIC_MAX_GAIN                0x39
+
+#define IC_RXPGAR_MASK         0x3F
+#define IC_RXPGAR_SHIFT                14
+#define IC_RXPGAL_MASK         0x3F
+#define IC_RXPGAL_SHIFT                21
+#define IC_RXPGAR              0x7B
+#define IC_RXPGAL              0x7B
+
+#endif /*__SIRF_AUDIO_CODEC_H*/
index 13045f2af4d32a7725961feabc628ac6e088e80c..42dff26b3a2af8cd0f0df9d1a744d9d890c21e0b 100644 (file)
@@ -312,14 +312,14 @@ static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
 /* mux controls */
 static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
 
-static const struct soc_enum sn95031_micl_enum =
-       SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 1, 2, sn95031_mic_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum,
+                           SN95031_ADCCONFIG, 1, sn95031_mic_texts);
 
 static const struct snd_kcontrol_new sn95031_micl_mux_control =
        SOC_DAPM_ENUM("Route", sn95031_micl_enum);
 
-static const struct soc_enum sn95031_micr_enum =
-       SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 3, 2, sn95031_mic_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum,
+                           SN95031_ADCCONFIG, 3, sn95031_mic_texts);
 
 static const struct snd_kcontrol_new sn95031_micr_mux_control =
        SOC_DAPM_ENUM("Route", sn95031_micr_enum);
@@ -328,26 +328,26 @@ static const char *sn95031_input_texts[] = {      "DMIC1", "DMIC2", "DMIC3",
                                                "DMIC4", "DMIC5", "DMIC6",
                                                "ADC Left", "ADC Right" };
 
-static const struct soc_enum sn95031_input1_enum =
-       SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 0, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum,
+                           SN95031_AUDIOMUX12, 0, sn95031_input_texts);
 
 static const struct snd_kcontrol_new sn95031_input1_mux_control =
        SOC_DAPM_ENUM("Route", sn95031_input1_enum);
 
-static const struct soc_enum sn95031_input2_enum =
-       SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 4, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum,
+                           SN95031_AUDIOMUX12, 4, sn95031_input_texts);
 
 static const struct snd_kcontrol_new sn95031_input2_mux_control =
        SOC_DAPM_ENUM("Route", sn95031_input2_enum);
 
-static const struct soc_enum sn95031_input3_enum =
-       SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 0, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum,
+                           SN95031_AUDIOMUX34, 0, sn95031_input_texts);
 
 static const struct snd_kcontrol_new sn95031_input3_mux_control =
        SOC_DAPM_ENUM("Route", sn95031_input3_enum);
 
-static const struct soc_enum sn95031_input4_enum =
-       SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 4, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum,
+                           SN95031_AUDIOMUX34, 4, sn95031_input_texts);
 
 static const struct snd_kcontrol_new sn95031_input4_mux_control =
        SOC_DAPM_ENUM("Route", sn95031_input4_enum);
@@ -359,19 +359,19 @@ static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"};
 /* 0dB to 30dB in 10dB steps */
 static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0);
 
-static const struct soc_enum sn95031_micmode1_enum =
-       SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text);
-static const struct soc_enum sn95031_micmode2_enum =
-       SOC_ENUM_SINGLE(SN95031_MICAMP2, 1, 2, sn95031_micmode_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum,
+                           SN95031_MICAMP1, 1, sn95031_micmode_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum,
+                           SN95031_MICAMP2, 1, sn95031_micmode_text);
 
 static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"};
 
-static const struct soc_enum sn95031_dmic12_cfg_enum =
-       SOC_ENUM_SINGLE(SN95031_DMICMUX, 0, 2, sn95031_dmic_cfg_text);
-static const struct soc_enum sn95031_dmic34_cfg_enum =
-       SOC_ENUM_SINGLE(SN95031_DMICMUX, 1, 2, sn95031_dmic_cfg_text);
-static const struct soc_enum sn95031_dmic56_cfg_enum =
-       SOC_ENUM_SINGLE(SN95031_DMICMUX, 2, 2, sn95031_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum,
+                           SN95031_DMICMUX, 0, sn95031_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum,
+                           SN95031_DMICMUX, 1, sn95031_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum,
+                           SN95031_DMICMUX, 2, sn95031_dmic_cfg_text);
 
 static const struct snd_kcontrol_new sn95031_snd_controls[] = {
        SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum),
@@ -825,8 +825,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
 {
        pr_debug("codec_probe called\n");
 
-       snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-
        /* PCM interface config
         * This sets the pcm rx slot conguration to max 6 slots
         * for max 4 dais (2 stereo and 2 mono)
index cc8debce752f73055a3253f5ac0928803fbc1091..56adb3e2def9ca00f16a50e59c141206b4ab68d7 100644 (file)
@@ -169,19 +169,19 @@ static const char * const ssm2518_drc_hold_time_text[] = {
        "682.24 ms", "1364 ms",
 };
 
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,
+static 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,
+static 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,
+static 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,
+static 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,
+static 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,
+static 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,
+static 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[] = {
@@ -648,16 +648,6 @@ static struct snd_soc_dai_driver ssm2518_dai = {
 
 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);
 }
 
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
new file mode 100644 (file)
index 0000000..abd63d5
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SSM2602/SSM2603/SSM2604 I2C audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ssm2602.h"
+
+/*
+ * ssm2602 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int ssm2602_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       return ssm2602_probe(&client->dev, id->driver_data,
+               devm_regmap_init_i2c(client, &ssm2602_regmap_config));
+}
+
+static int ssm2602_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id ssm2602_i2c_id[] = {
+       { "ssm2602", SSM2602 },
+       { "ssm2603", SSM2602 },
+       { "ssm2604", SSM2604 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
+static struct i2c_driver ssm2602_i2c_driver = {
+       .driver = {
+               .name = "ssm2602",
+               .owner = THIS_MODULE,
+       },
+       .probe = ssm2602_i2c_probe,
+       .remove = ssm2602_i2c_remove,
+       .id_table = ssm2602_i2c_id,
+};
+module_i2c_driver(ssm2602_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 I2C driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c
new file mode 100644 (file)
index 0000000..2bf55e2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SSM2602 SPI audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ssm2602.h"
+
+static int ssm2602_spi_probe(struct spi_device *spi)
+{
+       return ssm2602_probe(&spi->dev, SSM2602,
+               devm_regmap_init_spi(spi, &ssm2602_regmap_config));
+}
+
+static int ssm2602_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static struct spi_driver ssm2602_spi_driver = {
+       .driver = {
+               .name   = "ssm2602",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ssm2602_spi_probe,
+       .remove         = ssm2602_spi_remove,
+};
+module_spi_driver(ssm2602_spi_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2602 SPI driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
index af76bbd1b24fbde13e686618c9ab2409a8e18624..97b0454eb346b712d4e1847008b2340f99933f90 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
 #include <linux/regmap.h>
 #include <linux/slab.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 "ssm2602.h"
 
-enum ssm2602_type {
-       SSM2602,
-       SSM2604,
-};
-
 /* codec private data */
 struct ssm2602_priv {
        unsigned int sysclk;
-       struct snd_pcm_hw_constraint_list *sysclk_constraints;
+       const struct snd_pcm_hw_constraint_list *sysclk_constraints;
 
        struct regmap *regmap;
 
@@ -75,15 +63,16 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
 
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
-       "Line", "Mic", "None", "None", "None",
-       "None", "None", "None",
+       "Line", "Mic",
 };
 
 static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
 
 static const struct soc_enum ssm2602_enum[] = {
-       SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select),
-       SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
+       SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select),
+                       ssm2602_input_select),
+       SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph),
+                       ssm2602_deemph),
 };
 
 static const unsigned int ssm260x_outmix_tlv[] = {
@@ -197,7 +186,7 @@ static const unsigned int ssm2602_rates_12288000[] = {
        8000, 16000, 32000, 48000, 96000,
 };
 
-static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
+static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
        .list = ssm2602_rates_12288000,
        .count = ARRAY_SIZE(ssm2602_rates_12288000),
 };
@@ -206,7 +195,7 @@ static const unsigned int ssm2602_rates_11289600[] = {
        8000, 44100, 88200,
 };
 
-static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
+static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
        .list = ssm2602_rates_11289600,
        .count = ARRAY_SIZE(ssm2602_rates_11289600),
 };
@@ -529,7 +518,7 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int ssm2602_probe(struct snd_soc_codec *codec)
+static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 {
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -554,7 +543,7 @@ static int ssm2602_probe(struct snd_soc_codec *codec)
                        ARRAY_SIZE(ssm2602_routes));
 }
 
-static int ssm2604_probe(struct snd_soc_codec *codec)
+static int ssm2604_codec_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
@@ -568,18 +557,11 @@ static int ssm2604_probe(struct snd_soc_codec *codec)
                        ARRAY_SIZE(ssm2604_routes));
 }
 
-static int ssm260x_probe(struct snd_soc_codec *codec)
+static int ssm260x_codec_probe(struct snd_soc_codec *codec)
 {
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = ssm2602->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;
-       }
-
        ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@@ -597,10 +579,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
 
        switch (ssm2602->type) {
        case SSM2602:
-               ret = ssm2602_probe(codec);
+               ret = ssm2602_codec_probe(codec);
                break;
        case SSM2604:
-               ret = ssm2604_probe(codec);
+               ret = ssm2604_codec_probe(codec);
                break;
        }
 
@@ -620,7 +602,7 @@ static int ssm2602_remove(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
-       .probe =        ssm260x_probe,
+       .probe =        ssm260x_codec_probe,
        .remove =       ssm2602_remove,
        .suspend =      ssm2602_suspend,
        .resume =       ssm2602_resume,
@@ -639,7 +621,7 @@ static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
        return reg == SSM2602_RESET;
 }
 
-static const struct regmap_config ssm2602_regmap_config = {
+const struct regmap_config ssm2602_regmap_config = {
        .val_bits = 9,
        .reg_bits = 7,
 
@@ -650,134 +632,28 @@ static const struct regmap_config ssm2602_regmap_config = {
        .reg_defaults_raw = ssm2602_reg,
        .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
 };
+EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
 
-#if defined(CONFIG_SPI_MASTER)
-static int ssm2602_spi_probe(struct spi_device *spi)
+int ssm2602_probe(struct device *dev, enum ssm2602_type type,
+       struct regmap *regmap)
 {
        struct ssm2602_priv *ssm2602;
-       int ret;
-
-       ssm2602 = devm_kzalloc(&spi->dev, sizeof(struct ssm2602_priv),
-                              GFP_KERNEL);
-       if (ssm2602 == NULL)
-               return -ENOMEM;
-
-       spi_set_drvdata(spi, ssm2602);
-       ssm2602->type = SSM2602;
 
-       ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config);
-       if (IS_ERR(ssm2602->regmap))
-               return PTR_ERR(ssm2602->regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
-       ret = snd_soc_register_codec(&spi->dev,
-                       &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
-       return ret;
-}
-
-static int ssm2602_spi_remove(struct spi_device *spi)
-{
-       snd_soc_unregister_codec(&spi->dev);
-       return 0;
-}
-
-static struct spi_driver ssm2602_spi_driver = {
-       .driver = {
-               .name   = "ssm2602",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = ssm2602_spi_probe,
-       .remove         = ssm2602_spi_remove,
-};
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-/*
- * ssm2602 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
-static int ssm2602_i2c_probe(struct i2c_client *i2c,
-                            const struct i2c_device_id *id)
-{
-       struct ssm2602_priv *ssm2602;
-       int ret;
-
-       ssm2602 = devm_kzalloc(&i2c->dev, sizeof(struct ssm2602_priv),
-                              GFP_KERNEL);
+       ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL);
        if (ssm2602 == NULL)
                return -ENOMEM;
 
-       i2c_set_clientdata(i2c, ssm2602);
-       ssm2602->type = id->driver_data;
-
-       ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config);
-       if (IS_ERR(ssm2602->regmap))
-               return PTR_ERR(ssm2602->regmap);
-
-       ret = snd_soc_register_codec(&i2c->dev,
-                       &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
-       return ret;
-}
-
-static int ssm2602_i2c_remove(struct i2c_client *client)
-{
-       snd_soc_unregister_codec(&client->dev);
-       return 0;
-}
-
-static const struct i2c_device_id ssm2602_i2c_id[] = {
-       { "ssm2602", SSM2602 },
-       { "ssm2603", SSM2602 },
-       { "ssm2604", SSM2604 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
-
-/* corgi i2c codec control layer */
-static struct i2c_driver ssm2602_i2c_driver = {
-       .driver = {
-               .name = "ssm2602",
-               .owner = THIS_MODULE,
-       },
-       .probe = ssm2602_i2c_probe,
-       .remove = ssm2602_i2c_remove,
-       .id_table = ssm2602_i2c_id,
-};
-#endif
-
-
-static int __init ssm2602_modinit(void)
-{
-       int ret = 0;
-
-#if defined(CONFIG_SPI_MASTER)
-       ret = spi_register_driver(&ssm2602_spi_driver);
-       if (ret)
-               return ret;
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-       ret = i2c_add_driver(&ssm2602_i2c_driver);
-       if (ret)
-               return ret;
-#endif
-
-       return ret;
-}
-module_init(ssm2602_modinit);
-
-static void __exit ssm2602_exit(void)
-{
-#if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&ssm2602_spi_driver);
-#endif
+       dev_set_drvdata(dev, ssm2602);
+       ssm2602->type = SSM2602;
+       ssm2602->regmap = regmap;
 
-#if IS_ENABLED(CONFIG_I2C)
-       i2c_del_driver(&ssm2602_i2c_driver);
-#endif
+       return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602,
+               &ssm2602_dai, 1);
 }
-module_exit(ssm2602_exit);
+EXPORT_SYMBOL_GPL(ssm2602_probe);
 
 MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
 MODULE_AUTHOR("Cliff Cai");
index fbd07d7b73ca2ad7bfced7147de22cec746e7bc4..747538847689eda6f286aef308e03d23d965c0a7 100644 (file)
 #ifndef _SSM2602_H
 #define _SSM2602_H
 
+#include <linux/regmap.h>
+
+struct device;
+
+enum ssm2602_type {
+       SSM2602,
+       SSM2604,
+};
+
+extern const struct regmap_config ssm2602_regmap_config;
+
+int ssm2602_probe(struct device *dev, enum ssm2602_type type,
+       struct regmap *regmap);
+
 /* SSM2602 Codec Register definitions */
 
 #define SSM2602_LINVOL   0x00
index 2735361a4c3cfc5fbc652ee10d62ec2728626184..12577749b17b3b0c0b0298b66758934ae4e87bdd 100644 (file)
@@ -872,16 +872,6 @@ static int sta32x_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
-        * then do the I2C transactions itself.
-        */
-       codec->control_data = sta32x->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
-               goto err;
-       }
-
        /* Chip documentation explicitly requires that the reset values
         * of reserved register bits are left untouched.
         * Write the register default value to cache for reserved registers,
@@ -946,10 +936,6 @@ static int sta32x_probe(struct snd_soc_codec *codec)
        regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 
        return 0;
-
-err:
-       regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
-       return ret;
 }
 
 static int sta32x_remove(struct snd_soc_codec *codec)
index 40c07be9b5814f170f73fa1b3670d3813101bb67..a40c4b0196a3cfc42a0ebd464d067e0d379f9daa 100644 (file)
@@ -141,7 +141,7 @@ static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary",
 
 static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);
 static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0);
-static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
+static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
 
 static const struct snd_kcontrol_new sta529_snd_controls[] = {
        SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0,
@@ -193,8 +193,7 @@ static int sta529_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 snd_soc_codec *codec = dai->codec;
        int pdata, play_freq_val, record_freq_val;
        int bclk_to_fs_ratio;
 
@@ -322,16 +321,6 @@ static struct snd_soc_dai_driver sta529_dai = {
 
 static int sta529_probe(struct snd_soc_codec *codec)
 {
-       struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       codec->control_data = sta529->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
        sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
index a5455c1aea421daee730c56b1c0e4b1a3d2ce575..53b810d23feac4ce2530a7af6170044e22d4268a 100644 (file)
@@ -62,25 +62,25 @@ static const char *stac9766_boost1[] = {"0dB", "10dB"};
 static const char *stac9766_boost2[] = {"0dB", "20dB"};
 static const char *stac9766_stereo_mic[] = {"Off", "On"};
 
-static const struct soc_enum stac9766_record_enum =
-       SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux);
-static const struct soc_enum stac9766_mono_enum =
-       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux);
-static const struct soc_enum stac9766_mic_enum =
-       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux);
-static const struct soc_enum stac9766_SPDIF_enum =
-       SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux);
-static const struct soc_enum stac9766_popbypass_enum =
-       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux);
-static const struct soc_enum stac9766_record_all_enum =
-       SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2,
-                       stac9766_record_all_mux);
-static const struct soc_enum stac9766_boost1_enum =
-       SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */
-static const struct soc_enum stac9766_boost2_enum =
-       SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */
-static const struct soc_enum stac9766_stereo_mic_enum =
-       SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic);
+static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum,
+                           AC97_REC_SEL, 8, 0, stac9766_record_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum,
+                           AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum,
+                           AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum,
+                           AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum,
+                           AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum,
+                           AC97_STAC_ANALOG_SPECIAL, 12,
+                           stac9766_record_all_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum,
+                           AC97_MIC, 6, stac9766_boost1); /* 0/10dB */
+static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum,
+                           AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */
+static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum,
+                           AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic);
 
 static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0);
 static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250);
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
new file mode 100644 (file)
index 0000000..20fc460
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver I2C interface
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * 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/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic23.h"
+
+static int tlv320aic23_i2c_probe(struct i2c_client *i2c,
+                                const struct i2c_device_id *i2c_id)
+{
+       struct regmap *regmap;
+
+       if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EINVAL;
+
+       regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
+       return tlv320aic23_probe(&i2c->dev, regmap);
+}
+
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+       {"tlv320aic23", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+       .driver = {
+                  .name = "tlv320aic23-codec",
+                  },
+       .probe = tlv320aic23_i2c_probe,
+       .remove = __exit_p(tlv320aic23_i2c_remove),
+       .id_table = tlv320aic23_id,
+};
+
+module_i2c_driver(tlv320aic23_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c
new file mode 100644 (file)
index 0000000..3b387e4
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver SPI interface
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * 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/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "tlv320aic23.h"
+
+static int aic23_spi_probe(struct spi_device *spi)
+{
+       int ret;
+       struct regmap *regmap;
+
+       dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n");
+
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
+       regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap);
+       return tlv320aic23_probe(&spi->dev, regmap);
+}
+
+static int aic23_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static struct spi_driver aic23_spi = {
+       .driver = {
+               .name = "tlv320aic23",
+               .owner = THIS_MODULE,
+       },
+       .probe = aic23_spi_probe,
+       .remove = aic23_spi_remove,
+};
+
+module_spi_driver(aic23_spi);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
index 5d430cc56f51d42397c3190bf3bfb55b7f850dae..20864ee8793b5e24be689f6686a2217d9c5c13b9 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = {
        {  9, 0x0000 },
 };
 
-static const struct regmap_config tlv320aic23_regmap = {
+const struct regmap_config tlv320aic23_regmap = {
        .reg_bits = 7,
        .val_bits = 9,
 
@@ -60,20 +59,21 @@ static const struct regmap_config tlv320aic23_regmap = {
        .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
        .cache_type = REGCACHE_RBTREE,
 };
+EXPORT_SYMBOL(tlv320aic23_regmap);
 
 static const char *rec_src_text[] = { "Line", "Mic" };
 static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
 
-static const struct soc_enum rec_src_enum =
-       SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static SOC_ENUM_SINGLE_DECL(rec_src_enum,
+                           TLV320AIC23_ANLG, 2, rec_src_text);
 
 static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
 SOC_DAPM_ENUM("Input Select", rec_src_enum);
 
-static const struct soc_enum tlv320aic23_rec_src =
-       SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
-static const struct soc_enum tlv320aic23_deemph =
-       SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src,
+                           TLV320AIC23_ANLG, 2, rec_src_text);
+static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph,
+                           TLV320AIC23_DIGT, 1, deemph_text);
 
 static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
 static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
@@ -400,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
        struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 
        /* deactivate */
-       if (!codec->active) {
+       if (!snd_soc_codec_is_active(codec)) {
                udelay(50);
                snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
        }
@@ -557,16 +557,8 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int tlv320aic23_probe(struct snd_soc_codec *codec)
+static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        /* Reset codec */
        snd_soc_write(codec, TLV320AIC23_RESET, 0);
 
@@ -604,7 +596,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec)
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
-       .probe = tlv320aic23_probe,
+       .probe = tlv320aic23_codec_probe,
        .remove = tlv320aic23_remove,
        .suspend = tlv320aic23_suspend,
        .resume = tlv320aic23_resume,
@@ -617,56 +609,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
        .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
 };
 
-/*
- * If the i2c layer weren't so broken, we could pass this kind of data
- * around
- */
-static int tlv320aic23_codec_probe(struct i2c_client *i2c,
-                                  const struct i2c_device_id *i2c_id)
+int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
 {
        struct aic23 *aic23;
-       int ret;
 
-       if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -EINVAL;
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
-       aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL);
+       aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL);
        if (aic23 == NULL)
                return -ENOMEM;
 
-       aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
-       if (IS_ERR(aic23->regmap))
-               return PTR_ERR(aic23->regmap);
+       aic23->regmap = regmap;
 
-       i2c_set_clientdata(i2c, aic23);
+       dev_set_drvdata(dev, aic23);
 
-       ret =  snd_soc_register_codec(&i2c->dev,
-                       &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
-       return ret;
+       return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23,
+                                     &tlv320aic23_dai, 1);
 }
-static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
-{
-       snd_soc_unregister_codec(&i2c->dev);
-       return 0;
-}
-
-static const struct i2c_device_id tlv320aic23_id[] = {
-       {"tlv320aic23", 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
-
-static struct i2c_driver tlv320aic23_i2c_driver = {
-       .driver = {
-                  .name = "tlv320aic23-codec",
-                  },
-       .probe = tlv320aic23_codec_probe,
-       .remove = __exit_p(tlv320aic23_i2c_remove),
-       .id_table = tlv320aic23_id,
-};
-
-module_i2c_driver(tlv320aic23_i2c_driver);
+EXPORT_SYMBOL(tlv320aic23_probe);
 
 MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
 MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
index e804120bd3da3bae2354fe5bfd46809d93f561cb..3a7235a04a8966ea28a6cf31983ac2af892f5e17 100644 (file)
 #ifndef _TLV320AIC23_H
 #define _TLV320AIC23_H
 
+struct device;
+struct regmap_config;
+
+extern const struct regmap_config tlv320aic23_regmap;
+int tlv320aic23_probe(struct device *dev, struct regmap *regmap);
+
 /* Codec TLV320AIC23 */
 #define TLV320AIC23_LINVOL             0x00
 #define TLV320AIC23_RINVOL             0x01
index 94a658fa6d97408e84682cea3e3ecc4c9a01cc1d..43069de3d56ac595c2c9a047d7bea3c4a97079d4 100644 (file)
@@ -238,8 +238,9 @@ static struct snd_soc_dai_driver aic26_dai = {
  * ALSA controls
  */
 static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
-static const struct soc_enum aic26_capture_src_enum =
-       SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text);
+static SOC_ENUM_SINGLE_DECL(aic26_capture_src_enum,
+                           AIC26_REG_AUDIO_CTRL1, 12,
+                           aic26_capture_src_text);
 
 static const struct snd_kcontrol_new aic26_snd_controls[] = {
        /* Output */
@@ -295,8 +296,6 @@ static int aic26_probe(struct snd_soc_codec *codec)
        struct aic26 *aic26 = dev_get_drvdata(codec->dev);
        int ret, reg;
 
-       snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
-
        aic26->codec = codec;
 
        /* Reset the codec to power on defaults */
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
new file mode 100644 (file)
index 0000000..fa158cf
--- /dev/null
@@ -0,0 +1,1280 @@
+/*
+ * ALSA SoC TLV320AIC31XX codec driver
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * The TLV320AIC31xx series of audio codec is a low-power, highly integrated
+ * high performance codec which provides a stereo DAC, a mono ADC,
+ * and mono/stereo Class-D speaker driver.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.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 <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+#include "tlv320aic31xx.h"
+
+static const struct reg_default aic31xx_reg_defaults[] = {
+       { AIC31XX_CLKMUX, 0x00 },
+       { AIC31XX_PLLPR, 0x11 },
+       { AIC31XX_PLLJ, 0x04 },
+       { AIC31XX_PLLDMSB, 0x00 },
+       { AIC31XX_PLLDLSB, 0x00 },
+       { AIC31XX_NDAC, 0x01 },
+       { AIC31XX_MDAC, 0x01 },
+       { AIC31XX_DOSRMSB, 0x00 },
+       { AIC31XX_DOSRLSB, 0x80 },
+       { AIC31XX_NADC, 0x01 },
+       { AIC31XX_MADC, 0x01 },
+       { AIC31XX_AOSR, 0x80 },
+       { AIC31XX_IFACE1, 0x00 },
+       { AIC31XX_DATA_OFFSET, 0x00 },
+       { AIC31XX_IFACE2, 0x00 },
+       { AIC31XX_BCLKN, 0x01 },
+       { AIC31XX_DACSETUP, 0x14 },
+       { AIC31XX_DACMUTE, 0x0c },
+       { AIC31XX_LDACVOL, 0x00 },
+       { AIC31XX_RDACVOL, 0x00 },
+       { AIC31XX_ADCSETUP, 0x00 },
+       { AIC31XX_ADCFGA, 0x80 },
+       { AIC31XX_ADCVOL, 0x00 },
+       { AIC31XX_HPDRIVER, 0x04 },
+       { AIC31XX_SPKAMP, 0x06 },
+       { AIC31XX_DACMIXERROUTE, 0x00 },
+       { AIC31XX_LANALOGHPL, 0x7f },
+       { AIC31XX_RANALOGHPR, 0x7f },
+       { AIC31XX_LANALOGSPL, 0x7f },
+       { AIC31XX_RANALOGSPR, 0x7f },
+       { AIC31XX_HPLGAIN, 0x02 },
+       { AIC31XX_HPRGAIN, 0x02 },
+       { AIC31XX_SPLGAIN, 0x00 },
+       { AIC31XX_SPRGAIN, 0x00 },
+       { AIC31XX_MICBIAS, 0x00 },
+       { AIC31XX_MICPGA, 0x80 },
+       { AIC31XX_MICPGAPI, 0x00 },
+       { AIC31XX_MICPGAMI, 0x00 },
+};
+
+static bool aic31xx_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AIC31XX_PAGECTL: /* regmap implementation requires this */
+       case AIC31XX_RESET: /* always clears after write */
+       case AIC31XX_OT_FLAG:
+       case AIC31XX_ADCFLAG:
+       case AIC31XX_DACFLAG1:
+       case AIC31XX_DACFLAG2:
+       case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+       case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+       case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+       case AIC31XX_INTRDACFLAG2:
+       case AIC31XX_INTRADCFLAG2:
+               return true;
+       }
+       return false;
+}
+
+static bool aic31xx_writeable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case AIC31XX_OT_FLAG:
+       case AIC31XX_ADCFLAG:
+       case AIC31XX_DACFLAG1:
+       case AIC31XX_DACFLAG2:
+       case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+       case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+       case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+       case AIC31XX_INTRDACFLAG2:
+       case AIC31XX_INTRADCFLAG2:
+               return false;
+       }
+       return true;
+}
+
+static const struct regmap_range_cfg aic31xx_ranges[] = {
+       {
+               .range_min = 0,
+               .range_max = 12 * 128,
+               .selector_reg = AIC31XX_PAGECTL,
+               .selector_mask = 0xff,
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = 128,
+       },
+};
+
+static const struct regmap_config aic31xx_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .writeable_reg = aic31xx_writeable,
+       .volatile_reg = aic31xx_volatile,
+       .reg_defaults = aic31xx_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(aic31xx_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+       .ranges = aic31xx_ranges,
+       .num_ranges = ARRAY_SIZE(aic31xx_ranges),
+       .max_register = 12 * 128,
+};
+
+#define AIC31XX_NUM_SUPPLIES   6
+static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
+       "HPVDD",
+       "SPRVDD",
+       "SPLVDD",
+       "AVDD",
+       "IOVDD",
+       "DVDD",
+};
+
+struct aic31xx_disable_nb {
+       struct notifier_block nb;
+       struct aic31xx_priv *aic31xx;
+};
+
+struct aic31xx_priv {
+       struct snd_soc_codec *codec;
+       u8 i2c_regs_status;
+       struct device *dev;
+       struct regmap *regmap;
+       struct aic31xx_pdata pdata;
+       struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
+       struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
+       unsigned int sysclk;
+       int rate_div_line;
+};
+
+struct aic31xx_rate_divs {
+       u32 mclk;
+       u32 rate;
+       u8 p_val;
+       u8 pll_j;
+       u16 pll_d;
+       u16 dosr;
+       u8 ndac;
+       u8 mdac;
+       u8 aosr;
+       u8 nadc;
+       u8 madc;
+};
+
+/* ADC dividers can be disabled by cofiguring them to 0 */
+static const struct aic31xx_rate_divs aic31xx_divs[] = {
+       /* mclk      rate  pll: p  j     d     dosr ndac mdac  aors nadc madc */
+       /* 8k rate */
+       {12000000,   8000,      1, 8, 1920,     128,  48,  2,   128,  48,  2},
+       {24000000,   8000,      2, 8, 1920,     128,  48,  2,   128,  48,  2},
+       {25000000,   8000,      2, 7, 8643,     128,  48,  2,   128,  48,  2},
+       /* 11.025k rate */
+       {12000000,  11025,      1, 7, 5264,     128,  32,  2,   128,  32,  2},
+       {24000000,  11025,      2, 7, 5264,     128,  32,  2,   128,  32,  2},
+       {25000000,  11025,      2, 7, 2253,     128,  32,  2,   128,  32,  2},
+       /* 16k rate */
+       {12000000,  16000,      1, 8, 1920,     128,  24,  2,   128,  24,  2},
+       {24000000,  16000,      2, 8, 1920,     128,  24,  2,   128,  24,  2},
+       {25000000,  16000,      2, 7, 8643,     128,  24,  2,   128,  24,  2},
+       /* 22.05k rate */
+       {12000000,  22050,      1, 7, 5264,     128,  16,  2,   128,  16,  2},
+       {24000000,  22050,      2, 7, 5264,     128,  16,  2,   128,  16,  2},
+       {25000000,  22050,      2, 7, 2253,     128,  16,  2,   128,  16,  2},
+       /* 32k rate */
+       {12000000,  32000,      1, 8, 1920,     128,  12,  2,   128,  12,  2},
+       {24000000,  32000,      2, 8, 1920,     128,  12,  2,   128,  12,  2},
+       {25000000,  32000,      2, 7, 8643,     128,  12,  2,   128,  12,  2},
+       /* 44.1k rate */
+       {12000000,  44100,      1, 7, 5264,     128,   8,  2,   128,   8,  2},
+       {24000000,  44100,      2, 7, 5264,     128,   8,  2,   128,   8,  2},
+       {25000000,  44100,      2, 7, 2253,     128,   8,  2,   128,   8,  2},
+       /* 48k rate */
+       {12000000,  48000,      1, 8, 1920,     128,   8,  2,   128,   8,  2},
+       {24000000,  48000,      2, 8, 1920,     128,   8,  2,   128,   8,  2},
+       {25000000,  48000,      2, 7, 8643,     128,   8,  2,   128,   8,  2},
+       /* 88.2k rate */
+       {12000000,  88200,      1, 7, 5264,      64,   8,  2,    64,   8,  2},
+       {24000000,  88200,      2, 7, 5264,      64,   8,  2,    64,   8,  2},
+       {25000000,  88200,      2, 7, 2253,      64,   8,  2,    64,   8,  2},
+       /* 96k rate */
+       {12000000,  96000,      1, 8, 1920,      64,   8,  2,    64,   8,  2},
+       {24000000,  96000,      2, 8, 1920,      64,   8,  2,    64,   8,  2},
+       {25000000,  96000,      2, 7, 8643,      64,   8,  2,    64,   8,  2},
+       /* 176.4k rate */
+       {12000000, 176400,      1, 7, 5264,      32,   8,  2,    32,   8,  2},
+       {24000000, 176400,      2, 7, 5264,      32,   8,  2,    32,   8,  2},
+       {25000000, 176400,      2, 7, 2253,      32,   8,  2,    32,   8,  2},
+       /* 192k rate */
+       {12000000, 192000,      1, 8, 1920,      32,   8,  2,    32,   8,  2},
+       {24000000, 192000,      2, 8, 1920,      32,   8,  2,    32,   8,  2},
+       {25000000, 192000,      2, 7, 8643,      32,   8,  2,    32,   8,  2},
+};
+
+static const char * const ldac_in_text[] = {
+       "Off", "Left Data", "Right Data", "Mono"
+};
+
+static const char * const rdac_in_text[] = {
+       "Off", "Right Data", "Left Data", "Mono"
+};
+
+static SOC_ENUM_SINGLE_DECL(ldac_in_enum, AIC31XX_DACSETUP, 4, ldac_in_text);
+
+static SOC_ENUM_SINGLE_DECL(rdac_in_enum, AIC31XX_DACSETUP, 2, rdac_in_text);
+
+static const char * const mic_select_text[] = {
+       "Off", "FFR 10 Ohm", "FFR 20 Ohm", "FFR 40 Ohm"
+};
+
+static const
+SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text);
+
+static const
+SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text);
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0);
+static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_SCALE(hp_drv_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(class_D_drv_tlv, 600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
+
+/*
+ * controls to be exported to the user space
+ */
+static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
+       SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
+                          AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
+
+       SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
+                      adc_fgain_tlv),
+
+       SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
+       SOC_DOUBLE_R_S_TLV("ADC Capture Volume", AIC31XX_ADCVOL, AIC31XX_ADCVOL,
+                          0, -24, 40, 6, 0, adc_cgain_tlv),
+
+       SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
+                      119, 0, mic_pga_tlv),
+
+       SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
+                    AIC31XX_HPRGAIN, 2, 1, 0),
+       SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
+                        AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
+
+       SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
+                        AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic311x_snd_controls[] = {
+       SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+                    AIC31XX_SPRGAIN, 2, 1, 0),
+       SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+                        AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv),
+
+       SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+                        AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic310x_snd_controls[] = {
+       SOC_SINGLE("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+                  2, 1, 0),
+       SOC_SINGLE_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+                      3, 3, 0, class_D_drv_tlv),
+
+       SOC_SINGLE_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+                      0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new ldac_in_control =
+       SOC_DAPM_ENUM("DAC Left Input", ldac_in_enum);
+
+static const struct snd_kcontrol_new rdac_in_control =
+       SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
+
+static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
+                            unsigned int mask, unsigned int wbits, int sleep,
+                            int count)
+{
+       unsigned int bits;
+       int counter = count;
+       int ret = regmap_read(aic31xx->regmap, reg, &bits);
+       while ((bits & mask) != wbits && counter && !ret) {
+               usleep_range(sleep, sleep * 2);
+               ret = regmap_read(aic31xx->regmap, reg, &bits);
+               counter--;
+       }
+       if ((bits & mask) != wbits) {
+               dev_err(aic31xx->dev,
+                       "%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)\n",
+                       __func__, reg, bits, wbits, ret, mask,
+                       (count - counter) * sleep);
+               ret = -1;
+       }
+       return ret;
+}
+
+#define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg))
+
+static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
+                                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
+       unsigned int reg = AIC31XX_DACFLAG1;
+       unsigned int mask;
+
+       switch (WIDGET_BIT(w->reg, w->shift)) {
+       case WIDGET_BIT(AIC31XX_DACSETUP, 7):
+               mask = AIC31XX_LDACPWRSTATUS_MASK;
+               break;
+       case WIDGET_BIT(AIC31XX_DACSETUP, 6):
+               mask = AIC31XX_RDACPWRSTATUS_MASK;
+               break;
+       case WIDGET_BIT(AIC31XX_HPDRIVER, 7):
+               mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
+               break;
+       case WIDGET_BIT(AIC31XX_HPDRIVER, 6):
+               mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
+               break;
+       case WIDGET_BIT(AIC31XX_SPKAMP, 7):
+               mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
+               break;
+       case WIDGET_BIT(AIC31XX_SPKAMP, 6):
+               mask = AIC31XX_SPRDRVPWRSTATUS_MASK;
+               break;
+       case WIDGET_BIT(AIC31XX_ADCSETUP, 7):
+               mask = AIC31XX_ADCPWRSTATUS_MASK;
+               reg = AIC31XX_ADCFLAG;
+               break;
+       default:
+               dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
+                       w->name, __func__);
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
+       case SND_SOC_DAPM_POST_PMD:
+               return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
+       default:
+               dev_dbg(w->codec->dev,
+                       "Unhandled dapm widget event %d from %s\n",
+                       event, w->name);
+       }
+       return 0;
+}
+
+static const struct snd_kcontrol_new left_output_switches[] = {
+       SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
+       SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
+       SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_switches[] = {
+       SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
+       SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new p_term_mic1lp =
+       SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1rp =
+       SOC_DAPM_ENUM("MIC1RP P-Terminal", mic1rp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1lm =
+       SOC_DAPM_ENUM("MIC1LM P-Terminal", mic1lm_p_enum);
+
+static const struct snd_kcontrol_new m_term_mic1lm =
+       SOC_DAPM_ENUM("MIC1LM M-Terminal", mic1lm_m_enum);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpl_switch =
+       SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGHPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpr_switch =
+       SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGHPR, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spl_switch =
+       SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGSPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
+       SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGSPR, 7, 1, 0);
+
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* change mic bias voltage to user defined */
+               snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+                                   AIC31XX_MICBIAS_MASK,
+                                   aic31xx->pdata.micbias_vg <<
+                                   AIC31XX_MICBIAS_SHIFT);
+               dev_dbg(codec->dev, "%s: turned on\n", __func__);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               /* turn mic bias off */
+               snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+                                   AIC31XX_MICBIAS_MASK, 0);
+               dev_dbg(codec->dev, "%s: turned off\n", __func__);
+               break;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_MUX("DAC Left Input",
+                        SND_SOC_NOPM, 0, 0, &ldac_in_control),
+       SND_SOC_DAPM_MUX("DAC Right Input",
+                        SND_SOC_NOPM, 0, 0, &rdac_in_control),
+       /* DACs */
+       SND_SOC_DAPM_DAC_E("DAC Left", "Left Playback",
+                          AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback",
+                          AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* Output Mixers */
+       SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+                          left_output_switches,
+                          ARRAY_SIZE(left_output_switches)),
+       SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+                          right_output_switches,
+                          ARRAY_SIZE(right_output_switches)),
+
+       SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
+                           &aic31xx_dapm_hpl_switch),
+       SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
+                           &aic31xx_dapm_hpr_switch),
+
+       /* Output drivers */
+       SND_SOC_DAPM_OUT_DRV_E("HPL Driver", AIC31XX_HPDRIVER, 7, 0,
+                              NULL, 0, aic31xx_dapm_power_event,
+                              SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0,
+                              NULL, 0, aic31xx_dapm_power_event,
+                              SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+       /* ADC */
+       SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
+                          aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+
+       /* Input Selection to MIC_PGA */
+       SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
+                        &p_term_mic1lp),
+       SND_SOC_DAPM_MUX("MIC1RP P-Terminal", SND_SOC_NOPM, 0, 0,
+                        &p_term_mic1rp),
+       SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
+                        &p_term_mic1lm),
+
+       SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
+                        &m_term_mic1lm),
+       /* Enabling & Disabling MIC Gain Ctl */
+       SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
+                        7, 1, NULL, 0),
+
+       /* Mic Bias */
+       SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
+                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("MIC1LP"),
+       SND_SOC_DAPM_INPUT("MIC1RP"),
+       SND_SOC_DAPM_INPUT("MIC1LM"),
+};
+
+static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
+       /* AIC3111 and AIC3110 have stereo class-D amplifier */
+       SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+                              aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+                              SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0,
+                              aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+                              SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SWITCH("Speaker Left", SND_SOC_NOPM, 0, 0,
+                           &aic31xx_dapm_spl_switch),
+       SND_SOC_DAPM_SWITCH("Speaker Right", SND_SOC_NOPM, 0, 0,
+                           &aic31xx_dapm_spr_switch),
+       SND_SOC_DAPM_OUTPUT("SPL"),
+       SND_SOC_DAPM_OUTPUT("SPR"),
+};
+
+/* AIC3100 and AIC3120 have only mono class-D amplifier */
+static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
+       SND_SOC_DAPM_OUT_DRV_E("SPK ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+                              aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+                              SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SWITCH("Speaker", SND_SOC_NOPM, 0, 0,
+                           &aic31xx_dapm_spl_switch),
+       SND_SOC_DAPM_OUTPUT("SPK"),
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_audio_map[] = {
+       /* DAC Input Routing */
+       {"DAC Left Input", "Left Data", "DAC IN"},
+       {"DAC Left Input", "Right Data", "DAC IN"},
+       {"DAC Left Input", "Mono", "DAC IN"},
+       {"DAC Right Input", "Left Data", "DAC IN"},
+       {"DAC Right Input", "Right Data", "DAC IN"},
+       {"DAC Right Input", "Mono", "DAC IN"},
+       {"DAC Left", NULL, "DAC Left Input"},
+       {"DAC Right", NULL, "DAC Right Input"},
+
+       /* Mic input */
+       {"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
+       {"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
+       {"MIC1LP P-Terminal", "FFR 40 Ohm", "MIC1LP"},
+       {"MIC1RP P-Terminal", "FFR 10 Ohm", "MIC1RP"},
+       {"MIC1RP P-Terminal", "FFR 20 Ohm", "MIC1RP"},
+       {"MIC1RP P-Terminal", "FFR 40 Ohm", "MIC1RP"},
+       {"MIC1LM P-Terminal", "FFR 10 Ohm", "MIC1LM"},
+       {"MIC1LM P-Terminal", "FFR 20 Ohm", "MIC1LM"},
+       {"MIC1LM P-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+       {"MIC1LM M-Terminal", "FFR 10 Ohm", "MIC1LM"},
+       {"MIC1LM M-Terminal", "FFR 20 Ohm", "MIC1LM"},
+       {"MIC1LM M-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+       {"MIC_GAIN_CTL", NULL, "MIC1LP P-Terminal"},
+       {"MIC_GAIN_CTL", NULL, "MIC1RP P-Terminal"},
+       {"MIC_GAIN_CTL", NULL, "MIC1LM P-Terminal"},
+       {"MIC_GAIN_CTL", NULL, "MIC1LM M-Terminal"},
+
+       {"ADC", NULL, "MIC_GAIN_CTL"},
+
+       /* Left Output */
+       {"Output Left", "From Left DAC", "DAC Left"},
+       {"Output Left", "From MIC1LP", "MIC1LP"},
+       {"Output Left", "From MIC1RP", "MIC1RP"},
+
+       /* Right Output */
+       {"Output Right", "From Right DAC", "DAC Right"},
+       {"Output Right", "From MIC1RP", "MIC1RP"},
+
+       /* HPL path */
+       {"HP Left", "Switch", "Output Left"},
+       {"HPL Driver", NULL, "HP Left"},
+       {"HPL", NULL, "HPL Driver"},
+
+       /* HPR path */
+       {"HP Right", "Switch", "Output Right"},
+       {"HPR Driver", NULL, "HP Right"},
+       {"HPR", NULL, "HPR Driver"},
+};
+
+static const struct snd_soc_dapm_route
+aic311x_audio_map[] = {
+       /* SP L path */
+       {"Speaker Left", "Switch", "Output Left"},
+       {"SPL ClassD", NULL, "Speaker Left"},
+       {"SPL", NULL, "SPL ClassD"},
+
+       /* SP R path */
+       {"Speaker Right", "Switch", "Output Right"},
+       {"SPR ClassD", NULL, "Speaker Right"},
+       {"SPR", NULL, "SPR ClassD"},
+};
+
+static const struct snd_soc_dapm_route
+aic310x_audio_map[] = {
+       /* SP L path */
+       {"Speaker", "Switch", "Output Left"},
+       {"SPK ClassD", NULL, "Speaker"},
+       {"SPK", NULL, "SPK ClassD"},
+};
+
+static int aic31xx_add_controls(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+
+       if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
+               ret = snd_soc_add_codec_controls(
+                       codec, aic311x_snd_controls,
+                       ARRAY_SIZE(aic311x_snd_controls));
+       else
+               ret = snd_soc_add_codec_controls(
+                       codec, aic310x_snd_controls,
+                       ARRAY_SIZE(aic310x_snd_controls));
+
+       return ret;
+}
+
+static int aic31xx_add_widgets(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
+               ret = snd_soc_dapm_new_controls(
+                       dapm, aic311x_dapm_widgets,
+                       ARRAY_SIZE(aic311x_dapm_widgets));
+               if (ret)
+                       return ret;
+
+               ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map,
+                                             ARRAY_SIZE(aic311x_audio_map));
+               if (ret)
+                       return ret;
+       } else {
+               ret = snd_soc_dapm_new_controls(
+                       dapm, aic310x_dapm_widgets,
+                       ARRAY_SIZE(aic310x_dapm_widgets));
+               if (ret)
+                       return ret;
+
+               ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map,
+                                             ARRAY_SIZE(aic310x_audio_map));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int aic31xx_setup_pll(struct snd_soc_codec *codec,
+                            struct snd_pcm_hw_params *params)
+{
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int bclk_n = 0;
+       int i;
+
+       /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
+       snd_soc_update_bits(codec, AIC31XX_CLKMUX,
+                           AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
+       snd_soc_update_bits(codec, AIC31XX_IFACE2,
+                           AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);
+
+       for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
+               if (aic31xx_divs[i].rate == params_rate(params) &&
+                   aic31xx_divs[i].mclk == aic31xx->sysclk)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(aic31xx_divs)) {
+               dev_err(codec->dev, "%s: Sampling rate %u not supported\n",
+                       __func__, params_rate(params));
+               return -EINVAL;
+       }
+
+       /* PLL configuration */
+       snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
+                           (aic31xx_divs[i].p_val << 4) | 0x01);
+       snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
+
+       snd_soc_write(codec, AIC31XX_PLLDMSB,
+                     aic31xx_divs[i].pll_d >> 8);
+       snd_soc_write(codec, AIC31XX_PLLDLSB,
+                     aic31xx_divs[i].pll_d & 0xff);
+
+       /* DAC dividers configuration */
+       snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
+                           aic31xx_divs[i].ndac);
+       snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
+                           aic31xx_divs[i].mdac);
+
+       snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
+       snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
+
+       /* ADC dividers configuration. Write reset value 1 if not used. */
+       snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
+                           aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
+       snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
+                           aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);
+
+       snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
+
+       /* Bit clock divider configuration. */
+       bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac)
+               / snd_soc_params_to_frame_size(params);
+       if (bclk_n == 0) {
+               dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, AIC31XX_BCLKN,
+                           AIC31XX_PLL_MASK, bclk_n);
+
+       aic31xx->rate_div_line = i;
+
+       dev_dbg(codec->dev,
+               "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
+               aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
+               aic31xx_divs[i].p_val, aic31xx_divs[i].dosr,
+               aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
+               aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
+               aic31xx_divs[i].madc, bclk_n);
+
+       return 0;
+}
+
+static int aic31xx_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;
+       u8 data = 0;
+
+       dev_dbg(codec->dev, "## %s: format %d width %d rate %d\n",
+               __func__, params_format(params), params_width(params),
+               params_rate(params));
+
+       switch (params_width(params)) {
+       case 16:
+               break;
+       case 20:
+               data = (AIC31XX_WORD_LEN_20BITS <<
+                       AIC31XX_IFACE1_DATALEN_SHIFT);
+               break;
+       case 24:
+               data = (AIC31XX_WORD_LEN_24BITS <<
+                       AIC31XX_IFACE1_DATALEN_SHIFT);
+               break;
+       case 32:
+               data = (AIC31XX_WORD_LEN_32BITS <<
+                       AIC31XX_IFACE1_DATALEN_SHIFT);
+               break;
+       default:
+               dev_err(codec->dev, "%s: Unsupported format %d\n",
+                       __func__, params_format(params));
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, AIC31XX_IFACE1,
+                           AIC31XX_IFACE1_DATALEN_MASK,
+                           data);
+
+       return aic31xx_setup_pll(codec, params);
+}
+
+static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       if (mute) {
+               snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+                                   AIC31XX_DACMUTE_MASK,
+                                   AIC31XX_DACMUTE_MASK);
+       } else {
+               snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+                                   AIC31XX_DACMUTE_MASK, 0x0);
+       }
+
+       return 0;
+}
+
+static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                              unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 iface_reg1 = 0;
+       u8 iface_reg3 = 0;
+       u8 dsp_a_val = 0;
+
+       dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
+               break;
+       default:
+               dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               dsp_a_val = 0x1;
+       case SND_SOC_DAIFMT_DSP_B:
+               /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       iface_reg3 |= AIC31XX_BCLKINV_MASK;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               iface_reg1 |= (AIC31XX_DSP_MODE <<
+                              AIC31XX_IFACE1_DATATYPE_SHIFT);
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE <<
+                              AIC31XX_IFACE1_DATATYPE_SHIFT);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE <<
+                              AIC31XX_IFACE1_DATATYPE_SHIFT);
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI interface format\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, AIC31XX_IFACE1,
+                           AIC31XX_IFACE1_DATATYPE_MASK |
+                           AIC31XX_IFACE1_MASTER_MASK,
+                           iface_reg1);
+       snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET,
+                           AIC31XX_DATA_OFFSET_MASK,
+                           dsp_a_val);
+       snd_soc_update_bits(codec, AIC31XX_IFACE2,
+                           AIC31XX_BCLKINV_MASK,
+                           iface_reg3);
+
+       return 0;
+}
+
+static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
+               __func__, clk_id, freq, dir);
+
+       for (i = 0; aic31xx_divs[i].mclk != freq; i++) {
+               if (i == ARRAY_SIZE(aic31xx_divs)) {
+                       dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
+                               __func__, freq);
+                       return -EINVAL;
+               }
+       }
+
+       /* set clock on MCLK, BCLK, or GPIO1 as PLL input */
+       snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
+                           clk_id << AIC31XX_PLL_CLKIN_SHIFT);
+
+       aic31xx->sysclk = freq;
+       return 0;
+}
+
+static int aic31xx_regulator_event(struct notifier_block *nb,
+                                  unsigned long event, void *data)
+{
+       struct aic31xx_disable_nb *disable_nb =
+               container_of(nb, struct aic31xx_disable_nb, nb);
+       struct aic31xx_priv *aic31xx = disable_nb->aic31xx;
+
+       if (event & REGULATOR_EVENT_DISABLE) {
+               /*
+                * Put codec to reset and as at least one of the
+                * supplies was disabled.
+                */
+               if (gpio_is_valid(aic31xx->pdata.gpio_reset))
+                       gpio_set_value(aic31xx->pdata.gpio_reset, 0);
+
+               regcache_mark_dirty(aic31xx->regmap);
+               dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
+       }
+
+       return 0;
+}
+
+static void aic31xx_clk_on(struct snd_soc_codec *codec)
+{
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       u8 mask = AIC31XX_PM_MASK;
+       u8 on = AIC31XX_PM_MASK;
+
+       dev_dbg(codec->dev, "codec clock -> on (rate %d)\n",
+               aic31xx_divs[aic31xx->rate_div_line].rate);
+       snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, on);
+       mdelay(10);
+       snd_soc_update_bits(codec, AIC31XX_NDAC, mask, on);
+       snd_soc_update_bits(codec, AIC31XX_MDAC, mask, on);
+       if (aic31xx_divs[aic31xx->rate_div_line].nadc)
+               snd_soc_update_bits(codec, AIC31XX_NADC, mask, on);
+       if (aic31xx_divs[aic31xx->rate_div_line].madc)
+               snd_soc_update_bits(codec, AIC31XX_MADC, mask, on);
+       snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, on);
+}
+
+static void aic31xx_clk_off(struct snd_soc_codec *codec)
+{
+       u8 mask = AIC31XX_PM_MASK;
+       u8 off = 0;
+
+       dev_dbg(codec->dev, "codec clock -> off\n");
+       snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, off);
+       snd_soc_update_bits(codec, AIC31XX_MADC, mask, off);
+       snd_soc_update_bits(codec, AIC31XX_NADC, mask, off);
+       snd_soc_update_bits(codec, AIC31XX_MDAC, mask, off);
+       snd_soc_update_bits(codec, AIC31XX_NDAC, mask, off);
+       snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, off);
+}
+
+static int aic31xx_power_on(struct snd_soc_codec *codec)
+{
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
+                                   aic31xx->supplies);
+       if (ret)
+               return ret;
+
+       if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
+               gpio_set_value(aic31xx->pdata.gpio_reset, 1);
+               udelay(100);
+       }
+       regcache_cache_only(aic31xx->regmap, false);
+       ret = regcache_sync(aic31xx->regmap);
+       if (ret != 0) {
+               dev_err(codec->dev,
+                       "Failed to restore cache: %d\n", ret);
+               regcache_cache_only(aic31xx->regmap, true);
+               regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+                                      aic31xx->supplies);
+               return ret;
+       }
+       return 0;
+}
+
+static int aic31xx_power_off(struct snd_soc_codec *codec)
+{
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       regcache_cache_only(aic31xx->regmap, true);
+       ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+                                    aic31xx->supplies);
+
+       return ret;
+}
+
+static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
+               codec->dapm.bias_level, level);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+                       aic31xx_clk_on(codec);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               switch (codec->dapm.bias_level) {
+               case SND_SOC_BIAS_OFF:
+                       aic31xx_power_on(codec);
+                       break;
+               case SND_SOC_BIAS_PREPARE:
+                       aic31xx_clk_off(codec);
+                       break;
+               default:
+                       BUG();
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+                       aic31xx_power_off(codec);
+               break;
+       }
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int aic31xx_suspend(struct snd_soc_codec *codec)
+{
+       aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int aic31xx_resume(struct snd_soc_codec *codec)
+{
+       aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+
+static int aic31xx_codec_probe(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       dev_dbg(aic31xx->dev, "## %s\n", __func__);
+
+       aic31xx = snd_soc_codec_get_drvdata(codec);
+
+       aic31xx->codec = codec;
+
+       for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
+               aic31xx->disable_nb[i].nb.notifier_call =
+                       aic31xx_regulator_event;
+               aic31xx->disable_nb[i].aic31xx = aic31xx;
+               ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
+                                                 &aic31xx->disable_nb[i].nb);
+               if (ret) {
+                       dev_err(codec->dev,
+                               "Failed to request regulator notifier: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       regcache_cache_only(aic31xx->regmap, true);
+       regcache_mark_dirty(aic31xx->regmap);
+
+       ret = aic31xx_add_controls(codec);
+       if (ret)
+               return ret;
+
+       ret = aic31xx_add_widgets(codec);
+
+       return ret;
+}
+
+static int aic31xx_codec_remove(struct snd_soc_codec *codec)
+{
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+       int i;
+       /* power down chip */
+       aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+               regulator_unregister_notifier(aic31xx->supplies[i].consumer,
+                                             &aic31xx->disable_nb[i].nb);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
+       .probe                  = aic31xx_codec_probe,
+       .remove                 = aic31xx_codec_remove,
+       .suspend                = aic31xx_suspend,
+       .resume                 = aic31xx_resume,
+       .set_bias_level         = aic31xx_set_bias_level,
+       .controls               = aic31xx_snd_controls,
+       .num_controls           = ARRAY_SIZE(aic31xx_snd_controls),
+       .dapm_widgets           = aic31xx_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(aic31xx_dapm_widgets),
+       .dapm_routes            = aic31xx_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(aic31xx_audio_map),
+};
+
+static struct snd_soc_dai_ops aic31xx_dai_ops = {
+       .hw_params      = aic31xx_hw_params,
+       .set_sysclk     = aic31xx_set_dai_sysclk,
+       .set_fmt        = aic31xx_set_dai_fmt,
+       .digital_mute   = aic31xx_dac_mute,
+};
+
+static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
+       {
+               .name = "tlv320aic31xx-hifi",
+               .playback = {
+                       .stream_name     = "Playback",
+                       .channels_min    = 1,
+                       .channels_max    = 2,
+                       .rates           = AIC31XX_RATES,
+                       .formats         = AIC31XX_FORMATS,
+               },
+               .capture = {
+                       .stream_name     = "Capture",
+                       .channels_min    = 1,
+                       .channels_max    = 2,
+                       .rates           = AIC31XX_RATES,
+                       .formats         = AIC31XX_FORMATS,
+               },
+               .ops = &aic31xx_dai_ops,
+               .symmetric_rates = 1,
+       }
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic31xx_of_match[] = {
+       { .compatible = "ti,tlv320aic310x" },
+       { .compatible = "ti,tlv320aic311x" },
+       { .compatible = "ti,tlv320aic3100" },
+       { .compatible = "ti,tlv320aic3110" },
+       { .compatible = "ti,tlv320aic3120" },
+       { .compatible = "ti,tlv320aic3111" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
+
+static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
+{
+       struct device_node *np = aic31xx->dev->of_node;
+       unsigned int value = MICBIAS_2_0V;
+       int ret;
+
+       of_property_read_u32(np, "ai31xx-micbias-vg", &value);
+       switch (value) {
+       case MICBIAS_2_0V:
+       case MICBIAS_2_5V:
+       case MICBIAS_AVDDV:
+               aic31xx->pdata.micbias_vg = value;
+               break;
+       default:
+               dev_err(aic31xx->dev,
+                       "Bad ai31xx-micbias-vg value %d DT\n",
+                       value);
+               aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
+       }
+
+       ret = of_get_named_gpio(np, "gpio-reset", 0);
+       if (ret > 0)
+               aic31xx->pdata.gpio_reset = ret;
+}
+#else /* CONFIG_OF */
+static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
+{
+}
+#endif /* CONFIG_OF */
+
+static void aic31xx_device_init(struct aic31xx_priv *aic31xx)
+{
+       int ret, i;
+
+       dev_set_drvdata(aic31xx->dev, aic31xx);
+
+       if (dev_get_platdata(aic31xx->dev))
+               memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
+                      sizeof(aic31xx->pdata));
+       else if (aic31xx->dev->of_node)
+               aic31xx_pdata_from_of(aic31xx);
+
+       if (aic31xx->pdata.gpio_reset) {
+               ret = devm_gpio_request_one(aic31xx->dev,
+                                           aic31xx->pdata.gpio_reset,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "aic31xx-reset-pin");
+               if (ret < 0) {
+                       dev_err(aic31xx->dev, "not able to acquire gpio\n");
+                       return;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+               aic31xx->supplies[i].supply = aic31xx_supply_names[i];
+
+       ret = devm_regulator_bulk_get(aic31xx->dev,
+                                     ARRAY_SIZE(aic31xx->supplies),
+                                     aic31xx->supplies);
+       if (ret != 0)
+               dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
+
+}
+
+static int aic31xx_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct aic31xx_priv *aic31xx;
+       int ret;
+       const struct regmap_config *regmap_config;
+
+       dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
+               id->name, (int) id->driver_data);
+
+       regmap_config = &aic31xx_i2c_regmap;
+
+       aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
+       if (aic31xx == NULL)
+               return -ENOMEM;
+
+       aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
+       if (IS_ERR(aic31xx->regmap)) {
+               ret = PTR_ERR(aic31xx->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+       aic31xx->dev = &i2c->dev;
+
+       aic31xx->pdata.codec_type = id->driver_data;
+
+       aic31xx_device_init(aic31xx);
+
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
+                                    aic31xx_dai_driver,
+                                    ARRAY_SIZE(aic31xx_dai_driver));
+}
+
+static int aic31xx_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id aic31xx_i2c_id[] = {
+       { "tlv320aic310x", AIC3100 },
+       { "tlv320aic311x", AIC3110 },
+       { "tlv320aic3100", AIC3100 },
+       { "tlv320aic3110", AIC3110 },
+       { "tlv320aic3120", AIC3120 },
+       { "tlv320aic3111", AIC3111 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
+
+static struct i2c_driver aic31xx_i2c_driver = {
+       .driver = {
+               .name   = "tlv320aic31xx-codec",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(tlv320aic31xx_of_match),
+       },
+       .probe          = aic31xx_i2c_probe,
+       .remove         = aic31xx_i2c_remove,
+       .id_table       = aic31xx_i2c_id,
+};
+
+module_i2c_driver(aic31xx_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver");
+MODULE_AUTHOR("Jyri Sarha");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
new file mode 100644 (file)
index 0000000..52ed57c
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * ALSA SoC TLV320AIC31XX codec driver
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef _TLV320AIC31XX_H
+#define _TLV320AIC31XX_H
+
+#define AIC31XX_RATES  SNDRV_PCM_RATE_8000_192000
+
+#define AIC31XX_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+                        | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#define AIC31XX_STEREO_CLASS_D_BIT     0x1
+#define AIC31XX_MINIDSP_BIT            0x2
+
+enum aic31xx_type {
+       AIC3100 = 0,
+       AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
+       AIC3120 = AIC31XX_MINIDSP_BIT,
+       AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
+};
+
+struct aic31xx_pdata {
+       enum aic31xx_type codec_type;
+       unsigned int gpio_reset;
+       int micbias_vg;
+};
+
+/* Page Control Register */
+#define AIC31XX_PAGECTL                                0x00
+
+/* Page 0 Registers */
+/* Software reset register */
+#define AIC31XX_RESET                          0x01
+/* OT FLAG register */
+#define AIC31XX_OT_FLAG                                0x03
+/* Clock clock Gen muxing, Multiplexers*/
+#define AIC31XX_CLKMUX                         0x04
+/* PLL P and R-VAL register */
+#define AIC31XX_PLLPR                          0x05
+/* PLL J-VAL register */
+#define AIC31XX_PLLJ                           0x06
+/* PLL D-VAL MSB register */
+#define AIC31XX_PLLDMSB                                0x07
+/* PLL D-VAL LSB register */
+#define AIC31XX_PLLDLSB                                0x08
+/* DAC NDAC_VAL register*/
+#define AIC31XX_NDAC                           0x0B
+/* DAC MDAC_VAL register */
+#define AIC31XX_MDAC                           0x0C
+/* DAC OSR setting register 1, MSB value */
+#define AIC31XX_DOSRMSB                                0x0D
+/* DAC OSR setting register 2, LSB value */
+#define AIC31XX_DOSRLSB                                0x0E
+#define AIC31XX_MINI_DSP_INPOL                 0x10
+/* Clock setting register 8, PLL */
+#define AIC31XX_NADC                           0x12
+/* Clock setting register 9, PLL */
+#define AIC31XX_MADC                           0x13
+/* ADC Oversampling (AOSR) Register */
+#define AIC31XX_AOSR                           0x14
+/* Clock setting register 9, Multiplexers */
+#define AIC31XX_CLKOUTMUX                      0x19
+/* Clock setting register 10, CLOCKOUT M divider value */
+#define AIC31XX_CLKOUTMVAL                     0x1A
+/* Audio Interface Setting Register 1 */
+#define AIC31XX_IFACE1                         0x1B
+/* Audio Data Slot Offset Programming */
+#define AIC31XX_DATA_OFFSET                    0x1C
+/* Audio Interface Setting Register 2 */
+#define AIC31XX_IFACE2                         0x1D
+/* Clock setting register 11, BCLK N Divider */
+#define AIC31XX_BCLKN                          0x1E
+/* Audio Interface Setting Register 3, Secondary Audio Interface */
+#define AIC31XX_IFACESEC1                      0x1F
+/* Audio Interface Setting Register 4 */
+#define AIC31XX_IFACESEC2                      0x20
+/* Audio Interface Setting Register 5 */
+#define AIC31XX_IFACESEC3                      0x21
+/* I2C Bus Condition */
+#define AIC31XX_I2C                            0x22
+/* ADC FLAG */
+#define AIC31XX_ADCFLAG                                0x24
+/* DAC Flag Registers */
+#define AIC31XX_DACFLAG1                       0x25
+#define AIC31XX_DACFLAG2                       0x26
+/* Sticky Interrupt flag (overflow) */
+#define AIC31XX_OFFLAG                         0x27
+/* Sticy DAC Interrupt flags */
+#define AIC31XX_INTRDACFLAG                    0x2C
+/* Sticy ADC Interrupt flags */
+#define AIC31XX_INTRADCFLAG                    0x2D
+/* DAC Interrupt flags 2 */
+#define AIC31XX_INTRDACFLAG2                   0x2E
+/* ADC Interrupt flags 2 */
+#define AIC31XX_INTRADCFLAG2                   0x2F
+/* INT1 interrupt control */
+#define AIC31XX_INT1CTRL                       0x30
+/* INT2 interrupt control */
+#define AIC31XX_INT2CTRL                       0x31
+/* GPIO1 control */
+#define AIC31XX_GPIO1                          0x33
+
+#define AIC31XX_DACPRB                         0x3C
+/* ADC Instruction Set Register */
+#define AIC31XX_ADCPRB                         0x3D
+/* DAC channel setup register */
+#define AIC31XX_DACSETUP                       0x3F
+/* DAC Mute and volume control register */
+#define AIC31XX_DACMUTE                                0x40
+/* Left DAC channel digital volume control */
+#define AIC31XX_LDACVOL                                0x41
+/* Right DAC channel digital volume control */
+#define AIC31XX_RDACVOL                                0x42
+/* Headset detection */
+#define AIC31XX_HSDETECT                       0x43
+/* ADC Digital Mic */
+#define AIC31XX_ADCSETUP                       0x51
+/* ADC Digital Volume Control Fine Adjust */
+#define AIC31XX_ADCFGA                         0x52
+/* ADC Digital Volume Control Coarse Adjust */
+#define AIC31XX_ADCVOL                         0x53
+
+
+/* Page 1 Registers */
+/* Headphone drivers */
+#define AIC31XX_HPDRIVER                       0x9F
+/* Class-D Speakear Amplifier */
+#define AIC31XX_SPKAMP                         0xA0
+/* HP Output Drivers POP Removal Settings */
+#define AIC31XX_HPPOP                          0xA1
+/* Output Driver PGA Ramp-Down Period Control */
+#define AIC31XX_SPPGARAMP                      0xA2
+/* DAC_L and DAC_R Output Mixer Routing */
+#define AIC31XX_DACMIXERROUTE                  0xA3
+/* Left Analog Vol to HPL */
+#define AIC31XX_LANALOGHPL                     0xA4
+/* Right Analog Vol to HPR */
+#define AIC31XX_RANALOGHPR                     0xA5
+/* Left Analog Vol to SPL */
+#define AIC31XX_LANALOGSPL                     0xA6
+/* Right Analog Vol to SPR */
+#define AIC31XX_RANALOGSPR                     0xA7
+/* HPL Driver */
+#define AIC31XX_HPLGAIN                                0xA8
+/* HPR Driver */
+#define AIC31XX_HPRGAIN                                0xA9
+/* SPL Driver */
+#define AIC31XX_SPLGAIN                                0xAA
+/* SPR Driver */
+#define AIC31XX_SPRGAIN                                0xAB
+/* HP Driver Control */
+#define AIC31XX_HPCONTROL                      0xAC
+/* MIC Bias Control */
+#define AIC31XX_MICBIAS                                0xAE
+/* MIC PGA*/
+#define AIC31XX_MICPGA                         0xAF
+/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
+#define AIC31XX_MICPGAPI                       0xB0
+/* ADC Input Selection for M-Terminal */
+#define AIC31XX_MICPGAMI                       0xB1
+/* Input CM Settings */
+#define AIC31XX_MICPGACM                       0xB2
+
+/* Bits, masks and shifts */
+
+/* AIC31XX_CLKMUX */
+#define AIC31XX_PLL_CLKIN_MASK                 0x0c
+#define AIC31XX_PLL_CLKIN_SHIFT                        2
+#define AIC31XX_PLL_CLKIN_MCLK                 0
+#define AIC31XX_CODEC_CLKIN_MASK               0x03
+#define AIC31XX_CODEC_CLKIN_SHIFT              0
+#define AIC31XX_CODEC_CLKIN_PLL                        3
+#define AIC31XX_CODEC_CLKIN_BCLK               1
+
+/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC,
+   AIC31XX_BCLKN */
+#define AIC31XX_PLL_MASK               0x7f
+#define AIC31XX_PM_MASK                        0x80
+
+/* AIC31XX_IFACE1 */
+#define AIC31XX_WORD_LEN_16BITS                0x00
+#define AIC31XX_WORD_LEN_20BITS                0x01
+#define AIC31XX_WORD_LEN_24BITS                0x02
+#define AIC31XX_WORD_LEN_32BITS                0x03
+#define AIC31XX_IFACE1_DATALEN_MASK    0x30
+#define AIC31XX_IFACE1_DATALEN_SHIFT   (4)
+#define AIC31XX_IFACE1_DATATYPE_MASK   0xC0
+#define AIC31XX_IFACE1_DATATYPE_SHIFT  (6)
+#define AIC31XX_I2S_MODE               0x00
+#define AIC31XX_DSP_MODE               0x01
+#define AIC31XX_RIGHT_JUSTIFIED_MODE   0x02
+#define AIC31XX_LEFT_JUSTIFIED_MODE    0x03
+#define AIC31XX_IFACE1_MASTER_MASK     0x0C
+#define AIC31XX_BCLK_MASTER            0x08
+#define AIC31XX_WCLK_MASTER            0x04
+
+/* AIC31XX_DATA_OFFSET */
+#define AIC31XX_DATA_OFFSET_MASK       0xFF
+
+/* AIC31XX_IFACE2 */
+#define AIC31XX_BCLKINV_MASK           0x08
+#define AIC31XX_BDIVCLK_MASK           0x03
+#define AIC31XX_DAC2BCLK               0x00
+#define AIC31XX_DACMOD2BCLK            0x01
+#define AIC31XX_ADC2BCLK               0x02
+#define AIC31XX_ADCMOD2BCLK            0x03
+
+/* AIC31XX_ADCFLAG */
+#define AIC31XX_ADCPWRSTATUS_MASK              0x40
+
+/* AIC31XX_DACFLAG1 */
+#define AIC31XX_LDACPWRSTATUS_MASK             0x80
+#define AIC31XX_RDACPWRSTATUS_MASK             0x08
+#define AIC31XX_HPLDRVPWRSTATUS_MASK           0x20
+#define AIC31XX_HPRDRVPWRSTATUS_MASK           0x02
+#define AIC31XX_SPLDRVPWRSTATUS_MASK           0x10
+#define AIC31XX_SPRDRVPWRSTATUS_MASK           0x01
+
+/* AIC31XX_INTRDACFLAG */
+#define AIC31XX_HPSCDETECT_MASK                        0x80
+#define AIC31XX_BUTTONPRESS_MASK               0x20
+#define AIC31XX_HSPLUG_MASK                    0x10
+#define AIC31XX_LDRCTHRES_MASK                 0x08
+#define AIC31XX_RDRCTHRES_MASK                 0x04
+#define AIC31XX_DACSINT_MASK                   0x02
+#define AIC31XX_DACAINT_MASK                   0x01
+
+/* AIC31XX_INT1CTRL */
+#define AIC31XX_HSPLUGDET_MASK                 0x80
+#define AIC31XX_BUTTONPRESSDET_MASK            0x40
+#define AIC31XX_DRCTHRES_MASK                  0x20
+#define AIC31XX_AGCNOISE_MASK                  0x10
+#define AIC31XX_OC_MASK                                0x08
+#define AIC31XX_ENGINE_MASK                    0x04
+
+/* AIC31XX_DACSETUP */
+#define AIC31XX_SOFTSTEP_MASK                  0x03
+
+/* AIC31XX_DACMUTE */
+#define AIC31XX_DACMUTE_MASK                   0x0C
+
+/* AIC31XX_MICBIAS */
+#define AIC31XX_MICBIAS_MASK                   0x03
+#define AIC31XX_MICBIAS_SHIFT                  0
+
+#endif /* _TLV320AIC31XX_H */
index 688151ba309af2e3af8bdeea6a428850947d3773..1d9b117345a3ae6fc8182f73733603a34f6a20d7 100644 (file)
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/i2c.h>
 #include <linux/cdev.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
 
 #include <sound/tlv320aic32x4.h>
 #include <sound/core.h>
@@ -66,20 +69,32 @@ struct aic32x4_priv {
        u32 micpga_routing;
        bool swapdacs;
        int rstn_gpio;
+       struct clk *mclk;
+
+       struct regulator *supply_ldo;
+       struct regulator *supply_iov;
+       struct regulator *supply_dv;
+       struct regulator *supply_av;
 };
 
-/* 0dB min, 1dB steps */
-static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
 /* 0dB min, 0.5dB steps */
 static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
+/* -63.5dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
+/* -6dB min, 1dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
+/* -12dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
 
 static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
-       SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
-                       AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
-       SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
-                       AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
-       SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
-                       AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1),
+       SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+                       AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
+       SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
+                       AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
+                       tlv_driver_gain),
+       SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
+                       AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
+                       tlv_driver_gain),
        SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
                        AIC32X4_HPRGAIN, 6, 0x01, 1),
        SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
@@ -90,8 +105,8 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
        SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
        SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
 
-       SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
-                       AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
+       SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
+                       AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
        SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
                        AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
 
@@ -480,8 +495,18 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
 static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
+       struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
        switch (level) {
        case SND_SOC_BIAS_ON:
+               /* Switch on master clock */
+               ret = clk_prepare_enable(aic32x4->mclk);
+               if (ret) {
+                       dev_err(codec->dev, "Failed to enable master clock\n");
+                       return ret;
+               }
+
                /* Switch on PLL */
                snd_soc_update_bits(codec, AIC32X4_PLLPR,
                                    AIC32X4_PLLEN, AIC32X4_PLLEN);
@@ -509,29 +534,32 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* Switch off PLL */
-               snd_soc_update_bits(codec, AIC32X4_PLLPR,
-                                   AIC32X4_PLLEN, 0);
+               /* Switch off BCLK_N Divider */
+               snd_soc_update_bits(codec, AIC32X4_BCLKN,
+                                   AIC32X4_BCLKEN, 0);
 
-               /* Switch off NDAC Divider */
-               snd_soc_update_bits(codec, AIC32X4_NDAC,
-                                   AIC32X4_NDACEN, 0);
+               /* Switch off MADC Divider */
+               snd_soc_update_bits(codec, AIC32X4_MADC,
+                                   AIC32X4_MADCEN, 0);
+
+               /* Switch off NADC Divider */
+               snd_soc_update_bits(codec, AIC32X4_NADC,
+                                   AIC32X4_NADCEN, 0);
 
                /* Switch off MDAC Divider */
                snd_soc_update_bits(codec, AIC32X4_MDAC,
                                    AIC32X4_MDACEN, 0);
 
-               /* Switch off NADC Divider */
-               snd_soc_update_bits(codec, AIC32X4_NADC,
-                                   AIC32X4_NADCEN, 0);
+               /* Switch off NDAC Divider */
+               snd_soc_update_bits(codec, AIC32X4_NDAC,
+                                   AIC32X4_NDACEN, 0);
 
-               /* Switch off MADC Divider */
-               snd_soc_update_bits(codec, AIC32X4_MADC,
-                                   AIC32X4_MADCEN, 0);
+               /* Switch off PLL */
+               snd_soc_update_bits(codec, AIC32X4_PLLPR,
+                                   AIC32X4_PLLEN, 0);
 
-               /* Switch off BCLK_N Divider */
-               snd_soc_update_bits(codec, AIC32X4_BCLKN,
-                                   AIC32X4_BCLKEN, 0);
+               /* Switch off master clock */
+               clk_disable_unprepare(aic32x4->mclk);
                break;
        case SND_SOC_BIAS_OFF:
                break;
@@ -586,9 +614,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
        struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
        u32 tmp_reg;
 
-       snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-
-       if (aic32x4->rstn_gpio >= 0) {
+       if (gpio_is_valid(aic32x4->rstn_gpio)) {
                ndelay(10);
                gpio_set_value(aic32x4->rstn_gpio, 1);
        }
@@ -663,11 +689,122 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
        .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
 };
 
+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
+               struct device_node *np)
+{
+       aic32x4->swapdacs = false;
+       aic32x4->micpga_routing = 0;
+       aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+
+       return 0;
+}
+
+static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
+{
+       regulator_disable(aic32x4->supply_iov);
+
+       if (!IS_ERR(aic32x4->supply_ldo))
+               regulator_disable(aic32x4->supply_ldo);
+
+       if (!IS_ERR(aic32x4->supply_dv))
+               regulator_disable(aic32x4->supply_dv);
+
+       if (!IS_ERR(aic32x4->supply_av))
+               regulator_disable(aic32x4->supply_av);
+}
+
+static int aic32x4_setup_regulators(struct device *dev,
+               struct aic32x4_priv *aic32x4)
+{
+       int ret = 0;
+
+       aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
+       aic32x4->supply_iov = devm_regulator_get(dev, "iov");
+       aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
+       aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
+
+       /* Check if the regulator requirements are fulfilled */
+
+       if (IS_ERR(aic32x4->supply_iov)) {
+               dev_err(dev, "Missing supply 'iov'\n");
+               return PTR_ERR(aic32x4->supply_iov);
+       }
+
+       if (IS_ERR(aic32x4->supply_ldo)) {
+               if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               if (IS_ERR(aic32x4->supply_dv)) {
+                       dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
+                       return PTR_ERR(aic32x4->supply_dv);
+               }
+               if (IS_ERR(aic32x4->supply_av)) {
+                       dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
+                       return PTR_ERR(aic32x4->supply_av);
+               }
+       } else {
+               if (IS_ERR(aic32x4->supply_dv) &&
+                               PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               if (IS_ERR(aic32x4->supply_av) &&
+                               PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+       }
+
+       ret = regulator_enable(aic32x4->supply_iov);
+       if (ret) {
+               dev_err(dev, "Failed to enable regulator iov\n");
+               return ret;
+       }
+
+       if (!IS_ERR(aic32x4->supply_ldo)) {
+               ret = regulator_enable(aic32x4->supply_ldo);
+               if (ret) {
+                       dev_err(dev, "Failed to enable regulator ldo\n");
+                       goto error_ldo;
+               }
+       }
+
+       if (!IS_ERR(aic32x4->supply_dv)) {
+               ret = regulator_enable(aic32x4->supply_dv);
+               if (ret) {
+                       dev_err(dev, "Failed to enable regulator dv\n");
+                       goto error_dv;
+               }
+       }
+
+       if (!IS_ERR(aic32x4->supply_av)) {
+               ret = regulator_enable(aic32x4->supply_av);
+               if (ret) {
+                       dev_err(dev, "Failed to enable regulator av\n");
+                       goto error_av;
+               }
+       }
+
+       if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
+               aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
+
+       return 0;
+
+error_av:
+       if (!IS_ERR(aic32x4->supply_dv))
+               regulator_disable(aic32x4->supply_dv);
+
+error_dv:
+       if (!IS_ERR(aic32x4->supply_ldo))
+               regulator_disable(aic32x4->supply_ldo);
+
+error_ldo:
+       regulator_disable(aic32x4->supply_iov);
+       return ret;
+}
+
 static int aic32x4_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
        struct aic32x4_pdata *pdata = i2c->dev.platform_data;
        struct aic32x4_priv *aic32x4;
+       struct device_node *np = i2c->dev.of_node;
        int ret;
 
        aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv),
@@ -686,6 +823,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
                aic32x4->swapdacs = pdata->swapdacs;
                aic32x4->micpga_routing = pdata->micpga_routing;
                aic32x4->rstn_gpio = pdata->rstn_gpio;
+       } else if (np) {
+               ret = aic32x4_parse_dt(aic32x4, np);
+               if (ret) {
+                       dev_err(&i2c->dev, "Failed to parse DT node\n");
+                       return ret;
+               }
        } else {
                aic32x4->power_cfg = 0;
                aic32x4->swapdacs = false;
@@ -693,20 +836,44 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
                aic32x4->rstn_gpio = -1;
        }
 
-       if (aic32x4->rstn_gpio >= 0) {
+       aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk");
+       if (IS_ERR(aic32x4->mclk)) {
+               dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
+               return PTR_ERR(aic32x4->mclk);
+       }
+
+       if (gpio_is_valid(aic32x4->rstn_gpio)) {
                ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio,
                                GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
                if (ret != 0)
                        return ret;
        }
 
+       ret = aic32x4_setup_regulators(&i2c->dev, aic32x4);
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to setup regulators\n");
+               return ret;
+       }
+
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_aic32x4, &aic32x4_dai, 1);
-       return ret;
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to register codec\n");
+               aic32x4_disable_regulators(aic32x4);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, aic32x4);
+
+       return 0;
 }
 
 static int aic32x4_i2c_remove(struct i2c_client *client)
 {
+       struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client);
+
+       aic32x4_disable_regulators(aic32x4);
+
        snd_soc_unregister_codec(&client->dev);
        return 0;
 }
@@ -717,10 +884,17 @@ static const struct i2c_device_id aic32x4_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
 
+static const struct of_device_id aic32x4_of_id[] = {
+       { .compatible = "ti,tlv320aic32x4", },
+       { /* senitel */ }
+};
+MODULE_DEVICE_TABLE(of, aic32x4_of_id);
+
 static struct i2c_driver aic32x4_i2c_driver = {
        .driver = {
                .name = "tlv320aic32x4",
                .owner = THIS_MODULE,
+               .of_match_table = aic32x4_of_id,
        },
        .probe =    aic32x4_i2c_probe,
        .remove =   aic32x4_i2c_remove,
index 470fbfb4b3861314b6ecc74dfd95d5c2cd8b0d89..b1835103e9b4002ab44429d40bb16da8372f65aa 100644 (file)
@@ -1344,12 +1344,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
        INIT_LIST_HEAD(&aic3x->list);
        aic3x->codec = codec;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
                aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
                aic3x->disable_nb[i].aic3x = aic3x;
index 4f358393d6d63b721495ccc8330da431a9c38a20..6bfc8a17331b05c887a80199f05fa4fb38baac31 100644 (file)
@@ -122,7 +122,6 @@ struct tlv320dac33_priv {
        unsigned int uthr;
 
        enum dac33_state state;
-       enum snd_soc_control_type control_type;
        void *control_data;
 };
 
@@ -461,7 +460,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
        if (dac33->fifo_mode == ucontrol->value.integer.value[0])
                return 0;
        /* Do not allow changes while stream is running*/
-       if (codec->active)
+       if (snd_soc_codec_is_active(codec))
                return -EPERM;
 
        if (ucontrol->value.integer.value[0] < 0 ||
@@ -478,9 +477,7 @@ static const char *dac33_fifo_mode_texts[] = {
        "Bypass", "Mode 1", "Mode 7"
 };
 
-static const struct soc_enum dac33_fifo_mode_enum =
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
-                           dac33_fifo_mode_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(dac33_fifo_mode_enum, dac33_fifo_mode_texts);
 
 /* L/R Line Output Gain */
 static const char *lr_lineout_gain_texts[] = {
@@ -488,15 +485,13 @@ static const char *lr_lineout_gain_texts[] = {
        "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
 };
 
-static const struct soc_enum l_lineout_gain_enum =
-       SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
-                       ARRAY_SIZE(lr_lineout_gain_texts),
-                       lr_lineout_gain_texts);
+static SOC_ENUM_SINGLE_DECL(l_lineout_gain_enum,
+                           DAC33_LDAC_PWR_CTRL, 0,
+                           lr_lineout_gain_texts);
 
-static const struct soc_enum r_lineout_gain_enum =
-       SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
-                       ARRAY_SIZE(lr_lineout_gain_texts),
-                       lr_lineout_gain_texts);
+static SOC_ENUM_SINGLE_DECL(r_lineout_gain_enum,
+                           DAC33_RDAC_PWR_CTRL, 0,
+                           lr_lineout_gain_texts);
 
 /*
  * DACL/R digital volume control:
@@ -534,18 +529,16 @@ static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
 /* LOP L/R invert selection */
 static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"};
 
-static const struct soc_enum dac33_left_lom_enum =
-       SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 3,
-                       ARRAY_SIZE(dac33_lr_lom_texts),
-                       dac33_lr_lom_texts);
+static SOC_ENUM_SINGLE_DECL(dac33_left_lom_enum,
+                           DAC33_OUT_AMP_CTRL, 3,
+                           dac33_lr_lom_texts);
 
 static const struct snd_kcontrol_new dac33_dapm_left_lom_control =
 SOC_DAPM_ENUM("Route", dac33_left_lom_enum);
 
-static const struct soc_enum dac33_right_lom_enum =
-       SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 2,
-                       ARRAY_SIZE(dac33_lr_lom_texts),
-                       dac33_lr_lom_texts);
+static SOC_ENUM_SINGLE_DECL(dac33_right_lom_enum,
+                           DAC33_OUT_AMP_CTRL, 2,
+                           dac33_lr_lom_texts);
 
 static const struct snd_kcontrol_new dac33_dapm_right_lom_control =
 SOC_DAPM_ENUM("Route", dac33_right_lom_enum);
index 00665ada23e20bf37bc2b5e1af81b2a5afe3332e..975e0f760ac1b74d01289fed1016278ae5c66f8e 100644 (file)
@@ -415,10 +415,9 @@ static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = {
 static const char *twl4030_handsfreel_texts[] =
                {"Voice", "AudioL1", "AudioL2", "AudioR2"};
 
-static const struct soc_enum twl4030_handsfreel_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0,
-                       ARRAY_SIZE(twl4030_handsfreel_texts),
-                       twl4030_handsfreel_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_handsfreel_enum,
+                           TWL4030_REG_HFL_CTL, 0,
+                           twl4030_handsfreel_texts);
 
 static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =
 SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
@@ -431,10 +430,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
 static const char *twl4030_handsfreer_texts[] =
                {"Voice", "AudioR1", "AudioR2", "AudioL2"};
 
-static const struct soc_enum twl4030_handsfreer_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0,
-                       ARRAY_SIZE(twl4030_handsfreer_texts),
-                       twl4030_handsfreer_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_handsfreer_enum,
+                           TWL4030_REG_HFR_CTL, 0,
+                           twl4030_handsfreer_texts);
 
 static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =
 SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
@@ -448,10 +446,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
 static const char *twl4030_vibra_texts[] =
                {"AudioL1", "AudioR1", "AudioL2", "AudioR2"};
 
-static const struct soc_enum twl4030_vibra_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2,
-                       ARRAY_SIZE(twl4030_vibra_texts),
-                       twl4030_vibra_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibra_enum,
+                           TWL4030_REG_VIBRA_CTL, 2,
+                           twl4030_vibra_texts);
 
 static const struct snd_kcontrol_new twl4030_dapm_vibra_control =
 SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
@@ -460,10 +457,9 @@ SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
 static const char *twl4030_vibrapath_texts[] =
                {"Local vibrator", "Audio"};
 
-static const struct soc_enum twl4030_vibrapath_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4,
-                       ARRAY_SIZE(twl4030_vibrapath_texts),
-                       twl4030_vibrapath_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibrapath_enum,
+                           TWL4030_REG_VIBRA_CTL, 4,
+                           twl4030_vibrapath_texts);
 
 static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control =
 SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum);
@@ -490,10 +486,9 @@ static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = {
 static const char *twl4030_micpathtx1_texts[] =
                {"Analog", "Digimic0"};
 
-static const struct soc_enum twl4030_micpathtx1_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 0,
-                       ARRAY_SIZE(twl4030_micpathtx1_texts),
-                       twl4030_micpathtx1_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx1_enum,
+                           TWL4030_REG_ADCMICSEL, 0,
+                           twl4030_micpathtx1_texts);
 
 static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control =
 SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum);
@@ -502,10 +497,9 @@ SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum);
 static const char *twl4030_micpathtx2_texts[] =
                {"Analog", "Digimic1"};
 
-static const struct soc_enum twl4030_micpathtx2_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 2,
-                       ARRAY_SIZE(twl4030_micpathtx2_texts),
-                       twl4030_micpathtx2_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx2_enum,
+                           TWL4030_REG_ADCMICSEL, 2,
+                           twl4030_micpathtx2_texts);
 
 static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
 SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum);
@@ -955,19 +949,15 @@ static const char *twl4030_op_modes_texts[] = {
        "Option 2 (voice/audio)", "Option 1 (audio)"
 };
 
-static const struct soc_enum twl4030_op_modes_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0,
-                       ARRAY_SIZE(twl4030_op_modes_texts),
-                       twl4030_op_modes_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
+                           TWL4030_REG_CODEC_MODE, 0,
+                           twl4030_op_modes_texts);
 
 static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned short val;
-       unsigned short mask;
 
        if (twl4030->configured) {
                dev_err(codec->dev,
@@ -975,19 +965,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
                return -EBUSY;
        }
 
-       if (ucontrol->value.enumerated.item[0] > e->max - 1)
-               return -EINVAL;
-
-       val = ucontrol->value.enumerated.item[0] << e->shift_l;
-       mask = e->mask << e->shift_l;
-       if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->max - 1)
-                       return -EINVAL;
-               val |= ucontrol->value.enumerated.item[1] << e->shift_r;
-               mask |= e->mask << e->shift_r;
-       }
-
-       return snd_soc_update_bits(codec, e->reg, mask, val);
+       return snd_soc_put_enum_double(kcontrol, ucontrol);
 }
 
 /*
@@ -1044,10 +1022,9 @@ static const char *twl4030_avadc_clk_priority_texts[] = {
        "Voice high priority", "HiFi high priority"
 };
 
-static const struct soc_enum twl4030_avadc_clk_priority_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2,
-                       ARRAY_SIZE(twl4030_avadc_clk_priority_texts),
-                       twl4030_avadc_clk_priority_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_avadc_clk_priority_enum,
+                           TWL4030_REG_AVADC_CTL, 2,
+                           twl4030_avadc_clk_priority_texts);
 
 static const char *twl4030_rampdelay_texts[] = {
        "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
@@ -1055,40 +1032,36 @@ static const char *twl4030_rampdelay_texts[] = {
        "3495/2581/1748 ms"
 };
 
-static const struct soc_enum twl4030_rampdelay_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2,
-                       ARRAY_SIZE(twl4030_rampdelay_texts),
-                       twl4030_rampdelay_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_rampdelay_enum,
+                           TWL4030_REG_HS_POPN_SET, 2,
+                           twl4030_rampdelay_texts);
 
 /* Vibra H-bridge direction mode */
 static const char *twl4030_vibradirmode_texts[] = {
        "Vibra H-bridge direction", "Audio data MSB",
 };
 
-static const struct soc_enum twl4030_vibradirmode_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5,
-                       ARRAY_SIZE(twl4030_vibradirmode_texts),
-                       twl4030_vibradirmode_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibradirmode_enum,
+                           TWL4030_REG_VIBRA_CTL, 5,
+                           twl4030_vibradirmode_texts);
 
 /* Vibra H-bridge direction */
 static const char *twl4030_vibradir_texts[] = {
        "Positive polarity", "Negative polarity",
 };
 
-static const struct soc_enum twl4030_vibradir_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1,
-                       ARRAY_SIZE(twl4030_vibradir_texts),
-                       twl4030_vibradir_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibradir_enum,
+                           TWL4030_REG_VIBRA_CTL, 1,
+                           twl4030_vibradir_texts);
 
 /* Digimic Left and right swapping */
 static const char *twl4030_digimicswap_texts[] = {
        "Not swapped", "Swapped",
 };
 
-static const struct soc_enum twl4030_digimicswap_enum =
-       SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0,
-                       ARRAY_SIZE(twl4030_digimicswap_texts),
-                       twl4030_digimicswap_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_digimicswap_enum,
+                           TWL4030_REG_MISC_SET_1, 0,
+                           twl4030_digimicswap_texts);
 
 static const struct snd_kcontrol_new twl4030_snd_controls[] = {
        /* Codec operation mode control */
index 0afe8bef6765645ef75a9454f929c20b0d3c86b4..bd3a20647fdff04c0071bc9f77061eea457e77de 100644 (file)
@@ -81,7 +81,7 @@ struct twl6040_data {
 };
 
 /* set of rates for each pll: low-power and high-performance */
-static unsigned int lp_rates[] = {
+static const unsigned int lp_rates[] = {
        8000,
        11250,
        16000,
@@ -93,7 +93,7 @@ static unsigned int lp_rates[] = {
        96000,
 };
 
-static unsigned int hp_rates[] = {
+static const unsigned int hp_rates[] = {
        8000,
        16000,
        32000,
@@ -101,7 +101,7 @@ static unsigned int hp_rates[] = {
        96000,
 };
 
-static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
+static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
        { .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },
        { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
 };
@@ -392,8 +392,10 @@ static const char *twl6040_amicr_texts[] =
        {"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"};
 
 static const struct soc_enum twl6040_enum[] = {
-       SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 4, twl6040_amicl_texts),
-       SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 4, twl6040_amicr_texts),
+       SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3,
+                       ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts),
+       SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3,
+                       ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts),
 };
 
 static const char *twl6040_hs_texts[] = {
@@ -476,9 +478,8 @@ static const char *twl6040_power_mode_texts[] = {
        "Low-Power", "High-Performance",
 };
 
-static const struct soc_enum twl6040_power_mode_enum =
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_power_mode_texts),
-                       twl6040_power_mode_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
+                               twl6040_power_mode_texts);
 
 static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
index c94d4c1e3dacc1d7a51f2c6708848d56af6ecf9e..edf27acc1d77da6ba457cef5e8a403867e753fb2 100644 (file)
@@ -203,8 +203,7 @@ static int uda134x_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 snd_soc_codec *codec = dai->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
        u8 hw_params;
 
index 726df6d43c2b69227adc503e38397f977db4f220..e62e70781ec21fe72bac4137c518f1bf01794e88 100644 (file)
@@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
        /* the interpolator & decimator regs must only be written when the
         * codec DAI is active.
         */
-       if (!codec->active && (reg >= UDA1380_MVOL))
+       if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
                return 0;
        pr_debug("uda1380: hw write %x val %x\n", reg, value);
        if (codec->hw_write(codec->control_data, data, 3) == 3) {
@@ -237,25 +237,27 @@ static const char *uda1380_os_setting[] = {
 };
 
 static const struct soc_enum uda1380_deemp_enum[] = {
-       SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp),
-       SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp),
+       SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, ARRAY_SIZE(uda1380_deemp),
+                       uda1380_deemp),
+       SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, ARRAY_SIZE(uda1380_deemp),
+                       uda1380_deemp),
 };
-static const struct soc_enum uda1380_input_sel_enum =
-       SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel);          /* SEL_MIC, SEL_LNA */
-static const struct soc_enum uda1380_output_sel_enum =
-       SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel);          /* R02_EN_AVC */
-static const struct soc_enum uda1380_spf_enum =
-       SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode);         /* M */
-static const struct soc_enum uda1380_capture_sel_enum =
-       SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel);      /* SEL_SOURCE */
-static const struct soc_enum uda1380_sel_ns_enum =
-       SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns);          /* SEL_NS */
-static const struct soc_enum uda1380_mix_enum =
-       SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control);     /* MIX, MIX_POS */
-static const struct soc_enum uda1380_sdet_enum =
-       SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting);     /* SD_VALUE */
-static const struct soc_enum uda1380_os_enum =
-       SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting);       /* OS */
+static SOC_ENUM_SINGLE_DECL(uda1380_input_sel_enum,
+                           UDA1380_ADC, 2, uda1380_input_sel);         /* SEL_MIC, SEL_LNA */
+static SOC_ENUM_SINGLE_DECL(uda1380_output_sel_enum,
+                           UDA1380_PM, 7, uda1380_output_sel);         /* R02_EN_AVC */
+static SOC_ENUM_SINGLE_DECL(uda1380_spf_enum,
+                           UDA1380_MODE, 14, uda1380_spf_mode);                /* M */
+static SOC_ENUM_SINGLE_DECL(uda1380_capture_sel_enum,
+                           UDA1380_IFACE, 6, uda1380_capture_sel);     /* SEL_SOURCE */
+static SOC_ENUM_SINGLE_DECL(uda1380_sel_ns_enum,
+                           UDA1380_MIXER, 14, uda1380_sel_ns);         /* SEL_NS */
+static SOC_ENUM_SINGLE_DECL(uda1380_mix_enum,
+                           UDA1380_MIXER, 12, uda1380_mix_control);    /* MIX, MIX_POS */
+static SOC_ENUM_SINGLE_DECL(uda1380_sdet_enum,
+                           UDA1380_MIXER, 4, uda1380_sdet_setting);    /* SD_VALUE */
+static SOC_ENUM_SINGLE_DECL(uda1380_os_enum,
+                           UDA1380_MIXER, 0, uda1380_os_setting);      /* OS */
 
 /*
  * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB)
@@ -564,8 +566,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
 static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* shut down WSPLL power if running from this clock */
index b7ab2ef567c889ad7969c9bae6e2a4ca640b7de4..6be5f80b65f1ad632eeab797bfa6349c1ae800dc 100644 (file)
@@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
                return 0;
 
        /* Do not allow changes while stream is running */
-       if (codec->active)
+       if (snd_soc_codec_is_active(codec))
                return -EPERM;
 
        if (ucontrol->value.integer.value[0] < 0 ||
@@ -209,8 +209,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static const struct soc_enum wl1273_enum =
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
+static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
 
 static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
@@ -247,9 +246,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
 
 static const char * const wl1273_audio_strings[] = { "Digital", "Analog" };
 
-static const struct soc_enum wl1273_audio_enum =
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
-                           wl1273_audio_strings);
+static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
 
 static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
index 8ae50274ea8f12f275938e2cdab2c836db1f687e..83a2c872925c4bbd9a844ea36f8b5127fd72fd41 100644 (file)
@@ -786,8 +786,6 @@ static int wm2000_probe(struct snd_soc_codec *codec)
 {
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_REGMAP);
-
        /* This will trigger a transition to standby mode by default */
        wm2000_anc_set_mode(wm2000);
 
index 57ba315d0c84d41c4c5f8b390014cde50f84f85f..2e721e06671bd26c7dc65c7f7a546567d3c6d54c 100644 (file)
@@ -1113,11 +1113,10 @@ static const char *wm2200_rxanc_input_sel_texts[] = {
        "None", "IN1", "IN2", "IN3",
 };
 
-static const struct soc_enum wm2200_rxanc_input_sel =
-       SOC_ENUM_SINGLE(WM2200_RXANC_SRC,
-                       WM2200_IN_RXANC_SEL_SHIFT,
-                       ARRAY_SIZE(wm2200_rxanc_input_sel_texts),
-                       wm2200_rxanc_input_sel_texts);
+static SOC_ENUM_SINGLE_DECL(wm2200_rxanc_input_sel,
+                           WM2200_RXANC_SRC,
+                           WM2200_IN_RXANC_SEL_SHIFT,
+                           wm2200_rxanc_input_sel_texts);
 
 static const struct snd_kcontrol_new wm2200_snd_controls[] = {
 SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
@@ -1288,11 +1287,10 @@ static const char *wm2200_aec_loopback_texts[] = {
        "OUT1L", "OUT1R", "OUT2L", "OUT2R",
 };
 
-static const struct soc_enum wm2200_aec_loopback =
-       SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1,
-                       WM2200_AEC_LOOPBACK_SRC_SHIFT,
-                       ARRAY_SIZE(wm2200_aec_loopback_texts),
-                       wm2200_aec_loopback_texts);
+static SOC_ENUM_SINGLE_DECL(wm2200_aec_loopback,
+                           WM2200_DAC_AEC_CONTROL_1,
+                           WM2200_AEC_LOOPBACK_SRC_SHIFT,
+                           wm2200_aec_loopback_texts);
 
 static const struct snd_kcontrol_new wm2200_aec_loopback_mux =
        SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback);
@@ -1556,15 +1554,8 @@ static int wm2200_probe(struct snd_soc_codec *codec)
        int ret;
 
        wm2200->codec = codec;
-       codec->control_data = wm2200->regmap;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 
-       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;
-       }
-
        ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
        if (ret != 0)
                return ret;
index 4e3e31aaf5098e473391f578df6fe0c3c6042a95..eca983fad8918e2599b5c990eada31b2147ddc17 100644 (file)
@@ -506,21 +506,21 @@ static const char *wm5100_lhpf_mode_text[] = {
        "Low-pass", "High-pass"
 };
 
-static const struct soc_enum wm5100_lhpf1_mode =
-       SOC_ENUM_SINGLE(WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, 2,
-                       wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf1_mode,
+                           WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT,
+                           wm5100_lhpf_mode_text);
 
-static const struct soc_enum wm5100_lhpf2_mode =
-       SOC_ENUM_SINGLE(WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, 2,
-                       wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf2_mode,
+                           WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT,
+                           wm5100_lhpf_mode_text);
 
-static const struct soc_enum wm5100_lhpf3_mode =
-       SOC_ENUM_SINGLE(WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, 2,
-                       wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf3_mode,
+                           WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT,
+                           wm5100_lhpf_mode_text);
 
-static const struct soc_enum wm5100_lhpf4_mode =
-       SOC_ENUM_SINGLE(WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, 2,
-                       wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf4_mode,
+                           WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT,
+                           wm5100_lhpf_mode_text);
 
 static const struct snd_kcontrol_new wm5100_snd_controls[] = {
 SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL,
@@ -2100,6 +2100,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)
 int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
        struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        if (jack) {
                wm5100->jack = jack;
@@ -2117,9 +2118,14 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
                                    WM5100_ACCDET_RATE_MASK);
 
                /* We need the charge pump to power MICBIAS */
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2");
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_mutex_lock(dapm);
+
+               snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2");
+               snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+
+               snd_soc_dapm_sync_unlocked(dapm);
+
+               snd_soc_dapm_mutex_unlock(dapm);
 
                /* We start off just enabling microphone detection - even a
                 * plain headphone will trigger detection.
@@ -2337,13 +2343,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
        int ret, i;
 
        wm5100->codec = codec;
-       codec->control_data = wm5100->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;
-       }
 
        for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
                snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
index ce9c8e14d4bd105cfc33991604a06440e67ca1f0..dcf1d12cfef8f7bd5cb835d995eef1cb71e1ad93 100644 (file)
@@ -582,7 +582,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = w->codec;
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-       struct regmap *regmap = codec->control_data;
+       struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
        int i, patch_size;
 
@@ -622,13 +622,16 @@ static const unsigned int wm5102_osr_val[] = {
 
 static const struct soc_enum wm5102_hpout_osr[] = {
        SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
-                             ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+                             ARIZONA_OUT1_OSR_SHIFT, 0x7,
+                             ARRAY_SIZE(wm5102_osr_text),
                              wm5102_osr_text, wm5102_osr_val),
        SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
-                             ARIZONA_OUT2_OSR_SHIFT, 0x7, 3,
+                             ARIZONA_OUT2_OSR_SHIFT, 0x7,
+                             ARRAY_SIZE(wm5102_osr_text),
                              wm5102_osr_text, wm5102_osr_val),
        SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
-                             ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+                             ARIZONA_OUT3_OSR_SHIFT, 0x7,
+                             ARRAY_SIZE(wm5102_osr_text),
                              wm5102_osr_text, wm5102_osr_val),
 };
 
@@ -685,15 +688,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
 
-SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
-                  ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
-                  ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
-                  ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
-                  ARIZONA_EQ4_ENA_MASK),
-
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -705,6 +701,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -716,6 +714,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -727,6 +727,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -1758,9 +1760,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = priv->core.arizona->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+       ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
        if (ret != 0)
                return ret;
 
index 2c3c962d9a856fe12e391b4292cdf7dbd715cd6d..df5a38dd8328db5922a4db96758b50d81e6255ee 100644 (file)
@@ -136,7 +136,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = w->codec;
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-       struct regmap *regmap = codec->control_data;
+       struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
        int i, patch_size;
 
@@ -247,15 +247,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
 
-SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
-                  ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
-                  ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
-                  ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
-                  ARIZONA_EQ4_ENA_MASK),
-
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -267,6 +260,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -278,6 +273,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -289,6 +286,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -1588,10 +1587,9 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = priv->core.arizona->regmap;
        priv->core.arizona->dapm = &codec->dapm;
 
-       ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+       ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
        if (ret != 0)
                return ret;
 
index a183dcf3d5c12343884be365e0f50c90248135b8..757256bf7672ef9a44d156d895ca0537018ab852 100644 (file)
@@ -1505,9 +1505,7 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        if (ret != 0)
                return ret;
 
-       codec->control_data = wm8350->regmap;
-
-       snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+       snd_soc_codec_set_cache_io(codec, wm8350->regmap);
 
        /* Put the codec into reset if it wasn't already */
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
index 6d684d934f4de1e2b2c43dfc18d5659ada570cf1..146564feaea04156d8d0d2fe5608390047b4cad0 100644 (file)
@@ -1316,10 +1316,9 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
 
        snd_soc_codec_set_drvdata(codec, priv);
        priv->wm8400 = wm8400;
-       codec->control_data = wm8400->regmap;
        priv->codec = codec;
 
-       snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+       snd_soc_codec_set_cache_io(codec, wm8400->regmap);
 
        ret = devm_regulator_bulk_get(wm8400->dev,
                                 ARRAY_SIZE(power), &power[0]);
index 7df7d45727559e98501eef2500b3cc610ee8a4b0..1c1e328feeb862f84efbfca08b924c1313c69d4f 100644 (file)
@@ -589,20 +589,12 @@ static int wm8510_resume(struct snd_soc_codec *codec)
 
 static int wm8510_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        wm8510_reset(codec);
 
        /* power on device */
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       return ret;
+       return 0;
 }
 
 /* power down chip */
index 74d106dc76676d5481ae367ad2c5115e8d7df32a..601ee8178af1c0adb32a224daa3dbbc5ad40d1cf 100644 (file)
@@ -75,8 +75,8 @@ static const char *wm8523_zd_count_text[] = {
        "2048",
 };
 
-static const struct soc_enum wm8523_zc_count =
-       SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text);
+static SOC_ENUM_SINGLE_DECL(wm8523_zc_count, WM8523_ZERO_DETECT, 0,
+                           wm8523_zd_count_text);
 
 static const struct snd_kcontrol_new wm8523_controls[] = {
 SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
@@ -392,18 +392,11 @@ static int wm8523_resume(struct snd_soc_codec *codec)
 static int wm8523_probe(struct snd_soc_codec *codec)
 {
        struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
-       int ret;
 
        wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
        wm8523->rate_constraint.count =
                ARRAY_SIZE(wm8523->rate_constraint_list);
 
-       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;
-       }
-
        /* Change some default settings - latch VU and enable ZC */
        snd_soc_update_bits(codec, WM8523_DAC_GAINR,
                            WM8523_DACR_VU, WM8523_DACR_VU);
index 318989acbbe5fbb97878856ccab46330422f6bdf..af7ed8b5d4e187e5b85dc6f3d47b9f7711ca86b2 100644 (file)
@@ -504,8 +504,7 @@ static int wm8580_paif_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 snd_soc_codec *codec = dai->codec;
        struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
        u16 paifa = 0;
        u16 paifb = 0;
@@ -869,12 +868,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)
        struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
                                    wm8580->supplies);
        if (ret != 0) {
index d99f948c513cd80bf56f96f6657ce20224f2fb0d..b0fbcb377bafa5cffcc2d7cd78f7f131641cd089 100644 (file)
@@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
 
        /* deactivate */
-       if (!codec->active) {
+       if (!snd_soc_codec_is_active(codec)) {
                udelay(50);
                snd_soc_write(codec, WM8711_ACTIVE, 0x0);
        }
@@ -367,12 +367,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
 {
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8711_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
index cd89033e84c08a1d290cb012cee545273b35badd..bac7fc28fe71b34c0afc27f553cc01efebd6cf8d 100644 (file)
@@ -228,19 +228,10 @@ static int wm8728_resume(struct snd_soc_codec *codec)
 
 static int wm8728_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
-                      ret);
-               return ret;
-       }
-
        /* power on device */
        wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       return ret;
+       return 0;
 }
 
 static int wm8728_remove(struct snd_soc_codec *codec)
index 029720366ff8f65f7d6b208216f7cba64b6523af..d74f43975b90fb3e90a5b7b36b0239e4f6e52aeb 100644 (file)
@@ -83,8 +83,8 @@ static bool wm8731_writeable(struct device *dev, unsigned int reg)
 
 static const char *wm8731_input_select[] = {"Line In", "Mic"};
 
-static const struct soc_enum wm8731_insel_enum =
-       SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select);
+static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum,
+                           WM8731_APANA, 2, wm8731_input_select);
 
 static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
 
@@ -583,13 +583,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
        int ret = 0, i;
 
-       codec->control_data = wm8731->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
                wm8731->supplies[i].supply = wm8731_supply_names[i];
 
index 2f167a8ca01b507cb3b61521de5db174b186b073..b27f26cdc04932dfb5d62224f9abd20de921f7cb 100644 (file)
@@ -99,29 +99,29 @@ static const char *micbias_enum_text[] = {
        "100%",
 };
 
-static const struct soc_enum micbias_enum =
-       SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text);
+static SOC_ENUM_SINGLE_DECL(micbias_enum,
+                           WM8737_MIC_PREAMP_CONTROL, 0, micbias_enum_text);
 
 static const char *low_cutoff_text[] = {
        "Low", "High"
 };
 
-static const struct soc_enum low_3d =
-       SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(low_3d,
+                           WM8737_3D_ENHANCE, 6, low_cutoff_text);
 
 static const char *high_cutoff_text[] = {
        "High", "Low"
 };
 
-static const struct soc_enum high_3d =
-       SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(high_3d,
+                           WM8737_3D_ENHANCE, 5, high_cutoff_text);
 
 static const char *alc_fn_text[] = {
        "Disabled", "Right", "Left", "Stereo"
 };
 
-static const struct soc_enum alc_fn =
-       SOC_ENUM_SINGLE(WM8737_ALC1, 7, 4, alc_fn_text);
+static SOC_ENUM_SINGLE_DECL(alc_fn,
+                           WM8737_ALC1, 7, alc_fn_text);
 
 static const char *alc_hold_text[] = {
        "0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms",
@@ -129,24 +129,24 @@ static const char *alc_hold_text[] = {
        "10.916s", "21.832s", "43.691s"
 };
 
-static const struct soc_enum alc_hold =
-       SOC_ENUM_SINGLE(WM8737_ALC2, 0, 16, alc_hold_text);
+static SOC_ENUM_SINGLE_DECL(alc_hold,
+                           WM8737_ALC2, 0, alc_hold_text);
 
 static const char *alc_atk_text[] = {
        "8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms",
        "1.075s", "2.15s", "4.3s", "8.6s"
 };
 
-static const struct soc_enum alc_atk =
-       SOC_ENUM_SINGLE(WM8737_ALC3, 0, 11, alc_atk_text);
+static SOC_ENUM_SINGLE_DECL(alc_atk,
+                           WM8737_ALC3, 0, alc_atk_text);
 
 static const char *alc_dcy_text[] = {
        "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s",
        "4.3s", "8.6s", "17.2s", "34.41s"
 };
 
-static const struct soc_enum alc_dcy =
-       SOC_ENUM_SINGLE(WM8737_ALC3, 4, 11, alc_dcy_text);
+static SOC_ENUM_SINGLE_DECL(alc_dcy,
+                           WM8737_ALC3, 4, alc_dcy_text);
 
 static const struct snd_kcontrol_new wm8737_snd_controls[] = {
 SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
@@ -191,8 +191,8 @@ static const char *linsel_text[] = {
        "LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",
 };
 
-static const struct soc_enum linsel_enum =
-       SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text);
+static SOC_ENUM_SINGLE_DECL(linsel_enum,
+                           WM8737_AUDIO_PATH_L, 7, linsel_text);
 
 static const struct snd_kcontrol_new linsel_mux =
        SOC_DAPM_ENUM("LINSEL", linsel_enum);
@@ -202,8 +202,8 @@ static const char *rinsel_text[] = {
        "RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",
 };
 
-static const struct soc_enum rinsel_enum =
-       SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text);
+static SOC_ENUM_SINGLE_DECL(rinsel_enum,
+                           WM8737_AUDIO_PATH_R, 7, rinsel_text);
 
 static const struct snd_kcontrol_new rinsel_mux =
        SOC_DAPM_ENUM("RINSEL", rinsel_enum);
@@ -212,15 +212,15 @@ static const char *bypass_text[] = {
        "Direct", "Preamp"
 };
 
-static const struct soc_enum lbypass_enum =
-       SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text);
+static SOC_ENUM_SINGLE_DECL(lbypass_enum,
+                           WM8737_MIC_PREAMP_CONTROL, 2, bypass_text);
 
 static const struct snd_kcontrol_new lbypass_mux =
        SOC_DAPM_ENUM("Left Bypass", lbypass_enum);
 
 
-static const struct soc_enum rbypass_enum =
-       SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text);
+static SOC_ENUM_SINGLE_DECL(rbypass_enum,
+                           WM8737_MIC_PREAMP_CONTROL, 3, bypass_text);
 
 static const struct snd_kcontrol_new rbypass_mux =
        SOC_DAPM_ENUM("Left Bypass", rbypass_enum);
@@ -570,12 +570,6 @@ static int wm8737_probe(struct snd_soc_codec *codec)
        struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
                                    wm8737->supplies);
        if (ret != 0) {
@@ -644,7 +638,7 @@ static const struct regmap_config wm8737_regmap = {
        .volatile_reg = wm8737_volatile,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8737_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -758,7 +752,7 @@ static struct spi_driver wm8737_spi_driver = {
 static int __init wm8737_modinit(void)
 {
        int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
        ret = i2c_add_driver(&wm8737_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n",
@@ -781,7 +775,7 @@ static void __exit wm8737_exit(void)
 #if defined(CONFIG_SPI_MASTER)
        spi_unregister_driver(&wm8737_spi_driver);
 #endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
        i2c_del_driver(&wm8737_i2c_driver);
 #endif
 }
index 2895c8d3b5e4cce600114dcab949f28b82cf2c7e..b33542a046073504a5ee5d16af4ca4a6698b5e86 100644 (file)
@@ -44,7 +44,7 @@ struct wm8741_priv {
        struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
        unsigned int sysclk;
-       struct snd_pcm_hw_constraint_list *sysclk_constraints;
+       const struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
 static const struct reg_default wm8741_reg_defaults[] = {
@@ -122,74 +122,74 @@ static struct {
        { 6, 768 },
 };
 
-static unsigned int rates_11289[] = {
+static const unsigned int rates_11289[] = {
        44100, 88235,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_11289 = {
+static const struct snd_pcm_hw_constraint_list constraints_11289 = {
        .count  = ARRAY_SIZE(rates_11289),
        .list   = rates_11289,
 };
 
-static unsigned int rates_12288[] = {
+static const unsigned int rates_12288[] = {
        32000, 48000, 96000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_12288 = {
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
        .count  = ARRAY_SIZE(rates_12288),
        .list   = rates_12288,
 };
 
-static unsigned int rates_16384[] = {
+static const unsigned int rates_16384[] = {
        32000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_16384 = {
+static const struct snd_pcm_hw_constraint_list constraints_16384 = {
        .count  = ARRAY_SIZE(rates_16384),
        .list   = rates_16384,
 };
 
-static unsigned int rates_16934[] = {
+static const unsigned int rates_16934[] = {
        44100, 88235,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_16934 = {
+static const struct snd_pcm_hw_constraint_list constraints_16934 = {
        .count  = ARRAY_SIZE(rates_16934),
        .list   = rates_16934,
 };
 
-static unsigned int rates_18432[] = {
+static const unsigned int rates_18432[] = {
        48000, 96000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_18432 = {
+static const struct snd_pcm_hw_constraint_list constraints_18432 = {
        .count  = ARRAY_SIZE(rates_18432),
        .list   = rates_18432,
 };
 
-static unsigned int rates_22579[] = {
+static const unsigned int rates_22579[] = {
        44100, 88235, 1764000
 };
 
-static struct snd_pcm_hw_constraint_list constraints_22579 = {
+static const struct snd_pcm_hw_constraint_list constraints_22579 = {
        .count  = ARRAY_SIZE(rates_22579),
        .list   = rates_22579,
 };
 
-static unsigned int rates_24576[] = {
+static const unsigned int rates_24576[] = {
        32000, 48000, 96000, 192000
 };
 
-static struct snd_pcm_hw_constraint_list constraints_24576 = {
+static const struct snd_pcm_hw_constraint_list constraints_24576 = {
        .count  = ARRAY_SIZE(rates_24576),
        .list   = rates_24576,
 };
 
-static unsigned int rates_36864[] = {
+static const unsigned int rates_36864[] = {
        48000, 96000, 19200
 };
 
-static struct snd_pcm_hw_constraint_list constraints_36864 = {
+static const struct snd_pcm_hw_constraint_list constraints_36864 = {
        .count  = ARRAY_SIZE(rates_36864),
        .list   = rates_36864,
 };
@@ -429,12 +429,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)
                goto err_get;
        }
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err_enable;
-       }
-
        ret = wm8741_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
index 78616a638a55ad4a76f11559f08c6dc4bdb708f6..33990b63d21428a8f8281ff98b1c071f907b211e 100644 (file)
@@ -702,12 +702,6 @@ static int wm8750_probe(struct snd_soc_codec *codec)
 {
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8750_reset(codec);
        if (ret < 0) {
                printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
index be85da93a2682fb89c7c668042f772fc08ca7452..cbb8d55052a44a56bcfc22c00d1b64beeeb47da9 100644 (file)
@@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
        if (wm8753->dai_func == ucontrol->value.integer.value[0])
                return 0;
 
-       if (codec->active)
+       if (snd_soc_codec_is_active(codec))
                return -EBUSY;
 
        ioctl = snd_soc_read(codec, WM8753_IOCTL);
@@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
        /* the digital mute covers the HiFi and Voice DAC's on the WM8753.
         * make sure we check if they are not both active when we mute */
        if (mute && wm8753->dai_func == 1) {
-               if (!codec->active)
+               if (!snd_soc_codec_is_active(codec))
                        snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
        } else {
                if (mute)
@@ -1440,7 +1440,6 @@ static void wm8753_work(struct work_struct *work)
 static int wm8753_suspend(struct snd_soc_codec *codec)
 {
        wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       codec->cache_sync = 1;
        return 0;
 }
 
@@ -1471,13 +1470,6 @@ static int wm8753_probe(struct snd_soc_codec *codec)
 
        INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work);
 
-       codec->control_data = wm8753->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8753_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
index 5bce2101348514aa6508dc9dac7f895d176ae0d9..c61aeb38efb8a191cd142a7b54f65e348e07d4fb 100644 (file)
@@ -580,12 +580,6 @@ static int wm8770_probe(struct snd_soc_codec *codec)
        wm8770 = snd_soc_codec_get_drvdata(codec);
        wm8770->codec = codec;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
                                    wm8770->supplies);
        if (ret) {
index ef824672523206a1a3f5d593647a20ae5487b941..70952ceb278b8699a11600c011bf8bcf35e99699 100644 (file)
@@ -430,12 +430,6 @@ static int wm8776_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8776_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
index 9bc8206a68071267cbb18856dc5c9722930af147..ee76f0fb429967c4f563450a111d3ce651540fd0 100644 (file)
@@ -92,7 +92,7 @@ WM8804_REGULATOR_EVENT(0)
 WM8804_REGULATOR_EVENT(1)
 
 static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
-static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
+static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
 
 static const struct snd_kcontrol_new wm8804_snd_controls[] = {
        SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
@@ -546,14 +546,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)
 
        wm8804 = snd_soc_codec_get_drvdata(codec);
 
-       codec->control_data = wm8804->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
-               return ret;
-       }
-
        for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
                wm8804->supplies[i].supply = wm8804_supply_names[i];
 
index 43c2201cb90131ebdb66e2f10326f4c904700011..d09fdce57f5a85d8b35c195feb68db70d069edc6 100644 (file)
@@ -1178,13 +1178,7 @@ static int wm8900_resume(struct snd_soc_codec *codec)
 
 static int wm8900_probe(struct snd_soc_codec *codec)
 {
-       int ret = 0, reg;
-
-       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;
-       }
+       int reg;
 
        reg = snd_soc_read(codec, WM8900_REG_ID);
        if (reg != 0x8900) {
index eebcb1da3b7b10769f0e265f95c90a6638266f71..b0084a127d18c6214636ed96ef40f3ae8b4b56ae 100644 (file)
@@ -489,28 +489,28 @@ static const char *hpf_mode_text[] = {
        "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
 };
 
-static const struct soc_enum hpf_mode =
-       SOC_ENUM_SINGLE(WM8903_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(hpf_mode,
+                           WM8903_ADC_DIGITAL_0, 5, hpf_mode_text);
 
 static const char *osr_text[] = {
        "Low power", "High performance"
 };
 
-static const struct soc_enum adc_osr =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_ADC_0, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+                           WM8903_ANALOGUE_ADC_0, 0, osr_text);
 
-static const struct soc_enum dac_osr =
-       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+                           WM8903_DAC_DIGITAL_1, 0, osr_text);
 
 static const char *drc_slope_text[] = {
        "1", "1/2", "1/4", "1/8", "1/16", "0"
 };
 
-static const struct soc_enum drc_slope_r0 =
-       SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text);
+static SOC_ENUM_SINGLE_DECL(drc_slope_r0,
+                           WM8903_DRC_2, 3, drc_slope_text);
 
-static const struct soc_enum drc_slope_r1 =
-       SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text);
+static SOC_ENUM_SINGLE_DECL(drc_slope_r1,
+                           WM8903_DRC_2, 0, drc_slope_text);
 
 static const char *drc_attack_text[] = {
        "instantaneous",
@@ -518,125 +518,125 @@ static const char *drc_attack_text[] = {
        "46.4ms", "92.8ms", "185.6ms"
 };
 
-static const struct soc_enum drc_attack =
-       SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text);
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+                           WM8903_DRC_1, 12, drc_attack_text);
 
 static const char *drc_decay_text[] = {
        "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
        "23.87s", "47.56s"
 };
 
-static const struct soc_enum drc_decay =
-       SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+                           WM8903_DRC_1, 8, drc_decay_text);
 
 static const char *drc_ff_delay_text[] = {
        "5 samples", "9 samples"
 };
 
-static const struct soc_enum drc_ff_delay =
-       SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text);
+static SOC_ENUM_SINGLE_DECL(drc_ff_delay,
+                           WM8903_DRC_0, 5, drc_ff_delay_text);
 
 static const char *drc_qr_decay_text[] = {
        "0.725ms", "1.45ms", "5.8ms"
 };
 
-static const struct soc_enum drc_qr_decay =
-       SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_decay,
+                           WM8903_DRC_1, 4, drc_qr_decay_text);
 
 static const char *drc_smoothing_text[] = {
        "Low", "Medium", "High"
 };
 
-static const struct soc_enum drc_smoothing =
-       SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text);
+static SOC_ENUM_SINGLE_DECL(drc_smoothing,
+                           WM8903_DRC_0, 11, drc_smoothing_text);
 
 static const char *soft_mute_text[] = {
        "Fast (fs/2)", "Slow (fs/32)"
 };
 
-static const struct soc_enum soft_mute =
-       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text);
+static SOC_ENUM_SINGLE_DECL(soft_mute,
+                           WM8903_DAC_DIGITAL_1, 10, soft_mute_text);
 
 static const char *mute_mode_text[] = {
        "Hard", "Soft"
 };
 
-static const struct soc_enum mute_mode =
-       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
+static SOC_ENUM_SINGLE_DECL(mute_mode,
+                           WM8903_DAC_DIGITAL_1, 9, mute_mode_text);
 
 static const char *companding_text[] = {
        "ulaw", "alaw"
 };
 
-static const struct soc_enum dac_companding =
-       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text);
+static SOC_ENUM_SINGLE_DECL(dac_companding,
+                           WM8903_AUDIO_INTERFACE_0, 0, companding_text);
 
-static const struct soc_enum adc_companding =
-       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text);
+static SOC_ENUM_SINGLE_DECL(adc_companding,
+                           WM8903_AUDIO_INTERFACE_0, 2, companding_text);
 
 static const char *input_mode_text[] = {
        "Single-Ended", "Differential Line", "Differential Mic"
 };
 
-static const struct soc_enum linput_mode_enum =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(linput_mode_enum,
+                           WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text);
 
-static const struct soc_enum rinput_mode_enum =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(rinput_mode_enum,
+                           WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text);
 
 static const char *linput_mux_text[] = {
        "IN1L", "IN2L", "IN3L"
 };
 
-static const struct soc_enum linput_enum =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text);
+static SOC_ENUM_SINGLE_DECL(linput_enum,
+                           WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text);
 
-static const struct soc_enum linput_inv_enum =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text);
+static SOC_ENUM_SINGLE_DECL(linput_inv_enum,
+                           WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text);
 
 static const char *rinput_mux_text[] = {
        "IN1R", "IN2R", "IN3R"
 };
 
-static const struct soc_enum rinput_enum =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text);
+static SOC_ENUM_SINGLE_DECL(rinput_enum,
+                           WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text);
 
-static const struct soc_enum rinput_inv_enum =
-       SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
+static SOC_ENUM_SINGLE_DECL(rinput_inv_enum,
+                           WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text);
 
 
 static const char *sidetone_text[] = {
        "None", "Left", "Right"
 };
 
-static const struct soc_enum lsidetone_enum =
-       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(lsidetone_enum,
+                           WM8903_DAC_DIGITAL_0, 2, sidetone_text);
 
-static const struct soc_enum rsidetone_enum =
-       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(rsidetone_enum,
+                           WM8903_DAC_DIGITAL_0, 0, sidetone_text);
 
 static const char *adcinput_text[] = {
        "ADC", "DMIC"
 };
 
-static const struct soc_enum adcinput_enum =
-       SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text);
+static SOC_ENUM_SINGLE_DECL(adcinput_enum,
+                           WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text);
 
 static const char *aif_text[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum lcapture_enum =
-       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(lcapture_enum,
+                           WM8903_AUDIO_INTERFACE_0, 7, aif_text);
 
-static const struct soc_enum rcapture_enum =
-       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(rcapture_enum,
+                           WM8903_AUDIO_INTERFACE_0, 6, aif_text);
 
-static const struct soc_enum lplay_enum =
-       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(lplay_enum,
+                           WM8903_AUDIO_INTERFACE_0, 5, aif_text);
 
-static const struct soc_enum rplay_enum =
-       SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(rplay_enum,
+                           WM8903_AUDIO_INTERFACE_0, 4, aif_text);
 
 static const struct snd_kcontrol_new wm8903_snd_controls[] = {
 
@@ -1897,21 +1897,13 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 static int wm8903_probe(struct snd_soc_codec *codec)
 {
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int ret;
 
        wm8903->codec = codec;
-       codec->control_data = wm8903->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;
-       }
 
        /* power on device */
        wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       return ret;
+       return 0;
 }
 
 /* power down chip */
index 53bbfac6a83ad14ed43d2aafca2514ea3a319468..49c35c36935e45ed478191ac063c8816fd618a27 100644 (file)
@@ -552,18 +552,20 @@ static const char *input_mode_text[] = {
        "Single-Ended", "Differential Line", "Differential Mic"
 };
 
-static const struct soc_enum lin_mode =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(lin_mode,
+                           WM8904_ANALOGUE_LEFT_INPUT_1, 0,
+                           input_mode_text);
 
-static const struct soc_enum rin_mode =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(rin_mode,
+                           WM8904_ANALOGUE_RIGHT_INPUT_1, 0,
+                           input_mode_text);
 
 static const char *hpf_mode_text[] = {
        "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
 };
 
-static const struct soc_enum hpf_mode =
-       SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
+                           hpf_mode_text);
 
 static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
@@ -611,8 +613,7 @@ static const char *drc_path_text[] = {
        "ADC", "DAC"
 };
 
-static const struct soc_enum drc_path =
-       SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text);
+static SOC_ENUM_SINGLE_DECL(drc_path, WM8904_DRC_0, 14, drc_path_text);
 
 static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {
 SOC_SINGLE_TLV("Digital Playback Boost Volume", 
@@ -858,14 +859,14 @@ static const char *lin_text[] = {
        "IN1L", "IN2L", "IN3L"
 };
 
-static const struct soc_enum lin_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text);
+static SOC_ENUM_SINGLE_DECL(lin_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 2,
+                           lin_text);
 
 static const struct snd_kcontrol_new lin_mux =
        SOC_DAPM_ENUM("Left Capture Mux", lin_enum);
 
-static const struct soc_enum lin_inv_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text);
+static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4,
+                           lin_text);
 
 static const struct snd_kcontrol_new lin_inv_mux =
        SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum);
@@ -874,14 +875,14 @@ static const char *rin_text[] = {
        "IN1R", "IN2R", "IN3R"
 };
 
-static const struct soc_enum rin_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text);
+static SOC_ENUM_SINGLE_DECL(rin_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 2,
+                           rin_text);
 
 static const struct snd_kcontrol_new rin_mux =
        SOC_DAPM_ENUM("Right Capture Mux", rin_enum);
 
-static const struct soc_enum rin_inv_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text);
+static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4,
+                           rin_text);
 
 static const struct snd_kcontrol_new rin_inv_mux =
        SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum);
@@ -890,26 +891,26 @@ static const char *aif_text[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum aifoutl_enum =
-       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutl_enum, WM8904_AUDIO_INTERFACE_0, 7,
+                           aif_text);
 
 static const struct snd_kcontrol_new aifoutl_mux =
        SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
 
-static const struct soc_enum aifoutr_enum =
-       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutr_enum, WM8904_AUDIO_INTERFACE_0, 6,
+                           aif_text);
 
 static const struct snd_kcontrol_new aifoutr_mux =
        SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
 
-static const struct soc_enum aifinl_enum =
-       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinl_enum, WM8904_AUDIO_INTERFACE_0, 5,
+                           aif_text);
 
 static const struct snd_kcontrol_new aifinl_mux =
        SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
 
-static const struct soc_enum aifinr_enum =
-       SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinr_enum, WM8904_AUDIO_INTERFACE_0, 4,
+                           aif_text);
 
 static const struct snd_kcontrol_new aifinr_mux =
        SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
@@ -991,26 +992,26 @@ static const char *out_mux_text[] = {
        "DAC", "Bypass"
 };
 
-static const struct soc_enum hpl_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpl_enum, WM8904_ANALOGUE_OUT12_ZC, 3,
+                           out_mux_text);
 
 static const struct snd_kcontrol_new hpl_mux =
        SOC_DAPM_ENUM("HPL Mux", hpl_enum);
 
-static const struct soc_enum hpr_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpr_enum, WM8904_ANALOGUE_OUT12_ZC, 2,
+                           out_mux_text);
 
 static const struct snd_kcontrol_new hpr_mux =
        SOC_DAPM_ENUM("HPR Mux", hpr_enum);
 
-static const struct soc_enum linel_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(linel_enum, WM8904_ANALOGUE_OUT12_ZC, 1,
+                           out_mux_text);
 
 static const struct snd_kcontrol_new linel_mux =
        SOC_DAPM_ENUM("LINEL Mux", linel_enum);
 
-static const struct soc_enum liner_enum =
-       SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(liner_enum, WM8904_ANALOGUE_OUT12_ZC, 0,
+                           out_mux_text);
 
 static const struct snd_kcontrol_new liner_mux =
        SOC_DAPM_ENUM("LINER Mux", liner_enum);
@@ -1019,14 +1020,14 @@ static const char *sidetone_text[] = {
        "None", "Left", "Right"
 };
 
-static const struct soc_enum dacl_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone_enum, WM8904_DAC_DIGITAL_0, 2,
+                           sidetone_text);
 
 static const struct snd_kcontrol_new dacl_sidetone_mux =
        SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum);
 
-static const struct soc_enum dacr_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone_enum, WM8904_DAC_DIGITAL_0, 0,
+                           sidetone_text);
 
 static const struct snd_kcontrol_new dacr_sidetone_mux =
        SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum);
@@ -1981,7 +1982,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
        dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
                wm8904->num_retune_mobile_texts);
 
-       wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
+       wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts;
        wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
 
        ret = snd_soc_add_codec_controls(codec, &control, 1);
@@ -2022,7 +2023,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
                for (i = 0; i < pdata->num_drc_cfgs; i++)
                        wm8904->drc_texts[i] = pdata->drc_cfgs[i].name;
 
-               wm8904->drc_enum.max = pdata->num_drc_cfgs;
+               wm8904->drc_enum.items = pdata->num_drc_cfgs;
                wm8904->drc_enum.texts = wm8904->drc_texts;
 
                ret = snd_soc_add_codec_controls(codec, &control, 1);
@@ -2047,9 +2048,6 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
 static int wm8904_probe(struct snd_soc_codec *codec)
 {
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       codec->control_data = wm8904->regmap;
 
        switch (wm8904->devtype) {
        case WM8904:
@@ -2063,12 +2061,6 @@ static int wm8904_probe(struct snd_soc_codec *codec)
                return -EINVAL;
        }
 
-       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;
-       }
-
        wm8904_handle_pdata(codec);
 
        wm8904_add_widgets(codec);
index b404c26c1753407c849c61fdc5ac2db5254deaf0..fc6eec9ad66b16f01c20fb486e5efd8ee9ce16ae 100644 (file)
@@ -154,22 +154,22 @@ static const struct reg_default wm8940_reg_defaults[] = {
 };
 
 static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
-static const struct soc_enum wm8940_adc_companding_enum
-= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
-static const struct soc_enum wm8940_dac_companding_enum
-= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding);
+static SOC_ENUM_SINGLE_DECL(wm8940_adc_companding_enum,
+                           WM8940_COMPANDINGCTL, 1, wm8940_companding);
+static SOC_ENUM_SINGLE_DECL(wm8940_dac_companding_enum,
+                           WM8940_COMPANDINGCTL, 3, wm8940_companding);
 
 static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
-static const struct soc_enum wm8940_alc_mode_enum
-= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm8940_alc_mode_enum,
+                           WM8940_ALC3, 8, wm8940_alc_mode_text);
 
 static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
-static const struct soc_enum wm8940_mic_bias_level_enum
-= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text);
+static SOC_ENUM_SINGLE_DECL(wm8940_mic_bias_level_enum,
+                           WM8940_INPUTCTL, 8, wm8940_mic_bias_level_text);
 
 static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
-static const struct soc_enum wm8940_filter_mode_enum
-= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm8940_filter_mode_enum,
+                           WM8940_ADC, 7, wm8940_filter_mode_text);
 
 static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
 static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0);
@@ -712,12 +712,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
        int ret;
        u16 reg;
 
-       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;
-       }
-
        ret = wm8940_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
index 82c8ba9757202402cfe53e44b0a7dd587df502b5..fecd4e4f4c5731c6d9cbeefaa782bbef632e1daa 100644 (file)
@@ -416,22 +416,21 @@ static const char *bass_mode_text[] = {
        "Linear", "Adaptive",
 };
 
-static const struct soc_enum bass_mode =
-       SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text);
+static SOC_ENUM_SINGLE_DECL(bass_mode, WM8955_BASS_CONTROL, 7, bass_mode_text);
 
 static const char *bass_cutoff_text[] = {
        "Low", "High"
 };
 
-static const struct soc_enum bass_cutoff =
-       SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(bass_cutoff, WM8955_BASS_CONTROL, 6,
+                           bass_cutoff_text);
 
 static const char *treble_cutoff_text[] = {
        "High", "Low"
 };
 
-static const struct soc_enum treble_cutoff =
-       SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8955_TREBLE_CONTROL, 2,
+                           treble_cutoff_text);
 
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
 static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0);
@@ -896,14 +895,6 @@ static int wm8955_probe(struct snd_soc_codec *codec)
        struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
        int ret, i;
 
-       codec->control_data = wm8955->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
                wm8955->supplies[i].supply = wm8955_supply_names[i];
 
index d4248e00160e35a0bede71fcfbd7db785d49de89..7ac2e511403ce595963bd38cd9ce48401555f88d 100644 (file)
@@ -944,7 +944,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                for (i = 0; i < pdata->num_mbc_cfgs; i++)
                        wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
 
-               wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+               wm8994->mbc_enum.items = pdata->num_mbc_cfgs;
                wm8994->mbc_enum.texts = wm8994->mbc_texts;
 
                ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
@@ -973,7 +973,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                for (i = 0; i < pdata->num_vss_cfgs; i++)
                        wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
 
-               wm8994->vss_enum.max = pdata->num_vss_cfgs;
+               wm8994->vss_enum.items = pdata->num_vss_cfgs;
                wm8994->vss_enum.texts = wm8994->vss_texts;
 
                ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
@@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
                        wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
 
-               wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
+               wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs;
                wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 
                ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
@@ -1034,7 +1034,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
                        wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
 
-               wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
+               wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs;
                wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
 
                ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
index f156010e52bc1ae5f206e1ddcf1b3a62aa1c1f2d..d04e9cad445c391046f0d586005668e62d1e997b 100644 (file)
@@ -976,12 +976,6 @@ static int wm8960_probe(struct snd_soc_codec *codec)
                        wm8960->set_bias_level = wm8960_set_bias_level_capless;
        }
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8960_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
index 900328e28a1596cc1cd189185f18460113de440c..9c88f04442b3777c0e5a8dad0dda0f4e301ef4b8 100644 (file)
@@ -317,15 +317,15 @@ static const char *adc_hpf_text[] = {
        "Hi-fi", "Voice 1", "Voice 2", "Voice 3",
 };
 
-static const struct soc_enum adc_hpf =
-       SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(adc_hpf,
+                           WM8961_ADC_DAC_CONTROL_2, 7, adc_hpf_text);
 
 static const char *dac_deemph_text[] = {
        "None", "32kHz", "44.1kHz", "48kHz",
 };
 
-static const struct soc_enum dac_deemph =
-       SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text);
+static SOC_ENUM_SINGLE_DECL(dac_deemph,
+                           WM8961_ADC_DAC_CONTROL_1, 1, dac_deemph_text);
 
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
 static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0);
@@ -385,11 +385,11 @@ static const char *sidetone_text[] = {
        "None", "Left", "Right"
 };
 
-static const struct soc_enum dacl_sidetone =
-       SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+                           WM8961_DSP_SIDETONE_0, 2, sidetone_text);
 
-static const struct soc_enum dacr_sidetone =
-       SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+                           WM8961_DSP_SIDETONE_1, 2, sidetone_text);
 
 static const struct snd_kcontrol_new dacl_mux =
        SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone);
@@ -836,15 +836,8 @@ static struct snd_soc_dai_driver wm8961_dai = {
 static int wm8961_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret = 0;
        u16 reg;
 
-       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;
-       }
-
        /* Enable class W */
        reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);
        reg |= WM8961_CP_DYN_PWR_MASK;
index 97db3b45b4113ad5fe7f7d42dd0e4e018b8c8c51..5522d2566c6742d5ee19f91b4358b30f51276b62 100644 (file)
@@ -1479,7 +1479,9 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 
 static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
 {
-       return regcache_sync_region(codec->control_data,
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+       return regcache_sync_region(wm8962->regmap,
                                    WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
 }
 
@@ -1658,16 +1660,16 @@ static const char *cap_hpf_mode_text[] = {
        "Hi-fi", "Application"
 };
 
-static const struct soc_enum cap_hpf_mode =
-       SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(cap_hpf_mode,
+                           WM8962_ADC_DAC_CONTROL_2, 10, cap_hpf_mode_text);
 
 
 static const char *cap_lhpf_mode_text[] = {
        "LPF", "HPF"
 };
 
-static const struct soc_enum cap_lhpf_mode =
-       SOC_ENUM_SINGLE(WM8962_LHPF1, 1, 2, cap_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(cap_lhpf_mode,
+                           WM8962_LHPF1, 1, cap_lhpf_mode_text);
 
 static const struct snd_kcontrol_new wm8962_snd_controls[] = {
 SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
@@ -2014,40 +2016,40 @@ static int dsp2_event(struct snd_soc_dapm_widget *w,
 
 static const char *st_text[] = { "None", "Left", "Right" };
 
-static const struct soc_enum str_enum =
-       SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text);
+static SOC_ENUM_SINGLE_DECL(str_enum,
+                           WM8962_DAC_DSP_MIXING_1, 2, st_text);
 
 static const struct snd_kcontrol_new str_mux =
        SOC_DAPM_ENUM("Right Sidetone", str_enum);
 
-static const struct soc_enum stl_enum =
-       SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text);
+static SOC_ENUM_SINGLE_DECL(stl_enum,
+                           WM8962_DAC_DSP_MIXING_2, 2, st_text);
 
 static const struct snd_kcontrol_new stl_mux =
        SOC_DAPM_ENUM("Left Sidetone", stl_enum);
 
 static const char *outmux_text[] = { "DAC", "Mixer" };
 
-static const struct soc_enum spkoutr_enum =
-       SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(spkoutr_enum,
+                           WM8962_SPEAKER_MIXER_2, 7, outmux_text);
 
 static const struct snd_kcontrol_new spkoutr_mux =
        SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
 
-static const struct soc_enum spkoutl_enum =
-       SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(spkoutl_enum,
+                           WM8962_SPEAKER_MIXER_1, 7, outmux_text);
 
 static const struct snd_kcontrol_new spkoutl_mux =
        SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
 
-static const struct soc_enum hpoutr_enum =
-       SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(hpoutr_enum,
+                           WM8962_HEADPHONE_MIXER_2, 7, outmux_text);
 
 static const struct snd_kcontrol_new hpoutr_mux =
        SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
 
-static const struct soc_enum hpoutl_enum =
-       SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(hpoutl_enum,
+                           WM8962_HEADPHONE_MIXER_1, 7, outmux_text);
 
 static const struct snd_kcontrol_new hpoutl_mux =
        SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
@@ -2884,9 +2886,13 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
        snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
 
-       try_wait_for_completion(&wm8962->fll_lock);
+       reinit_completion(&wm8962->fll_lock);
 
-       pm_runtime_get_sync(codec->dev);
+       ret = pm_runtime_get_sync(codec->dev);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to resume device: %d\n", ret);
+               return ret;
+       }
 
        snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
                            WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
@@ -2894,8 +2900,6 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
        dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
-       ret = 0;
-
        /* This should be a massive overestimate but go even
         * higher if we'll error out
         */
@@ -2909,14 +2913,17 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
        if (timeout == 0 && wm8962->irq) {
                dev_err(codec->dev, "FLL lock timed out");
-               ret = -ETIMEDOUT;
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                   WM8962_FLL_ENA, 0);
+               pm_runtime_put(codec->dev);
+               return -ETIMEDOUT;
        }
 
        wm8962->fll_fref = Fref;
        wm8962->fll_fout = Fout;
        wm8962->fll_src = source;
 
-       return ret;
+       return 0;
 }
 
 static int wm8962_mute(struct snd_soc_dai *dai, int mute)
@@ -3003,9 +3010,16 @@ static irqreturn_t wm8962_irq(int irq, void *data)
        unsigned int active;
        int reg, ret;
 
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               dev_err(dev, "Failed to resume: %d\n", ret);
+               return IRQ_NONE;
+       }
+
        ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK,
                          &mask);
        if (ret != 0) {
+               pm_runtime_put(dev);
                dev_err(dev, "Failed to read interrupt mask: %d\n",
                        ret);
                return IRQ_NONE;
@@ -3013,14 +3027,17 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 
        ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active);
        if (ret != 0) {
+               pm_runtime_put(dev);
                dev_err(dev, "Failed to read interrupt: %d\n", ret);
                return IRQ_NONE;
        }
 
        active &= ~mask;
 
-       if (!active)
+       if (!active) {
+               pm_runtime_put(dev);
                return IRQ_NONE;
+       }
 
        /* Acknowledge the interrupts */
        ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active);
@@ -3070,6 +3087,8 @@ static irqreturn_t wm8962_irq(int irq, void *data)
                                   msecs_to_jiffies(250));
        }
 
+       pm_runtime_put(dev);
+
        return IRQ_HANDLED;
 }
 
@@ -3089,6 +3108,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int irq_mask, enable;
 
        wm8962->jack = jack;
@@ -3109,14 +3129,18 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
        snd_soc_jack_report(wm8962->jack, 0,
                            SND_JACK_MICROPHONE | SND_JACK_BTN_0);
 
+       snd_soc_dapm_mutex_lock(dapm);
+
        if (jack) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS");
+               snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+               snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
        } else {
-               snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK");
-               snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
        }
 
+       snd_soc_dapm_mutex_unlock(dapm);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm8962_mic_detect);
@@ -3400,13 +3424,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        bool dmicclk, dmicdat;
 
        wm8962->codec = codec;
-       codec->control_data = wm8962->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;
-       }
 
        wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
        wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
index 67aba78a7ca5d8de561d2a3c70a0f5a6e4307f7d..09b7b42002210b717e9ded871d4932fc1003a744 100644 (file)
@@ -648,12 +648,6 @@ static int wm8971_probe(struct snd_soc_codec *codec)
        int ret = 0;
        u16 reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work);
        wm8971_workq = create_workqueue("wm8971");
        if (wm8971_workq == NULL)
index 15f45c7bd8334971bb63235ade92a26cb82c2f57..0627c56fa44e5441050984797d7117c85a9d75df 100644 (file)
@@ -84,8 +84,8 @@ static const struct soc_enum wm8974_enum[] = {
 
 static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" };
 
-static const struct soc_enum wm8974_auxmode =
-       SOC_ENUM_SINGLE(WM8974_INPUT,  3, 2, wm8974_auxmode_text);
+static SOC_ENUM_SINGLE_DECL(wm8974_auxmode,
+                           WM8974_INPUT,  3, wm8974_auxmode_text);
 
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
 static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
@@ -593,12 +593,6 @@ static int wm8974_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8974_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
index d8fc531c0e59f0604ae72a4a0a1af68d010317c3..28ef46c91f62fa6883bd567f7f18a27dec40883e 100644 (file)
@@ -117,21 +117,21 @@ static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"};
 static const char *wm8978_alc3[] = {"ALC", "Limiter"};
 static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"};
 
-static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
-                                 wm8978_companding);
-static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
-                                 wm8978_companding);
-static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
-static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
-static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
-static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
-static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
-static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
-static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
-static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
-static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
-static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
-static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
+static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
+                           wm8978_companding);
+static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
+                           wm8978_companding);
+static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
+static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
+static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
+static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
+static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
+static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
+static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
+static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
 
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
 static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
@@ -975,19 +975,13 @@ static const int update_reg[] = {
 static int wm8978_probe(struct snd_soc_codec *codec)
 {
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
-       int ret = 0, i;
+       int i;
 
        /*
         * Set default system clock to PLL, it is more precise, this is also the
         * default hardware setting
         */
        wm8978->sysclk = WM8978_PLL;
-       codec->control_data = wm8978->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
 
        /*
         * Set the update bit in all registers, that have one. This way all
index aa41ba0dfff4d288c5078da552acb4484df1f32e..2b9bfa53efbfeea53d4d8033f10b0d50e4074f38 100644 (file)
@@ -205,49 +205,44 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
 static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
 
 static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
-static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7,
-                                 alc_sel_text);
+static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text);
 
 static const char *alc_mode_text[] = { "ALC", "Limiter" };
-static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8,
-                                 alc_mode_text);
+static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text);
 
 static const char *filter_mode_text[] = { "Audio", "Application" };
-static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7,
-                                 filter_mode_text);
+static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7,
+                           filter_mode_text);
 
 static const char *eq_bw_text[] = { "Narrow", "Wide" };
 static const char *eqmode_text[] = { "Capture", "Playback" };
-static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
 
 static const char *eq1_cutoff_text[] = {
        "80Hz", "105Hz", "135Hz", "175Hz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5,
-                                 eq1_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5,
+                           eq1_cutoff_text);
 static const char *eq2_cutoff_text[] = {
        "230Hz", "300Hz", "385Hz", "500Hz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5,
-                                 eq2_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text);
 static const char *eq3_cutoff_text[] = {
        "650Hz", "850Hz", "1.1kHz", "1.4kHz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5,
-                                 eq3_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text);
 static const char *eq4_cutoff_text[] = {
        "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5,
-                                 eq4_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text);
 static const char *eq5_cutoff_text[] = {
        "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
-                                 eq5_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
+                           eq5_cutoff_text);
 
 static const char *depth_3d_text[] = {
        "Off",
@@ -267,8 +262,8 @@ static const char *depth_3d_text[] = {
        "93.3%",
        "100%"
 };
-static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0,
-                                 depth_3d_text);
+static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0,
+                           depth_3d_text);
 
 static const struct snd_kcontrol_new wm8983_snd_controls[] = {
        SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL,
@@ -1000,12 +995,6 @@ static int wm8983_probe(struct snd_soc_codec *codec)
        int ret;
        int i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
-               return ret;
-       }
-
        ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@@ -1129,7 +1118,7 @@ static struct spi_driver wm8983_spi_driver = {
 };
 #endif
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
 static int wm8983_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -1182,7 +1171,7 @@ static int __init wm8983_modinit(void)
 {
        int ret = 0;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
        ret = i2c_add_driver(&wm8983_i2c_driver);
        if (ret) {
                printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n",
@@ -1202,7 +1191,7 @@ module_init(wm8983_modinit);
 
 static void __exit wm8983_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
        i2c_del_driver(&wm8983_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)
index 271b517911a4bc0d4d6003356afcf7a1cc317bed..5473dc969585de3852feb6cbbdca7d09b4ace49f 100644 (file)
@@ -226,52 +226,48 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
 static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
 
 static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
-static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7,
-                                 alc_sel_text);
+static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text);
 
 static const char *alc_mode_text[] = { "ALC", "Limiter" };
-static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8,
-                                 alc_mode_text);
+static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text);
 
 static const char *filter_mode_text[] = { "Audio", "Application" };
-static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
-                                 filter_mode_text);
+static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+                           filter_mode_text);
 
 static const char *eq_bw_text[] = { "Narrow", "Wide" };
 static const char *eqmode_text[] = { "Capture", "Playback" };
-static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
 
 static const char *eq1_cutoff_text[] = {
        "80Hz", "105Hz", "135Hz", "175Hz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
-                                 eq1_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+                           eq1_cutoff_text);
 static const char *eq2_cutoff_text[] = {
        "230Hz", "300Hz", "385Hz", "500Hz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5,
-                                 eq2_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text);
 static const char *eq3_cutoff_text[] = {
        "650Hz", "850Hz", "1.1kHz", "1.4kHz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
-                                 eq3_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+                           eq3_cutoff_text);
 static const char *eq4_cutoff_text[] = {
        "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5,
-                                 eq4_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text);
 static const char *eq5_cutoff_text[] = {
        "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
 };
-static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
                                  eq5_cutoff_text);
 
 static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
-static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
 
 static const char *depth_3d_text[] = {
        "Off",
@@ -291,8 +287,7 @@ static const char *depth_3d_text[] = {
        "93.3%",
        "100%"
 };
-static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0,
-                                 depth_3d_text);
+static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text);
 
 static const struct snd_kcontrol_new wm8985_snd_controls[] = {
        SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
@@ -1000,13 +995,6 @@ static int wm8985_probe(struct snd_soc_codec *codec)
        int ret;
 
        wm8985 = snd_soc_codec_get_drvdata(codec);
-       codec->control_data = wm8985->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
-               return ret;
-       }
 
        for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
                wm8985->supplies[i].supply = wm8985_supply_names[i];
index a55e1c2c382edde43985e2213f0502564bf8e17b..3a1ae4f5164df1272a517906ed873fc7ff7b2cd0 100644 (file)
@@ -116,7 +116,7 @@ static bool wm8988_writeable(struct device *dev, unsigned int reg)
 struct wm8988_priv {
        struct regmap *regmap;
        unsigned int sysclk;
-       struct snd_pcm_hw_constraint_list *sysclk_constraints;
+       const struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
 #define wm8988_reset(c)        snd_soc_write(c, WM8988_RESET, 0)
@@ -126,46 +126,46 @@ struct wm8988_priv {
  */
 
 static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};
-static const struct soc_enum bass_boost =
-       SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt);
+static SOC_ENUM_SINGLE_DECL(bass_boost,
+                           WM8988_BASS, 7, bass_boost_txt);
 
 static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
-static const struct soc_enum bass_filter =
-       SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt);
+static SOC_ENUM_SINGLE_DECL(bass_filter,
+                           WM8988_BASS, 6, bass_filter_txt);
 
 static const char *treble_txt[] = {"8kHz", "4kHz"};
-static const struct soc_enum treble =
-       SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt);
+static SOC_ENUM_SINGLE_DECL(treble,
+                           WM8988_TREBLE, 6, treble_txt);
 
 static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};
-static const struct soc_enum stereo_3d_lc =
-       SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt);
+static SOC_ENUM_SINGLE_DECL(stereo_3d_lc,
+                           WM8988_3D, 5, stereo_3d_lc_txt);
 
 static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};
-static const struct soc_enum stereo_3d_uc =
-       SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt);
+static SOC_ENUM_SINGLE_DECL(stereo_3d_uc,
+                           WM8988_3D, 6, stereo_3d_uc_txt);
 
 static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};
-static const struct soc_enum stereo_3d_func =
-       SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt);
+static SOC_ENUM_SINGLE_DECL(stereo_3d_func,
+                           WM8988_3D, 7, stereo_3d_func_txt);
 
 static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};
-static const struct soc_enum alc_func =
-       SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt);
+static SOC_ENUM_SINGLE_DECL(alc_func,
+                           WM8988_ALC1, 7, alc_func_txt);
 
 static const char *ng_type_txt[] = {"Constant PGA Gain",
                                    "Mute ADC Output"};
-static const struct soc_enum ng_type =
-       SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt);
+static SOC_ENUM_SINGLE_DECL(ng_type,
+                           WM8988_NGATE, 1, ng_type_txt);
 
 static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};
-static const struct soc_enum deemph =
-       SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt);
+static SOC_ENUM_SINGLE_DECL(deemph,
+                           WM8988_ADCDAC, 1, deemph_txt);
 
 static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",
                                   "L + R Invert"};
-static const struct soc_enum adcpol =
-       SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt);
+static SOC_ENUM_SINGLE_DECL(adcpol,
+                           WM8988_ADCDAC, 5, adcpol_txt);
 
 static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
 static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
@@ -317,16 +317,16 @@ static const struct snd_kcontrol_new wm8988_right_pga_controls =
 
 /* Differential Mux */
 static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
-static const struct soc_enum diffmux =
-       SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel);
+static SOC_ENUM_SINGLE_DECL(diffmux,
+                           WM8988_ADCIN, 8, wm8988_diff_sel);
 static const struct snd_kcontrol_new wm8988_diffmux_controls =
        SOC_DAPM_ENUM("Route", diffmux);
 
 /* Mono ADC Mux */
 static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",
        "Mono (Right)", "Digital Mono"};
-static const struct soc_enum monomux =
-       SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux);
+static SOC_ENUM_SINGLE_DECL(monomux,
+                           WM8988_ADCIN, 6, wm8988_mono_mux);
 static const struct snd_kcontrol_new wm8988_monomux_controls =
        SOC_DAPM_ENUM("Route", monomux);
 
@@ -521,30 +521,30 @@ static inline int get_coeff(int mclk, int rate)
 
 /* The set of rates we can generate from the above for each SYSCLK */
 
-static unsigned int rates_12288[] = {
+static const unsigned int rates_12288[] = {
        8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_12288 = {
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
        .count  = ARRAY_SIZE(rates_12288),
        .list   = rates_12288,
 };
 
-static unsigned int rates_112896[] = {
+static const unsigned int rates_112896[] = {
        8000, 11025, 22050, 44100,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_112896 = {
+static const struct snd_pcm_hw_constraint_list constraints_112896 = {
        .count  = ARRAY_SIZE(rates_112896),
        .list   = rates_112896,
 };
 
-static unsigned int rates_12[] = {
+static const unsigned int rates_12[] = {
        8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
        48000, 88235, 96000,
 };
 
-static struct snd_pcm_hw_constraint_list constraints_12 = {
+static const struct snd_pcm_hw_constraint_list constraints_12 = {
        .count  = ARRAY_SIZE(rates_12),
        .list   = rates_12,
 };
@@ -810,16 +810,8 @@ static int wm8988_resume(struct snd_soc_codec *codec)
 
 static int wm8988_probe(struct snd_soc_codec *codec)
 {
-       struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       codec->control_data = wm8988->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        ret = wm8988_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
index 0ccd4d8d043bbcf0d0f689bc947c93545d88b16b..c413c19914534c4fe34e55778a474691743e156f 100644 (file)
@@ -157,26 +157,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 static const char *wm8990_digital_sidetone[] =
        {"None", "Left ADC", "Right ADC", "Reserved"};
 
-static const struct soc_enum wm8990_left_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE,
-       WM8990_ADC_TO_DACL_SHIFT,
-       WM8990_ADC_TO_DACL_MASK,
-       wm8990_digital_sidetone);
-
-static const struct soc_enum wm8990_right_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE,
-       WM8990_ADC_TO_DACR_SHIFT,
-       WM8990_ADC_TO_DACR_MASK,
-       wm8990_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8990_left_digital_sidetone_enum,
+                           WM8990_DIGITAL_SIDE_TONE,
+                           WM8990_ADC_TO_DACL_SHIFT,
+                           wm8990_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8990_right_digital_sidetone_enum,
+                           WM8990_DIGITAL_SIDE_TONE,
+                           WM8990_ADC_TO_DACR_SHIFT,
+                           wm8990_digital_sidetone);
 
 static const char *wm8990_adcmode[] =
        {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
 
-static const struct soc_enum wm8990_right_adcmode_enum =
-SOC_ENUM_SINGLE(WM8990_ADC_CTRL,
-       WM8990_ADC_HPF_CUT_SHIFT,
-       WM8990_ADC_HPF_CUT_MASK,
-       wm8990_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8990_right_adcmode_enum,
+                           WM8990_ADC_CTRL,
+                           WM8990_ADC_HPF_CUT_SHIFT,
+                           wm8990_adcmode);
 
 static const struct snd_kcontrol_new wm8990_snd_controls[] = {
 /* INMIXL */
@@ -475,9 +472,9 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,
 static const char *wm8990_ainlmux[] =
        {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
 
-static const struct soc_enum wm8990_ainlmux_enum =
-SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT,
-       ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8990_ainlmux_enum,
+                           WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT,
+                           wm8990_ainlmux);
 
 static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls =
 SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);
@@ -488,9 +485,9 @@ SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);
 static const char *wm8990_ainrmux[] =
        {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
 
-static const struct soc_enum wm8990_ainrmux_enum =
-SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT,
-       ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum,
+                           WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT,
+                           wm8990_ainrmux);
 
 static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls =
 SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum);
@@ -1292,14 +1289,6 @@ static int wm8990_resume(struct snd_soc_codec *codec)
  */
 static int wm8990_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
        wm8990_reset(codec);
 
        /* charge output caps */
index dba0306c42a5c54aa459cc4fe1593b08c92a5abf..844cc4a60d667ef8f67dd7b35f29b3834c07b938 100644 (file)
@@ -171,26 +171,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 static const char *wm8991_digital_sidetone[] =
 {"None", "Left ADC", "Right ADC", "Reserved"};
 
-static const struct soc_enum wm8991_left_digital_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
-                       WM8991_ADC_TO_DACL_SHIFT,
-                       WM8991_ADC_TO_DACL_MASK,
-                       wm8991_digital_sidetone);
-
-static const struct soc_enum wm8991_right_digital_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
-                       WM8991_ADC_TO_DACR_SHIFT,
-                       WM8991_ADC_TO_DACR_MASK,
-                       wm8991_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8991_left_digital_sidetone_enum,
+                           WM8991_DIGITAL_SIDE_TONE,
+                           WM8991_ADC_TO_DACL_SHIFT,
+                           wm8991_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8991_right_digital_sidetone_enum,
+                           WM8991_DIGITAL_SIDE_TONE,
+                           WM8991_ADC_TO_DACR_SHIFT,
+                           wm8991_digital_sidetone);
 
 static const char *wm8991_adcmode[] =
 {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
 
-static const struct soc_enum wm8991_right_adcmode_enum =
-       SOC_ENUM_SINGLE(WM8991_ADC_CTRL,
-                       WM8991_ADC_HPF_CUT_SHIFT,
-                       WM8991_ADC_HPF_CUT_MASK,
-                       wm8991_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8991_right_adcmode_enum,
+                           WM8991_ADC_CTRL,
+                           WM8991_ADC_HPF_CUT_SHIFT,
+                           wm8991_adcmode);
 
 static const struct snd_kcontrol_new wm8991_snd_controls[] = {
        /* INMIXL */
@@ -486,9 +483,9 @@ static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {
 static const char *wm8991_ainlmux[] =
 {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
 
-static const struct soc_enum wm8991_ainlmux_enum =
-       SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
-                       ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8991_ainlmux_enum,
+                           WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
+                           wm8991_ainlmux);
 
 static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
        SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum);
@@ -499,9 +496,9 @@ static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
 static const char *wm8991_ainrmux[] =
 {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
 
-static const struct soc_enum wm8991_ainrmux_enum =
-       SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
-                       ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum,
+                           WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
+                           wm8991_ainrmux);
 
 static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
        SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);
@@ -1251,17 +1248,6 @@ static int wm8991_remove(struct snd_soc_codec *codec)
 
 static int wm8991_probe(struct snd_soc_codec *codec)
 {
-       struct wm8991_priv *wm8991;
-       int ret;
-
-       wm8991 = snd_soc_codec_get_drvdata(codec);
-
-       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;
-       }
-
        wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
index 2ee23a39622c14f2cdbc072cdcdb496e8291e9c0..f825dc04ebe12cd4e41c19369fa254048189327f 100644 (file)
@@ -646,8 +646,8 @@ static const char *dac_deemph_text[] = {
        "48kHz",
 };
 
-static const struct soc_enum dac_deemph =
-       SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text);
+static SOC_ENUM_SINGLE_DECL(dac_deemph,
+                           WM8993_DAC_CTRL, 4, dac_deemph_text);
 
 static const char *adc_hpf_text[] = {
        "Hi-Fi",
@@ -656,16 +656,16 @@ static const char *adc_hpf_text[] = {
        "Voice 3",
 };
 
-static const struct soc_enum adc_hpf =
-       SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(adc_hpf,
+                           WM8993_ADC_CTRL, 5, adc_hpf_text);
 
 static const char *drc_path_text[] = {
        "ADC",
        "DAC"
 };
 
-static const struct soc_enum drc_path =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text);
+static SOC_ENUM_SINGLE_DECL(drc_path,
+                           WM8993_DRC_CONTROL_1, 14, drc_path_text);
 
 static const char *drc_r0_text[] = {
        "1",
@@ -676,8 +676,8 @@ static const char *drc_r0_text[] = {
        "0",
 };
 
-static const struct soc_enum drc_r0 =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text);
+static SOC_ENUM_SINGLE_DECL(drc_r0,
+                           WM8993_DRC_CONTROL_3, 8, drc_r0_text);
 
 static const char *drc_r1_text[] = {
        "1",
@@ -687,8 +687,8 @@ static const char *drc_r1_text[] = {
        "0",
 };
 
-static const struct soc_enum drc_r1 =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text);
+static SOC_ENUM_SINGLE_DECL(drc_r1,
+                           WM8993_DRC_CONTROL_4, 13, drc_r1_text);
 
 static const char *drc_attack_text[] = {
        "Reserved",
@@ -705,8 +705,8 @@ static const char *drc_attack_text[] = {
        "185.6ms",
 };
 
-static const struct soc_enum drc_attack =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text);
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+                           WM8993_DRC_CONTROL_2, 12, drc_attack_text);
 
 static const char *drc_decay_text[] = {
        "186ms",
@@ -720,16 +720,16 @@ static const char *drc_decay_text[] = {
        "47.56ms",
 };
 
-static const struct soc_enum drc_decay =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+                           WM8993_DRC_CONTROL_2, 8, drc_decay_text);
 
 static const char *drc_ff_text[] = {
        "5 samples",
        "9 samples",
 };
 
-static const struct soc_enum drc_ff =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text);
+static SOC_ENUM_SINGLE_DECL(drc_ff,
+                           WM8993_DRC_CONTROL_3, 7, drc_ff_text);
 
 static const char *drc_qr_rate_text[] = {
        "0.725ms",
@@ -737,8 +737,8 @@ static const char *drc_qr_rate_text[] = {
        "5.8ms",
 };
 
-static const struct soc_enum drc_qr_rate =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_rate,
+                           WM8993_DRC_CONTROL_3, 0, drc_qr_rate_text);
 
 static const char *drc_smooth_text[] = {
        "Low",
@@ -746,8 +746,8 @@ static const char *drc_smooth_text[] = {
        "High",
 };
 
-static const struct soc_enum drc_smooth =
-       SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text);
+static SOC_ENUM_SINGLE_DECL(drc_smooth,
+                           WM8993_DRC_CONTROL_1, 4, drc_smooth_text);
 
 static const struct snd_kcontrol_new wm8993_snd_controls[] = {
 SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
@@ -841,26 +841,26 @@ static const char *aif_text[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum aifoutl_enum =
-       SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutl_enum,
+                           WM8993_AUDIO_INTERFACE_1, 15, aif_text);
 
 static const struct snd_kcontrol_new aifoutl_mux =
        SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
 
-static const struct soc_enum aifoutr_enum =
-       SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutr_enum,
+                           WM8993_AUDIO_INTERFACE_1, 14, aif_text);
 
 static const struct snd_kcontrol_new aifoutr_mux =
        SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
 
-static const struct soc_enum aifinl_enum =
-       SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinl_enum,
+                           WM8993_AUDIO_INTERFACE_2, 15, aif_text);
 
 static const struct snd_kcontrol_new aifinl_mux =
        SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
 
-static const struct soc_enum aifinr_enum =
-       SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinr_enum,
+                           WM8993_AUDIO_INTERFACE_2, 14, aif_text);
 
 static const struct snd_kcontrol_new aifinr_mux =
        SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
@@ -869,14 +869,14 @@ static const char *sidetone_text[] = {
        "None", "Left", "Right"
 };
 
-static const struct soc_enum sidetonel_enum =
-       SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetonel_enum,
+                           WM8993_DIGITAL_SIDE_TONE, 2, sidetone_text);
 
 static const struct snd_kcontrol_new sidetonel_mux =
        SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum);
 
-static const struct soc_enum sidetoner_enum =
-       SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetoner_enum,
+                           WM8993_DIGITAL_SIDE_TONE, 0, sidetone_text);
 
 static const struct snd_kcontrol_new sidetoner_mux =
        SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum);
@@ -1493,13 +1493,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
        wm8993->hubs_data.dcs_codes_r = -2;
        wm8993->hubs_data.series_startup = 1;
 
-       codec->control_data = wm8993->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;
-       }
-
        /* Latch volume update bits and default ZC on */
        snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
                            WM8993_DAC_VU, WM8993_DAC_VU);
@@ -1559,8 +1552,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
 
 static int wm8993_remove(struct snd_soc_codec *codec)
 {
-       struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-
        wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
index adb72063d44ef6a0a5c9da1e2a53bd0d16a67825..6303537f54c6d0dde224f7f1c2ee028a7c5c930b 100644 (file)
@@ -1344,8 +1344,7 @@ static const char *adc_mux_text[] = {
        "DMIC",
 };
 
-static SOC_ENUM_SINGLE_DECL(adc_enum,
-                           0, 0, adc_mux_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
 
 static const struct snd_kcontrol_new adcl_mux =
        SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
@@ -2554,43 +2553,52 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        switch (mode) {
        case WM8994_VMID_NORMAL:
+               snd_soc_dapm_mutex_lock(dapm);
+
                if (wm8994->hubs.lineout1_se) {
-                       snd_soc_dapm_disable_pin(&codec->dapm,
-                                                "LINEOUT1N Driver");
-                       snd_soc_dapm_disable_pin(&codec->dapm,
-                                                "LINEOUT1P Driver");
+                       snd_soc_dapm_disable_pin_unlocked(dapm,
+                                                         "LINEOUT1N Driver");
+                       snd_soc_dapm_disable_pin_unlocked(dapm,
+                                                         "LINEOUT1P Driver");
                }
                if (wm8994->hubs.lineout2_se) {
-                       snd_soc_dapm_disable_pin(&codec->dapm,
-                                                "LINEOUT2N Driver");
-                       snd_soc_dapm_disable_pin(&codec->dapm,
-                                                "LINEOUT2P Driver");
+                       snd_soc_dapm_disable_pin_unlocked(dapm,
+                                                         "LINEOUT2N Driver");
+                       snd_soc_dapm_disable_pin_unlocked(dapm,
+                                                         "LINEOUT2P Driver");
                }
 
                /* Do the sync with the old mode to allow it to clean up */
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_sync_unlocked(dapm);
                wm8994->vmid_mode = mode;
+
+               snd_soc_dapm_mutex_unlock(dapm);
                break;
 
        case WM8994_VMID_FORCE:
+               snd_soc_dapm_mutex_lock(dapm);
+
                if (wm8994->hubs.lineout1_se) {
-                       snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                     "LINEOUT1N Driver");
-                       snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                     "LINEOUT1P Driver");
+                       snd_soc_dapm_force_enable_pin_unlocked(dapm,
+                                                              "LINEOUT1N Driver");
+                       snd_soc_dapm_force_enable_pin_unlocked(dapm,
+                                                              "LINEOUT1P Driver");
                }
                if (wm8994->hubs.lineout2_se) {
-                       snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                     "LINEOUT2N Driver");
-                       snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                     "LINEOUT2P Driver");
+                       snd_soc_dapm_force_enable_pin_unlocked(dapm,
+                                                              "LINEOUT2N Driver");
+                       snd_soc_dapm_force_enable_pin_unlocked(dapm,
+                                                              "LINEOUT2P Driver");
                }
 
                wm8994->vmid_mode = mode;
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_sync_unlocked(dapm);
+
+               snd_soc_dapm_mutex_unlock(dapm);
                break;
 
        default:
@@ -3242,7 +3250,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
        dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
                wm8994->num_retune_mobile_texts);
 
-       wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
+       wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts;
        wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
        ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
@@ -3298,7 +3306,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                for (i = 0; i < pdata->num_drc_cfgs; i++)
                        wm8994->drc_texts[i] = pdata->drc_cfgs[i].name;
 
-               wm8994->drc_enum.max = pdata->num_drc_cfgs;
+               wm8994->drc_enum.items = pdata->num_drc_cfgs;
                wm8994->drc_enum.texts = wm8994->drc_texts;
 
                ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
@@ -3990,9 +3998,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        int ret, i;
 
        wm8994->hubs.codec = codec;
-       codec->control_data = control->regmap;
 
-       snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
+       snd_soc_codec_set_cache_io(codec, control->regmap);
 
        mutex_init(&wm8994->accdet_lock);
        INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
index 4300caff17838b59d195ba629b1e0c94b3eb3574..d3152cf5bd5607490f34b7fe3fdb49915343e4da 100644 (file)
@@ -423,24 +423,24 @@ static const char *in1l_text[] = {
        "Differential", "Single-ended IN1LN", "Single-ended IN1LP"
 };
 
-static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
-                                 2, in1l_text);
+static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+                           2, in1l_text);
 
 static const char *in1r_text[] = {
        "Differential", "Single-ended IN1RN", "Single-ended IN1RP"
 };
 
-static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
-                                 0, in1r_text);
+static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+                           0, in1r_text);
 
 static const char *dmic_src_text[] = {
        "DMICDAT1", "DMICDAT2", "DMICDAT3"
 };
 
-static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5,
-                                 8, dmic_src_text);
-static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5,
-                                 6, dmic_src_text);
+static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5,
+                           8, dmic_src_text);
+static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5,
+                           6, dmic_src_text);
 
 static const struct snd_kcontrol_new wm8995_snd_controls[] = {
        SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME,
@@ -561,10 +561,8 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec;
-       struct wm8995_priv *wm8995;
 
        codec = w->codec;
-       wm8995 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -783,14 +781,12 @@ static const char *sidetone_text[] = {
        "ADC/DMIC1", "DMIC2",
 };
 
-static const struct soc_enum sidetone1_enum =
-       SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text);
 
 static const struct snd_kcontrol_new sidetone1_mux =
        SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
 
-static const struct soc_enum sidetone2_enum =
-       SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text);
 
 static const struct snd_kcontrol_new sidetone2_mux =
        SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
@@ -886,8 +882,7 @@ static const char *adc_mux_text[] = {
        "DMIC",
 };
 
-static const struct soc_enum adc_enum =
-       SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
 
 static const struct snd_kcontrol_new adcl_mux =
        SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
@@ -899,14 +894,14 @@ static const char *spk_src_text[] = {
        "DAC1L", "DAC1R", "DAC2L", "DAC2R"
 };
 
-static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1,
-                                 0, spk_src_text);
-static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1,
-                                 0, spk_src_text);
-static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2,
-                                 0, spk_src_text);
-static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2,
-                                 0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1,
+                           0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1,
+                           0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2,
+                           0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2,
+                           0, spk_src_text);
 
 static const struct snd_kcontrol_new spk1l_mux =
        SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum);
@@ -2047,13 +2042,6 @@ static int wm8995_probe(struct snd_soc_codec *codec)
        wm8995 = snd_soc_codec_get_drvdata(codec);
        wm8995->codec = codec;
 
-       codec->control_data = wm8995->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;
-       }
-
        for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)
                wm8995->supplies[i].supply = wm8995_supply_names[i];
 
index 1a7655b0aa2230890df4f5b82c34a609f7128f05..c6cbb3b8ace96a8d462159d975ae5525b5ac7ed4 100644 (file)
@@ -311,28 +311,28 @@ static const char *sidetone_hpf_text[] = {
        "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
 };
 
-static const struct soc_enum sidetone_hpf =
-       SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 7, sidetone_hpf_text);
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+                           WM8996_SIDETONE, 7, sidetone_hpf_text);
 
 static const char *hpf_mode_text[] = {
        "HiFi", "Custom", "Voice"
 };
 
-static const struct soc_enum dsp1tx_hpf_mode =
-       SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_mode,
+                           WM8996_DSP1_TX_FILTERS, 3, hpf_mode_text);
 
-static const struct soc_enum dsp2tx_hpf_mode =
-       SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_mode,
+                           WM8996_DSP2_TX_FILTERS, 3, hpf_mode_text);
 
 static const char *hpf_cutoff_text[] = {
        "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
 };
 
-static const struct soc_enum dsp1tx_hpf_cutoff =
-       SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_cutoff,
+                           WM8996_DSP1_TX_FILTERS, 0, hpf_cutoff_text);
 
-static const struct soc_enum dsp2tx_hpf_cutoff =
-       SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_cutoff,
+                           WM8996_DSP2_TX_FILTERS, 0, hpf_cutoff_text);
 
 static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
 {
@@ -780,14 +780,14 @@ static const char *sidetone_text[] = {
        "IN1", "IN2",
 };
 
-static const struct soc_enum left_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8996_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(left_sidetone_enum,
+                           WM8996_SIDETONE, 0, sidetone_text);
 
 static const struct snd_kcontrol_new left_sidetone =
        SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
 
-static const struct soc_enum right_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8996_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(right_sidetone_enum,
+                           WM8996_SIDETONE, 1, sidetone_text);
 
 static const struct snd_kcontrol_new right_sidetone =
        SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
@@ -796,14 +796,14 @@ static const char *spk_text[] = {
        "DAC1L", "DAC1R", "DAC2L", "DAC2R"
 };
 
-static const struct soc_enum spkl_enum =
-       SOC_ENUM_SINGLE(WM8996_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+static SOC_ENUM_SINGLE_DECL(spkl_enum,
+                           WM8996_LEFT_PDM_SPEAKER, 0, spk_text);
 
 static const struct snd_kcontrol_new spkl_mux =
        SOC_DAPM_ENUM("SPKL", spkl_enum);
 
-static const struct soc_enum spkr_enum =
-       SOC_ENUM_SINGLE(WM8996_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+static SOC_ENUM_SINGLE_DECL(spkr_enum,
+                           WM8996_RIGHT_PDM_SPEAKER, 0, spk_text);
 
 static const struct snd_kcontrol_new spkr_mux =
        SOC_DAPM_ENUM("SPKR", spkr_enum);
@@ -812,8 +812,8 @@ static const char *dsp1rx_text[] = {
        "AIF1", "AIF2"
 };
 
-static const struct soc_enum dsp1rx_enum =
-       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+static SOC_ENUM_SINGLE_DECL(dsp1rx_enum,
+                           WM8996_POWER_MANAGEMENT_8, 0, dsp1rx_text);
 
 static const struct snd_kcontrol_new dsp1rx =
        SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
@@ -822,8 +822,8 @@ static const char *dsp2rx_text[] = {
         "AIF2", "AIF1"
 };
 
-static const struct soc_enum dsp2rx_enum =
-       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+static SOC_ENUM_SINGLE_DECL(dsp2rx_enum,
+                           WM8996_POWER_MANAGEMENT_8, 4, dsp2rx_text);
 
 static const struct snd_kcontrol_new dsp2rx =
        SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
@@ -832,8 +832,8 @@ static const char *aif2tx_text[] = {
        "DSP2", "DSP1", "AIF1"
 };
 
-static const struct soc_enum aif2tx_enum =
-       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+static SOC_ENUM_SINGLE_DECL(aif2tx_enum,
+                           WM8996_POWER_MANAGEMENT_8, 6, aif2tx_text);
 
 static const struct snd_kcontrol_new aif2tx =
        SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
@@ -842,14 +842,14 @@ static const char *inmux_text[] = {
        "ADC", "DMIC1", "DMIC2"
 };
 
-static const struct soc_enum in1_enum =
-       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+static SOC_ENUM_SINGLE_DECL(in1_enum,
+                           WM8996_POWER_MANAGEMENT_7, 0, inmux_text);
 
 static const struct snd_kcontrol_new in1_mux =
        SOC_DAPM_ENUM("IN1 Mux", in1_enum);
 
-static const struct soc_enum in2_enum =
-       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+static SOC_ENUM_SINGLE_DECL(in2_enum,
+                           WM8996_POWER_MANAGEMENT_7, 4, inmux_text);
 
 static const struct snd_kcontrol_new in2_mux =
        SOC_DAPM_ENUM("IN2 Mux", in2_enum);
@@ -1608,8 +1608,8 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
                                msleep(5);
                        }
 
-                       regcache_cache_only(codec->control_data, false);
-                       regcache_sync(codec->control_data);
+                       regcache_cache_only(wm8996->regmap, false);
+                       regcache_sync(wm8996->regmap);
                }
 
                /* Bypass the MICBIASes for lowest power */
@@ -1620,10 +1620,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_OFF:
-               regcache_cache_only(codec->control_data, true);
+               regcache_cache_only(wm8996->regmap, true);
                if (wm8996->pdata.ldo_ena >= 0) {
                        gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
-                       regcache_cache_only(codec->control_data, true);
+                       regcache_cache_only(wm8996->regmap, true);
                }
                regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
                                       wm8996->supplies);
@@ -2251,6 +2251,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                  wm8996_polarity_fn polarity_cb)
 {
        struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        wm8996->jack = jack;
        wm8996->detecting = true;
@@ -2267,8 +2268,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                            WM8996_MICB2_DISCH, 0);
 
        /* LDO2 powers the microphones, SYSCLK clocks detection */
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+       snd_soc_dapm_mutex_lock(dapm);
+
+       snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
+       snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+
+       snd_soc_dapm_mutex_unlock(dapm);
 
        /* We start off just enabling microphone detection - even a
         * plain headphone will trigger detection.
@@ -2595,7 +2600,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
        dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
                wm8996->num_retune_mobile_texts);
 
-       wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts;
+       wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts;
        wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
 
        ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
@@ -2628,14 +2633,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
        init_completion(&wm8996->dcs_done);
        init_completion(&wm8996->fll_lock);
 
-       codec->control_data = wm8996->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);
-               goto err;
-       }
-
        if (wm8996->pdata.num_retune_mobile_cfgs)
                wm8996_retune_mobile_pdata(codec);
        else
@@ -2674,13 +2671,11 @@ static int wm8996_probe(struct snd_soc_codec *codec)
                } else {
                        dev_err(codec->dev, "Failed to request IRQ: %d\n",
                                ret);
+                       return ret;
                }
        }
 
        return 0;
-
-err:
-       return ret;
 }
 
 static int wm8996_remove(struct snd_soc_codec *codec)
index 555115ee2159eadd3083f522d8cd682000216a48..004186b6bd48131932ac8fceca088548b9df9eb5 100644 (file)
@@ -86,7 +86,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = w->codec;
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-       struct regmap *regmap = codec->control_data;
+       struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
        int i, patch_size;
 
@@ -123,10 +123,12 @@ static const unsigned int wm8997_osr_val[] = {
 
 static const struct soc_enum wm8997_hpout_osr[] = {
        SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
-                             ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+                             ARIZONA_OUT1_OSR_SHIFT, 0x7,
+                             ARRAY_SIZE(wm8997_osr_text),
                              wm8997_osr_text, wm8997_osr_val),
        SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
-                             ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+                             ARIZONA_OUT3_OSR_SHIFT, 0x7,
+                             ARRAY_SIZE(wm8997_osr_text),
                              wm8997_osr_text, wm8997_osr_val),
 };
 
@@ -170,15 +172,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
 
-SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
-                  ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
-                  ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
-                  ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
-                  ARIZONA_EQ4_ENA_MASK),
-
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -190,6 +185,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -201,6 +198,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -212,6 +211,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
 SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
               24, 0, eq_tlv),
 
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
 SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
               24, 0, eq_tlv),
 SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -1052,9 +1053,7 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
        struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       codec->control_data = priv->core.arizona->regmap;
-
-       ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+       ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
        if (ret != 0)
                return ret;
 
index 0982c1d38ec458205628b2fdd52ccc87a499db97..d18eff31fbbc618243a9b0db38e603e7af92bb30 100644 (file)
@@ -268,8 +268,7 @@ static const char *drc_high_text[] = {
        "0",
 };
 
-static const struct soc_enum drc_high =
-       SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text);
+static SOC_ENUM_SINGLE_DECL(drc_high, WM9081_DRC_3, 3, drc_high_text);
 
 static const char *drc_low_text[] = {
        "1",
@@ -279,8 +278,7 @@ static const char *drc_low_text[] = {
        "0",
 };
 
-static const struct soc_enum drc_low =
-       SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text);
+static SOC_ENUM_SINGLE_DECL(drc_low, WM9081_DRC_3, 0, drc_low_text);
 
 static const char *drc_atk_text[] = {
        "181us",
@@ -297,8 +295,7 @@ static const char *drc_atk_text[] = {
        "185.6ms",
 };
 
-static const struct soc_enum drc_atk =
-       SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text);
+static SOC_ENUM_SINGLE_DECL(drc_atk, WM9081_DRC_2, 12, drc_atk_text);
 
 static const char *drc_dcy_text[] = {
        "186ms",
@@ -312,8 +309,7 @@ static const char *drc_dcy_text[] = {
        "47.56s",
 };
 
-static const struct soc_enum drc_dcy =
-       SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text);
+static SOC_ENUM_SINGLE_DECL(drc_dcy, WM9081_DRC_2, 8, drc_dcy_text);
 
 static const char *drc_qr_dcy_text[] = {
        "0.725ms",
@@ -321,8 +317,7 @@ static const char *drc_qr_dcy_text[] = {
        "5.8ms",
 };
 
-static const struct soc_enum drc_qr_dcy =
-       SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_dcy, WM9081_DRC_2, 4, drc_qr_dcy_text);
 
 static const char *dac_deemph_text[] = {
        "None",
@@ -331,16 +326,16 @@ static const char *dac_deemph_text[] = {
        "48kHz",
 };
 
-static const struct soc_enum dac_deemph =
-       SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text);
+static SOC_ENUM_SINGLE_DECL(dac_deemph, WM9081_DAC_DIGITAL_2, 1,
+                           dac_deemph_text);
 
 static const char *speaker_mode_text[] = {
        "Class D",
        "Class AB",
 };
 
-static const struct soc_enum speaker_mode =
-       SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text);
+static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
+                           speaker_mode_text);
 
 static int speaker_mode_get(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
@@ -1265,15 +1260,6 @@ static struct snd_soc_dai_driver wm9081_dai = {
 static int wm9081_probe(struct snd_soc_codec *codec)
 {
        struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       codec->control_data = wm9081->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;
-       }
 
        /* Enable zero cross by default */
        snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT,
@@ -1288,7 +1274,7 @@ static int wm9081_probe(struct snd_soc_codec *codec)
                                     ARRAY_SIZE(wm9081_eq_controls));
        }
 
-       return ret;
+       return 0;
 }
 
 static int wm9081_remove(struct snd_soc_codec *codec)
index a07fe1618eec439d3ba001573331f4046b4e2095..87934171f0637da2c2a307893a641a43b0193e0b 100644 (file)
@@ -522,16 +522,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
 
 static int wm9090_probe(struct snd_soc_codec *codec)
 {
-       struct wm9090_priv *wm9090 = dev_get_drvdata(codec->dev);
-       int ret;
-
-       codec->control_data = wm9090->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;
-       }
-
        /* Configure some defaults; they will be written out when we
         * bring the bias up.
         */
index 70ce6793c5bd51cc8f32c893d28932e2db6358da..c0b7f45dfa37799a51c4de4caef2249005fe87a2 100644 (file)
@@ -67,12 +67,12 @@ static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};
 static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",
        "Line", "Stereo Mix", "Mono Mix", "Phone"};
 
-static const struct soc_enum wm9705_enum_mic =
-       SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic);
-static const struct soc_enum wm9705_enum_rec_l =
-       SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel);
-static const struct soc_enum wm9705_enum_rec_r =
-       SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_mic,
+                           AC97_GENERAL_PURPOSE, 8, wm9705_mic);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_l,
+                           AC97_REC_SEL, 8, wm9705_rec_sel);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_r,
+                           AC97_REC_SEL, 0, wm9705_rec_sel);
 
 /* Headphone Mixer */
 static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = {
index 444626fcab40d42aed3b6df03e9cf86f43dd3423..bb5f7b4e3ebbfe016146343c9c1178f568c93517 100644 (file)
@@ -684,24 +684,38 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                }
 
                if (reg) {
-                       buf = wm_adsp_buf_alloc(region->data,
-                                               le32_to_cpu(region->len),
-                                               &buf_list);
-                       if (!buf) {
-                               adsp_err(dsp, "Out of memory\n");
-                               ret = -ENOMEM;
-                               goto out_fw;
-                       }
+                       size_t to_write = PAGE_SIZE;
+                       size_t remain = le32_to_cpu(region->len);
+                       const u8 *data = region->data;
+
+                       while (remain > 0) {
+                               if (remain < PAGE_SIZE)
+                                       to_write = remain;
+
+                               buf = wm_adsp_buf_alloc(data,
+                                                       to_write,
+                                                       &buf_list);
+                               if (!buf) {
+                                       adsp_err(dsp, "Out of memory\n");
+                                       ret = -ENOMEM;
+                                       goto out_fw;
+                               }
 
-                       ret = regmap_raw_write_async(regmap, reg, buf->buf,
-                                                    le32_to_cpu(region->len));
-                       if (ret != 0) {
-                               adsp_err(dsp,
-                                       "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
-                                       file, regions,
-                                       le32_to_cpu(region->len), offset,
-                                       region_name, ret);
-                               goto out_fw;
+                               ret = regmap_raw_write_async(regmap, reg,
+                                                            buf->buf,
+                                                            to_write);
+                               if (ret != 0) {
+                                       adsp_err(dsp,
+                                               "%s.%d: Failed to write %zd bytes at %d in %s: %d\n",
+                                               file, regions,
+                                               to_write, offset,
+                                               region_name, ret);
+                                       goto out_fw;
+                               }
+
+                               data += to_write;
+                               reg += to_write / 2;
+                               remain -= to_write;
                        }
                }
 
@@ -1679,6 +1693,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                        list_del(&alg_region->list);
                        kfree(alg_region);
                }
+
+               adsp_dbg(dsp, "Shutdown complete\n");
                break;
 
        default:
index b371066dd5bc914d24a79fe604d1eec9bfdd0e1e..b6209662ab13f8c5031908a0408494064d7b5299 100644 (file)
@@ -50,16 +50,16 @@ static const char *speaker_ref_text[] = {
        "VMID",
 };
 
-static const struct soc_enum speaker_ref =
-       SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text);
+static SOC_ENUM_SINGLE_DECL(speaker_ref,
+                           WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
 
 static const char *speaker_mode_text[] = {
        "Class D",
        "Class AB",
 };
 
-static const struct soc_enum speaker_mode =
-       SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text);
+static SOC_ENUM_SINGLE_DECL(speaker_mode,
+                           WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
 
 static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 {
@@ -735,15 +735,15 @@ static const char *hp_mux_text[] = {
        "DAC",
 };
 
-static const struct soc_enum hpl_enum =
-       SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpl_enum,
+                           WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
 
 const struct snd_kcontrol_new wm_hubs_hpl_mux =
        WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
 EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
 
-static const struct soc_enum hpr_enum =
-       SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpr_enum,
+                           WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
 
 const struct snd_kcontrol_new wm_hubs_hpr_mux =
        WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
index 5e3bc3c6801a6bbf9512731f6cd094b2eb41511f..cab98a580053bd9978e2ba8317583654fe09cf74 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_data/edma.h>
 #include <linux/i2c.h>
 #include <linux/of_platform.h>
+#include <linux/clk.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include "davinci-i2s.h"
 
 struct snd_soc_card_drvdata_davinci {
+       struct clk *mclk;
        unsigned sysclk;
 };
 
+static int evm_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *soc_card = rtd->codec->card;
+       struct snd_soc_card_drvdata_davinci *drvdata =
+               snd_soc_card_get_drvdata(soc_card);
+
+       if (drvdata->mclk)
+               return clk_prepare_enable(drvdata->mclk);
+
+       return 0;
+}
+
+static void evm_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *soc_card = rtd->codec->card;
+       struct snd_soc_card_drvdata_davinci *drvdata =
+               snd_soc_card_get_drvdata(soc_card);
+
+       if (drvdata->mclk)
+               clk_disable_unprepare(drvdata->mclk);
+}
+
 static int evm_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
@@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops evm_ops = {
+       .startup = evm_startup,
+       .shutdown = evm_shutdown,
        .hw_params = evm_hw_params,
 };
 
@@ -95,35 +123,29 @@ static const struct snd_soc_dapm_route audio_map[] = {
 /* Logic for a aic3x as connected on a davinci-evm */
 static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_card *card = rtd->card;
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct device_node *np = codec->card->dev->of_node;
        int ret;
 
        /* Add davinci-evm specific widgets */
-       snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
+       snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        if (np) {
-               ret = snd_soc_of_parse_audio_routing(codec->card,
-                                                       "ti,audio-routing");
+               ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
                if (ret)
                        return ret;
        } else {
                /* Set up davinci-evm specific audio path audio_map */
-               snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+               snd_soc_dapm_add_routes(&card->dapm, audio_map,
+                                       ARRAY_SIZE(audio_map));
        }
 
        /* not connected */
-       snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
-       snd_soc_dapm_disable_pin(dapm, "HPLCOM");
-       snd_soc_dapm_disable_pin(dapm, "HPRCOM");
-
-       /* always connected */
-       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
-       snd_soc_dapm_enable_pin(dapm, "Line Out");
-       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-       snd_soc_dapm_enable_pin(dapm, "Line In");
+       snd_soc_dapm_nc_pin(&codec->dapm, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(&codec->dapm, "HPLCOM");
+       snd_soc_dapm_nc_pin(&codec->dapm, "HPRCOM");
 
        return 0;
 }
@@ -348,6 +370,7 @@ static int davinci_evm_probe(struct platform_device *pdev)
                of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
        struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
        struct snd_soc_card_drvdata_davinci *drvdata = NULL;
+       struct clk *mclk;
        int ret = 0;
 
        evm_soc_card.dai_link = dai;
@@ -367,13 +390,38 @@ static int davinci_evm_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       mclk = devm_clk_get(&pdev->dev, "mclk");
+       if (PTR_ERR(mclk) == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else if (IS_ERR(mclk)) {
+               dev_dbg(&pdev->dev, "mclk not found.\n");
+               mclk = NULL;
+       }
+
        drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
+       drvdata->mclk = mclk;
+
        ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
-       if (ret < 0)
-               return -EINVAL;
+
+       if (ret < 0) {
+               if (!drvdata->mclk) {
+                       dev_err(&pdev->dev,
+                               "No clock or clock rate defined.\n");
+                       return -EINVAL;
+               }
+               drvdata->sysclk = clk_get_rate(drvdata->mclk);
+       } else if (drvdata->mclk) {
+               unsigned int requestd_rate = drvdata->sysclk;
+               clk_set_rate(drvdata->mclk, drvdata->sysclk);
+               drvdata->sysclk = clk_get_rate(drvdata->mclk);
+               if (drvdata->sysclk != requestd_rate)
+                       dev_warn(&pdev->dev,
+                                "Could not get requested rate %u using %u.\n",
+                                requestd_rate, drvdata->sysclk);
+       }
 
        snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
        ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
index 670afa29e30d0d5b97f7c60601d1e40793b5b499..a01ae97c90aae4aba50ccf21184adb1a519f7dcc 100644 (file)
 #include "davinci-pcm.h"
 #include "davinci-mcasp.h"
 
+struct davinci_mcasp_context {
+       u32     txfmtctl;
+       u32     rxfmtctl;
+       u32     txfmt;
+       u32     rxfmt;
+       u32     aclkxctl;
+       u32     aclkrctl;
+       u32     pdir;
+};
+
 struct davinci_mcasp {
        struct davinci_pcm_dma_params dma_params[2];
        struct snd_dmaengine_dai_dma_data dma_data[2];
@@ -53,6 +63,9 @@ struct davinci_mcasp {
        u16     bclk_lrclk_ratio;
        int     streams;
 
+       int     sysclk_freq;
+       bool    bclk_master;
+
        /* McASP FIFO related */
        u8      txnumevt;
        u8      rxnumevt;
@@ -60,15 +73,7 @@ struct davinci_mcasp {
        bool    dat_port;
 
 #ifdef CONFIG_PM_SLEEP
-       struct {
-               u32     txfmtctl;
-               u32     rxfmtctl;
-               u32     txfmt;
-               u32     rxfmt;
-               u32     aclkxctl;
-               u32     aclkrctl;
-               u32     pdir;
-       } context;
+       struct davinci_mcasp_context context;
 #endif
 };
 
@@ -294,6 +299,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+               mcasp->bclk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
@@ -305,6 +311,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+               mcasp->bclk_master = 0;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* codec is clock and frame master */
@@ -316,6 +323,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
                               ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+               mcasp->bclk_master = 0;
                break;
 
        default:
@@ -410,6 +418,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
        }
 
+       mcasp->sysclk_freq = freq;
+
        return 0;
 }
 
@@ -603,20 +613,23 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        u8 fifo_level;
        u8 slots = mcasp->tdm_slots;
        u8 active_serializers;
-       int channels;
+       int channels = params_channels(params);
        int ret;
-       struct snd_interval *pcm_channels = hw_param_interval(params,
-                                       SNDRV_PCM_HW_PARAM_CHANNELS);
-       channels = pcm_channels->min;
 
-       active_serializers = (channels + slots - 1) / slots;
+       /* If mcasp is BCLK master we need to set BCLK divider */
+       if (mcasp->bclk_master) {
+               unsigned int bclk_freq = snd_soc_params_to_bclk(params);
+               if (mcasp->sysclk_freq % bclk_freq != 0) {
+                       dev_err(mcasp->dev, "Can't produce requred BCLK\n");
+                       return -EINVAL;
+               }
+               davinci_mcasp_set_clkdiv(
+                       cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
+       }
 
-       if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL)
-               return -EINVAL;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_level = mcasp->txnumevt * active_serializers;
-       else
-               fifo_level = mcasp->rxnumevt * active_serializers;
+       ret = mcasp_common_hw_param(mcasp, substream->stream, channels);
+       if (ret)
+               return ret;
 
        if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
                ret = mcasp_dit_hw_param(mcasp);
@@ -658,6 +671,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       /* Calculate FIFO level */
+       active_serializers = (channels + slots - 1) / slots;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               fifo_level = mcasp->txnumevt * active_serializers;
+       else
+               fifo_level = mcasp->rxnumevt * active_serializers;
+
        if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
                dma_params->acnt = 4;
        else
@@ -719,6 +739,43 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .set_sysclk     = davinci_mcasp_set_sysclk,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp_context *context = &mcasp->context;
+
+       context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
+       context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+       context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
+       context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
+       context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+       context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
+       context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+
+       return 0;
+}
+
+static int davinci_mcasp_resume(struct snd_soc_dai *dai)
+{
+       struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+       struct davinci_mcasp_context *context = &mcasp->context;
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+
+       return 0;
+}
+#else
+#define davinci_mcasp_suspend NULL
+#define davinci_mcasp_resume NULL
+#endif
+
 #define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
 
 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -735,6 +792,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        {
                .name           = "davinci-mcasp.0",
+               .suspend        = davinci_mcasp_suspend,
+               .resume         = davinci_mcasp_resume,
                .playback       = {
                        .channels_min   = 2,
                        .channels_max   = 32 * 16,
@@ -768,28 +827,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
 };
 
 /* Some HW specific values and defaults. The rest is filled in from DT. */
-static struct snd_platform_data dm646x_mcasp_pdata = {
+static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
        .tx_dma_offset = 0x400,
        .rx_dma_offset = 0x400,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_1,
 };
 
-static struct snd_platform_data da830_mcasp_pdata = {
+static struct davinci_mcasp_pdata da830_mcasp_pdata = {
        .tx_dma_offset = 0x2000,
        .rx_dma_offset = 0x2000,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_2,
 };
 
-static struct snd_platform_data am33xx_mcasp_pdata = {
+static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
        .tx_dma_offset = 0,
        .rx_dma_offset = 0,
        .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_3,
 };
 
-static struct snd_platform_data dra7_mcasp_pdata = {
+static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
        .tx_dma_offset = 0x200,
        .rx_dma_offset = 0x284,
        .asp_chan_q = EVENTQ_0,
@@ -857,11 +916,11 @@ err1:
        return ret;
 }
 
-static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
+static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
                                                struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct snd_platform_data *pdata = NULL;
+       struct davinci_mcasp_pdata *pdata = NULL;
        const struct of_device_id *match =
                        of_match_device(mcasp_dt_ids, &pdev->dev);
        struct of_phandle_args dma_spec;
@@ -874,7 +933,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata = pdev->dev.platform_data;
                return pdata;
        } else if (match) {
-               pdata = (struct snd_platform_data *) match->data;
+               pdata = (struct davinci_mcasp_pdata*) match->data;
        } else {
                /* control shouldn't reach here. something is wrong */
                ret = -EINVAL;
@@ -966,9 +1025,10 @@ nodata:
 
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
-       struct davinci_pcm_dma_params *dma_data;
+       struct davinci_pcm_dma_params *dma_params;
+       struct snd_dmaengine_dai_dma_data *dma_data;
        struct resource *mem, *ioarea, *res, *dat;
-       struct snd_platform_data *pdata;
+       struct davinci_mcasp_pdata *pdata;
        struct davinci_mcasp *mcasp;
        int ret;
 
@@ -1035,41 +1095,49 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (dat)
                mcasp->dat_port = true;
 
-       dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
-       dma_data->asp_chan_q = pdata->asp_chan_q;
-       dma_data->ram_chan_q = pdata->ram_chan_q;
-       dma_data->sram_pool = pdata->sram_pool;
-       dma_data->sram_size = pdata->sram_size_playback;
+       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dma_params->asp_chan_q = pdata->asp_chan_q;
+       dma_params->ram_chan_q = pdata->ram_chan_q;
+       dma_params->sram_pool = pdata->sram_pool;
+       dma_params->sram_size = pdata->sram_size_playback;
        if (dat)
-               dma_data->dma_addr = dat->start;
+               dma_params->dma_addr = dat->start;
        else
-               dma_data->dma_addr = mem->start + pdata->tx_dma_offset;
+               dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
 
        /* Unconditional dmaengine stuff */
-       mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr;
+       dma_data->addr = dma_params->dma_addr;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (res)
-               dma_data->channel = res->start;
+               dma_params->channel = res->start;
        else
-               dma_data->channel = pdata->tx_dma_channel;
+               dma_params->channel = pdata->tx_dma_channel;
 
-       dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
-       dma_data->asp_chan_q = pdata->asp_chan_q;
-       dma_data->ram_chan_q = pdata->ram_chan_q;
-       dma_data->sram_pool = pdata->sram_pool;
-       dma_data->sram_size = pdata->sram_size_capture;
+       /* dmaengine filter data for DT and non-DT boot */
+       if (pdev->dev.of_node)
+               dma_data->filter_data = "tx";
+       else
+               dma_data->filter_data = &dma_params->channel;
+
+       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+       dma_params->asp_chan_q = pdata->asp_chan_q;
+       dma_params->ram_chan_q = pdata->ram_chan_q;
+       dma_params->sram_pool = pdata->sram_pool;
+       dma_params->sram_size = pdata->sram_size_capture;
        if (dat)
-               dma_data->dma_addr = dat->start;
+               dma_params->dma_addr = dat->start;
        else
-               dma_data->dma_addr = mem->start + pdata->rx_dma_offset;
+               dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
 
        /* Unconditional dmaengine stuff */
-       mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr;
+       dma_data->addr = dma_params->dma_addr;
 
        if (mcasp->version < MCASP_VERSION_3) {
                mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
-               /* dma_data->dma_addr is pointing to the data port address */
+               /* dma_params->dma_addr is pointing to the data port address */
                mcasp->dat_port = true;
        } else {
                mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
@@ -1077,13 +1145,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (res)
-               dma_data->channel = res->start;
+               dma_params->channel = res->start;
        else
-               dma_data->channel = pdata->rx_dma_channel;
+               dma_params->channel = pdata->rx_dma_channel;
 
-       /* Unconditional dmaengine stuff */
-       mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
-       mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+       /* dmaengine filter data for DT and non-DT boot */
+       if (pdev->dev.of_node)
+               dma_data->filter_data = "rx";
+       else
+               dma_data->filter_data = &dma_params->channel;
 
        dev_set_drvdata(&pdev->dev, mcasp);
 
@@ -1127,49 +1197,12 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int davinci_mcasp_suspend(struct device *dev)
-{
-       struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
-       mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
-       mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
-       mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
-       mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
-       mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
-       mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
-       mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
-
-       return 0;
-}
-
-static int davinci_mcasp_resume(struct device *dev)
-{
-       struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl);
-       mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir);
-
-       return 0;
-}
-#endif
-
-SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
-                 davinci_mcasp_suspend,
-                 davinci_mcasp_resume);
-
 static struct platform_driver davinci_mcasp_driver = {
        .probe          = davinci_mcasp_probe,
        .remove         = davinci_mcasp_remove,
        .driver         = {
                .name   = "davinci-mcasp",
                .owner  = THIS_MODULE,
-               .pm     = &davinci_mcasp_pm_ops,
                .of_match_table = mcasp_dt_ids,
        },
 };
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c
new file mode 100644 (file)
index 0000000..d38afb1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.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.
+ */
+
+#include <linux/module.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/edma.h>
+
+static const struct snd_pcm_hardware edma_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_BATCH |
+                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_INTERLEAVED,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 64 * 1024,
+       .periods_min            = 2,
+       .periods_max            = 19, /* Limit by edma dmaengine driver */
+};
+
+static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
+       .pcm_hardware = &edma_pcm_hardware,
+       .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+       .compat_filter_fn = edma_filter_fn,
+       .prealloc_buffer_size = 128 * 1024,
+};
+
+int edma_pcm_platform_register(struct device *dev)
+{
+       return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
+                                       SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/davinci/edma-pcm.h
new file mode 100644 (file)
index 0000000..894c378
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.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.
+ */
+
+#ifndef __EDMA_PCM_H__
+#define __EDMA_PCM_H__
+
+int edma_pcm_platform_register(struct device *dev);
+
+#endif /* __EDMA_PCM_H__ */
index 07f8f141727d99c19403f2994ac42ce63ff6f23a..338a91642471846fd424a99aa6760406a39532d6 100644 (file)
@@ -1,5 +1,6 @@
 config SND_SOC_FSL_SAI
        tristate
+       select REGMAP_MMIO
        select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_SOC_FSL_SSI
@@ -7,9 +8,12 @@ config SND_SOC_FSL_SSI
 
 config SND_SOC_FSL_SPDIF
        tristate
+       select REGMAP_MMIO
 
 config SND_SOC_FSL_ESAI
        tristate
+       select REGMAP_MMIO
+       select SND_SOC_FSL_UTILS
 
 config SND_SOC_FSL_UTILS
        tristate
@@ -117,6 +121,7 @@ if SND_IMX_SOC
 
 config SND_SOC_IMX_SSI
        tristate
+       select SND_SOC_FSL_UTILS
 
 config SND_SOC_IMX_PCM_FIQ
        tristate
@@ -168,12 +173,14 @@ config SND_SOC_EUKREA_TLV320
        depends on MACH_EUKREA_MBIMX27_BASEBOARD \
                || MACH_EUKREA_MBIMXSD25_BASEBOARD \
                || MACH_EUKREA_MBIMXSD35_BASEBOARD \
-               || MACH_EUKREA_MBIMXSD51_BASEBOARD
+               || MACH_EUKREA_MBIMXSD51_BASEBOARD \
+               || (OF && ARM)
        depends on I2C
-       select SND_SOC_TLV320AIC23
-       select SND_SOC_IMX_PCM_FIQ
+       select SND_SOC_TLV320AIC23_I2C
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_IMX_SSI
+       select SND_SOC_FSL_SSI
+       select SND_SOC_IMX_PCM_DMA
        help
          Enable I2S based access to the TLV320AIC23B codec attached
          to the SSI interface
@@ -204,7 +211,6 @@ config SND_SOC_IMX_SPDIF
        tristate "SoC Audio support for i.MX boards with S/PDIF"
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_FSL_SPDIF
-       select REGMAP_MMIO
        help
          SoC Audio support for i.MX boards with S/PDIF
          Say Y if you want to add support for SoC audio on an i.MX board with
index 5983740be1230324c3319f39864112a24ce0a17d..eb093d5b85c4cce3f0bf10616aeb1fcc61f859e9 100644 (file)
  *
  */
 
+#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/device.h>
 #include <linux/i2c.h>
 #include <sound/core.h>
@@ -26,6 +29,7 @@
 
 #include "../codecs/tlv320aic23.h"
 #include "imx-ssi.h"
+#include "fsl_ssi.h"
 #include "imx-audmux.h"
 
 #define CODEC_CLOCK 12000000
@@ -41,7 +45,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                                  SND_SOC_DAIFMT_NB_NF |
                                  SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
+       /* fsl_ssi lacks the set_fmt ops. */
+       if (ret && ret != -ENOTSUPP) {
                dev_err(cpu_dai->dev,
                        "Failed to set the cpu dai format.\n");
                return ret;
@@ -63,11 +68,13 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
                        "Failed to set the codec sysclk.\n");
                return ret;
        }
+
        snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
 
        ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
                                SND_SOC_CLOCK_IN);
-       if (ret) {
+       /* fsl_ssi lacks the set_sysclk ops */
+       if (ret && ret != -EINVAL) {
                dev_err(cpu_dai->dev,
                        "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n");
                return ret;
@@ -84,14 +91,10 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
        .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name  = "imx-ssi.0",
-       .codec_name     = "tlv320aic23-codec.0-001a",
-       .cpu_dai_name   = "imx-ssi.0",
        .ops            = &eukrea_tlv320_snd_ops,
 };
 
 static struct snd_soc_card eukrea_tlv320 = {
-       .name           = "cpuimx-audio",
        .owner          = THIS_MODULE,
        .dai_link       = &eukrea_tlv320_dai,
        .num_links      = 1,
@@ -101,8 +104,65 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
 {
        int ret;
        int int_port = 0, ext_port;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np, *codec_np;
 
-       if (machine_is_eukrea_cpuimx27()) {
+       eukrea_tlv320.dev = &pdev->dev;
+       if (np) {
+               ret = snd_soc_of_parse_card_name(&eukrea_tlv320,
+                                                "eukrea,model");
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "eukrea,model node missing or invalid.\n");
+                       goto err;
+               }
+
+               ssi_np = of_parse_phandle(pdev->dev.of_node,
+                                         "ssi-controller", 0);
+               if (!ssi_np) {
+                       dev_err(&pdev->dev,
+                               "ssi-controller missing or invalid.\n");
+                       ret = -ENODEV;
+                       goto err;
+               }
+
+               codec_np = of_parse_phandle(ssi_np, "codec-handle", 0);
+               if (codec_np)
+                       eukrea_tlv320_dai.codec_of_node = codec_np;
+               else
+                       dev_err(&pdev->dev, "codec-handle node missing or invalid.\n");
+
+               ret = of_property_read_u32(np, "fsl,mux-int-port", &int_port);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "fsl,mux-int-port node missing or invalid.\n");
+                       return ret;
+               }
+               ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "fsl,mux-ext-port node 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--;
+
+               eukrea_tlv320_dai.cpu_of_node = ssi_np;
+               eukrea_tlv320_dai.platform_of_node = ssi_np;
+       } else {
+               eukrea_tlv320_dai.cpu_dai_name = "imx-ssi.0";
+               eukrea_tlv320_dai.platform_name = "imx-ssi.0";
+               eukrea_tlv320_dai.codec_name = "tlv320aic23-codec.0-001a";
+               eukrea_tlv320.name = "cpuimx-audio";
+       }
+
+       if (machine_is_eukrea_cpuimx27() ||
+           of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) {
                imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
                        IMX_AUDMUX_V1_PCR_SYN |
                        IMX_AUDMUX_V1_PCR_TFSDIR |
@@ -119,8 +179,12 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
                );
        } else if (machine_is_eukrea_cpuimx25sd() ||
                   machine_is_eukrea_cpuimx35sd() ||
-                  machine_is_eukrea_cpuimx51sd()) {
-               ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3;
+                  machine_is_eukrea_cpuimx51sd() ||
+                  of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) {
+               if (!np)
+                       ext_port = machine_is_eukrea_cpuimx25sd() ?
+                               4 : 3;
+
                imx_audmux_v2_configure_port(int_port,
                        IMX_AUDMUX_V2_PTCR_SYN |
                        IMX_AUDMUX_V2_PTCR_TFSDIR |
@@ -134,14 +198,27 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
                        IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)
                );
        } else {
-               /* return happy. We might run on a totally different machine */
-               return 0;
+               if (np) {
+                       /* The eukrea,asoc-tlv320 driver was explicitely
+                        * requested (through the device tree).
+                        */
+                       dev_err(&pdev->dev,
+                               "Missing or invalid audmux DT node.\n");
+                       return -ENODEV;
+               } else {
+                       /* Return happy.
+                        * We might run on a totally different machine.
+                        */
+                       return 0;
+               }
        }
 
-       eukrea_tlv320.dev = &pdev->dev;
        ret = snd_soc_register_card(&eukrea_tlv320);
+err:
        if (ret)
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+       if (np)
+               of_node_put(ssi_np);
 
        return ret;
 }
@@ -153,10 +230,17 @@ static int eukrea_tlv320_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id imx_tlv320_dt_ids[] = {
+       { .compatible = "eukrea,asoc-tlv320"},
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_tlv320_dt_ids);
+
 static struct platform_driver eukrea_tlv320_driver = {
        .driver = {
                .name = "eukrea_tlv320",
                .owner = THIS_MODULE,
+               .of_match_table = imx_tlv320_dt_ids,
        },
        .probe = eukrea_tlv320_probe,
        .remove = eukrea_tlv320_remove,
index c84026c991347f99014dad7df74c57731b789e24..c8e5db1414d7e75f4077728765a210877f4b3cd9 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "fsl_esai.h"
 #include "imx-pcm.h"
+#include "fsl_utils.h"
 
 #define FSL_ESAI_RATES         SNDRV_PCM_RATE_8000_192000
 #define FSL_ESAI_FORMATS       (SNDRV_PCM_FMTBIT_S8 | \
@@ -431,17 +432,26 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int fsl_esai_startup(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
+       int ret;
        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 
        /*
         * Some platforms might use the same bit to gate all three or two of
         * clocks, so keep all clocks open/close at the same time for safety
         */
-       clk_prepare_enable(esai_priv->coreclk);
-       if (!IS_ERR(esai_priv->extalclk))
-               clk_prepare_enable(esai_priv->extalclk);
-       if (!IS_ERR(esai_priv->fsysclk))
-               clk_prepare_enable(esai_priv->fsysclk);
+       ret = clk_prepare_enable(esai_priv->coreclk);
+       if (ret)
+               return ret;
+       if (!IS_ERR(esai_priv->extalclk)) {
+               ret = clk_prepare_enable(esai_priv->extalclk);
+               if (ret)
+                       goto err_extalck;
+       }
+       if (!IS_ERR(esai_priv->fsysclk)) {
+               ret = clk_prepare_enable(esai_priv->fsysclk);
+               if (ret)
+                       goto err_fsysclk;
+       }
 
        if (!dai->active) {
                /* Reset Port C */
@@ -463,6 +473,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
        }
 
        return 0;
+
+err_fsysclk:
+       if (!IS_ERR(esai_priv->extalclk))
+               clk_disable_unprepare(esai_priv->extalclk);
+err_extalck:
+       clk_disable_unprepare(esai_priv->coreclk);
+
+       return ret;
 }
 
 static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
@@ -564,6 +582,7 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = {
        .hw_params = fsl_esai_hw_params,
        .set_sysclk = fsl_esai_set_dai_sysclk,
        .set_fmt = fsl_esai_set_dai_fmt,
+       .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
        .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
 };
 
@@ -661,7 +680,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static const struct regmap_config fsl_esai_regmap_config = {
+static struct regmap_config fsl_esai_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -687,6 +706,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
        esai_priv->pdev = pdev;
        strcpy(esai_priv->name, np->name);
 
+       if (of_property_read_bool(np, "big-endian"))
+               fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(&pdev->dev, res);
index cdd3fa8307044d715b196b4c060d1e1c831f8e75..c4a42311167371446cfd5e24b2c23c418e796627 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dmaengine.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/dmaengine_pcm.h>
 
 #include "fsl_sai.h"
 
-static inline u32 sai_readl(struct fsl_sai *sai,
-               const void __iomem *addr)
-{
-       u32 val;
-
-       val = __raw_readl(addr);
-
-       if (likely(sai->big_endian_regs))
-               val = be32_to_cpu(val);
-       else
-               val = le32_to_cpu(val);
-       rmb();
-
-       return val;
-}
-
-static inline void sai_writel(struct fsl_sai *sai,
-               u32 val, void __iomem *addr)
-{
-       wmb();
-       if (likely(sai->big_endian_regs))
-               val = cpu_to_be32(val);
-       else
-               val = cpu_to_le32(val);
-
-       __raw_writel(val, addr);
-}
-
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int fsl_dir)
 {
@@ -61,7 +34,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
        else
                reg_cr2 = FSL_SAI_RCR2;
 
-       val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+       regmap_read(sai->regmap, reg_cr2, &val_cr2);
+
        val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
 
        switch (clk_id) {
@@ -81,7 +55,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                return -EINVAL;
        }
 
-       sai_writel(sai, val_cr2, sai->base + reg_cr2);
+       regmap_write(sai->regmap, reg_cr2, val_cr2);
 
        return 0;
 }
@@ -89,32 +63,22 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
 static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int dir)
 {
-       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        int ret;
 
        if (dir == SND_SOC_CLOCK_IN)
                return 0;
 
-       ret = clk_prepare_enable(sai->clk);
-       if (ret)
-               return ret;
-
        ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
                                        FSL_FMT_TRANSMITTER);
        if (ret) {
                dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
-               goto err_clk;
+               return ret;
        }
 
        ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
                                        FSL_FMT_RECEIVER);
-       if (ret) {
+       if (ret)
                dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
-               goto err_clk;
-       }
-
-err_clk:
-       clk_disable_unprepare(sai->clk);
 
        return ret;
 }
@@ -133,43 +97,84 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                reg_cr4 = FSL_SAI_RCR4;
        }
 
-       val_cr2 = sai_readl(sai, sai->base + reg_cr2);
-       val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+       regmap_read(sai->regmap, reg_cr2, &val_cr2);
+       regmap_read(sai->regmap, reg_cr4, &val_cr4);
 
        if (sai->big_endian_data)
                val_cr4 &= ~FSL_SAI_CR4_MF;
        else
                val_cr4 |= FSL_SAI_CR4_MF;
 
+       /* DAI mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               /*
+                * Frame low, 1clk before data, one word length for frame sync,
+                * frame sync starts one serial clock cycle earlier,
+                * that is, together with the last bit of the previous
+                * data word.
+                */
+               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               /*
+                * Frame high, one word length for frame sync,
+                * frame sync asserts with the first bit of the frame.
+                */
+               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               /*
+                * Frame high, 1clk before data, one bit for frame sync,
+                * frame sync starts one serial clock cycle earlier,
+                * that is, together with the last bit of the previous
+                * data word.
+                */
+               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr4 &= ~FSL_SAI_CR4_FSP;
                val_cr4 |= FSL_SAI_CR4_FSE;
+               sai->is_dsp_mode = true;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               /*
+                * Frame high, one bit for frame sync,
+                * frame sync asserts with the first bit of the frame.
+                */
+               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
+               sai->is_dsp_mode = true;
                break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               /* To be done */
        default:
                return -EINVAL;
        }
 
+       /* DAI clock inversion */
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_IB_IF:
-               val_cr4 |= FSL_SAI_CR4_FSP;
-               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               /* Invert both clocks */
+               val_cr2 ^= FSL_SAI_CR2_BCP;
+               val_cr4 ^= FSL_SAI_CR4_FSP;
                break;
        case SND_SOC_DAIFMT_IB_NF:
-               val_cr4 &= ~FSL_SAI_CR4_FSP;
-               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               /* Invert bit clock */
+               val_cr2 ^= FSL_SAI_CR2_BCP;
                break;
        case SND_SOC_DAIFMT_NB_IF:
-               val_cr4 |= FSL_SAI_CR4_FSP;
-               val_cr2 |= FSL_SAI_CR2_BCP;
+               /* Invert frame clock */
+               val_cr4 ^= FSL_SAI_CR4_FSP;
                break;
        case SND_SOC_DAIFMT_NB_NF:
-               val_cr4 &= ~FSL_SAI_CR4_FSP;
-               val_cr2 |= FSL_SAI_CR2_BCP;
+               /* Nothing to do for both normal cases */
                break;
        default:
                return -EINVAL;
        }
 
+       /* DAI clock master masks */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
@@ -179,39 +184,37 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
                val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
                break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+               val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
+               val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+               break;
        default:
                return -EINVAL;
        }
 
-       sai_writel(sai, val_cr2, sai->base + reg_cr2);
-       sai_writel(sai, val_cr4, sai->base + reg_cr4);
+       regmap_write(sai->regmap, reg_cr2, val_cr2);
+       regmap_write(sai->regmap, reg_cr4, val_cr4);
 
        return 0;
 }
 
 static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        int ret;
 
-       ret = clk_prepare_enable(sai->clk);
-       if (ret)
-               return ret;
-
        ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
        if (ret) {
                dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
-               goto err_clk;
+               return ret;
        }
 
        ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
-       if (ret) {
+       if (ret)
                dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
-               goto err_clk;
-       }
-
-err_clk:
-       clk_disable_unprepare(sai->clk);
 
        return ret;
 }
@@ -235,16 +238,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                reg_mr = FSL_SAI_RMR;
        }
 
-       val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+       regmap_read(sai->regmap, reg_cr4, &val_cr4);
+       regmap_read(sai->regmap, reg_cr4, &val_cr5);
+
        val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
        val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
 
-       val_cr5 = sai_readl(sai, sai->base + reg_cr5);
        val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
        val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
        val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
 
-       val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+       if (!sai->is_dsp_mode)
+               val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+
        val_cr5 |= FSL_SAI_CR5_WNW(word_width);
        val_cr5 |= FSL_SAI_CR5_W0W(word_width);
 
@@ -257,9 +263,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
        val_mr = ~0UL - ((1 << channels) - 1);
 
-       sai_writel(sai, val_cr4, sai->base + reg_cr4);
-       sai_writel(sai, val_cr5, sai->base + reg_cr5);
-       sai_writel(sai, val_mr, sai->base + reg_mr);
+       regmap_write(sai->regmap, reg_cr4, val_cr4);
+       regmap_write(sai->regmap, reg_cr5, val_cr5);
+       regmap_write(sai->regmap, reg_mr, val_mr);
 
        return 0;
 }
@@ -268,44 +274,42 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
-       u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3;
-
-       val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2);
-       val_cr2 &= ~FSL_SAI_CR2_SYNC;
-       sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2);
+       u32 tcsr, rcsr;
 
-       val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2);
-       val_cr2 |= FSL_SAI_CR2_SYNC;
-       sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2);
+       /*
+        * The transmitter bit clock and frame sync are to be
+        * used by both the transmitter and receiver.
+        */
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
+                          ~FSL_SAI_CR2_SYNC);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
+                          FSL_SAI_CR2_SYNC);
 
-       tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
-       rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
+       regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
+       regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                tcsr |= FSL_SAI_CSR_FRDE;
                rcsr &= ~FSL_SAI_CSR_FRDE;
-               reg_cr3 = FSL_SAI_TCR3;
        } else {
                rcsr |= FSL_SAI_CSR_FRDE;
                tcsr &= ~FSL_SAI_CSR_FRDE;
-               reg_cr3 = FSL_SAI_RCR3;
        }
 
-       val_cr3 = sai_readl(sai, sai->base + reg_cr3);
-
+       /*
+        * It is recommended that the transmitter is the last enabled
+        * and the first disabled.
+        */
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                tcsr |= FSL_SAI_CSR_TERE;
                rcsr |= FSL_SAI_CSR_TERE;
-               val_cr3 |= FSL_SAI_CR3_TRCE;
 
-               sai_writel(sai, val_cr3, sai->base + reg_cr3);
-               sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
-               sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+               regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
+               regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
                break;
-
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -314,11 +318,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
                        rcsr &= ~FSL_SAI_CSR_TERE;
                }
 
-               val_cr3 &= ~FSL_SAI_CR3_TRCE;
-
-               sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
-               sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
-               sai_writel(sai, val_cr3, sai->base + reg_cr3);
+               regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
+               regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
                break;
        default:
                return -EINVAL;
@@ -331,16 +332,32 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 reg;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               reg = FSL_SAI_TCR3;
+       else
+               reg = FSL_SAI_RCR3;
+
+       regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+                          FSL_SAI_CR3_TRCE);
 
-       return clk_prepare_enable(sai->clk);
+       return 0;
 }
 
 static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+       u32 reg;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               reg = FSL_SAI_TCR3;
+       else
+               reg = FSL_SAI_RCR3;
 
-       clk_disable_unprepare(sai->clk);
+       regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+                          ~FSL_SAI_CR3_TRCE);
 }
 
 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -355,18 +372,13 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
 static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
-       int ret;
 
-       ret = clk_prepare_enable(sai->clk);
-       if (ret)
-               return ret;
-
-       sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
-       sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
-       sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
-       sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
-
-       clk_disable_unprepare(sai->clk);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
+                          FSL_SAI_MAXBURST_TX * 2);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
+                          FSL_SAI_MAXBURST_RX - 1);
 
        snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
                                &sai->dma_params_rx);
@@ -397,26 +409,109 @@ static const struct snd_soc_component_driver fsl_component = {
        .name           = "fsl-sai",
 };
 
+static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case FSL_SAI_TCSR:
+       case FSL_SAI_TCR1:
+       case FSL_SAI_TCR2:
+       case FSL_SAI_TCR3:
+       case FSL_SAI_TCR4:
+       case FSL_SAI_TCR5:
+       case FSL_SAI_TFR:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RCSR:
+       case FSL_SAI_RCR1:
+       case FSL_SAI_RCR2:
+       case FSL_SAI_RCR3:
+       case FSL_SAI_RCR4:
+       case FSL_SAI_RCR5:
+       case FSL_SAI_RDR:
+       case FSL_SAI_RFR:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case FSL_SAI_TFR:
+       case FSL_SAI_RFR:
+       case FSL_SAI_TDR:
+       case FSL_SAI_RDR:
+               return true;
+       default:
+               return false;
+       }
+
+}
+
+static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case FSL_SAI_TCSR:
+       case FSL_SAI_TCR1:
+       case FSL_SAI_TCR2:
+       case FSL_SAI_TCR3:
+       case FSL_SAI_TCR4:
+       case FSL_SAI_TCR5:
+       case FSL_SAI_TDR:
+       case FSL_SAI_TMR:
+       case FSL_SAI_RCSR:
+       case FSL_SAI_RCR1:
+       case FSL_SAI_RCR2:
+       case FSL_SAI_RCR3:
+       case FSL_SAI_RCR4:
+       case FSL_SAI_RCR5:
+       case FSL_SAI_RMR:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static struct regmap_config fsl_sai_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+
+       .max_register = FSL_SAI_RMR,
+       .readable_reg = fsl_sai_readable_reg,
+       .volatile_reg = fsl_sai_volatile_reg,
+       .writeable_reg = fsl_sai_writeable_reg,
+};
+
 static int fsl_sai_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct fsl_sai *sai;
        struct resource *res;
+       void __iomem *base;
        int ret;
 
        sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
        if (!sai)
                return -ENOMEM;
 
+       sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
+       if (sai->big_endian_regs)
+               fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
+       sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       sai->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(sai->base))
-               return PTR_ERR(sai->base);
-
-       sai->clk = devm_clk_get(&pdev->dev, "sai");
-       if (IS_ERR(sai->clk)) {
-               dev_err(&pdev->dev, "Cannot get SAI's clock\n");
-               return PTR_ERR(sai->clk);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "sai", base, &fsl_sai_regmap_config);
+       if (IS_ERR(sai->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               return PTR_ERR(sai->regmap);
        }
 
        sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
@@ -424,9 +519,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
        sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
        sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
 
-       sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
-       sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
-
        platform_set_drvdata(pdev, sai);
 
        ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
index 41bb62e6936150b689791a4fe33dccbe2ab2ea85..e432260be598ed2cabebbdadcbb60730d96166ed 100644 (file)
                         SNDRV_PCM_FMTBIT_S20_3LE |\
                         SNDRV_PCM_FMTBIT_S24_LE)
 
+/* SAI Register Map Register */
+#define FSL_SAI_TCSR   0x00 /* SAI Transmit Control */
+#define FSL_SAI_TCR1   0x04 /* SAI Transmit Configuration 1 */
+#define FSL_SAI_TCR2   0x08 /* SAI Transmit Configuration 2 */
+#define FSL_SAI_TCR3   0x0c /* SAI Transmit Configuration 3 */
+#define FSL_SAI_TCR4   0x10 /* SAI Transmit Configuration 4 */
+#define FSL_SAI_TCR5   0x14 /* SAI Transmit Configuration 5 */
+#define FSL_SAI_TDR    0x20 /* SAI Transmit Data */
+#define FSL_SAI_TFR    0x40 /* SAI Transmit FIFO */
+#define FSL_SAI_TMR    0x60 /* SAI Transmit Mask */
+#define FSL_SAI_RCSR   0x80 /* SAI Receive Control */
+#define FSL_SAI_RCR1   0x84 /* SAI Receive Configuration 1 */
+#define FSL_SAI_RCR2   0x88 /* SAI Receive Configuration 2 */
+#define FSL_SAI_RCR3   0x8c /* SAI Receive Configuration 3 */
+#define FSL_SAI_RCR4   0x90 /* SAI Receive Configuration 4 */
+#define FSL_SAI_RCR5   0x94 /* SAI Receive Configuration 5 */
+#define FSL_SAI_RDR    0xa0 /* SAI Receive Data */
+#define FSL_SAI_RFR    0xc0 /* SAI Receive FIFO */
+#define FSL_SAI_RMR    0xe0 /* SAI Receive Mask */
+
 /* SAI Transmit/Recieve Control Register */
-#define FSL_SAI_TCSR           0x00
-#define FSL_SAI_RCSR           0x80
 #define FSL_SAI_CSR_TERE       BIT(31)
 #define FSL_SAI_CSR_FWF                BIT(17)
 #define FSL_SAI_CSR_FRIE       BIT(8)
 #define FSL_SAI_CSR_FRDE       BIT(0)
 
-/* SAI Transmit Data/FIFO/MASK Register */
-#define FSL_SAI_TDR            0x20
-#define FSL_SAI_TFR            0x40
-#define FSL_SAI_TMR            0x60
-
-/* SAI Recieve Data/FIFO/MASK Register */
-#define FSL_SAI_RDR            0xa0
-#define FSL_SAI_RFR            0xc0
-#define FSL_SAI_RMR            0xe0
-
 /* SAI Transmit and Recieve Configuration 1 Register */
-#define FSL_SAI_TCR1           0x04
-#define FSL_SAI_RCR1           0x84
+#define FSL_SAI_CR1_RFW_MASK   0x1f
 
 /* SAI Transmit and Recieve Configuration 2 Register */
-#define FSL_SAI_TCR2           0x08
-#define FSL_SAI_RCR2           0x88
 #define FSL_SAI_CR2_SYNC       BIT(30)
 #define FSL_SAI_CR2_MSEL_MASK  (0xff << 26)
 #define FSL_SAI_CR2_MSEL_BUS   0
 #define FSL_SAI_CR2_BCD_MSTR   BIT(24)
 
 /* SAI Transmit and Recieve Configuration 3 Register */
-#define FSL_SAI_TCR3           0x0c
-#define FSL_SAI_RCR3           0x8c
 #define FSL_SAI_CR3_TRCE       BIT(16)
 #define FSL_SAI_CR3_WDFL(x)    (x)
 #define FSL_SAI_CR3_WDFL_MASK  0x1f
 
 /* SAI Transmit and Recieve Configuration 4 Register */
-#define FSL_SAI_TCR4           0x10
-#define FSL_SAI_RCR4           0x90
 #define FSL_SAI_CR4_FRSZ(x)    (((x) - 1) << 16)
 #define FSL_SAI_CR4_FRSZ_MASK  (0x1f << 16)
 #define FSL_SAI_CR4_SYWD(x)    (((x) - 1) << 8)
@@ -69,8 +70,6 @@
 #define FSL_SAI_CR4_FSD_MSTR   BIT(0)
 
 /* SAI Transmit and Recieve Configuration 5 Register */
-#define FSL_SAI_TCR5           0x14
-#define FSL_SAI_RCR5           0x94
 #define FSL_SAI_CR5_WNW(x)     (((x) - 1) << 24)
 #define FSL_SAI_CR5_WNW_MASK   (0x1f << 24)
 #define FSL_SAI_CR5_W0W(x)     (((x) - 1) << 16)
 #define FSL_SAI_MAXBURST_RX 6
 
 struct fsl_sai {
-       struct clk *clk;
-
-       void __iomem *base;
+       struct regmap *regmap;
 
        bool big_endian_regs;
        bool big_endian_data;
+       bool is_dsp_mode;
 
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
index 4d075f1abe7803387bb01dbb39a2d66a0eac4c59..6452ca83d8893eb35cdc842b8991366c4684c6e2 100644 (file)
@@ -911,8 +911,8 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
 
-       dai->playback_dma_data = &spdif_private->dma_params_tx;
-       dai->capture_dma_data = &spdif_private->dma_params_rx;
+       snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx,
+                                 &spdif_private->dma_params_rx);
 
        snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
 
@@ -985,7 +985,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static const struct regmap_config fsl_spdif_regmap_config = {
+static struct regmap_config fsl_spdif_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
@@ -1105,6 +1105,9 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
        spdif_priv->cpu_dai_drv.name = spdif_priv->name;
 
+       if (of_property_read_bool(np, "big-endian"))
+               fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(&pdev->dev, res);
index b9e42b503a37728b8a20a14a3979ada69ed82872..2ac7755da8768dfe2b12a9d35a5aa5eda9e1d766 100644 (file)
@@ -86,6 +86,33 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
 }
 EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
 
+/**
+ * fsl_asoc_xlate_tdm_slot_mask - generate TDM slot TX/RX mask.
+ *
+ * @slots: Number of slots in use.
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
+ *
+ * This function used to generate the TDM slot TX/RX mask. And the TX/RX
+ * mask will use a 0 bit for an active slot as default, and the default
+ * active bits are at the LSB of the mask value.
+ */
+int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
+                                   unsigned int *tx_mask,
+                                   unsigned int *rx_mask)
+{
+       if (!slots)
+               return -EINVAL;
+
+       if (tx_mask)
+               *tx_mask = ~((1 << slots) - 1);
+       if (rx_mask)
+               *rx_mask = ~((1 << slots) - 1);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_xlate_tdm_slot_mask);
+
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale ASoC utility code");
 MODULE_LICENSE("GPL v2");
index b2951126527c0868595954f0857cf99a05dbd5df..df535db40313e61ae25d6e46ba68a149c5e62346 100644 (file)
@@ -22,5 +22,7 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
                             struct snd_soc_dai_link *dai,
                             unsigned int *dma_channel_id,
                             unsigned int *dma_id);
-
+int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
+                                   unsigned int *tx_mask,
+                                   unsigned int *rx_mask);
 #endif /* _FSL_UTILS_H */
index 6553202dd48c09d19fe2916447f553023276a897..7abf6a07957451235ee2863144d3a7377890f1fc 100644 (file)
@@ -270,18 +270,17 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
        if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
-out:
-       return ret;
+       return 0;
 }
 
 static int ssi_irq = 0;
index df552fa1aa65f13faee928c63d2a8b8bf6c9eae4..ab2fdd76b693a28aacbcef5aa0edf8aded9727e5 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/platform_data/asoc-imx-ssi.h>
 
 #include "imx-ssi.h"
+#include "fsl_utils.h"
 
 #define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
 
@@ -339,6 +340,7 @@ static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
        .set_fmt        = imx_ssi_set_dai_fmt,
        .set_clkdiv     = imx_ssi_set_dai_clkdiv,
        .set_sysclk     = imx_ssi_set_dai_sysclk,
+       .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
        .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
        .trigger        = imx_ssi_trigger,
 };
index fce63252bdbbfda7cc1d7d0cefa2295f26faf43d..804749a6c61e3241763eace3f935f95b978a0d17 100644 (file)
@@ -214,12 +214,6 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets,
-                                 ARRAY_SIZE(wm1133_ev1_widgets));
-
-       snd_soc_dapm_add_routes(dapm, wm1133_ev1_map,
-                               ARRAY_SIZE(wm1133_ev1_map));
-
        /* Headphone jack detection */
        snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
        snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
@@ -257,6 +251,11 @@ static struct snd_soc_card wm1133_ev1 = {
        .owner = THIS_MODULE,
        .dai_link = &wm1133_ev1_dai,
        .num_links = 1,
+
+       .dapm_widgets = wm1133_ev1_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets),
+       .dapm_routes = wm1133_ev1_map,
+       .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map),
 };
 
 static struct platform_device *wm1133_ev1_snd_device;
index 2a1b1b5b5221089f32e395087e9c4651ddd00799..21f1ccbdf58299624816d312a61aff0b8ffa53fb 100644 (file)
@@ -9,48 +9,77 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
 #include <sound/simple_card.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+
+struct simple_card_data {
+       struct snd_soc_card snd_card;
+       struct simple_dai_props {
+               struct asoc_simple_dai cpu_dai;
+               struct asoc_simple_dai codec_dai;
+       } *dai_props;
+       struct snd_soc_dai_link dai_link[];     /* dynamically allocated */
+};
 
 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
-                                      struct asoc_simple_dai *set,
-                                      unsigned int daifmt)
+                                      struct asoc_simple_dai *set)
 {
-       int ret = 0;
+       int ret;
 
-       daifmt |= set->fmt;
+       if (set->fmt) {
+               ret = snd_soc_dai_set_fmt(dai, set->fmt);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dai->dev, "simple-card: set_fmt error\n");
+                       goto err;
+               }
+       }
 
-       if (daifmt)
-               ret = snd_soc_dai_set_fmt(dai, daifmt);
+       if (set->sysclk) {
+               ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dai->dev, "simple-card: set_sysclk error\n");
+                       goto err;
+               }
+       }
 
-       if (ret == -ENOTSUPP) {
-               dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n");
-               ret = 0;
+       if (set->slots) {
+               ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
+                                               set->slots,
+                                               set->slot_width);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
+                       goto err;
+               }
        }
 
-       if (!ret && set->sysclk)
-               ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
+       ret = 0;
 
+err:
        return ret;
 }
 
 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct asoc_simple_card_info *info =
+       struct simple_card_data *priv =
                                snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_dai *codec = rtd->codec_dai;
        struct snd_soc_dai *cpu = rtd->cpu_dai;
-       unsigned int daifmt = info->daifmt;
-       int ret;
+       struct simple_dai_props *dai_props;
+       int num, ret;
 
-       ret = __asoc_simple_card_dai_init(codec, &info->codec_dai, daifmt);
+       num = rtd - rtd->card->rtd;
+       dai_props = &priv->dai_props[num];
+       ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
        if (ret < 0)
                return ret;
 
-       ret = __asoc_simple_card_dai_init(cpu, &info->cpu_dai, daifmt);
+       ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
        if (ret < 0)
                return ret;
 
@@ -59,9 +88,12 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 
 static int
 asoc_simple_card_sub_parse_of(struct device_node *np,
+                             unsigned int daifmt,
                              struct asoc_simple_dai *dai,
-                             struct device_node **node)
+                             const struct device_node **p_node,
+                             const char **name)
 {
+       struct device_node *node;
        struct clk *clk;
        int ret;
 
@@ -69,14 +101,20 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
         * get node via "sound-dai = <&phandle port>"
         * it will be used as xxx_of_node on soc_bind_dai_link()
         */
-       *node = of_parse_phandle(np, "sound-dai", 0);
-       if (!*node)
+       node = of_parse_phandle(np, "sound-dai", 0);
+       if (!node)
                return -ENODEV;
+       *p_node = node;
 
        /* get dai->name */
-       ret = snd_soc_of_get_dai_name(np, &dai->name);
+       ret = snd_soc_of_get_dai_name(np, name);
        if (ret < 0)
-               goto parse_error;
+               return ret;
+
+       /* parse TDM slot */
+       ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
+       if (ret)
+               return ret;
 
        /*
         * bitclock-inversion, frame-inversion
@@ -84,6 +122,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
         * and specific "format" if it has
         */
        dai->fmt = snd_soc_of_parse_daifmt(np, NULL);
+       dai->fmt |= daifmt;
 
        /*
         * dai->sysclk come from
@@ -95,7 +134,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
                clk = of_clk_get(np, 0);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       goto parse_error;
+                       return ret;
                }
 
                dai->sysclk = clk_get_rate(clk);
@@ -104,164 +143,278 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
                                     "system-clock-frequency",
                                     &dai->sysclk);
        } else {
-               clk = of_clk_get(*node, 0);
+               clk = of_clk_get(node, 0);
                if (!IS_ERR(clk))
                        dai->sysclk = clk_get_rate(clk);
        }
 
-       ret = 0;
+       return 0;
+}
+
+static int simple_card_cpu_codec_of(struct device_node *node,
+                               int daifmt,
+                               struct snd_soc_dai_link *dai_link,
+                               struct simple_dai_props *dai_props)
+{
+       struct device_node *np;
+       int ret;
 
-parse_error:
-       of_node_put(*node);
+       /* CPU sub-node */
+       ret = -EINVAL;
+       np = of_get_child_by_name(node, "simple-audio-card,cpu");
+       if (np) {
+               ret = asoc_simple_card_sub_parse_of(np, daifmt,
+                                               &dai_props->cpu_dai,
+                                               &dai_link->cpu_of_node,
+                                               &dai_link->cpu_dai_name);
+               of_node_put(np);
+       }
+       if (ret < 0)
+               return ret;
 
+       /* CODEC sub-node */
+       ret = -EINVAL;
+       np = of_get_child_by_name(node, "simple-audio-card,codec");
+       if (np) {
+               ret = asoc_simple_card_sub_parse_of(np, daifmt,
+                                               &dai_props->codec_dai,
+                                               &dai_link->codec_of_node,
+                                               &dai_link->codec_dai_name);
+               of_node_put(np);
+       }
        return ret;
 }
 
 static int asoc_simple_card_parse_of(struct device_node *node,
-                                    struct asoc_simple_card_info *info,
+                                    struct simple_card_data *priv,
                                     struct device *dev,
-                                    struct device_node **of_cpu,
-                                    struct device_node **of_codec,
-                                    struct device_node **of_platform)
+                                    int multi)
 {
+       struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
+       struct simple_dai_props *dai_props = priv->dai_props;
        struct device_node *np;
        char *name;
+       unsigned int daifmt;
        int ret;
 
+       /* parsing the card name from DT */
+       snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
+
        /* get CPU/CODEC common format via simple-audio-card,format */
-       info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
+       daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
                (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
 
+       /* off-codec widgets */
+       if (of_property_read_bool(node, "simple-audio-card,widgets")) {
+               ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
+                                       "simple-audio-card,widgets");
+               if (ret)
+                       return ret;
+       }
+
        /* DAPM routes */
        if (of_property_read_bool(node, "simple-audio-card,routing")) {
-               ret = snd_soc_of_parse_audio_routing(&info->snd_card,
+               ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
                                        "simple-audio-card,routing");
                if (ret)
                        return ret;
        }
 
-       /* CPU sub-node */
-       ret = -EINVAL;
-       np = of_get_child_by_name(node, "simple-audio-card,cpu");
-       if (np)
-               ret = asoc_simple_card_sub_parse_of(np,
-                                                 &info->cpu_dai,
-                                                 of_cpu);
-       if (ret < 0)
-               return ret;
+       /* loop on the DAI links */
+       np = NULL;
+       for (;;) {
+               if (multi) {
+                       np = of_get_next_child(node, np);
+                       if (!np)
+                               break;
+               }
 
-       /* CODEC sub-node */
-       ret = -EINVAL;
-       np = of_get_child_by_name(node, "simple-audio-card,codec");
-       if (np)
-               ret = asoc_simple_card_sub_parse_of(np,
-                                                 &info->codec_dai,
-                                                 of_codec);
-       if (ret < 0)
-               return ret;
+               ret = simple_card_cpu_codec_of(multi ? np : node,
+                                       daifmt, dai_link, dai_props);
+               if (ret < 0)
+                       goto err;
+
+               /*
+                * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
+                * while the other bits should be identical unless buggy SW/HW design.
+                */
+               dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
+
+               if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               /* simple-card assumes platform == cpu */
+               dai_link->platform_of_node = dai_link->cpu_of_node;
+
+               name = devm_kzalloc(dev,
+                                   strlen(dai_link->cpu_dai_name)   +
+                                   strlen(dai_link->codec_dai_name) + 2,
+                                   GFP_KERNEL);
+               sprintf(name, "%s-%s", dai_link->cpu_dai_name,
+                                       dai_link->codec_dai_name);
+               dai_link->name = dai_link->stream_name = name;
 
-       if (!info->cpu_dai.name || !info->codec_dai.name)
-               return -EINVAL;
+               if (!multi)
+                       break;
+
+               dai_link++;
+               dai_props++;
+       }
 
        /* card name is created from CPU/CODEC dai name */
-       name = devm_kzalloc(dev,
-                           strlen(info->cpu_dai.name)   +
-                           strlen(info->codec_dai.name) + 2,
-                           GFP_KERNEL);
-       sprintf(name, "%s-%s", info->cpu_dai.name, info->codec_dai.name);
-       info->name = info->card = name;
-
-       /* simple-card assumes platform == cpu */
-       *of_platform = *of_cpu;
-
-       dev_dbg(dev, "card-name : %s\n", info->card);
-       dev_dbg(dev, "platform : %04x\n", info->daifmt);
+       dai_link = priv->snd_card.dai_link;
+       if (!priv->snd_card.name)
+               priv->snd_card.name = dai_link->name;
+
+       dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
+       dev_dbg(dev, "platform : %04x\n", daifmt);
+       dai_props = priv->dai_props;
        dev_dbg(dev, "cpu : %s / %04x / %d\n",
-               info->cpu_dai.name,
-               info->cpu_dai.fmt,
-               info->cpu_dai.sysclk);
+               dai_link->cpu_dai_name,
+               dai_props->cpu_dai.fmt,
+               dai_props->cpu_dai.sysclk);
        dev_dbg(dev, "codec : %s / %04x / %d\n",
-               info->codec_dai.name,
-               info->codec_dai.fmt,
-               info->codec_dai.sysclk);
+               dai_link->codec_dai_name,
+               dai_props->codec_dai.fmt,
+               dai_props->codec_dai.sysclk);
 
        return 0;
+
+err:
+       of_node_put(np);
+       return ret;
+}
+
+/* update the reference count of the devices nodes at end of probe */
+static int asoc_simple_card_unref(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct snd_soc_dai_link *dai_link;
+       struct device_node *np;
+       int num_links;
+
+       for (num_links = 0, dai_link = card->dai_link;
+            num_links < card->num_links;
+            num_links++, dai_link++) {
+               np = (struct device_node *) dai_link->cpu_of_node;
+               if (np)
+                       of_node_put(np);
+               np = (struct device_node *) dai_link->codec_of_node;
+               if (np)
+                       of_node_put(np);
+       }
+       return 0;
 }
 
 static int asoc_simple_card_probe(struct platform_device *pdev)
 {
-       struct asoc_simple_card_info *cinfo;
+       struct simple_card_data *priv;
+       struct snd_soc_dai_link *dai_link;
        struct device_node *np = pdev->dev.of_node;
-       struct device_node *of_cpu, *of_codec, *of_platform;
        struct device *dev = &pdev->dev;
-       int ret;
+       int num_links, multi, ret;
+
+       /* get the number of DAI links */
+       if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
+               num_links = of_get_child_count(np);
+               multi = 1;
+       } else {
+               num_links = 1;
+               multi = 0;
+       }
 
-       cinfo           = NULL;
-       of_cpu          = NULL;
-       of_codec        = NULL;
-       of_platform     = NULL;
+       /* allocate the private data and the DAI link array */
+       priv = devm_kzalloc(dev,
+                       sizeof(*priv) + sizeof(*dai_link) * num_links,
+                       GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
-       cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
-       if (!cinfo)
+       /*
+        * init snd_soc_card
+        */
+       priv->snd_card.owner = THIS_MODULE;
+       priv->snd_card.dev = dev;
+       dai_link = priv->dai_link;
+       priv->snd_card.dai_link = dai_link;
+       priv->snd_card.num_links = num_links;
+
+       /* get room for the other properties */
+       priv->dai_props = devm_kzalloc(dev,
+                       sizeof(*priv->dai_props) * num_links,
+                       GFP_KERNEL);
+       if (!priv->dai_props)
                return -ENOMEM;
 
        if (np && of_device_is_available(np)) {
-               cinfo->snd_card.dev = dev;
 
-               ret = asoc_simple_card_parse_of(np, cinfo, dev,
-                                               &of_cpu,
-                                               &of_codec,
-                                               &of_platform);
+               ret = asoc_simple_card_parse_of(np, priv, dev, multi);
                if (ret < 0) {
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "parse error %d\n", ret);
-                       return ret;
+                       goto err;
                }
+
+               /*
+                * soc_bind_dai_link() will check cpu name
+                * after of_node matching if dai_link has cpu_dai_name.
+                * but, it will never match if name was created by fmt_single_name()
+                * remove cpu_dai_name to escape name matching.
+                * see
+                *      fmt_single_name()
+                *      fmt_multiple_name()
+                */
+               if (num_links == 1)
+                       dai_link->cpu_dai_name = NULL;
+
        } else {
-               if (!dev->platform_data) {
+               struct asoc_simple_card_info *cinfo;
+
+               cinfo = dev->platform_data;
+               if (!cinfo) {
                        dev_err(dev, "no info for asoc-simple-card\n");
                        return -EINVAL;
                }
 
-               memcpy(cinfo, dev->platform_data, sizeof(*cinfo));
-               cinfo->snd_card.dev = dev;
-       }
+               if (!cinfo->name        ||
+                   !cinfo->codec_dai.name      ||
+                   !cinfo->codec       ||
+                   !cinfo->platform    ||
+                   !cinfo->cpu_dai.name) {
+                       dev_err(dev, "insufficient asoc_simple_card_info settings\n");
+                       return -EINVAL;
+               }
 
-       if (!cinfo->name        ||
-           !cinfo->card        ||
-           !cinfo->codec_dai.name      ||
-           !(cinfo->codec              || of_codec)    ||
-           !(cinfo->platform           || of_platform) ||
-           !(cinfo->cpu_dai.name       || of_cpu)) {
-               dev_err(dev, "insufficient asoc_simple_card_info settings\n");
-               return -EINVAL;
+               priv->snd_card.name     = (cinfo->card) ? cinfo->card : cinfo->name;
+               dai_link->name          = cinfo->name;
+               dai_link->stream_name   = cinfo->name;
+               dai_link->platform_name = cinfo->platform;
+               dai_link->codec_name    = cinfo->codec;
+               dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
+               dai_link->codec_dai_name = cinfo->codec_dai.name;
+               memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
+                                       sizeof(priv->dai_props->cpu_dai));
+               memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
+                                       sizeof(priv->dai_props->codec_dai));
+
+               priv->dai_props->cpu_dai.fmt    |= cinfo->daifmt;
+               priv->dai_props->codec_dai.fmt  |= cinfo->daifmt;
        }
 
        /*
         * init snd_soc_dai_link
         */
-       cinfo->snd_link.name            = cinfo->name;
-       cinfo->snd_link.stream_name     = cinfo->name;
-       cinfo->snd_link.cpu_dai_name    = cinfo->cpu_dai.name;
-       cinfo->snd_link.platform_name   = cinfo->platform;
-       cinfo->snd_link.codec_name      = cinfo->codec;
-       cinfo->snd_link.codec_dai_name  = cinfo->codec_dai.name;
-       cinfo->snd_link.cpu_of_node     = of_cpu;
-       cinfo->snd_link.codec_of_node   = of_codec;
-       cinfo->snd_link.platform_of_node = of_platform;
-       cinfo->snd_link.init            = asoc_simple_card_dai_init;
+       dai_link->init = asoc_simple_card_dai_init;
 
-       /*
-        * init snd_soc_card
-        */
-       cinfo->snd_card.name            = cinfo->card;
-       cinfo->snd_card.owner           = THIS_MODULE;
-       cinfo->snd_card.dai_link        = &cinfo->snd_link;
-       cinfo->snd_card.num_links       = 1;
+       snd_soc_card_set_drvdata(&priv->snd_card, priv);
 
-       snd_soc_card_set_drvdata(&cinfo->snd_card, cinfo);
+       ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
 
-       return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card);
+err:
+       asoc_simple_card_unref(pdev);
+       return ret;
 }
 
 static const struct of_device_id asoc_simple_of_match[] = {
index 61c10bf503d229f7a191a12ceb17232b63af4597..3c81b3891209731cc96b021038fe35e327a568e5 100644 (file)
@@ -2,12 +2,50 @@ config SND_MFLD_MACHINE
        tristate "SOC Machine Audio driver for Intel Medfield MID platform"
        depends on INTEL_SCU_IPC
        select SND_SOC_SN95031
-       select SND_SST_PLATFORM
+       select SND_SST_MFLD_PLATFORM
        help
           This adds support for ASoC machine driver for Intel(R) MID Medfield platform
           used as alsa device in audio substem in Intel(R) MID devices
           Say Y if you have such a device
           If unsure select "N".
 
-config SND_SST_PLATFORM
+config SND_SST_MFLD_PLATFORM
        tristate
+
+config SND_SOC_INTEL_SST
+       tristate "ASoC support for Intel(R) Smart Sound Technology"
+       select SND_SOC_INTEL_SST_ACPI if ACPI
+       depends on (X86 || COMPILE_TEST)
+       help
+          This adds support for Intel(R) Smart Sound Technology (SST).
+          Say Y if you have such a device
+          If unsure select "N".
+
+config SND_SOC_INTEL_SST_ACPI
+       tristate
+
+config SND_SOC_INTEL_HASWELL
+       tristate
+
+config SND_SOC_INTEL_BAYTRAIL
+       tristate
+
+config SND_SOC_INTEL_HASWELL_MACH
+       tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
+       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+       select SND_SOC_INTEL_HASWELL
+       select SND_SOC_RT5640
+       help
+         This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
+         Ultrabook platforms.
+         Say Y if you have such a device
+         If unsure select "N".
+
+config SND_SOC_INTEL_BYT_RT5640_MACH
+       tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
+       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+       select SND_SOC_INTEL_BAYTRAIL
+       select SND_SOC_RT5640
+       help
+         This adds audio driver for Intel Baytrail platform based boards
+         with the RT5640 audio codec.
index 639883339465f1dcccd6f60d6544ee7ba532f8e3..edeb79ae3dff211c975295d982df133205591012 100644 (file)
@@ -1,5 +1,28 @@
-snd-soc-sst-platform-objs := sst_platform.o
+# Core support
+snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
+snd-soc-sst-acpi-objs := sst-acpi.o
+
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o
 snd-soc-mfld-machine-objs := mfld_machine.o
 
-obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o
+obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
 obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
+
+obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o
+obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
+
+# Platform Support
+snd-soc-sst-haswell-pcm-objs := \
+       sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o
+snd-soc-sst-baytrail-pcm-objs := \
+       sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
+
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
+
+# Machine support
+snd-soc-sst-haswell-objs := haswell.o
+snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
+
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
+obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
new file mode 100644 (file)
index 0000000..eff97c8
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Intel Baytrail SST RT5640 machine driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5640.h"
+
+#include "sst-dsp.h"
+
+static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
+       {"IN2P", NULL, "Headset Mic"},
+       {"IN2N", NULL, "Headset Mic"},
+       {"DMIC1", NULL, "Internal Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Speaker", NULL, "SPOLP"},
+       {"Speaker", NULL, "SPOLN"},
+       {"Speaker", NULL, "SPORP"},
+       {"Speaker", NULL, "SPORN"},
+};
+
+static const struct snd_kcontrol_new byt_rt5640_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic"),
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int byt_rt5640_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;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+                                    params_rate(params) * 256,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
+               return ret;
+       }
+       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
+                                 params_rate(params) * 64,
+                                 params_rate(params) * 256);
+       if (ret < 0) {
+               dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_codec *codec = runtime->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_card *card = runtime->card;
+
+       card->dapm.idle_bias_off = true;
+
+       ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
+                                       ARRAY_SIZE(byt_rt5640_controls));
+       if (ret) {
+               dev_err(card->dev, "unable to add card controls\n");
+               return ret;
+       }
+
+       snd_soc_dapm_ignore_suspend(dapm, "HPOL");
+       snd_soc_dapm_ignore_suspend(dapm, "HPOR");
+
+       snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
+       snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
+       snd_soc_dapm_ignore_suspend(dapm, "SPORP");
+       snd_soc_dapm_ignore_suspend(dapm, "SPORN");
+
+       snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+       snd_soc_dapm_enable_pin(dapm, "Headphone");
+       snd_soc_dapm_enable_pin(dapm, "Speaker");
+       snd_soc_dapm_enable_pin(dapm, "Internal Mic");
+
+       snd_soc_dapm_sync(dapm);
+       return ret;
+}
+
+static struct snd_soc_ops byt_rt5640_ops = {
+       .hw_params = byt_rt5640_hw_params,
+};
+
+static struct snd_soc_dai_link byt_rt5640_dais[] = {
+       {
+               .name = "Baytrail Audio",
+               .stream_name = "Audio",
+               .cpu_dai_name = "Front-cpu-dai",
+               .codec_dai_name = "rt5640-aif1",
+               .codec_name = "i2c-10EC5640:00",
+               .platform_name = "baytrail-pcm-audio",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .init = byt_rt5640_init,
+               .ignore_suspend = 1,
+               .ops = &byt_rt5640_ops,
+       },
+       {
+               .name = "Baytrail Voice",
+               .stream_name = "Voice",
+               .cpu_dai_name = "Mic1-cpu-dai",
+               .codec_dai_name = "rt5640-aif1",
+               .codec_name = "i2c-10EC5640:00",
+               .platform_name = "baytrail-pcm-audio",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
+               .init = NULL,
+               .ignore_suspend = 1,
+               .ops = &byt_rt5640_ops,
+       },
+};
+
+static struct snd_soc_card byt_rt5640_card = {
+       .name = "byt-rt5640",
+       .dai_link = byt_rt5640_dais,
+       .num_links = ARRAY_SIZE(byt_rt5640_dais),
+       .dapm_widgets = byt_rt5640_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
+       .dapm_routes = byt_rt5640_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+};
+
+static int byt_rt5640_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &byt_rt5640_card;
+       struct device *dev = &pdev->dev;
+
+       card->dev = &pdev->dev;
+       dev_set_drvdata(dev, card);
+       return snd_soc_register_card(card);
+}
+
+static int byt_rt5640_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver byt_rt5640_audio = {
+       .probe = byt_rt5640_probe,
+       .remove = byt_rt5640_remove,
+       .driver = {
+               .name = "byt-rt5640",
+               .owner = THIS_MODULE,
+       },
+};
+module_platform_driver(byt_rt5640_audio)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
+MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:byt-rt5640");
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
new file mode 100644 (file)
index 0000000..54345a2
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Intel Haswell Lynxpoint SST Audio
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "sst-dsp.h"
+#include "sst-haswell-ipc.h"
+
+#include "../codecs/rt5640.h"
+
+/* Haswell ULT platforms have a Headphone and Mic jack */
+static const struct snd_soc_dapm_widget haswell_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
+
+       {"Headphones", NULL, "HPOR"},
+       {"Headphones", NULL, "HPOL"},
+       {"IN2P", NULL, "Mic"},
+
+       /* CODEC BE connections */
+       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 16 bit */
+       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
+                                   SNDRV_PCM_FORMAT_S16_LE);
+       return 0;
+}
+
+static int haswell_rt5640_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;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
+               SND_SOC_CLOCK_IN);
+
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+               return ret;
+       }
+
+       /* set correct codec filter for DAI format and clock config */
+       snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
+
+       return ret;
+}
+
+static struct snd_soc_ops haswell_rt5640_ops = {
+       .hw_params = haswell_rt5640_hw_params,
+};
+
+static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+       struct sst_hsw *haswell = pdata->dsp;
+       int ret;
+
+       /* Set ADSP SSP port settings */
+       ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
+               SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+               SST_HSW_DEVICE_CLOCK_MASTER, 9);
+       if (ret < 0) {
+               dev_err(rtd->dev, "failed to set device config\n");
+               return ret;
+       }
+
+       /* always connected */
+       snd_soc_dapm_enable_pin(dapm, "Headphones");
+       snd_soc_dapm_enable_pin(dapm, "Mic");
+
+       return 0;
+}
+
+static struct snd_soc_dai_link haswell_rt5640_dais[] = {
+       /* Front End DAI links */
+       {
+               .name = "System",
+               .stream_name = "System Playback",
+               .cpu_dai_name = "System Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .init = haswell_rtd_init,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Offload0",
+               .stream_name = "Offload0 Playback",
+               .cpu_dai_name = "Offload0 Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Offload1",
+               .stream_name = "Offload1 Playback",
+               .cpu_dai_name = "Offload1 Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+       },
+       {
+               .name = "Loopback",
+               .stream_name = "Loopback",
+               .cpu_dai_name = "Loopback Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 0,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+       },
+       {
+               .name = "Capture",
+               .stream_name = "Capture",
+               .cpu_dai_name = "Capture Pin",
+               .platform_name = "haswell-pcm-audio",
+               .dynamic = 1,
+               .codec_name = "snd-soc-dummy",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+       },
+
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "Codec",
+               .be_id = 0,
+               .cpu_dai_name = "snd-soc-dummy-dai",
+               .platform_name = "snd-soc-dummy",
+               .no_pcm = 1,
+               .codec_name = "i2c-INT33CA:00",
+               .codec_dai_name = "rt5640-aif1",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = haswell_ssp0_fixup,
+               .ops = &haswell_rt5640_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+       },
+};
+
+/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
+static struct snd_soc_card haswell_rt5640 = {
+       .name = "haswell-rt5640",
+       .owner = THIS_MODULE,
+       .dai_link = haswell_rt5640_dais,
+       .num_links = ARRAY_SIZE(haswell_rt5640_dais),
+       .dapm_widgets = haswell_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
+       .dapm_routes = haswell_rt5640_map,
+       .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
+       .fully_routed = true,
+};
+
+static int haswell_audio_probe(struct platform_device *pdev)
+{
+       haswell_rt5640.dev = &pdev->dev;
+
+       return snd_soc_register_card(&haswell_rt5640);
+}
+
+static int haswell_audio_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&haswell_rt5640);
+       return 0;
+}
+
+static struct platform_driver haswell_audio = {
+       .probe = haswell_audio_probe,
+       .remove = haswell_audio_remove,
+       .driver = {
+               .name = "haswell-audio",
+               .owner = THIS_MODULE,
+       },
+};
+
+module_platform_driver(haswell_audio)
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:haswell-audio");
index d3d4c32434f7614d944296b34b9b87f6c80a66b3..031d78783fc8cb8c824f961947c640685f7f95fb 100644 (file)
@@ -53,6 +53,7 @@ enum soc_mic_bias_zones {
 
 static unsigned int    hs_switch;
 static unsigned int    lo_dac;
+static struct snd_soc_codec *mfld_codec;
 
 struct mfld_mc_private {
        void __iomem *int_base;
@@ -100,40 +101,47 @@ static int headset_get_switch(struct snd_kcontrol *kcontrol,
 static int headset_set_switch(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 snd_soc_dapm_context *dapm = &card->dapm;
 
        if (ucontrol->value.integer.value[0] == hs_switch)
                return 0;
 
+       snd_soc_dapm_mutex_lock(dapm);
+
        if (ucontrol->value.integer.value[0]) {
                pr_debug("hs_set HS path\n");
-               snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
-               snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
        } else {
                pr_debug("hs_set EP path\n");
-               snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
-               snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
        }
-       snd_soc_dapm_sync(&codec->dapm);
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+
        hs_switch = ucontrol->value.integer.value[0];
 
        return 0;
 }
 
-static void lo_enable_out_pins(struct snd_soc_codec *codec)
+static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
 {
-       snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL");
-       snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR");
-       snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL");
-       snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR");
-       snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT");
-       snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
        if (hs_switch) {
-               snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
-               snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
        } else {
-               snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
-               snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
        }
 }
 
@@ -147,45 +155,53 @@ static int lo_get_switch(struct snd_kcontrol *kcontrol,
 static int lo_set_switch(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 snd_soc_dapm_context *dapm = &card->dapm;
 
        if (ucontrol->value.integer.value[0] == lo_dac)
                return 0;
 
+       snd_soc_dapm_mutex_lock(dapm);
+
        /* we dont want to work with last state of lineout so just enable all
         * pins and then disable pins not required
         */
-       lo_enable_out_pins(codec);
+       lo_enable_out_pins(dapm);
+
        switch (ucontrol->value.integer.value[0]) {
        case 0:
                pr_debug("set vibra path\n");
-               snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT");
-               snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT");
-               snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
+               snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
                break;
 
        case 1:
                pr_debug("set hs  path\n");
-               snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
-               snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
-               snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
                break;
 
        case 2:
                pr_debug("set spkr path\n");
-               snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL");
-               snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR");
-               snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
+               snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
                break;
 
        case 3:
                pr_debug("set null path\n");
-               snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL");
-               snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR");
-               snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
+               snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
+               snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
                break;
        }
-       snd_soc_dapm_sync(&codec->dapm);
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
+
        lo_dac = ucontrol->value.integer.value[0];
        return 0;
 }
@@ -221,26 +237,11 @@ static void mfld_jack_check(unsigned int intr_status)
 
 static int mfld_init(struct snd_soc_pcm_runtime *runtime)
 {
-       struct snd_soc_codec *codec = runtime->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
        int ret_val;
 
-       /* Add jack sense widgets */
-       snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
-
-       /* Set up the map */
-       snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
+       mfld_codec = runtime->codec;
 
-       /* always connected */
-       snd_soc_dapm_enable_pin(dapm, "Headphones");
-       snd_soc_dapm_enable_pin(dapm, "Mic");
-
-       ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
-                               ARRAY_SIZE(mfld_snd_controls));
-       if (ret_val) {
-               pr_err("soc_add_controls failed %d", ret_val);
-               return ret_val;
-       }
        /* default is earpiece pin, userspace sets it explcitly */
        snd_soc_dapm_disable_pin(dapm, "Headphones");
        /* default is lineout NC, userspace sets it explcitly */
@@ -253,7 +254,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        snd_soc_dapm_disable_pin(dapm, "LINEINR");
 
        /* Headset and button jack detection */
-       ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
+       ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
                        SND_JACK_BTN_1, &mfld_jack);
        if (ret_val) {
@@ -335,6 +336,13 @@ static struct snd_soc_card snd_soc_card_mfld = {
        .owner = THIS_MODULE,
        .dai_link = mfld_msic_dailink,
        .num_links = ARRAY_SIZE(mfld_msic_dailink),
+
+       .controls = mfld_snd_controls,
+       .num_controls = ARRAY_SIZE(mfld_snd_controls),
+       .dapm_widgets = mfld_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
+       .dapm_routes = mfld_map,
+       .num_dapm_routes = ARRAY_SIZE(mfld_map),
 };
 
 static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c
new file mode 100644 (file)
index 0000000..5d06eec
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Intel SST loader on ACPI systems
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-dsp.h"
+
+#define SST_LPT_DSP_DMA_ADDR_OFFSET    0x0F0000
+#define SST_WPT_DSP_DMA_ADDR_OFFSET    0x0FE000
+#define SST_LPT_DSP_DMA_SIZE           (1024 - 1)
+
+/* Descriptor for SST ASoC machine driver */
+struct sst_acpi_mach {
+       /* ACPI ID for the matching machine driver. Audio codec for instance */
+       const u8 id[ACPI_ID_LEN];
+       /* machine driver name */
+       const char *drv_name;
+       /* firmware file name */
+       const char *fw_filename;
+};
+
+/* Descriptor for setting up SST platform data */
+struct sst_acpi_desc {
+       const char *drv_name;
+       struct sst_acpi_mach *machines;
+       /* Platform resource indexes. Must set to -1 if not used */
+       int resindex_lpe_base;
+       int resindex_pcicfg_base;
+       int resindex_fw_base;
+       int irqindex_host_ipc;
+       int resindex_dma_base;
+       /* Unique number identifying the SST core on platform */
+       int sst_id;
+       /* DMA only valid when resindex_dma_base != -1*/
+       int dma_engine;
+       int dma_size;
+};
+
+struct sst_acpi_priv {
+       struct platform_device *pdev_mach;
+       struct platform_device *pdev_pcm;
+       struct sst_pdata sst_pdata;
+       struct sst_acpi_desc *desc;
+       struct sst_acpi_mach *mach;
+};
+
+static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
+{
+       struct platform_device *pdev = context;
+       struct device *dev = &pdev->dev;
+       struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+       struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+       struct sst_acpi_desc *desc = sst_acpi->desc;
+       struct sst_acpi_mach *mach = sst_acpi->mach;
+
+       sst_pdata->fw = fw;
+       if (!fw) {
+               dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
+               return;
+       }
+
+       /* register PCM and DAI driver */
+       sst_acpi->pdev_pcm =
+               platform_device_register_data(dev, desc->drv_name, -1,
+                                             sst_pdata, sizeof(*sst_pdata));
+       if (IS_ERR(sst_acpi->pdev_pcm)) {
+               dev_err(dev, "Cannot register device %s. Error %d\n",
+                       desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
+       }
+
+       return;
+}
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+                                      void *context, void **ret)
+{
+       *(bool *)context = true;
+       return AE_OK;
+}
+
+static struct sst_acpi_mach *sst_acpi_find_machine(
+       struct sst_acpi_mach *machines)
+{
+       struct sst_acpi_mach *mach;
+       bool found = false;
+
+       for (mach = machines; mach->id[0]; mach++)
+               if (ACPI_SUCCESS(acpi_get_devices(mach->id,
+                                                 sst_acpi_mach_match,
+                                                 &found, NULL)) && found)
+                       return mach;
+
+       return NULL;
+}
+
+static int sst_acpi_probe(struct platform_device *pdev)
+{
+       const struct acpi_device_id *id;
+       struct device *dev = &pdev->dev;
+       struct sst_acpi_priv *sst_acpi;
+       struct sst_pdata *sst_pdata;
+       struct sst_acpi_mach *mach;
+       struct sst_acpi_desc *desc;
+       struct resource *mmio;
+       int ret = 0;
+
+       sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
+       if (sst_acpi == NULL)
+               return -ENOMEM;
+
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!id)
+               return -ENODEV;
+
+       desc = (struct sst_acpi_desc *)id->driver_data;
+       mach = sst_acpi_find_machine(desc->machines);
+       if (mach == NULL) {
+               dev_err(dev, "No matching ASoC machine driver found\n");
+               return -ENODEV;
+       }
+
+       sst_pdata = &sst_acpi->sst_pdata;
+       sst_pdata->id = desc->sst_id;
+       sst_acpi->desc = desc;
+       sst_acpi->mach = mach;
+
+       if (desc->resindex_dma_base >= 0) {
+               sst_pdata->dma_engine = desc->dma_engine;
+               sst_pdata->dma_base = desc->resindex_dma_base;
+               sst_pdata->dma_size = desc->dma_size;
+       }
+
+       if (desc->irqindex_host_ipc >= 0)
+               sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
+
+       if (desc->resindex_lpe_base >= 0) {
+               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+                                            desc->resindex_lpe_base);
+               if (mmio) {
+                       sst_pdata->lpe_base = mmio->start;
+                       sst_pdata->lpe_size = resource_size(mmio);
+               }
+       }
+
+       if (desc->resindex_pcicfg_base >= 0) {
+               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+                                            desc->resindex_pcicfg_base);
+               if (mmio) {
+                       sst_pdata->pcicfg_base = mmio->start;
+                       sst_pdata->pcicfg_size = resource_size(mmio);
+               }
+       }
+
+       if (desc->resindex_fw_base >= 0) {
+               mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+                                            desc->resindex_fw_base);
+               if (mmio) {
+                       sst_pdata->fw_base = mmio->start;
+                       sst_pdata->fw_size = resource_size(mmio);
+               }
+       }
+
+       platform_set_drvdata(pdev, sst_acpi);
+
+       /* register machine driver */
+       sst_acpi->pdev_mach =
+               platform_device_register_data(dev, mach->drv_name, -1,
+                                             sst_pdata, sizeof(*sst_pdata));
+       if (IS_ERR(sst_acpi->pdev_mach))
+               return PTR_ERR(sst_acpi->pdev_mach);
+
+       /* continue SST probing after firmware is loaded */
+       ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
+                                     dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
+       if (ret)
+               platform_device_unregister(sst_acpi->pdev_mach);
+
+       return ret;
+}
+
+static int sst_acpi_remove(struct platform_device *pdev)
+{
+       struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+       struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+
+       platform_device_unregister(sst_acpi->pdev_mach);
+       if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
+               platform_device_unregister(sst_acpi->pdev_pcm);
+       release_firmware(sst_pdata->fw);
+
+       return 0;
+}
+
+static struct sst_acpi_mach haswell_machines[] = {
+       { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+       {}
+};
+
+static struct sst_acpi_desc sst_acpi_haswell_desc = {
+       .drv_name = "haswell-pcm-audio",
+       .machines = haswell_machines,
+       .resindex_lpe_base = 0,
+       .resindex_pcicfg_base = 1,
+       .resindex_fw_base = -1,
+       .irqindex_host_ipc = 0,
+       .sst_id = SST_DEV_ID_LYNX_POINT,
+       .dma_engine = SST_DMA_TYPE_DW,
+       .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
+       .dma_size = SST_LPT_DSP_DMA_SIZE,
+};
+
+static struct sst_acpi_mach broadwell_machines[] = {
+       { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+       {}
+};
+
+static struct sst_acpi_desc sst_acpi_broadwell_desc = {
+       .drv_name = "haswell-pcm-audio",
+       .machines = broadwell_machines,
+       .resindex_lpe_base = 0,
+       .resindex_pcicfg_base = 1,
+       .resindex_fw_base = -1,
+       .irqindex_host_ipc = 0,
+       .sst_id = SST_DEV_ID_WILDCAT_POINT,
+       .dma_engine = SST_DMA_TYPE_DW,
+       .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
+       .dma_size = SST_LPT_DSP_DMA_SIZE,
+};
+
+static struct sst_acpi_mach baytrail_machines[] = {
+       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
+       {}
+};
+
+static struct sst_acpi_desc sst_acpi_baytrail_desc = {
+       .drv_name = "baytrail-pcm-audio",
+       .machines = baytrail_machines,
+       .resindex_lpe_base = 0,
+       .resindex_pcicfg_base = 1,
+       .resindex_fw_base = 2,
+       .irqindex_host_ipc = 5,
+       .sst_id = SST_DEV_ID_BYT,
+       .resindex_dma_base = -1,
+};
+
+static struct acpi_device_id sst_acpi_match[] = {
+       { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
+       { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
+       { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
+
+static struct platform_driver sst_acpi_driver = {
+       .probe = sst_acpi_probe,
+       .remove = sst_acpi_remove,
+       .driver = {
+               .name = "sst-acpi",
+               .owner = THIS_MODULE,
+               .acpi_match_table = ACPI_PTR(sst_acpi_match),
+       },
+};
+module_platform_driver(sst_acpi_driver);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
+MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
new file mode 100644 (file)
index 0000000..a50bf7f
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Intel Baytrail SST DSP driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+#include "sst-baytrail-ipc.h"
+
+#define SST_BYT_FW_SIGNATURE_SIZE      4
+#define SST_BYT_FW_SIGN                        "$SST"
+
+#define SST_BYT_IRAM_OFFSET    0xC0000
+#define SST_BYT_DRAM_OFFSET    0x100000
+#define SST_BYT_SHIM_OFFSET    0x140000
+
+enum sst_ram_type {
+       SST_BYT_IRAM    = 1,
+       SST_BYT_DRAM    = 2,
+       SST_BYT_CACHE   = 3,
+};
+
+struct dma_block_info {
+       enum sst_ram_type       type;   /* IRAM/DRAM */
+       u32                     size;   /* Bytes */
+       u32                     ram_offset; /* Offset in I/DRAM */
+       u32                     rsvd;   /* Reserved field */
+};
+
+struct fw_header {
+       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+       u32 file_size; /* size of fw minus this header */
+       u32 modules; /*  # of modules */
+       u32 file_format; /* version of header format */
+       u32 reserved[4];
+};
+
+struct sst_byt_fw_module_header {
+       unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+       u32 mod_size; /* size of module */
+       u32 blocks; /* # of blocks */
+       u32 type; /* codec type, pp lib */
+       u32 entry_point;
+};
+
+static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+                               struct sst_byt_fw_module_header *module)
+{
+       struct dma_block_info *block;
+       struct sst_module *mod;
+       struct sst_module_data block_data;
+       struct sst_module_template template;
+       int count;
+
+       memset(&template, 0, sizeof(template));
+       template.id = module->type;
+       template.entry = module->entry_point;
+       template.p.type = SST_MEM_DRAM;
+       template.p.data_type = SST_DATA_P;
+       template.s.type = SST_MEM_DRAM;
+       template.s.data_type = SST_DATA_S;
+
+       mod = sst_module_new(fw, &template, NULL);
+       if (mod == NULL)
+               return -ENOMEM;
+
+       block = (void *)module + sizeof(*module);
+
+       for (count = 0; count < module->blocks; count++) {
+
+               if (block->size <= 0) {
+                       dev_err(dsp->dev, "block %d size invalid\n", count);
+                       return -EINVAL;
+               }
+
+               switch (block->type) {
+               case SST_BYT_IRAM:
+                       block_data.offset = block->ram_offset +
+                                           dsp->addr.iram_offset;
+                       block_data.type = SST_MEM_IRAM;
+                       break;
+               case SST_BYT_DRAM:
+                       block_data.offset = block->ram_offset +
+                                           dsp->addr.dram_offset;
+                       block_data.type = SST_MEM_DRAM;
+                       break;
+               case SST_BYT_CACHE:
+                       block_data.offset = block->ram_offset +
+                                           (dsp->addr.fw_ext - dsp->addr.lpe);
+                       block_data.type = SST_MEM_CACHE;
+                       break;
+               default:
+                       dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
+                               block->type, count);
+                       return -EINVAL;
+               }
+
+               block_data.size = block->size;
+               block_data.data_type = SST_DATA_M;
+               block_data.data = (void *)block + sizeof(*block);
+
+               sst_module_insert_fixed_block(mod, &block_data);
+
+               block = (void *)block + sizeof(*block) + block->size;
+       }
+       return 0;
+}
+
+static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
+{
+       struct fw_header *header;
+       struct sst_byt_fw_module_header *module;
+       struct sst_dsp *dsp = sst_fw->dsp;
+       int ret, count;
+
+       /* Read the header information from the data pointer */
+       header = (struct fw_header *)sst_fw->dma_buf;
+
+       /* verify FW */
+       if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
+           (sst_fw->size != header->file_size + sizeof(*header))) {
+               /* Invalid FW signature */
+               dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dsp->dev,
+               "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+               header->signature, header->file_size, header->modules,
+               header->file_format, sizeof(*header));
+
+       module = (void *)sst_fw->dma_buf + sizeof(*header);
+       for (count = 0; count < header->modules; count++) {
+               /* module */
+               ret = sst_byt_parse_module(dsp, sst_fw, module);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "invalid module %d\n", count);
+                       return ret;
+               }
+               module = (void *)module + sizeof(*module) + module->mod_size;
+       }
+
+       return 0;
+}
+
+static void sst_byt_dump_shim(struct sst_dsp *sst)
+{
+       int i;
+       u64 reg;
+
+       for (i = 0; i <= 0xF0; i += 8) {
+               reg = sst_dsp_shim_read64_unlocked(sst, i);
+               if (reg)
+                       dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
+                               i, reg);
+       }
+
+       for (i = 0x00; i <= 0xff; i += 4) {
+               reg = readl(sst->addr.pci_cfg + i);
+               if (reg)
+                       dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
+                               i, (u32)reg);
+       }
+}
+
+static irqreturn_t sst_byt_irq(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       u64 isrx;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&sst->spinlock);
+
+       isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+       if (isrx & SST_ISRX_DONE) {
+               /* ADSP has processed the message request from IA */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
+                                                   SST_BYT_IPCX_DONE, 0);
+               ret = IRQ_WAKE_THREAD;
+       }
+       if (isrx & SST_BYT_ISRX_REQUEST) {
+               /* mask message request from ADSP and do processing later */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+                                                   SST_BYT_IMRX_REQUEST,
+                                                   SST_BYT_IMRX_REQUEST);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       spin_unlock(&sst->spinlock);
+
+       return ret;
+}
+
+static void sst_byt_boot(struct sst_dsp *sst)
+{
+       int tries = 10;
+
+       /* release stall and wait to unstall */
+       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
+       while (tries--) {
+               if (!(sst_dsp_shim_read64(sst, SST_CSR) &
+                     SST_BYT_CSR_PWAITMODE))
+                       break;
+               msleep(100);
+       }
+       if (tries < 0) {
+               dev_err(sst->dev, "unable to start DSP\n");
+               sst_byt_dump_shim(sst);
+       }
+}
+
+static void sst_byt_reset(struct sst_dsp *sst)
+{
+       /* put DSP into reset, set reset vector and stall */
+       sst_dsp_shim_update_bits64(sst, SST_CSR,
+               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
+               SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
+
+       udelay(10);
+
+       /* take DSP out of reset and keep stalled for FW loading */
+       sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
+}
+
+struct sst_adsp_memregion {
+       u32 start;
+       u32 end;
+       int blocks;
+       enum sst_mem_type type;
+};
+
+/* BYT test stuff */
+static const struct sst_adsp_memregion byt_region[] = {
+       {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
+       {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+};
+
+static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       sst->addr.lpe_base = pdata->lpe_base;
+       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+       if (!sst->addr.lpe)
+               return -ENODEV;
+
+       /* ADSP PCI MMIO config space */
+       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+       if (!sst->addr.pci_cfg) {
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Extended FW allocation */
+       sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
+       if (!sst->addr.fw_ext) {
+               iounmap(sst->addr.pci_cfg);
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Shim */
+       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+
+       sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
+                            SST_BYT_IPC_MAX_PAYLOAD_SIZE,
+                            SST_BYT_MAILBOX_OFFSET,
+                            SST_BYT_IPC_MAX_PAYLOAD_SIZE);
+
+       sst->irq = pdata->irq;
+
+       return 0;
+}
+
+static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       const struct sst_adsp_memregion *region;
+       struct device *dev;
+       int ret = -ENODEV, i, j, region_count;
+       u32 offset, size;
+
+       dev = sst->dev;
+
+       switch (sst->id) {
+       case SST_DEV_ID_BYT:
+               region = byt_region;
+               region_count = ARRAY_SIZE(byt_region);
+               sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
+               sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
+               sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
+               break;
+       default:
+               dev_err(dev, "failed to get mem resources\n");
+               return ret;
+       }
+
+       ret = sst_byt_resource_map(sst, pdata);
+       if (ret < 0) {
+               dev_err(dev, "failed to map resources\n");
+               return ret;
+       }
+
+       /*
+        * save the physical address of extended firmware block in the first
+        * 4 bytes of the mailbox
+        */
+       memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
+              &pdata->fw_base, sizeof(u32));
+
+       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       /* enable Interrupt from both sides */
+       sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
+       sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
+
+       /* register DSP memory blocks - ideally we should get this from ACPI */
+       for (i = 0; i < region_count; i++) {
+               offset = region[i].start;
+               size = (region[i].end - region[i].start) / region[i].blocks;
+
+               /* register individual memory blocks */
+               for (j = 0; j < region[i].blocks; j++) {
+                       sst_mem_block_register(sst, offset, size,
+                                              region[i].type, NULL, j, sst);
+                       offset += size;
+               }
+       }
+
+       return 0;
+}
+
+static void sst_byt_free(struct sst_dsp *sst)
+{
+       sst_mem_block_unregister_all(sst);
+       iounmap(sst->addr.lpe);
+       iounmap(sst->addr.pci_cfg);
+       iounmap(sst->addr.fw_ext);
+}
+
+struct sst_ops sst_byt_ops = {
+       .reset = sst_byt_reset,
+       .boot = sst_byt_boot,
+       .write = sst_shim32_write,
+       .read = sst_shim32_read,
+       .write64 = sst_shim32_write64,
+       .read64 = sst_shim32_read64,
+       .ram_read = sst_memcpy_fromio_32,
+       .ram_write = sst_memcpy_toio_32,
+       .irq_handler = sst_byt_irq,
+       .init = sst_byt_init,
+       .free = sst_byt_free,
+       .parse_fw = sst_byt_parse_fw_image,
+};
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
new file mode 100644 (file)
index 0000000..d0eaeee
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+
+#include "sst-baytrail-ipc.h"
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+/* IPC message timeout */
+#define IPC_TIMEOUT_MSECS      300
+#define IPC_BOOT_MSECS         200
+
+#define IPC_EMPTY_LIST_SIZE    8
+
+/* IPC header bits */
+#define IPC_HEADER_MSG_ID_MASK 0xff
+#define IPC_HEADER_MSG_ID(x)   ((x) & IPC_HEADER_MSG_ID_MASK)
+#define IPC_HEADER_STR_ID_SHIFT        8
+#define IPC_HEADER_STR_ID_MASK 0x1f
+#define IPC_HEADER_STR_ID(x)   (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
+#define IPC_HEADER_LARGE_SHIFT 13
+#define IPC_HEADER_LARGE(x)    (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
+#define IPC_HEADER_DATA_SHIFT  16
+#define IPC_HEADER_DATA_MASK   0x3fff
+#define IPC_HEADER_DATA(x)     (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
+
+/* mask for differentiating between notification and reply message */
+#define IPC_NOTIFICATION       (0x1 << 7)
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM    0x20
+#define IPC_IA_FREE_STREAM     0x21
+#define IPC_IA_PAUSE_STREAM    0x24
+#define IPC_IA_RESUME_STREAM   0x25
+#define IPC_IA_DROP_STREAM     0x26
+#define IPC_IA_START_STREAM    0x30
+
+/* notification messages */
+#define IPC_IA_FW_INIT_CMPLT   0x81
+#define IPC_SST_PERIOD_ELAPSED 0x97
+
+/* IPC messages between host and ADSP */
+struct sst_byt_address_info {
+       u32 addr;
+       u32 size;
+} __packed;
+
+struct sst_byt_str_type {
+       u8 codec_type;
+       u8 str_type;
+       u8 operation;
+       u8 protected_str;
+       u8 time_slots;
+       u8 reserved;
+       u16 result;
+} __packed;
+
+struct sst_byt_pcm_params {
+       u8 num_chan;
+       u8 pcm_wd_sz;
+       u8 use_offload_path;
+       u8 reserved;
+       u32 sfreq;
+       u8 channel_map[8];
+} __packed;
+
+struct sst_byt_frames_info {
+       u16 num_entries;
+       u16 rsrvd;
+       u32 frag_size;
+       struct sst_byt_address_info ring_buf_info[8];
+} __packed;
+
+struct sst_byt_alloc_params {
+       struct sst_byt_str_type str_type;
+       struct sst_byt_pcm_params pcm_params;
+       struct sst_byt_frames_info frame_info;
+} __packed;
+
+struct sst_byt_alloc_response {
+       struct sst_byt_str_type str_type;
+       u8 reserved[88];
+} __packed;
+
+struct sst_byt_start_stream_params {
+       u32 byte_offset;
+} __packed;
+
+struct sst_byt_tstamp {
+       u64 ring_buffer_counter;
+       u64 hardware_counter;
+       u64 frames_decoded;
+       u64 bytes_decoded;
+       u64 bytes_copied;
+       u32 sampling_frequency;
+       u32 channel_peak[8];
+} __packed;
+
+/* driver internal IPC message structure */
+struct ipc_message {
+       struct list_head list;
+       u64 header;
+
+       /* direction wrt host CPU */
+       char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
+       size_t tx_size;
+       char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
+       size_t rx_size;
+
+       wait_queue_head_t waitq;
+       bool complete;
+       bool wait;
+       int errno;
+};
+
+struct sst_byt_stream;
+struct sst_byt;
+
+/* stream infomation */
+struct sst_byt_stream {
+       struct list_head node;
+
+       /* configuration */
+       struct sst_byt_alloc_params request;
+       struct sst_byt_alloc_response reply;
+
+       /* runtime info */
+       struct sst_byt *byt;
+       int str_id;
+       bool commited;
+       bool running;
+
+       /* driver callback */
+       u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
+       void *pdata;
+};
+
+/* SST Baytrail IPC data */
+struct sst_byt {
+       struct device *dev;
+       struct sst_dsp *dsp;
+
+       /* stream */
+       struct list_head stream_list;
+
+       /* boot */
+       wait_queue_head_t boot_wait;
+       bool boot_complete;
+
+       /* IPC messaging */
+       struct list_head tx_list;
+       struct list_head rx_list;
+       struct list_head empty_list;
+       wait_queue_head_t wait_txq;
+       struct task_struct *tx_thread;
+       struct kthread_worker kworker;
+       struct kthread_work kwork;
+       struct ipc_message *msg;
+};
+
+static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
+{
+       u64 header;
+
+       header = IPC_HEADER_MSG_ID(msg_id) |
+                IPC_HEADER_STR_ID(str_id) |
+                IPC_HEADER_LARGE(large) |
+                IPC_HEADER_DATA(data) |
+                SST_BYT_IPCX_BUSY;
+
+       return header;
+}
+
+static inline u16 sst_byt_header_msg_id(u64 header)
+{
+       return header & IPC_HEADER_MSG_ID_MASK;
+}
+
+static inline u8 sst_byt_header_str_id(u64 header)
+{
+       return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
+}
+
+static inline u16 sst_byt_header_data(u64 header)
+{
+       return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
+}
+
+static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
+                                                int stream_id)
+{
+       struct sst_byt_stream *stream;
+
+       list_for_each_entry(stream, &byt->stream_list, node) {
+               if (stream->str_id == stream_id)
+                       return stream;
+       }
+
+       return NULL;
+}
+
+static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text)
+{
+       struct sst_dsp *sst = byt->dsp;
+       u64 isr, ipcd, imrx, ipcx;
+
+       ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
+       isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+       ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
+
+       dev_err(byt->dev,
+               "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
+               text, ipcx, isr, ipcd, imrx);
+}
+
+/* locks held by caller */
+static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt)
+{
+       struct ipc_message *msg = NULL;
+
+       if (!list_empty(&byt->empty_list)) {
+               msg = list_first_entry(&byt->empty_list,
+                                      struct ipc_message, list);
+               list_del(&msg->list);
+       }
+
+       return msg;
+}
+
+static void sst_byt_ipc_tx_msgs(struct kthread_work *work)
+{
+       struct sst_byt *byt =
+               container_of(work, struct sst_byt, kwork);
+       struct ipc_message *msg;
+       u64 ipcx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+       if (list_empty(&byt->tx_list)) {
+               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+               return;
+       }
+
+       /* if the DSP is busy we will TX messages after IRQ */
+       ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX);
+       if (ipcx & SST_BYT_IPCX_BUSY) {
+               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+               return;
+       }
+
+       msg = list_first_entry(&byt->tx_list, struct ipc_message, list);
+
+       list_move(&msg->list, &byt->rx_list);
+
+       /* send the message */
+       if (msg->header & IPC_HEADER_LARGE(true))
+               sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size);
+       sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header);
+
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+}
+
+static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
+                                                struct ipc_message *msg)
+{
+       msg->complete = true;
+
+       if (!msg->wait)
+               list_add_tail(&msg->list, &byt->empty_list);
+       else
+               wake_up(&msg->waitq);
+}
+
+static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
+                               void *rx_data)
+{
+       unsigned long flags;
+       int ret;
+
+       /* wait for DSP completion */
+       ret = wait_event_timeout(msg->waitq, msg->complete,
+                                msecs_to_jiffies(IPC_TIMEOUT_MSECS));
+
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+       if (ret == 0) {
+               list_del(&msg->list);
+               sst_byt_ipc_shim_dbg(byt, "message timeout");
+
+               ret = -ETIMEDOUT;
+       } else {
+
+               /* copy the data returned from DSP */
+               if (msg->rx_size)
+                       memcpy(rx_data, msg->rx_data, msg->rx_size);
+               ret = msg->errno;
+       }
+
+       list_add_tail(&msg->list, &byt->empty_list);
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+       return ret;
+}
+
+static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header,
+                                 void *tx_data, size_t tx_bytes,
+                                 void *rx_data, size_t rx_bytes, int wait)
+{
+       unsigned long flags;
+       struct ipc_message *msg;
+
+       spin_lock_irqsave(&byt->dsp->spinlock, flags);
+
+       msg = sst_byt_msg_get_empty(byt);
+       if (msg == NULL) {
+               spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+               return -EBUSY;
+       }
+
+       msg->header = header;
+       msg->tx_size = tx_bytes;
+       msg->rx_size = rx_bytes;
+       msg->wait = wait;
+       msg->errno = 0;
+       msg->complete = false;
+
+       if (tx_bytes) {
+               /* msg content = lower 32-bit of the header + data */
+               *(u32 *)msg->tx_data = (u32)(header & (u32)-1);
+               memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes);
+               msg->tx_size += sizeof(u32);
+       }
+
+       list_add_tail(&msg->list, &byt->tx_list);
+       spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+
+       queue_kthread_work(&byt->kworker, &byt->kwork);
+
+       if (wait)
+               return sst_byt_tx_wait_done(byt, msg, rx_data);
+       else
+               return 0;
+}
+
+static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header,
+                                         void *tx_data, size_t tx_bytes,
+                                         void *rx_data, size_t rx_bytes)
+{
+       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
+                                     rx_data, rx_bytes, 1);
+}
+
+static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header,
+                                               void *tx_data, size_t tx_bytes)
+{
+       return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
+                                     NULL, 0, 0);
+}
+
+static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt,
+                                                 u64 header)
+{
+       struct ipc_message *msg = NULL, *_msg;
+       u64 mask;
+
+       /* match reply to message sent based on msg and stream IDs */
+       mask = IPC_HEADER_MSG_ID_MASK |
+              IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
+       header &= mask;
+
+       if (list_empty(&byt->rx_list)) {
+               dev_err(byt->dev,
+                       "ipc: rx list is empty but received 0x%llx\n", header);
+               goto out;
+       }
+
+       list_for_each_entry(_msg, &byt->rx_list, list) {
+               if ((_msg->header & mask) == header) {
+                       msg = _msg;
+                       break;
+               }
+       }
+
+out:
+       return msg;
+}
+
+static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
+{
+       struct sst_byt_stream *stream;
+       u64 header = msg->header;
+       u8 stream_id = sst_byt_header_str_id(header);
+       u8 stream_msg = sst_byt_header_msg_id(header);
+
+       stream = sst_byt_get_stream(byt, stream_id);
+       if (stream == NULL)
+               return;
+
+       switch (stream_msg) {
+       case IPC_IA_DROP_STREAM:
+       case IPC_IA_PAUSE_STREAM:
+       case IPC_IA_FREE_STREAM:
+               stream->running = false;
+               break;
+       case IPC_IA_START_STREAM:
+       case IPC_IA_RESUME_STREAM:
+               stream->running = true;
+               break;
+       }
+}
+
+static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
+{
+       struct ipc_message *msg;
+
+       msg = sst_byt_reply_find_msg(byt, header);
+       if (msg == NULL)
+               return 1;
+
+       if (header & IPC_HEADER_LARGE(true)) {
+               msg->rx_size = sst_byt_header_data(header);
+               sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
+       }
+
+       /* update any stream states */
+       sst_byt_stream_update(byt, msg);
+
+       list_del(&msg->list);
+       /* wake up */
+       sst_byt_tx_msg_reply_complete(byt, msg);
+
+       return 1;
+}
+
+static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
+{
+       dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
+
+       byt->boot_complete = true;
+       wake_up(&byt->boot_wait);
+}
+
+static int sst_byt_process_notification(struct sst_byt *byt,
+                                       unsigned long *flags)
+{
+       struct sst_dsp *sst = byt->dsp;
+       struct sst_byt_stream *stream;
+       u64 header;
+       u8 msg_id, stream_id;
+       int handled = 1;
+
+       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       msg_id = sst_byt_header_msg_id(header);
+
+       switch (msg_id) {
+       case IPC_SST_PERIOD_ELAPSED:
+               stream_id = sst_byt_header_str_id(header);
+               stream = sst_byt_get_stream(byt, stream_id);
+               if (stream && stream->running && stream->notify_position) {
+                       spin_unlock_irqrestore(&sst->spinlock, *flags);
+                       stream->notify_position(stream, stream->pdata);
+                       spin_lock_irqsave(&sst->spinlock, *flags);
+               }
+               break;
+       case IPC_IA_FW_INIT_CMPLT:
+               sst_byt_fw_ready(byt, header);
+               break;
+       }
+
+       return handled;
+}
+
+static irqreturn_t sst_byt_irq_thread(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       struct sst_byt *byt = sst_dsp_get_thread_context(sst);
+       u64 header;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+
+       header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+       if (header & SST_BYT_IPCD_BUSY) {
+               if (header & IPC_NOTIFICATION) {
+                       /* message from ADSP */
+                       sst_byt_process_notification(byt, &flags);
+               } else {
+                       /* reply from ADSP */
+                       sst_byt_process_reply(byt, header);
+               }
+               /*
+                * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
+                * processed the message and can accept new. Clear data part
+                * of the header
+                */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
+                       SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
+                       IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
+                       SST_BYT_IPCD_DONE);
+               /* unmask message request interrupts */
+               sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+                       SST_BYT_IMRX_REQUEST, 0);
+       }
+
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       /* continue to send any remaining messages... */
+       queue_kthread_work(&byt->kworker, &byt->kwork);
+
+       return IRQ_HANDLED;
+}
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+       u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
+       void *data)
+{
+       struct sst_byt_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL)
+               return NULL;
+
+       list_add(&stream->node, &byt->stream_list);
+       stream->notify_position = notify_position;
+       stream->pdata = data;
+       stream->byt = byt;
+       stream->str_id = id;
+
+       return stream;
+}
+
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           int bits)
+{
+       stream->request.pcm_params.pcm_wd_sz = bits;
+       return 0;
+}
+
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+                               struct sst_byt_stream *stream, u8 channels)
+{
+       stream->request.pcm_params.num_chan = channels;
+       return 0;
+}
+
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           unsigned int rate)
+{
+       stream->request.pcm_params.sfreq = rate;
+       return 0;
+}
+
+/* stream sonfiguration */
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+                       int codec_type, int stream_type, int operation)
+{
+       stream->request.str_type.codec_type = codec_type;
+       stream->request.str_type.str_type = stream_type;
+       stream->request.str_type.operation = operation;
+       stream->request.str_type.time_slots = 0xc;
+
+       return 0;
+}
+
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+                         uint32_t buffer_addr, uint32_t buffer_size)
+{
+       stream->request.frame_info.num_entries = 1;
+       stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
+       stream->request.frame_info.ring_buf_info[0].size = buffer_size;
+       /* calculate bytes per 4 ms fragment */
+       stream->request.frame_info.frag_size =
+               stream->request.pcm_params.sfreq *
+               stream->request.pcm_params.num_chan *
+               stream->request.pcm_params.pcm_wd_sz / 8 *
+               4 / 1000;
+       return 0;
+}
+
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       struct sst_byt_alloc_params *str_req = &stream->request;
+       struct sst_byt_alloc_response *reply = &stream->reply;
+       u64 header;
+       int ret;
+
+       header = sst_byt_header(IPC_IA_ALLOC_STREAM,
+                               sizeof(*str_req) + sizeof(u32),
+                               true, stream->str_id);
+       ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req),
+                                     reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(byt->dev, "ipc: error stream commit failed\n");
+               return ret;
+       }
+
+       stream->commited = true;
+
+       return 0;
+}
+
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       u64 header;
+       int ret = 0;
+
+       if (!stream->commited)
+               goto out;
+
+       header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
+       ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
+       if (ret < 0) {
+               dev_err(byt->dev, "ipc: free stream %d failed\n",
+                       stream->str_id);
+               return -EAGAIN;
+       }
+
+       stream->commited = false;
+out:
+       list_del(&stream->node);
+       kfree(stream);
+
+       return ret;
+}
+
+static int sst_byt_stream_operations(struct sst_byt *byt, int type,
+                                    int stream_id, int wait)
+{
+       struct sst_byt_start_stream_params start_stream;
+       u64 header;
+       void *tx_msg = NULL;
+       size_t size = 0;
+
+       if (type != IPC_IA_START_STREAM) {
+               header = sst_byt_header(type, 0, false, stream_id);
+       } else {
+               start_stream.byte_offset = 0;
+               header = sst_byt_header(IPC_IA_START_STREAM,
+                                       sizeof(start_stream) + sizeof(u32),
+                                       true, stream_id);
+               tx_msg = &start_stream;
+               size = sizeof(start_stream);
+       }
+
+       if (wait)
+               return sst_byt_ipc_tx_msg_wait(byt, header,
+                                              tx_msg, size, NULL, 0);
+       else
+               return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
+}
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to start stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       /* don't stop streams that are not commited */
+       if (!stream->commited)
+               return 0;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
+                       stream->str_id);
+       return ret;
+}
+
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+       int ret;
+
+       ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
+                                       stream->str_id, 0);
+       if (ret < 0)
+               dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
+                       stream->str_id);
+
+       return ret;
+}
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+                            struct sst_byt_stream *stream, int buffer_size)
+{
+       struct sst_dsp *sst = byt->dsp;
+       struct sst_byt_tstamp fw_tstamp;
+       u8 str_id = stream->str_id;
+       u32 tstamp_offset;
+
+       tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
+       memcpy_fromio(&fw_tstamp,
+                     sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
+
+       return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
+}
+
+static int msg_empty_list_init(struct sst_byt *byt)
+{
+       struct ipc_message *msg;
+       int i;
+
+       byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+       if (byt->msg == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+               init_waitqueue_head(&byt->msg[i].waitq);
+               list_add(&byt->msg[i].list, &byt->empty_list);
+       }
+
+       return 0;
+}
+
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
+{
+       return byt->dsp;
+}
+
+static struct sst_dsp_device byt_dev = {
+       .thread = sst_byt_irq_thread,
+       .ops = &sst_byt_ops,
+};
+
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt;
+       struct sst_fw *byt_sst_fw;
+       int err;
+
+       dev_dbg(dev, "initialising Byt DSP IPC\n");
+
+       byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
+       if (byt == NULL)
+               return -ENOMEM;
+
+       byt->dev = dev;
+       INIT_LIST_HEAD(&byt->stream_list);
+       INIT_LIST_HEAD(&byt->tx_list);
+       INIT_LIST_HEAD(&byt->rx_list);
+       INIT_LIST_HEAD(&byt->empty_list);
+       init_waitqueue_head(&byt->boot_wait);
+       init_waitqueue_head(&byt->wait_txq);
+
+       err = msg_empty_list_init(byt);
+       if (err < 0)
+               return -ENOMEM;
+
+       /* start the IPC message thread */
+       init_kthread_worker(&byt->kworker);
+       byt->tx_thread = kthread_run(kthread_worker_fn,
+                                    &byt->kworker,
+                                    dev_name(byt->dev));
+       if (IS_ERR(byt->tx_thread)) {
+               err = PTR_ERR(byt->tx_thread);
+               dev_err(byt->dev, "error failed to create message TX task\n");
+               goto err_free_msg;
+       }
+       init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs);
+
+       byt_dev.thread_context = byt;
+
+       /* init SST shim */
+       byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
+       if (byt->dsp == NULL) {
+               err = -ENODEV;
+               goto err_free_msg;
+       }
+
+       /* keep the DSP in reset state for base FW loading */
+       sst_dsp_reset(byt->dsp);
+
+       byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
+       if (byt_sst_fw  == NULL) {
+               err = -ENODEV;
+               dev_err(dev, "error: failed to load firmware\n");
+               goto fw_err;
+       }
+
+       /* wait for DSP boot completion */
+       sst_dsp_boot(byt->dsp);
+       err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+                                msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (err == 0) {
+               err = -EIO;
+               dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+               goto boot_err;
+       }
+
+       pdata->dsp = byt;
+
+       return 0;
+
+boot_err:
+       sst_dsp_reset(byt->dsp);
+       sst_fw_free(byt_sst_fw);
+fw_err:
+       sst_dsp_free(byt->dsp);
+err_free_msg:
+       kfree(byt->msg);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
+
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_byt *byt = pdata->dsp;
+
+       sst_dsp_reset(byt->dsp);
+       sst_fw_free_all(byt->dsp);
+       sst_dsp_free(byt->dsp);
+       kfree(byt->msg);
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
new file mode 100644 (file)
index 0000000..f172b64
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __SST_BYT_IPC_H
+#define __SST_BYT_IPC_H
+
+#include <linux/types.h>
+
+struct sst_byt;
+struct sst_byt_stream;
+struct sst_pdata;
+extern struct sst_ops sst_byt_ops;
+
+
+#define SST_BYT_MAILBOX_OFFSET         0x144000
+#define SST_BYT_TIMESTAMP_OFFSET       (SST_BYT_MAILBOX_OFFSET + 0x800)
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_BYT_IPC_MAX_PAYLOAD_SIZE   200
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+       uint32_t (*get_write_position)(struct sst_byt_stream *stream,
+                                      void *data),
+       void *data);
+
+/* stream configuration */
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           int bits);
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+                               struct sst_byt_stream *stream, u8 channels);
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+                           unsigned int rate);
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+                       int codec_type, int stream_type, int operation);
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+                         uint32_t buffer_addr, uint32_t buffer_size);
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+                            struct sst_byt_stream *stream, int buffer_size);
+
+/* init */
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
+
+#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
new file mode 100644 (file)
index 0000000..6d101f3
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Intel Baytrail SST PCM Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "sst-baytrail-ipc.h"
+#include "sst-dsp-priv.h"
+#include "sst-dsp.h"
+
+#define BYT_PCM_COUNT          2
+
+static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FORMAT_S24_LE,
+       .period_bytes_min       = 384,
+       .period_bytes_max       = 48000,
+       .periods_min            = 2,
+       .periods_max            = 250,
+       .buffer_bytes_max       = 96000,
+};
+
+/* private data for each PCM DSP stream */
+struct sst_byt_pcm_data {
+       struct sst_byt_stream *stream;
+       struct snd_pcm_substream *substream;
+       struct mutex mutex;
+};
+
+/* private data for the driver */
+struct sst_byt_priv_data {
+       /* runtime DSP */
+       struct sst_byt *byt;
+
+       /* DAI data */
+       struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+};
+
+/* this may get called several times by oss emulation */
+static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_byt *byt = pdata->byt;
+       u32 rate, bits;
+       u8 channels;
+       int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+       dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
+
+       ret = sst_byt_stream_type(byt, pcm_data->stream,
+                                 1, 1, !playback);
+       if (ret < 0) {
+               dev_err(rtd->dev, "failed to set stream format %d\n", ret);
+               return ret;
+       }
+
+       rate = params_rate(params);
+       ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set rate %d\n", rate);
+               return ret;
+       }
+
+       bits = snd_pcm_format_width(params_format(params));
+       ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set formats %d\n",
+                       params_rate(params));
+               return ret;
+       }
+
+       channels = (u8)(params_channels(params) & 0xF);
+       ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "could not set channels %d\n",
+                       params_rate(params));
+               return ret;
+       }
+
+       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+
+       ret = sst_byt_stream_buffer(byt, pcm_data->stream,
+                                   substream->dma_buffer.addr,
+                                   params_buffer_bytes(params));
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
+               return ret;
+       }
+
+       ret = sst_byt_stream_commit(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "PCM: hw_free\n");
+       snd_pcm_lib_free_pages(substream);
+
+       return 0;
+}
+
+static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_byt *byt = pdata->byt;
+
+       dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               sst_byt_stream_start(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sst_byt_stream_resume(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               sst_byt_stream_stop(byt, pcm_data->stream);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sst_byt_stream_pause(byt, pcm_data->stream);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
+{
+       struct sst_byt_pcm_data *pcm_data = data;
+       struct snd_pcm_substream *substream = pcm_data->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       u32 pos;
+
+       pos = frames_to_bytes(runtime,
+                             (runtime->control->appl_ptr %
+                              runtime->buffer_size));
+
+       dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+
+       snd_pcm_period_elapsed(substream);
+       return pos;
+}
+
+static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_byt *byt = pdata->byt;
+       snd_pcm_uframes_t offset;
+       int pos;
+
+       pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
+                                      snd_pcm_lib_buffer_bytes(substream));
+       offset = bytes_to_frames(runtime, pos);
+
+       dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
+               frames_to_bytes(runtime, (u32)offset));
+       return offset;
+}
+
+static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_byt *byt = pdata->byt;
+
+       dev_dbg(rtd->dev, "PCM: open\n");
+
+       pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+       mutex_lock(&pcm_data->mutex);
+
+       snd_soc_pcm_set_drvdata(rtd, pcm_data);
+       pcm_data->substream = substream;
+
+       snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
+
+       pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
+                                             byt_notify_pointer, pcm_data);
+       if (pcm_data->stream == NULL) {
+               dev_err(rtd->dev, "failed to create stream\n");
+               mutex_unlock(&pcm_data->mutex);
+               return -EINVAL;
+       }
+
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sst_byt_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_byt *byt = pdata->byt;
+       int ret;
+
+       dev_dbg(rtd->dev, "PCM: close\n");
+
+       mutex_lock(&pcm_data->mutex);
+       ret = sst_byt_stream_free(byt, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "Free stream fail\n");
+               goto out;
+       }
+       pcm_data->stream = NULL;
+
+out:
+       mutex_unlock(&pcm_data->mutex);
+       return ret;
+}
+
+static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
+                           struct vm_area_struct *vma)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->dev, "PCM: mmap\n");
+       return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops sst_byt_pcm_ops = {
+       .open           = sst_byt_pcm_open,
+       .close          = sst_byt_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = sst_byt_pcm_hw_params,
+       .hw_free        = sst_byt_pcm_hw_free,
+       .trigger        = sst_byt_pcm_trigger,
+       .pointer        = sst_byt_pcm_pointer,
+       .mmap           = sst_byt_pcm_mmap,
+};
+
+static void sst_byt_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       size_t size;
+       int ret = 0;
+
+       ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+           pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               size = sst_byt_pcm_hardware.buffer_bytes_max;
+               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                                           SNDRV_DMA_TYPE_DEV,
+                                                           rtd->card->dev,
+                                                           size, size);
+               if (ret) {
+                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static struct snd_soc_dai_driver byt_dais[] = {
+       {
+               .name  = "Front-cpu-dai",
+               .playback = {
+                       .stream_name = "System Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S24_3LE |
+                                  SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+       {
+               .name  = "Mic1-cpu-dai",
+               .capture = {
+                       .stream_name = "Analog Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+};
+
+static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
+{
+       struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
+       struct sst_byt_priv_data *priv_data;
+       int i;
+
+       if (!plat_data)
+               return -ENODEV;
+
+       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
+                                GFP_KERNEL);
+       priv_data->byt = plat_data->dsp;
+       snd_soc_platform_set_drvdata(platform, priv_data);
+
+       for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
+               mutex_init(&priv_data->pcm[i].mutex);
+
+       return 0;
+}
+
+static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
+{
+       return 0;
+}
+
+static struct snd_soc_platform_driver byt_soc_platform = {
+       .probe          = sst_byt_pcm_probe,
+       .remove         = sst_byt_pcm_remove,
+       .ops            = &sst_byt_pcm_ops,
+       .pcm_new        = sst_byt_pcm_new,
+       .pcm_free       = sst_byt_pcm_free,
+};
+
+static const struct snd_soc_component_driver byt_dai_component = {
+       .name           = "byt-dai",
+};
+
+static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+       int ret;
+
+       ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
+       if (ret < 0)
+               return -ENODEV;
+
+       ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
+       if (ret < 0)
+               goto err_plat;
+
+       ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
+                                        byt_dais, ARRAY_SIZE(byt_dais));
+       if (ret < 0)
+               goto err_comp;
+
+       return 0;
+
+err_comp:
+       snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+       sst_byt_dsp_free(&pdev->dev, sst_pdata);
+       return ret;
+}
+
+static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
+       sst_byt_dsp_free(&pdev->dev, sst_pdata);
+
+       return 0;
+}
+
+static struct platform_driver sst_byt_pcm_driver = {
+       .driver = {
+               .name = "baytrail-pcm-audio",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = sst_byt_pcm_dev_probe,
+       .remove = sst_byt_pcm_dev_remove,
+};
+module_platform_driver(sst_byt_pcm_driver);
+
+MODULE_AUTHOR("Jarkko Nikula");
+MODULE_DESCRIPTION("Baytrail PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:baytrail-pcm-audio");
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
new file mode 100644 (file)
index 0000000..fe8e81a
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Intel Smart Sound Technology
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SOUND_SOC_SST_DSP_PRIV_H
+#define __SOUND_SOC_SST_DSP_PRIV_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+
+struct sst_mem_block;
+struct sst_module;
+struct sst_fw;
+
+/*
+ * DSP Operations exported by platform Audio DSP driver.
+ */
+struct sst_ops {
+       /* DSP core boot / reset */
+       void (*boot)(struct sst_dsp *);
+       void (*reset)(struct sst_dsp *);
+
+       /* Shim IO */
+       void (*write)(void __iomem *addr, u32 offset, u32 value);
+       u32 (*read)(void __iomem *addr, u32 offset);
+       void (*write64)(void __iomem *addr, u32 offset, u64 value);
+       u64 (*read64)(void __iomem *addr, u32 offset);
+
+       /* DSP I/DRAM IO */
+       void (*ram_read)(struct sst_dsp *sst, void  *dest, void __iomem *src,
+               size_t bytes);
+       void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src,
+               size_t bytes);
+
+       void (*dump)(struct sst_dsp *);
+
+       /* IRQ handlers */
+       irqreturn_t (*irq_handler)(int irq, void *context);
+
+       /* SST init and free */
+       int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata);
+       void (*free)(struct sst_dsp *sst);
+
+       /* FW module parser/loader */
+       int (*parse_fw)(struct sst_fw *sst_fw);
+};
+
+/*
+ * Audio DSP memory offsets and addresses.
+ */
+struct sst_addr {
+       u32 lpe_base;
+       u32 shim_offset;
+       u32 iram_offset;
+       u32 dram_offset;
+       void __iomem *lpe;
+       void __iomem *shim;
+       void __iomem *pci_cfg;
+       void __iomem *fw_ext;
+};
+
+/*
+ * Audio DSP Mailbox configuration.
+ */
+struct sst_mailbox {
+       void __iomem *in_base;
+       void __iomem *out_base;
+       size_t in_size;
+       size_t out_size;
+};
+
+/*
+ * Audio DSP Firmware data types.
+ */
+enum sst_data_type {
+       SST_DATA_M      = 0, /* module block data */
+       SST_DATA_P      = 1, /* peristant data (text, data) */
+       SST_DATA_S      = 2, /* scratch data (usually buffers) */
+};
+
+/*
+ * Audio DSP memory block types.
+ */
+enum sst_mem_type {
+       SST_MEM_IRAM = 0,
+       SST_MEM_DRAM = 1,
+       SST_MEM_ANY  = 2,
+       SST_MEM_CACHE= 3,
+};
+
+/*
+ * Audio DSP Generic Firmware File.
+ *
+ * SST Firmware files can consist of 1..N modules. This generic structure is
+ * used to manage each firmware file and it's modules regardless of SST firmware
+ * type. A SST driver may load multiple FW files.
+ */
+struct sst_fw {
+       struct sst_dsp *dsp;
+
+       /* base addresses of FW file data */
+       dma_addr_t dmable_fw_paddr;     /* physical address of fw data */
+       void *dma_buf;                  /* virtual address of fw data */
+       u32 size;                       /* size of fw data */
+
+       /* lists */
+       struct list_head list;          /* DSP list of FW */
+       struct list_head module_list;   /* FW list of modules */
+
+       void *private;                  /* core doesn't touch this */
+};
+
+/*
+ * Audio DSP Generic Module data.
+ *
+ * This is used to dsecribe any sections of persistent (text and data) and
+ * scratch (buffers) of module data in ADSP memory space.
+ */
+struct sst_module_data {
+
+       enum sst_mem_type type;         /* destination memory type */
+       enum sst_data_type data_type;   /* type of module data */
+
+       u32 size;               /* size in bytes */
+       u32 offset;             /* offset in FW file */
+       u32 data_offset;        /* offset in ADSP memory space */
+       void *data;             /* module data */
+};
+
+/*
+ * Audio DSP Generic Module Template.
+ *
+ * Used to define and register a new FW module. This data is extracted from
+ * FW module header information.
+ */
+struct sst_module_template {
+       u32 id;
+       u32 entry;                      /* entry point */
+       struct sst_module_data s;       /* scratch data */
+       struct sst_module_data p;       /* peristant data */
+};
+
+/*
+ * Audio DSP Generic Module.
+ *
+ * Each Firmware file can consist of 1..N modules. A module can span multiple
+ * ADSP memory blocks. The simplest FW will be a file with 1 module.
+ */
+struct sst_module {
+       struct sst_dsp *dsp;
+       struct sst_fw *sst_fw;          /* parent FW we belong too */
+
+       /* module configuration */
+       u32 id;
+       u32 entry;                      /* module entry point */
+       u32 offset;                     /* module offset in firmware file */
+       u32 size;                       /* module size */
+       struct sst_module_data s;       /* scratch data */
+       struct sst_module_data p;       /* peristant data */
+
+       /* runtime */
+       u32 usage_count;                /* can be unloaded if count == 0 */
+       void *private;                  /* core doesn't touch this */
+
+       /* lists */
+       struct list_head block_list;    /* Module list of blocks in use */
+       struct list_head list;          /* DSP list of modules */
+       struct list_head list_fw;       /* FW list of modules */
+};
+
+/*
+ * SST Memory Block operations.
+ */
+struct sst_block_ops {
+       int (*enable)(struct sst_mem_block *block);
+       int (*disable)(struct sst_mem_block *block);
+};
+
+/*
+ * SST Generic Memory Block.
+ *
+ * SST ADP  memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be
+ * power gated.
+ */
+struct sst_mem_block {
+       struct sst_dsp *dsp;
+       struct sst_module *module;      /* module that uses this block */
+
+       /* block config */
+       u32 offset;                     /* offset from base */
+       u32 size;                       /* block size */
+       u32 index;                      /* block index 0..N */
+       enum sst_mem_type type;         /* block memory type IRAM/DRAM */
+       struct sst_block_ops *ops;      /* block operations, if any */
+
+       /* block status */
+       enum sst_data_type data_type;   /* data type held in this block */
+       u32 bytes_used;                 /* bytes in use by modules */
+       void *private;                  /* generic core does not touch this */
+       int users;                      /* number of modules using this block */
+
+       /* block lists */
+       struct list_head module_list;   /* Module list of blocks */
+       struct list_head list;          /* Map list of free/used blocks */
+};
+
+/*
+ * Generic SST Shim Interface.
+ */
+struct sst_dsp {
+
+       /* runtime */
+       struct sst_dsp_device *sst_dev;
+       spinlock_t spinlock;    /* IPC locking */
+       struct mutex mutex;     /* DSP FW lock */
+       struct device *dev;
+       void *thread_context;
+       int irq;
+       u32 id;
+
+       /* list of free and used ADSP memory blocks */
+       struct list_head used_block_list;
+       struct list_head free_block_list;
+
+       /* operations */
+       struct sst_ops *ops;
+
+       /* debug FS */
+       struct dentry *debugfs_root;
+
+       /* base addresses */
+       struct sst_addr addr;
+
+       /* mailbox */
+       struct sst_mailbox mailbox;
+
+       /* SST FW files loaded and their modules */
+       struct list_head module_list;
+       struct list_head fw_list;
+
+       /* platform data */
+       struct sst_pdata *pdata;
+
+       /* DMA FW loading */
+       struct sst_dma *dma;
+       bool fw_use_dma;
+};
+
+/* Size optimised DRAM/IRAM memcpy */
+static inline void sst_dsp_write(struct sst_dsp *sst, void *src,
+       u32 dest_offset, size_t bytes)
+{
+       sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes);
+}
+
+static inline void sst_dsp_read(struct sst_dsp *sst, void *dest,
+       u32 src_offset, size_t bytes)
+{
+       sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes);
+}
+
+static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst)
+{
+       return sst->thread_context;
+}
+
+/* Create/Free FW files - can contain multiple modules */
+struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
+       const struct firmware *fw, void *private);
+void sst_fw_free(struct sst_fw *sst_fw);
+void sst_fw_free_all(struct sst_dsp *dsp);
+
+/* Create/Free firmware modules */
+struct sst_module *sst_module_new(struct sst_fw *sst_fw,
+       struct sst_module_template *template, void *private);
+void sst_module_free(struct sst_module *sst_module);
+int sst_module_insert(struct sst_module *sst_module);
+int sst_module_remove(struct sst_module *sst_module);
+int sst_module_insert_fixed_block(struct sst_module *module,
+       struct sst_module_data *data);
+struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
+
+/* allocate/free pesistent/scratch memory regions managed by drv */
+struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
+void sst_mem_block_free_scratch(struct sst_dsp *dsp,
+       struct sst_module *scratch);
+int sst_block_module_remove(struct sst_module *module);
+
+/* Register the DSPs memory blocks - would be nice to read from ACPI */
+struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
+       u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
+       void *private);
+void sst_mem_block_unregister_all(struct sst_dsp *dsp);
+
+#endif
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
new file mode 100644 (file)
index 0000000..0c129fd
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Intel Smart Sound Technology (SST) DSP Core Driver
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/intel-sst.h>
+
+/* Internal generic low-level SST IO functions - can be overidden */
+void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
+{
+       writel(value, addr + offset);
+}
+EXPORT_SYMBOL_GPL(sst_shim32_write);
+
+u32 sst_shim32_read(void __iomem *addr, u32 offset)
+{
+       return readl(addr + offset);
+}
+EXPORT_SYMBOL_GPL(sst_shim32_read);
+
+void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
+{
+       memcpy_toio(addr + offset, &value, sizeof(value));
+}
+EXPORT_SYMBOL_GPL(sst_shim32_write64);
+
+u64 sst_shim32_read64(void __iomem *addr, u32 offset)
+{
+       u64 val;
+
+       memcpy_fromio(&val, addr + offset, sizeof(val));
+       return val;
+}
+EXPORT_SYMBOL_GPL(sst_shim32_read64);
+
+static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
+       u32 *src, size_t bytes)
+{
+       int i, words = bytes >> 2;
+
+       for (i = 0; i < words; i++)
+               writel(src[i], dest + i);
+}
+
+static inline void _sst_memcpy_fromio_32(u32 *dest,
+       const volatile __iomem u32 *src, size_t bytes)
+{
+       int i, words = bytes >> 2;
+
+       for (i = 0; i < words; i++)
+               dest[i] = readl(src + i);
+}
+
+void sst_memcpy_toio_32(struct sst_dsp *sst,
+       void __iomem *dest, void *src, size_t bytes)
+{
+       _sst_memcpy_toio_32(dest, src, bytes);
+}
+EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
+
+void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
+       void __iomem *src, size_t bytes)
+{
+       _sst_memcpy_fromio_32(dest, src, bytes);
+}
+EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
+
+/* Public API */
+void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       sst->ops->write(sst->addr.shim, offset, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
+
+u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       val = sst->ops->read(sst->addr.shim, offset);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
+
+void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       sst->ops->write64(sst->addr.shim, offset, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
+
+u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
+{
+       unsigned long flags;
+       u64 val;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       val = sst->ops->read64(sst->addr.shim, offset);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
+
+void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
+{
+       sst->ops->write(sst->addr.shim, offset, value);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
+
+u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
+{
+       return sst->ops->read(sst->addr.shim, offset);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
+
+void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
+{
+       sst->ops->write64(sst->addr.shim, offset, value);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
+
+u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
+{
+       return sst->ops->read64(sst->addr.shim, offset);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
+
+int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value)
+{
+       bool change;
+       unsigned int old, new;
+       u32 ret;
+
+       ret = sst_dsp_shim_read_unlocked(sst, offset);
+
+       old = ret;
+       new = (old & (~mask)) | (value & mask);
+
+       change = (old != new);
+       if (change)
+               sst_dsp_shim_write_unlocked(sst, offset, new);
+
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
+
+int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
+                               u64 mask, u64 value)
+{
+       bool change;
+       u64 old, new;
+
+       old = sst_dsp_shim_read64_unlocked(sst, offset);
+
+       new = (old & (~mask)) | (value & mask);
+
+       change = (old != new);
+       if (change)
+               sst_dsp_shim_write64_unlocked(sst, offset, new);
+
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
+
+int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value)
+{
+       unsigned long flags;
+       bool change;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
+
+int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
+                               u64 mask, u64 value)
+{
+       unsigned long flags;
+       bool change;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+       change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+       return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
+
+void sst_dsp_dump(struct sst_dsp *sst)
+{
+       sst->ops->dump(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dump);
+
+void sst_dsp_reset(struct sst_dsp *sst)
+{
+       sst->ops->reset(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_reset);
+
+int sst_dsp_boot(struct sst_dsp *sst)
+{
+       sst->ops->boot(sst);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_boot);
+
+void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
+{
+       sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
+       trace_sst_ipc_msg_tx(msg);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
+
+u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
+{
+       u32 msg;
+
+       msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
+       trace_sst_ipc_msg_rx(msg);
+
+       return msg;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
+
+int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
+       u32 outbox_offset, size_t outbox_size)
+{
+       sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
+       sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
+       sst->mailbox.in_size = inbox_size;
+       sst->mailbox.out_size = outbox_size;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
+
+void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_outbox_write(bytes);
+
+       memcpy_toio(sst->mailbox.out_base, message, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
+
+void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_outbox_read(bytes);
+
+       memcpy_fromio(message, sst->mailbox.out_base, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
+
+void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_inbox_write(bytes);
+
+       memcpy_toio(sst->mailbox.in_base, message, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
+
+void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
+{
+       u32 i;
+
+       trace_sst_ipc_inbox_read(bytes);
+
+       memcpy_fromio(message, sst->mailbox.in_base, bytes);
+
+       for (i = 0; i < bytes; i += 4)
+               trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
+
+struct sst_dsp *sst_dsp_new(struct device *dev,
+       struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
+{
+       struct sst_dsp *sst;
+       int err;
+
+       dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
+
+       sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
+       if (sst == NULL)
+               return NULL;
+
+       spin_lock_init(&sst->spinlock);
+       mutex_init(&sst->mutex);
+       sst->dev = dev;
+       sst->thread_context = sst_dev->thread_context;
+       sst->sst_dev = sst_dev;
+       sst->id = pdata->id;
+       sst->irq = pdata->irq;
+       sst->ops = sst_dev->ops;
+       sst->pdata = pdata;
+       INIT_LIST_HEAD(&sst->used_block_list);
+       INIT_LIST_HEAD(&sst->free_block_list);
+       INIT_LIST_HEAD(&sst->module_list);
+       INIT_LIST_HEAD(&sst->fw_list);
+
+       /* Initialise SST Audio DSP */
+       if (sst->ops->init) {
+               err = sst->ops->init(sst, pdata);
+               if (err < 0)
+                       return NULL;
+       }
+
+       /* Register the ISR */
+       err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
+               sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
+       if (err)
+               goto irq_err;
+
+       return sst;
+
+irq_err:
+       if (sst->ops->free)
+               sst->ops->free(sst);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_new);
+
+void sst_dsp_free(struct sst_dsp *sst)
+{
+       free_irq(sst->irq, sst);
+       if (sst->ops->free)
+               sst->ops->free(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_free);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("Intel SST Core");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
new file mode 100644 (file)
index 0000000..74052b5
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Intel Smart Sound Technology (SST) Core
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SOUND_SOC_SST_DSP_H
+#define __SOUND_SOC_SST_DSP_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+/* SST Device IDs  */
+#define SST_DEV_ID_LYNX_POINT          0x33C8
+#define SST_DEV_ID_WILDCAT_POINT       0x3438
+#define SST_DEV_ID_BYT                 0x0F28
+
+/* Supported SST DMA Devices */
+#define SST_DMA_TYPE_DW                1
+#define SST_DMA_TYPE_MID       2
+
+/* SST Shim register map
+ * The register naming can differ between products. Some products also
+ * contain extra functionality.
+ */
+#define SST_CSR                        0x00
+#define SST_PISR               0x08
+#define SST_PIMR               0x10
+#define SST_ISRX               0x18
+#define SST_ISRD               0x20
+#define SST_IMRX               0x28
+#define SST_IMRD               0x30
+#define SST_IPCX               0x38 /* IPC IA -> SST */
+#define SST_IPCD               0x40 /* IPC SST -> IA */
+#define SST_ISRSC              0x48
+#define SST_ISRLPESC           0x50
+#define SST_IMRSC              0x58
+#define SST_IMRLPESC           0x60
+#define SST_IPCSC              0x68
+#define SST_IPCLPESC           0x70
+#define SST_CLKCTL             0x78
+#define SST_CSR2               0x80
+#define SST_LTRC               0xE0
+#define SST_HDMC               0xE8
+#define SST_DBGO               0xF0
+
+#define SST_SHIM_SIZE          0x100
+#define SST_PWMCTRL             0x1000
+
+/* SST Shim Register bits
+ * The register bit naming can differ between products. Some products also
+ * contain extra functionality.
+ */
+
+/* CSR / CS */
+#define SST_CSR_RST            (0x1 << 1)
+#define SST_CSR_SBCS0          (0x1 << 2)
+#define SST_CSR_SBCS1          (0x1 << 3)
+#define SST_CSR_DCS(x)         (x << 4)
+#define SST_CSR_DCS_MASK       (0x7 << 4)
+#define SST_CSR_STALL          (0x1 << 10)
+#define SST_CSR_S0IOCS         (0x1 << 21)
+#define SST_CSR_S1IOCS         (0x1 << 23)
+#define SST_CSR_LPCS           (0x1 << 31)
+#define SST_BYT_CSR_RST                (0x1 << 0)
+#define SST_BYT_CSR_VECTOR_SEL (0x1 << 1)
+#define SST_BYT_CSR_STALL      (0x1 << 2)
+#define SST_BYT_CSR_PWAITMODE  (0x1 << 3)
+
+/*  ISRX / ISC */
+#define SST_ISRX_BUSY          (0x1 << 1)
+#define SST_ISRX_DONE          (0x1 << 0)
+#define SST_BYT_ISRX_REQUEST   (0x1 << 1)
+
+/*  ISRD / ISD */
+#define SST_ISRD_BUSY          (0x1 << 1)
+#define SST_ISRD_DONE          (0x1 << 0)
+
+/* IMRX / IMC */
+#define SST_IMRX_BUSY          (0x1 << 1)
+#define SST_IMRX_DONE          (0x1 << 0)
+#define SST_BYT_IMRX_REQUEST   (0x1 << 1)
+
+/*  IPCX / IPCC */
+#define        SST_IPCX_DONE           (0x1 << 30)
+#define        SST_IPCX_BUSY           (0x1 << 31)
+#define SST_BYT_IPCX_DONE      ((u64)0x1 << 62)
+#define SST_BYT_IPCX_BUSY      ((u64)0x1 << 63)
+
+/*  IPCD */
+#define        SST_IPCD_DONE           (0x1 << 30)
+#define        SST_IPCD_BUSY           (0x1 << 31)
+#define SST_BYT_IPCD_DONE      ((u64)0x1 << 62)
+#define SST_BYT_IPCD_BUSY      ((u64)0x1 << 63)
+
+/* CLKCTL */
+#define SST_CLKCTL_SMOS(x)     (x << 24)
+#define SST_CLKCTL_MASK                (3 << 24)
+#define SST_CLKCTL_DCPLCG      (1 << 18)
+#define SST_CLKCTL_SCOE1       (1 << 17)
+#define SST_CLKCTL_SCOE0       (1 << 16)
+
+/* CSR2 / CS2 */
+#define SST_CSR2_SDFD_SSP0     (1 << 1)
+#define SST_CSR2_SDFD_SSP1     (1 << 2)
+
+/* LTRC */
+#define SST_LTRC_VAL(x)                (x << 0)
+
+/* HDMC */
+#define SST_HDMC_HDDA0(x)      (x << 0)
+#define SST_HDMC_HDDA1(x)      (x << 7)
+
+
+/* SST Vendor Defined Registers and bits */
+#define SST_VDRTCTL0           0xa0
+#define SST_VDRTCTL1           0xa4
+#define SST_VDRTCTL2           0xa8
+#define SST_VDRTCTL3           0xaC
+
+/* VDRTCTL0 */
+#define SST_VDRTCL0_DSRAMPGE_SHIFT     16
+#define SST_VDRTCL0_DSRAMPGE_MASK      (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
+#define SST_VDRTCL0_ISRAMPGE_SHIFT     6
+#define SST_VDRTCL0_ISRAMPGE_MASK      (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
+
+struct sst_dsp;
+
+/*
+ * SST Device.
+ *
+ * This structure is populated by the SST core driver.
+ */
+struct sst_dsp_device {
+       /* Mandatory fields */
+       struct sst_ops *ops;
+       irqreturn_t (*thread)(int irq, void *context);
+       void *thread_context;
+};
+
+/*
+ * SST Platform Data.
+ */
+struct sst_pdata {
+       /* ACPI data */
+       u32 lpe_base;
+       u32 lpe_size;
+       u32 pcicfg_base;
+       u32 pcicfg_size;
+       u32 fw_base;
+       u32 fw_size;
+       int irq;
+
+       /* Firmware */
+       const struct firmware *fw;
+
+       /* DMA */
+       u32 dma_base;
+       u32 dma_size;
+       int dma_engine;
+
+       /* DSP */
+       u32 id;
+       void *dsp;
+};
+
+/* Initialization */
+struct sst_dsp *sst_dsp_new(struct device *dev,
+       struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
+void sst_dsp_free(struct sst_dsp *sst);
+
+/* SHIM Read / Write */
+void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
+u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value);
+void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
+u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
+                               u64 mask, u64 value);
+
+/* SHIM Read / Write Unlocked for callers already holding sst lock */
+void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
+u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
+                               u32 mask, u32 value);
+void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
+u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
+                                       u64 mask, u64 value);
+
+/* Internal generic low-level SST IO functions - can be overidden */
+void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
+u32 sst_shim32_read(void __iomem *addr, u32 offset);
+void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
+u64 sst_shim32_read64(void __iomem *addr, u32 offset);
+void sst_memcpy_toio_32(struct sst_dsp *sst,
+                       void __iomem *dest, void *src, size_t bytes);
+void sst_memcpy_fromio_32(struct sst_dsp *sst,
+                         void *dest, void __iomem *src, size_t bytes);
+
+/* DSP reset & boot */
+void sst_dsp_reset(struct sst_dsp *sst);
+int sst_dsp_boot(struct sst_dsp *sst);
+
+/* Msg IO */
+void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
+u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp);
+
+/* Mailbox management */
+int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset,
+       size_t inbox_size, u32 outbox_offset, size_t outbox_size);
+void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
+
+/* Debug */
+void sst_dsp_dump(struct sst_dsp *sst);
+
+#endif
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
new file mode 100644 (file)
index 0000000..f768710
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * Intel SST Firmware Loader
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/pci.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
+{
+       u32 i;
+
+       /* copy one 32 bit word at a time as 64 bit access is not supported */
+       for (i = 0; i < bytes; i += 4)
+               memcpy_toio(dest + i, src + i, 4);
+}
+
+/* create new generic firmware object */
+struct sst_fw *sst_fw_new(struct sst_dsp *dsp, 
+       const struct firmware *fw, void *private)
+{
+       struct sst_fw *sst_fw;
+       int err;
+
+       if (!dsp->ops->parse_fw)
+               return NULL;
+
+       sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL);
+       if (sst_fw == NULL)
+               return NULL;
+
+       sst_fw->dsp = dsp;
+       sst_fw->private = private;
+       sst_fw->size = fw->size;
+
+       err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
+       if (err < 0) {
+               kfree(sst_fw);
+               return NULL;
+       }
+
+       /* allocate DMA buffer to store FW data */
+       sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size,
+                               &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
+       if (!sst_fw->dma_buf) {
+               dev_err(dsp->dev, "error: DMA alloc failed\n");
+               kfree(sst_fw);
+               return NULL;
+       }
+
+       /* copy FW data to DMA-able memory */
+       memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size);
+
+       /* call core specific FW paser to load FW data into DSP */
+       err = dsp->ops->parse_fw(sst_fw);
+       if (err < 0) {
+               dev_err(dsp->dev, "error: parse fw failed %d\n", err);
+               goto parse_err;
+       }
+
+       mutex_lock(&dsp->mutex);
+       list_add(&sst_fw->list, &dsp->fw_list);
+       mutex_unlock(&dsp->mutex);
+
+       return sst_fw;
+
+parse_err:
+       dma_free_coherent(dsp->dev, sst_fw->size,
+                               sst_fw->dma_buf,
+                               sst_fw->dmable_fw_paddr);
+       kfree(sst_fw);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_fw_new);
+
+/* free single firmware object */
+void sst_fw_free(struct sst_fw *sst_fw)
+{
+       struct sst_dsp *dsp = sst_fw->dsp;
+
+       mutex_lock(&dsp->mutex);
+       list_del(&sst_fw->list);
+       mutex_unlock(&dsp->mutex);
+
+       dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+                       sst_fw->dmable_fw_paddr);
+       kfree(sst_fw);
+}
+EXPORT_SYMBOL_GPL(sst_fw_free);
+
+/* free all firmware objects */
+void sst_fw_free_all(struct sst_dsp *dsp)
+{
+       struct sst_fw *sst_fw, *t;
+
+       mutex_lock(&dsp->mutex);
+       list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+
+               list_del(&sst_fw->list);
+               dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+                       sst_fw->dmable_fw_paddr);
+               kfree(sst_fw);
+       }
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_fw_free_all);
+
+/* create a new SST generic module from FW template */
+struct sst_module *sst_module_new(struct sst_fw *sst_fw,
+       struct sst_module_template *template, void *private)
+{
+       struct sst_dsp *dsp = sst_fw->dsp;
+       struct sst_module *sst_module;
+
+       sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL);
+       if (sst_module == NULL)
+               return NULL;
+
+       sst_module->id = template->id;
+       sst_module->dsp = dsp;
+       sst_module->sst_fw = sst_fw;
+
+       memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data));
+       memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data));
+
+       INIT_LIST_HEAD(&sst_module->block_list);
+
+       mutex_lock(&dsp->mutex);
+       list_add(&sst_module->list, &dsp->module_list);
+       mutex_unlock(&dsp->mutex);
+
+       return sst_module;
+}
+EXPORT_SYMBOL_GPL(sst_module_new);
+
+/* free firmware module and remove from available list */
+void sst_module_free(struct sst_module *sst_module)
+{
+       struct sst_dsp *dsp = sst_module->dsp;
+
+       mutex_lock(&dsp->mutex);
+       list_del(&sst_module->list);
+       mutex_unlock(&dsp->mutex);
+
+       kfree(sst_module);
+}
+EXPORT_SYMBOL_GPL(sst_module_free);
+
+static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type,
+       u32 offset)
+{
+       struct sst_mem_block *block;
+
+       list_for_each_entry(block, &dsp->free_block_list, list) {
+               if (block->type == type && block->offset == offset)
+                       return block;
+       }
+
+       return NULL;
+}
+
+static int block_alloc_contiguous(struct sst_module *module,
+       struct sst_module_data *data, u32 offset, int size)
+{
+       struct list_head tmp = LIST_HEAD_INIT(tmp);
+       struct sst_dsp *dsp = module->dsp;
+       struct sst_mem_block *block;
+
+       while (size > 0) {
+               block = find_block(dsp, data->type, offset);
+               if (!block) {
+                       list_splice(&tmp, &dsp->free_block_list);
+                       return -ENOMEM;
+               }
+
+               list_move_tail(&block->list, &tmp);
+               offset += block->size;
+               size -= block->size;
+       }
+
+       list_splice(&tmp, &dsp->used_block_list);
+       return 0;
+}
+
+/* allocate free DSP blocks for module data - callers hold locks */
+static int block_alloc(struct sst_module *module,
+       struct sst_module_data *data)
+{
+       struct sst_dsp *dsp = module->dsp;
+       struct sst_mem_block *block, *tmp;
+       int ret = 0;
+
+       if (data->size == 0)
+               return 0;
+
+       /* find first free whole blocks that can hold module */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+
+               /* ignore blocks with wrong type */
+               if (block->type != data->type)
+                       continue;
+
+               if (data->size > block->size)
+                       continue;
+
+               data->offset = block->offset;
+               block->data_type = data->data_type;
+               block->bytes_used = data->size % block->size;
+               list_add(&block->module_list, &module->block_list);
+               list_move(&block->list, &dsp->used_block_list);
+               dev_dbg(dsp->dev, " *module %d added block %d:%d\n",
+                       module->id, block->type, block->index);
+               return 0;
+       }
+
+       /* then find free multiple blocks that can hold module */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+
+               /* ignore blocks with wrong type */
+               if (block->type != data->type)
+                       continue;
+
+               /* do we span > 1 blocks */
+               if (data->size > block->size) {
+                       ret = block_alloc_contiguous(module, data,
+                               block->offset + block->size,
+                               data->size - block->size);
+                       if (ret == 0)
+                               return ret;
+               }
+       }
+
+       /* not enough free block space */
+       return -ENOMEM;
+}
+
+/* remove module from memory - callers hold locks */
+static void block_module_remove(struct sst_module *module)
+{
+       struct sst_mem_block *block, *tmp;
+       struct sst_dsp *dsp = module->dsp;
+       int err;
+
+       /* disable each block  */
+       list_for_each_entry(block, &module->block_list, module_list) {
+
+               if (block->ops && block->ops->disable) {
+                       err = block->ops->disable(block);
+                       if (err < 0)
+                               dev_err(dsp->dev,
+                                       "error: cant disable block %d:%d\n",
+                                       block->type, block->index);
+               }
+       }
+
+       /* mark each block as free */
+       list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
+               list_del(&block->module_list);
+               list_move(&block->list, &dsp->free_block_list);
+       }
+}
+
+/* prepare the memory block to receive data from host - callers hold locks */
+static int block_module_prepare(struct sst_module *module)
+{
+       struct sst_mem_block *block;
+       int ret = 0;
+
+       /* enable each block so that's it'e ready for module P/S data */
+       list_for_each_entry(block, &module->block_list, module_list) {
+
+               if (block->ops && block->ops->enable) {
+                       ret = block->ops->enable(block);
+                       if (ret < 0) {
+                               dev_err(module->dsp->dev,
+                                       "error: cant disable block %d:%d\n",
+                                       block->type, block->index);
+                               goto err;
+                       }
+               }
+       }
+       return ret;
+
+err:
+       list_for_each_entry(block, &module->block_list, module_list) {
+               if (block->ops && block->ops->disable)
+                       block->ops->disable(block);
+       }
+       return ret;
+}
+
+/* allocate memory blocks for static module addresses - callers hold locks */
+static int block_alloc_fixed(struct sst_module *module,
+       struct sst_module_data *data)
+{
+       struct sst_dsp *dsp = module->dsp;
+       struct sst_mem_block *block, *tmp;
+       u32 end = data->offset + data->size, block_end;
+       int err;
+
+       /* only IRAM/DRAM blocks are managed */
+       if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM)
+               return 0;
+
+       /* are blocks already attached to this module */
+       list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
+
+               /* force compacting mem blocks of the same data_type */
+               if (block->data_type != data->data_type)
+                       continue;
+
+               block_end = block->offset + block->size;
+
+               /* find block that holds section */
+               if (data->offset >= block->offset && end < block_end)
+                       return 0;
+
+               /* does block span more than 1 section */
+               if (data->offset >= block->offset && data->offset < block_end) {
+
+                       err = block_alloc_contiguous(module, data,
+                               block->offset + block->size,
+                               data->size - block->size + data->offset - block->offset);
+                       if (err < 0)
+                               return -ENOMEM;
+
+                       /* module already owns blocks */
+                       return 0;
+               }
+       }
+
+       /* find first free blocks that can hold section in free list */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+               block_end = block->offset + block->size;
+
+               /* find block that holds section */
+               if (data->offset >= block->offset && end < block_end) {
+
+                       /* add block */
+                       block->data_type = data->data_type;
+                       list_move(&block->list, &dsp->used_block_list);
+                       list_add(&block->module_list, &module->block_list);
+                       return 0;
+               }
+
+               /* does block span more than 1 section */
+               if (data->offset >= block->offset && data->offset < block_end) {
+
+                       err = block_alloc_contiguous(module, data,
+                               block->offset + block->size,
+                               data->size - block->size);
+                       if (err < 0)
+                               return -ENOMEM;
+
+                       /* add block */
+                       block->data_type = data->data_type;
+                       list_move(&block->list, &dsp->used_block_list);
+                       list_add(&block->module_list, &module->block_list);
+                       return 0;
+               }
+
+       }
+
+       return -ENOMEM;
+}
+
+/* Load fixed module data into DSP memory blocks */
+int sst_module_insert_fixed_block(struct sst_module *module,
+       struct sst_module_data *data)
+{
+       struct sst_dsp *dsp = module->dsp;
+       int ret;
+
+       mutex_lock(&dsp->mutex);
+
+       /* alloc blocks that includes this section */
+       ret = block_alloc_fixed(module, data);
+       if (ret < 0) {
+               dev_err(dsp->dev,
+                       "error: no free blocks for section at offset 0x%x size 0x%x\n",
+                       data->offset, data->size);
+               mutex_unlock(&dsp->mutex);
+               return -ENOMEM;
+       }
+
+       /* prepare DSP blocks for module copy */
+       ret = block_module_prepare(module);
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: fw module prepare failed\n");
+               goto err;
+       }
+
+       /* copy partial module data to blocks */
+       sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size);
+
+       mutex_unlock(&dsp->mutex);
+       return ret;
+
+err:
+       block_module_remove(module);
+       mutex_unlock(&dsp->mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block);
+
+/* Unload entire module from DSP memory */
+int sst_block_module_remove(struct sst_module *module)
+{
+       struct sst_dsp *dsp = module->dsp;
+
+       mutex_lock(&dsp->mutex);
+       block_module_remove(module);
+       mutex_unlock(&dsp->mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_block_module_remove);
+
+/* register a DSP memory block for use with FW based modules */
+struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
+       u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
+       void *private)
+{
+       struct sst_mem_block *block;
+
+       block = kzalloc(sizeof(*block), GFP_KERNEL);
+       if (block == NULL)
+               return NULL;
+
+       block->offset = offset;
+       block->size = size;
+       block->index = index;
+       block->type = type;
+       block->dsp = dsp;
+       block->private = private;
+       block->ops = ops;
+
+       mutex_lock(&dsp->mutex);
+       list_add(&block->list, &dsp->free_block_list);
+       mutex_unlock(&dsp->mutex);
+
+       return block;
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_register);
+
+/* unregister all DSP memory blocks */
+void sst_mem_block_unregister_all(struct sst_dsp *dsp)
+{
+       struct sst_mem_block *block, *tmp;
+
+       mutex_lock(&dsp->mutex);
+
+       /* unregister used blocks */
+       list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) {
+               list_del(&block->list);
+               kfree(block);
+       }
+
+       /* unregister free blocks */
+       list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+               list_del(&block->list);
+               kfree(block);
+       }
+
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all);
+
+/* allocate scratch buffer blocks */
+struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
+{
+       struct sst_module *sst_module, *scratch;
+       struct sst_mem_block *block, *tmp;
+       u32 block_size;
+       int ret = 0;
+
+       scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL);
+       if (scratch == NULL)
+               return NULL;
+
+       mutex_lock(&dsp->mutex);
+
+       /* calculate required scratch size */
+       list_for_each_entry(sst_module, &dsp->module_list, list) {
+               if (scratch->s.size > sst_module->s.size)
+                       scratch->s.size = scratch->s.size;
+               else
+                       scratch->s.size = sst_module->s.size;
+       }
+
+       dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n",
+               scratch->s.size);
+
+       /* init scratch module */
+       scratch->dsp = dsp;
+       scratch->s.type = SST_MEM_DRAM;
+       scratch->s.data_type = SST_DATA_S;
+       INIT_LIST_HEAD(&scratch->block_list);
+
+       /* check free blocks before looking at used blocks for space */
+       if (!list_empty(&dsp->free_block_list))
+               block = list_first_entry(&dsp->free_block_list,
+                       struct sst_mem_block, list);
+       else
+               block = list_first_entry(&dsp->used_block_list,
+                       struct sst_mem_block, list);
+       block_size = block->size;
+
+       /* allocate blocks for module scratch buffers */
+       dev_dbg(dsp->dev, "allocating scratch blocks\n");
+       ret = block_alloc(scratch, &scratch->s);
+       if (ret < 0) {
+               dev_err(dsp->dev, "error: can't alloc scratch blocks\n");
+               goto err;
+       }
+
+       /* assign the same offset of scratch to each module */
+       list_for_each_entry(sst_module, &dsp->module_list, list)
+               sst_module->s.offset = scratch->s.offset;
+
+       mutex_unlock(&dsp->mutex);
+       return scratch;
+
+err:
+       list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
+               list_del(&block->module_list);
+       mutex_unlock(&dsp->mutex);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch);
+
+/* free all scratch blocks */
+void sst_mem_block_free_scratch(struct sst_dsp *dsp,
+       struct sst_module *scratch)
+{
+       struct sst_mem_block *block, *tmp;
+
+       mutex_lock(&dsp->mutex);
+
+       list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
+               list_del(&block->module_list);
+
+       mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch);
+
+/* get a module from it's unique ID */
+struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
+{
+       struct sst_module *module;
+
+       mutex_lock(&dsp->mutex);
+
+       list_for_each_entry(module, &dsp->module_list, list) {
+               if (module->id == id) {
+                       mutex_unlock(&dsp->mutex);
+                       return module;
+               }
+       }
+
+       mutex_unlock(&dsp->mutex);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_module_get_from_id);
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
new file mode 100644 (file)
index 0000000..f5ebf36
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Intel Haswell SST DSP driver
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+#include "sst-haswell-ipc.h"
+
+#include <trace/events/hswadsp.h>
+
+#define SST_HSW_FW_SIGNATURE_SIZE      4
+#define SST_HSW_FW_SIGN                        "$SST"
+#define SST_HSW_FW_LIB_SIGN            "$LIB"
+
+#define SST_WPT_SHIM_OFFSET    0xFB000
+#define SST_LP_SHIM_OFFSET     0xE7000
+#define SST_WPT_IRAM_OFFSET    0xA0000
+#define SST_LP_IRAM_OFFSET     0x80000
+
+#define SST_SHIM_PM_REG                0x84
+
+#define SST_HSW_IRAM   1
+#define SST_HSW_DRAM   2
+#define SST_HSW_REGS   3
+
+struct dma_block_info {
+       __le32 type;            /* IRAM/DRAM */
+       __le32 size;            /* Bytes */
+       __le32 ram_offset;      /* Offset in I/DRAM */
+       __le32 rsvd;            /* Reserved field */
+} __attribute__((packed));
+
+struct fw_module_info {
+       __le32 persistent_size;
+       __le32 scratch_size;
+} __attribute__((packed));
+
+struct fw_header {
+       unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */
+       __le32 file_size;               /* size of fw minus this header */
+       __le32 modules;         /*  # of modules */
+       __le32 file_format;     /* version of header format */
+       __le32 reserved[4];
+} __attribute__((packed));
+
+struct fw_module_header {
+       unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */
+       __le32 mod_size;        /* size of module */
+       __le32 blocks;  /* # of blocks */
+       __le16 padding;
+       __le16 type;    /* codec type, pp lib */
+       __le32 entry_point;
+       struct fw_module_info info;
+} __attribute__((packed));
+
+static void hsw_free(struct sst_dsp *sst);
+
+static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+       struct fw_module_header *module)
+{
+       struct dma_block_info *block;
+       struct sst_module *mod;
+       struct sst_module_data block_data;
+       struct sst_module_template template;
+       int count;
+       void __iomem *ram;
+
+       /* TODO: allowed module types need to be configurable */
+       if (module->type != SST_HSW_MODULE_BASE_FW
+               && module->type != SST_HSW_MODULE_PCM_SYSTEM
+               && module->type != SST_HSW_MODULE_PCM
+               && module->type != SST_HSW_MODULE_PCM_REFERENCE
+               && module->type != SST_HSW_MODULE_PCM_CAPTURE
+               && module->type != SST_HSW_MODULE_LPAL)
+               return 0;
+
+       dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
+               module->signature, module->mod_size,
+               module->blocks, module->type);
+       dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
+       dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
+               module->info.persistent_size, module->info.scratch_size);
+
+       memset(&template, 0, sizeof(template));
+       template.id = module->type;
+       template.entry = module->entry_point;
+       template.p.size = module->info.persistent_size;
+       template.p.type = SST_MEM_DRAM;
+       template.p.data_type = SST_DATA_P;
+       template.s.size = module->info.scratch_size;
+       template.s.type = SST_MEM_DRAM;
+       template.s.data_type = SST_DATA_S;
+
+       mod = sst_module_new(fw, &template, NULL);
+       if (mod == NULL)
+               return -ENOMEM;
+
+       block = (void *)module + sizeof(*module);
+
+       for (count = 0; count < module->blocks; count++) {
+
+               if (block->size <= 0) {
+                       dev_err(dsp->dev,
+                               "error: block %d size invalid\n", count);
+                       sst_module_free(mod);
+                       return -EINVAL;
+               }
+
+               switch (block->type) {
+               case SST_HSW_IRAM:
+                       ram = dsp->addr.lpe;
+                       block_data.offset =
+                               block->ram_offset + dsp->addr.iram_offset;
+                       block_data.type = SST_MEM_IRAM;
+                       break;
+               case SST_HSW_DRAM:
+                       ram = dsp->addr.lpe;
+                       block_data.offset = block->ram_offset;
+                       block_data.type = SST_MEM_DRAM;
+                       break;
+               default:
+                       dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
+                               block->type, count);
+                       sst_module_free(mod);
+                       return -EINVAL;
+               }
+
+               block_data.size = block->size;
+               block_data.data_type = SST_DATA_M;
+               block_data.data = (void *)block + sizeof(*block);
+               block_data.data_offset = block_data.data - fw->dma_buf;
+
+               dev_dbg(dsp->dev, "copy firmware block %d type 0x%x "
+                       "size 0x%x ==> ram %p offset 0x%x\n",
+                       count, block->type, block->size, ram,
+                       block->ram_offset);
+
+               sst_module_insert_fixed_block(mod, &block_data);
+
+               block = (void *)block + sizeof(*block) + block->size;
+       }
+       return 0;
+}
+
+static int hsw_parse_fw_image(struct sst_fw *sst_fw)
+{
+       struct fw_header *header;
+       struct sst_module *scratch;
+       struct fw_module_header *module;
+       struct sst_dsp *dsp = sst_fw->dsp;
+       struct sst_hsw *hsw = sst_fw->private;
+       int ret, count;
+
+       /* Read the header information from the data pointer */
+       header = (struct fw_header *)sst_fw->dma_buf;
+
+       /* verify FW */
+       if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
+               (sst_fw->size != header->file_size + sizeof(*header))) {
+               dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+               header->file_size, header->modules,
+               header->file_format, sizeof(*header));
+
+       /* parse each module */
+       module = (void *)sst_fw->dma_buf + sizeof(*header);
+       for (count = 0; count < header->modules; count++) {
+
+               /* module */
+               ret = hsw_parse_module(dsp, sst_fw, module);
+               if (ret < 0) {
+                       dev_err(dsp->dev, "error: invalid module %d\n", count);
+                       return ret;
+               }
+               module = (void *)module + sizeof(*module) + module->mod_size;
+       }
+
+       /* allocate persistent/scratch mem regions */
+       scratch = sst_mem_block_alloc_scratch(dsp);
+       if (scratch == NULL)
+               return -ENOMEM;
+
+       sst_hsw_set_scratch_module(hsw, scratch);
+
+       return 0;
+}
+
+static irqreturn_t hsw_irq(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       u32 isr;
+       int ret = IRQ_NONE;
+
+       spin_lock(&sst->spinlock);
+
+       /* Interrupt arrived, check src */
+       isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
+       if (isr & SST_ISRX_DONE) {
+               trace_sst_irq_done(isr,
+                       sst_dsp_shim_read_unlocked(sst, SST_IMRX));
+
+               /* Mask Done interrupt before return */
+               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                       SST_IMRX_DONE, SST_IMRX_DONE);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       if (isr & SST_ISRX_BUSY) {
+               trace_sst_irq_busy(isr,
+                       sst_dsp_shim_read_unlocked(sst, SST_IMRX));
+
+               /* Mask Busy interrupt before return */
+               sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                       SST_IMRX_BUSY, SST_IMRX_BUSY);
+               ret = IRQ_WAKE_THREAD;
+       }
+
+       spin_unlock(&sst->spinlock);
+       return ret;
+}
+
+static void hsw_boot(struct sst_dsp *sst)
+{
+       /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
+
+       /* stall DSP core, set clk to 192/96Mhz */
+       sst_dsp_shim_update_bits_unlocked(sst,
+               SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
+               SST_CSR_STALL | SST_CSR_DCS(4));
+
+       /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
+               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
+               SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
+
+       /* disable DMA finish function for SSP0 & SSP1 */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
+               SST_CSR2_SDFD_SSP1);
+
+       /* enable DMA engine 0,1 all channels to access host memory */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC,
+               SST_HDMC_HDDA1(0xff)  | SST_HDMC_HDDA0(0xff),
+               SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff));
+
+       /* disable all clock gating */
+       writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+       /* set DSP to RUN */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
+}
+
+static void hsw_reset(struct sst_dsp *sst)
+{
+       /* put DSP into reset and stall */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL);
+
+       /* keep in reset for 10ms */
+       mdelay(10);
+
+       /* take DSP out of reset and keep stalled for FW loading */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+               SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
+}
+
+struct sst_adsp_memregion {
+       u32 start;
+       u32 end;
+       int blocks;
+       enum sst_mem_type type;
+};
+
+/* lynx point ADSP mem regions */
+static const struct sst_adsp_memregion lp_region[] = {
+       {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+       {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
+       {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */
+};
+
+/* wild cat point ADSP mem regions */
+static const struct sst_adsp_memregion wpt_region[] = {
+       {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+       {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
+       {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */
+       {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */
+};
+
+static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       /* ADSP DRAM & IRAM */
+       sst->addr.lpe_base = pdata->lpe_base;
+       sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+       if (!sst->addr.lpe)
+               return -ENODEV;
+
+       /* ADSP PCI MMIO config space */
+       sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+       if (!sst->addr.pci_cfg) {
+               iounmap(sst->addr.lpe);
+               return -ENODEV;
+       }
+
+       /* SST Shim */
+       sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+       return 0;
+}
+
+static u32 hsw_block_get_bit(struct sst_mem_block *block)
+{
+       u32 bit = 0, shift = 0;
+
+       switch (block->type) {
+       case SST_MEM_DRAM:
+               shift = 16;
+               break;
+       case SST_MEM_IRAM:
+               shift = 6;
+               break;
+       default:
+               return 0;
+       }
+
+       bit = 1 << (block->index + shift);
+
+       return bit;
+}
+
+/* enable 32kB memory block - locks held by caller */
+static int hsw_block_enable(struct sst_mem_block *block)
+{
+       struct sst_dsp *sst = block->dsp;
+       u32 bit, val;
+
+       if (block->users++ > 0)
+               return 0;
+
+       dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
+               block->type, block->index, block->offset);
+
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       bit = hsw_block_get_bit(block);
+       writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       /* wait 18 DSP clock ticks */
+       udelay(10);
+
+       return 0;
+}
+
+/* disable 32kB memory block - locks held by caller */
+static int hsw_block_disable(struct sst_mem_block *block)
+{
+       struct sst_dsp *sst = block->dsp;
+       u32 bit, val;
+
+       if (--block->users > 0)
+               return 0;
+
+       dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
+               block->type, block->index, block->offset);
+
+       val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+       bit = hsw_block_get_bit(block);
+       writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       return 0;
+}
+
+static struct sst_block_ops sst_hsw_ops = {
+       .enable = hsw_block_enable,
+       .disable = hsw_block_disable,
+};
+
+static int hsw_enable_shim(struct sst_dsp *sst)
+{
+       int tries = 10;
+       u32 reg;
+
+       /* enable shim */
+       reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG);
+       writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG);
+
+       /* check that ADSP shim is enabled */
+       while (tries--) {
+               reg = sst_dsp_shim_read_unlocked(sst, SST_CSR);
+               if (reg != 0xffffffff)
+                       return 0;
+
+               msleep(1);
+       }
+
+       return -ENODEV;
+}
+
+static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+       const struct sst_adsp_memregion *region;
+       struct device *dev;
+       int ret = -ENODEV, i, j, region_count;
+       u32 offset, size;
+
+       dev = sst->dev;
+
+       switch (sst->id) {
+       case SST_DEV_ID_LYNX_POINT:
+               region = lp_region;
+               region_count = ARRAY_SIZE(lp_region);
+               sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
+               sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
+               break;
+       case SST_DEV_ID_WILDCAT_POINT:
+               region = wpt_region;
+               region_count = ARRAY_SIZE(wpt_region);
+               sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
+               sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
+               break;
+       default:
+               dev_err(dev, "error: failed to get mem resources\n");
+               return ret;
+       }
+
+       ret = hsw_acpi_resource_map(sst, pdata);
+       if (ret < 0) {
+               dev_err(dev, "error: failed to map resources\n");
+               return ret;
+       }
+
+       /* enable the DSP SHIM */
+       ret = hsw_enable_shim(sst);
+       if (ret < 0) {
+               dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
+               return ret;
+       }
+
+       ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       /* Enable Interrupt from both sides */
+       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0);
+       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD,
+               (0x3 | 0x1 << 16 | 0x3 << 21), 0x0);
+
+       /* register DSP memory blocks - ideally we should get this from ACPI */
+       for (i = 0; i < region_count; i++) {
+               offset = region[i].start;
+               size = (region[i].end - region[i].start) / region[i].blocks;
+
+               /* register individual memory blocks */
+               for (j = 0; j < region[i].blocks; j++) {
+                       sst_mem_block_register(sst, offset, size,
+                               region[i].type, &sst_hsw_ops, j, sst);
+                       offset += size;
+               }
+       }
+
+       /* set default power gating mask */
+       writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+       return 0;
+}
+
+static void hsw_free(struct sst_dsp *sst)
+{
+       sst_mem_block_unregister_all(sst);
+       iounmap(sst->addr.lpe);
+       iounmap(sst->addr.pci_cfg);
+}
+
+struct sst_ops haswell_ops = {
+       .reset = hsw_reset,
+       .boot = hsw_boot,
+       .write = sst_shim32_write,
+       .read = sst_shim32_read,
+       .write64 = sst_shim32_write64,
+       .read64 = sst_shim32_read64,
+       .ram_read = sst_memcpy_fromio_32,
+       .ram_write = sst_memcpy_toio_32,
+       .irq_handler = hsw_irq,
+       .init = hsw_init,
+       .free = hsw_free,
+       .parse_fw = hsw_parse_fw_image,
+};
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
new file mode 100644 (file)
index 0000000..f46bb4d
--- /dev/null
@@ -0,0 +1,1785 @@
+/*
+ *  Intel SST Haswell/Broadwell IPC Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+
+#include "sst-haswell-ipc.h"
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+/* Global Message - Generic */
+#define IPC_GLB_TYPE_SHIFT     24
+#define IPC_GLB_TYPE_MASK      (0x1f << IPC_GLB_TYPE_SHIFT)
+#define IPC_GLB_TYPE(x)                (x << IPC_GLB_TYPE_SHIFT)
+
+/* Global Message - Reply */
+#define IPC_GLB_REPLY_SHIFT    0
+#define IPC_GLB_REPLY_MASK     (0x1f << IPC_GLB_REPLY_SHIFT)
+#define IPC_GLB_REPLY_TYPE(x)  (x << IPC_GLB_REPLY_TYPE_SHIFT)
+
+/* Stream Message - Generic */
+#define IPC_STR_TYPE_SHIFT     20
+#define IPC_STR_TYPE_MASK      (0xf << IPC_STR_TYPE_SHIFT)
+#define IPC_STR_TYPE(x)                (x << IPC_STR_TYPE_SHIFT)
+#define IPC_STR_ID_SHIFT       16
+#define IPC_STR_ID_MASK                (0xf << IPC_STR_ID_SHIFT)
+#define IPC_STR_ID(x)          (x << IPC_STR_ID_SHIFT)
+
+/* Stream Message - Reply */
+#define IPC_STR_REPLY_SHIFT    0
+#define IPC_STR_REPLY_MASK     (0x1f << IPC_STR_REPLY_SHIFT)
+
+/* Stream Stage Message - Generic */
+#define IPC_STG_TYPE_SHIFT     12
+#define IPC_STG_TYPE_MASK      (0xf << IPC_STG_TYPE_SHIFT)
+#define IPC_STG_TYPE(x)                (x << IPC_STG_TYPE_SHIFT)
+#define IPC_STG_ID_SHIFT       10
+#define IPC_STG_ID_MASK                (0x3 << IPC_STG_ID_SHIFT)
+#define IPC_STG_ID(x)          (x << IPC_STG_ID_SHIFT)
+
+/* Stream Stage Message - Reply */
+#define IPC_STG_REPLY_SHIFT    0
+#define IPC_STG_REPLY_MASK     (0x1f << IPC_STG_REPLY_SHIFT)
+
+/* Debug Log Message - Generic */
+#define IPC_LOG_OP_SHIFT       20
+#define IPC_LOG_OP_MASK                (0xf << IPC_LOG_OP_SHIFT)
+#define IPC_LOG_OP_TYPE(x)     (x << IPC_LOG_OP_SHIFT)
+#define IPC_LOG_ID_SHIFT       16
+#define IPC_LOG_ID_MASK                (0xf << IPC_LOG_ID_SHIFT)
+#define IPC_LOG_ID(x)          (x << IPC_LOG_ID_SHIFT)
+
+/* IPC message timeout (msecs) */
+#define IPC_TIMEOUT_MSECS      300
+#define IPC_BOOT_MSECS         200
+#define IPC_MSG_WAIT           0
+#define IPC_MSG_NOWAIT         1
+
+/* Firmware Ready Message */
+#define IPC_FW_READY           (0x1 << 29)
+#define IPC_STATUS_MASK                (0x3 << 30)
+
+#define IPC_EMPTY_LIST_SIZE    8
+#define IPC_MAX_STREAMS                4
+
+/* Mailbox */
+#define IPC_MAX_MAILBOX_BYTES  256
+
+/* Global Message - Types and Replies */
+enum ipc_glb_type {
+       IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
+       IPC_GLB_PERFORMANCE_MONITOR = 1,        /* Performance monitoring actions */
+       IPC_GLB_ALLOCATE_STREAM = 3,            /* Request to allocate new stream */
+       IPC_GLB_FREE_STREAM = 4,                /* Request to free stream */
+       IPC_GLB_GET_FW_CAPABILITIES = 5,        /* Retrieves firmware capabilities */
+       IPC_GLB_STREAM_MESSAGE = 6,             /* Message directed to stream or its stages */
+       /* Request to store firmware context during D0->D3 transition */
+       IPC_GLB_REQUEST_DUMP = 7,
+       /* Request to restore firmware context during D3->D0 transition */
+       IPC_GLB_RESTORE_CONTEXT = 8,
+       IPC_GLB_GET_DEVICE_FORMATS = 9,         /* Set device format */
+       IPC_GLB_SET_DEVICE_FORMATS = 10,        /* Get device format */
+       IPC_GLB_SHORT_REPLY = 11,
+       IPC_GLB_ENTER_DX_STATE = 12,
+       IPC_GLB_GET_MIXER_STREAM_INFO = 13,     /* Request mixer stream params */
+       IPC_GLB_DEBUG_LOG_MESSAGE = 14,         /* Message to or from the debug logger. */
+       IPC_GLB_REQUEST_TRANSFER = 16,          /* < Request Transfer for host */
+       IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17,      /* Maximum message number */
+};
+
+enum ipc_glb_reply {
+       IPC_GLB_REPLY_SUCCESS = 0,              /* The operation was successful. */
+       IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1,  /* Invalid parameter was passed. */
+       IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */
+       IPC_GLB_REPLY_OUT_OF_RESOURCES = 3,     /* No resources to satisfy the request. */
+       IPC_GLB_REPLY_BUSY = 4,                 /* The system or resource is busy. */
+       IPC_GLB_REPLY_PENDING = 5,              /* The action was scheduled for processing.  */
+       IPC_GLB_REPLY_FAILURE = 6,              /* Critical error happened. */
+       IPC_GLB_REPLY_INVALID_REQUEST = 7,      /* Request can not be completed. */
+       IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8,  /* Processing stage was uninitialized. */
+       IPC_GLB_REPLY_NOT_FOUND = 9,            /* Required resource can not be found. */
+       IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10,  /* Source was not started. */
+};
+
+/* Stream Message - Types */
+enum ipc_str_operation {
+       IPC_STR_RESET = 0,
+       IPC_STR_PAUSE = 1,
+       IPC_STR_RESUME = 2,
+       IPC_STR_STAGE_MESSAGE = 3,
+       IPC_STR_NOTIFICATION = 4,
+       IPC_STR_MAX_MESSAGE
+};
+
+/* Stream Stage Message Types */
+enum ipc_stg_operation {
+       IPC_STG_GET_VOLUME = 0,
+       IPC_STG_SET_VOLUME,
+       IPC_STG_SET_WRITE_POSITION,
+       IPC_STG_SET_FX_ENABLE,
+       IPC_STG_SET_FX_DISABLE,
+       IPC_STG_SET_FX_GET_PARAM,
+       IPC_STG_SET_FX_SET_PARAM,
+       IPC_STG_SET_FX_GET_INFO,
+       IPC_STG_MUTE_LOOPBACK,
+       IPC_STG_MAX_MESSAGE
+};
+
+/* Stream Stage Message Types For Notification*/
+enum ipc_stg_operation_notify {
+       IPC_POSITION_CHANGED = 0,
+       IPC_STG_GLITCH,
+       IPC_STG_MAX_NOTIFY
+};
+
+enum ipc_glitch_type {
+       IPC_GLITCH_UNDERRUN = 1,
+       IPC_GLITCH_DECODER_ERROR,
+       IPC_GLITCH_DOUBLED_WRITE_POS,
+       IPC_GLITCH_MAX
+};
+
+/* Debug Control */
+enum ipc_debug_operation {
+       IPC_DEBUG_ENABLE_LOG = 0,
+       IPC_DEBUG_DISABLE_LOG = 1,
+       IPC_DEBUG_REQUEST_LOG_DUMP = 2,
+       IPC_DEBUG_NOTIFY_LOG_DUMP = 3,
+       IPC_DEBUG_MAX_DEBUG_LOG
+};
+
+/* Firmware Ready */
+struct sst_hsw_ipc_fw_ready {
+       u32 inbox_offset;
+       u32 outbox_offset;
+       u32 inbox_size;
+       u32 outbox_size;
+       u32 fw_info_size;
+       u8 fw_info[1];
+} __attribute__((packed));
+
+struct ipc_message {
+       struct list_head list;
+       u32 header;
+
+       /* direction wrt host CPU */
+       char tx_data[IPC_MAX_MAILBOX_BYTES];
+       size_t tx_size;
+       char rx_data[IPC_MAX_MAILBOX_BYTES];
+       size_t rx_size;
+
+       wait_queue_head_t waitq;
+       bool pending;
+       bool complete;
+       bool wait;
+       int errno;
+};
+
+struct sst_hsw_stream;
+struct sst_hsw;
+
+/* Stream infomation */
+struct sst_hsw_stream {
+       /* configuration */
+       struct sst_hsw_ipc_stream_alloc_req request;
+       struct sst_hsw_ipc_stream_alloc_reply reply;
+       struct sst_hsw_ipc_stream_free_req free_req;
+
+       /* Mixer info */
+       u32 mute_volume[SST_HSW_NO_CHANNELS];
+       u32 mute[SST_HSW_NO_CHANNELS];
+
+       /* runtime info */
+       struct sst_hsw *hsw;
+       int host_id;
+       bool commited;
+       bool running;
+
+       /* Notification work */
+       struct work_struct notify_work;
+       u32 header;
+
+       /* Position info from DSP */
+       struct sst_hsw_ipc_stream_set_position wpos;
+       struct sst_hsw_ipc_stream_get_position rpos;
+       struct sst_hsw_ipc_stream_glitch_position glitch;
+
+       /* Volume info */
+       struct sst_hsw_ipc_volume_req vol_req;
+
+       /* driver callback */
+       u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
+       void *pdata;
+
+       struct list_head node;
+};
+
+/* FW log ring information */
+struct sst_hsw_log_stream {
+       dma_addr_t dma_addr;
+       unsigned char *dma_area;
+       unsigned char *ring_descr;
+       int pages;
+       int size;
+
+       /* Notification work */
+       struct work_struct notify_work;
+       wait_queue_head_t readers_wait_q;
+       struct mutex rw_mutex;
+
+       u32 last_pos;
+       u32 curr_pos;
+       u32 reader_pos;
+
+       /* fw log config */
+       u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
+
+       struct sst_hsw *hsw;
+};
+
+/* SST Haswell IPC data */
+struct sst_hsw {
+       struct device *dev;
+       struct sst_dsp *dsp;
+       struct platform_device *pdev_pcm;
+
+       /* FW config */
+       struct sst_hsw_ipc_fw_ready fw_ready;
+       struct sst_hsw_ipc_fw_version version;
+       struct sst_module *scratch;
+       bool fw_done;
+
+       /* stream */
+       struct list_head stream_list;
+
+       /* global mixer */
+       struct sst_hsw_ipc_stream_info_reply mixer_info;
+       enum sst_hsw_volume_curve curve_type;
+       u32 curve_duration;
+       u32 mute[SST_HSW_NO_CHANNELS];
+       u32 mute_volume[SST_HSW_NO_CHANNELS];
+
+       /* DX */
+       struct sst_hsw_ipc_dx_reply dx;
+
+       /* boot */
+       wait_queue_head_t boot_wait;
+       bool boot_complete;
+       bool shutdown;
+
+       /* IPC messaging */
+       struct list_head tx_list;
+       struct list_head rx_list;
+       struct list_head empty_list;
+       wait_queue_head_t wait_txq;
+       struct task_struct *tx_thread;
+       struct kthread_worker kworker;
+       struct kthread_work kwork;
+       bool pending;
+       struct ipc_message *msg;
+
+       /* FW log stream */
+       struct sst_hsw_log_stream log_stream;
+};
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/hswadsp.h>
+
+static inline u32 msg_get_global_type(u32 msg)
+{
+       return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_global_reply(u32 msg)
+{
+       return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT;
+}
+
+static inline u32 msg_get_stream_type(u32 msg)
+{
+       return (msg & IPC_STR_TYPE_MASK) >>  IPC_STR_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_stage_type(u32 msg)
+{
+       return (msg & IPC_STG_TYPE_MASK) >>  IPC_STG_TYPE_SHIFT;
+}
+
+static inline u32 msg_set_stage_type(u32 msg, u32 type)
+{
+       return (msg & ~IPC_STG_TYPE_MASK) +
+               (type << IPC_STG_TYPE_SHIFT);
+}
+
+static inline u32 msg_get_stream_id(u32 msg)
+{
+       return (msg & IPC_STR_ID_MASK) >>  IPC_STR_ID_SHIFT;
+}
+
+static inline u32 msg_get_notify_reason(u32 msg)
+{
+       return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
+}
+
+u32 create_channel_map(enum sst_hsw_channel_config config)
+{
+       switch (config) {
+       case SST_HSW_CHANNEL_CONFIG_MONO:
+               return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER);
+       case SST_HSW_CHANNEL_CONFIG_STEREO:
+               return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_RIGHT << 4));
+       case SST_HSW_CHANNEL_CONFIG_2_POINT_1:
+               return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_RIGHT << 4)
+                       | (SST_HSW_CHANNEL_LFE << 8 ));
+       case SST_HSW_CHANNEL_CONFIG_3_POINT_0:
+               return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8));
+       case SST_HSW_CHANNEL_CONFIG_3_POINT_1:
+               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_LFE << 12));
+       case SST_HSW_CHANNEL_CONFIG_QUATRO:
+               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_RIGHT << 4)
+                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 8)
+                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12));
+       case SST_HSW_CHANNEL_CONFIG_4_POINT_0:
+               return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_CENTER_SURROUND << 12));
+       case SST_HSW_CHANNEL_CONFIG_5_POINT_0:
+               return (0xFFF00000 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_CENTER << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
+                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16));
+       case SST_HSW_CHANNEL_CONFIG_5_POINT_1:
+               return (0xFF000000 | SST_HSW_CHANNEL_CENTER
+                       | (SST_HSW_CHANNEL_LEFT << 4)
+                       | (SST_HSW_CHANNEL_RIGHT << 8)
+                       | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
+                       | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)
+                       | (SST_HSW_CHANNEL_LFE << 20));
+       case SST_HSW_CHANNEL_CONFIG_DUAL_MONO:
+               return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
+                       | (SST_HSW_CHANNEL_LEFT << 4));
+       default:
+               return 0xFFFFFFFF;
+       }
+}
+
+static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw,
+       int stream_id)
+{
+       struct sst_hsw_stream *stream;
+
+       list_for_each_entry(stream, &hsw->stream_list, node) {
+               if (stream->reply.stream_hw_id == stream_id)
+                       return stream;
+       }
+
+       return NULL;
+}
+
+static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text)
+{
+       struct sst_dsp *sst = hsw->dsp;
+       u32 isr, ipcd, imrx, ipcx;
+
+       ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX);
+       isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
+       ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+       imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX);
+
+       dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n",
+               text, ipcx, isr, ipcd, imrx);
+}
+
+/* locks held by caller */
+static struct ipc_message *msg_get_empty(struct sst_hsw *hsw)
+{
+       struct ipc_message *msg = NULL;
+
+       if (!list_empty(&hsw->empty_list)) {
+               msg = list_first_entry(&hsw->empty_list, struct ipc_message,
+                       list);
+               list_del(&msg->list);
+       }
+
+       return msg;
+}
+
+static void ipc_tx_msgs(struct kthread_work *work)
+{
+       struct sst_hsw *hsw =
+               container_of(work, struct sst_hsw, kwork);
+       struct ipc_message *msg;
+       unsigned long flags;
+       u32 ipcx;
+
+       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+
+       if (list_empty(&hsw->tx_list) || hsw->pending) {
+               spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+               return;
+       }
+
+       /* if the DSP is busy we will TX messages after IRQ */
+       ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX);
+       if (ipcx & SST_IPCX_BUSY) {
+               spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+               return;
+       }
+
+       msg = list_first_entry(&hsw->tx_list, struct ipc_message, list);
+
+       list_move(&msg->list, &hsw->rx_list);
+
+       /* send the message */
+       sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size);
+       sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY);
+
+       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+}
+
+/* locks held by caller */
+static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg)
+{
+       msg->complete = true;
+       trace_ipc_reply("completed", msg->header);
+
+       if (!msg->wait)
+               list_add_tail(&msg->list, &hsw->empty_list);
+       else
+               wake_up(&msg->waitq);
+}
+
+static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg,
+       void *rx_data)
+{
+       unsigned long flags;
+       int ret;
+
+       /* wait for DSP completion (in all cases atm inc pending) */
+       ret = wait_event_timeout(msg->waitq, msg->complete,
+               msecs_to_jiffies(IPC_TIMEOUT_MSECS));
+
+       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+       if (ret == 0) {
+               ipc_shim_dbg(hsw, "message timeout");
+
+               trace_ipc_error("error message timeout for", msg->header);
+               ret = -ETIMEDOUT;
+       } else {
+
+               /* copy the data returned from DSP */
+               if (msg->rx_size)
+                       memcpy(rx_data, msg->rx_data, msg->rx_size);
+               ret = msg->errno;
+       }
+
+       list_add_tail(&msg->list, &hsw->empty_list);
+       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+       return ret;
+}
+
+static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data,
+       size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait)
+{
+       struct ipc_message *msg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+
+       msg = msg_get_empty(hsw);
+       if (msg == NULL) {
+               spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+               return -EBUSY;
+       }
+
+       if (tx_bytes)
+               memcpy(msg->tx_data, tx_data, tx_bytes);
+
+       msg->header = header;
+       msg->tx_size = tx_bytes;
+       msg->rx_size = rx_bytes;
+       msg->wait = wait;
+       msg->errno = 0;
+       msg->pending = false;
+       msg->complete = false;
+
+       list_add_tail(&msg->list, &hsw->tx_list);
+       spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+
+       queue_kthread_work(&hsw->kworker, &hsw->kwork);
+
+       if (wait)
+               return tx_wait_done(hsw, msg, rx_data);
+       else
+               return 0;
+}
+
+static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header,
+       void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
+{
+       return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data,
+               rx_bytes, 1);
+}
+
+static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header,
+       void *tx_data, size_t tx_bytes)
+{
+       return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0);
+}
+
+static void hsw_fw_ready(struct sst_hsw *hsw, u32 header)
+{
+       struct sst_hsw_ipc_fw_ready fw_ready;
+       u32 offset;
+
+       offset = (header & 0x1FFFFFFF) << 3;
+
+       dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
+               header, offset);
+
+       /* copy data from the DSP FW ready offset */
+       sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready));
+
+       sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset,
+               fw_ready.inbox_size, fw_ready.outbox_offset,
+               fw_ready.outbox_size);
+
+       hsw->boot_complete = true;
+       wake_up(&hsw->boot_wait);
+
+       dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n",
+               fw_ready.inbox_offset, fw_ready.inbox_size);
+       dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n",
+               fw_ready.outbox_offset, fw_ready.outbox_size);
+}
+
+static void hsw_notification_work(struct work_struct *work)
+{
+       struct sst_hsw_stream *stream = container_of(work,
+                       struct sst_hsw_stream, notify_work);
+       struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch;
+       struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos;
+       struct sst_hsw *hsw = stream->hsw;
+       u32 reason;
+
+       reason = msg_get_notify_reason(stream->header);
+
+       switch (reason) {
+       case IPC_STG_GLITCH:
+               trace_ipc_notification("DSP stream under/overrun",
+                       stream->reply.stream_hw_id);
+               sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch));
+
+               dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n",
+                       glitch->glitch_type, glitch->present_pos,
+                       glitch->write_pos);
+               break;
+
+       case IPC_POSITION_CHANGED:
+               trace_ipc_notification("DSP stream position changed for",
+                       stream->reply.stream_hw_id);
+               sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos));
+
+               if (stream->notify_position)
+                       stream->notify_position(stream, stream->pdata);
+
+               break;
+       default:
+               dev_err(hsw->dev, "error: unknown notification 0x%x\n",
+                       stream->header);
+               break;
+       }
+
+       /* tell DSP that notification has been handled */
+       sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD,
+               SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+
+       /* unmask busy interrupt */
+       sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
+}
+
+static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header)
+{
+       struct ipc_message *msg;
+
+       /* clear reply bits & status bits */
+       header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
+
+       if (list_empty(&hsw->rx_list)) {
+               dev_err(hsw->dev, "error: rx list empty but received 0x%x\n",
+                       header);
+               return NULL;
+       }
+
+       list_for_each_entry(msg, &hsw->rx_list, list) {
+               if (msg->header == header)
+                       return msg;
+       }
+
+       return NULL;
+}
+
+static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg)
+{
+       struct sst_hsw_stream *stream;
+       u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
+       u32 stream_id = msg_get_stream_id(header);
+       u32 stream_msg = msg_get_stream_type(header);
+
+       stream = get_stream_by_id(hsw, stream_id);
+       if (stream == NULL)
+               return;
+
+       switch (stream_msg) {
+       case IPC_STR_STAGE_MESSAGE:
+       case IPC_STR_NOTIFICATION:
+       case IPC_STR_RESET:
+               break;
+       case IPC_STR_PAUSE:
+               stream->running = false;
+               trace_ipc_notification("stream paused",
+                       stream->reply.stream_hw_id);
+               break;
+       case IPC_STR_RESUME:
+               stream->running = true;
+               trace_ipc_notification("stream running",
+                       stream->reply.stream_hw_id);
+               break;
+       }
+}
+
+static int hsw_process_reply(struct sst_hsw *hsw, u32 header)
+{
+       struct ipc_message *msg;
+       u32 reply = msg_get_global_reply(header);
+
+       trace_ipc_reply("processing -->", header);
+
+       msg = reply_find_msg(hsw, header);
+       if (msg == NULL) {
+               trace_ipc_error("error: can't find message header", header);
+               return -EIO;
+       }
+
+       /* first process the header */
+       switch (reply) {
+       case IPC_GLB_REPLY_PENDING:
+               trace_ipc_pending_reply("received", header);
+               msg->pending = true;
+               hsw->pending = true;
+               return 1;
+       case IPC_GLB_REPLY_SUCCESS:
+               if (msg->pending) {
+                       trace_ipc_pending_reply("completed", header);
+                       sst_dsp_inbox_read(hsw->dsp, msg->rx_data,
+                               msg->rx_size);
+                       hsw->pending = false;
+               } else {
+                       /* copy data from the DSP */
+                       sst_dsp_outbox_read(hsw->dsp, msg->rx_data,
+                               msg->rx_size);
+               }
+               break;
+       /* these will be rare - but useful for debug */
+       case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE:
+               trace_ipc_error("error: unknown message type", header);
+               msg->errno = -EBADMSG;
+               break;
+       case IPC_GLB_REPLY_OUT_OF_RESOURCES:
+               trace_ipc_error("error: out of resources", header);
+               msg->errno = -ENOMEM;
+               break;
+       case IPC_GLB_REPLY_BUSY:
+               trace_ipc_error("error: reply busy", header);
+               msg->errno = -EBUSY;
+               break;
+       case IPC_GLB_REPLY_FAILURE:
+               trace_ipc_error("error: reply failure", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_STAGE_UNINITIALIZED:
+               trace_ipc_error("error: stage uninitialized", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_NOT_FOUND:
+               trace_ipc_error("error: reply not found", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_SOURCE_NOT_STARTED:
+               trace_ipc_error("error: source not started", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_INVALID_REQUEST:
+               trace_ipc_error("error: invalid request", header);
+               msg->errno = -EINVAL;
+               break;
+       case IPC_GLB_REPLY_ERROR_INVALID_PARAM:
+               trace_ipc_error("error: invalid parameter", header);
+               msg->errno = -EINVAL;
+               break;
+       default:
+               trace_ipc_error("error: unknown reply", header);
+               msg->errno = -EINVAL;
+               break;
+       }
+
+       /* update any stream states */
+       hsw_stream_update(hsw, msg);
+
+       /* wake up and return the error if we have waiters on this message ? */
+       list_del(&msg->list);
+       tx_msg_reply_complete(hsw, msg);
+
+       return 1;
+}
+
+static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
+{
+       u32 stream_msg, stream_id, stage_type;
+       struct sst_hsw_stream *stream;
+       int handled = 0;
+
+       stream_msg = msg_get_stream_type(header);
+       stream_id = msg_get_stream_id(header);
+       stage_type = msg_get_stage_type(header);
+
+       stream = get_stream_by_id(hsw, stream_id);
+       if (stream == NULL)
+               return handled;
+
+       stream->header = header;
+
+       switch (stream_msg) {
+       case IPC_STR_STAGE_MESSAGE:
+               dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n",
+                       header);
+               break;
+       case IPC_STR_NOTIFICATION:
+               schedule_work(&stream->notify_work);
+               break;
+       default:
+               /* handle pending message complete request */
+               handled = hsw_process_reply(hsw, header);
+               break;
+       }
+
+       return handled;
+}
+
+static int hsw_log_message(struct sst_hsw *hsw, u32 header)
+{
+       u32 operation = (header & IPC_LOG_OP_MASK) >>  IPC_LOG_OP_SHIFT;
+       struct sst_hsw_log_stream *stream = &hsw->log_stream;
+       int ret = 1;
+
+       if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) {
+               dev_err(hsw->dev,
+                       "error: log msg not implemented 0x%8.8x\n", header);
+               return 0;
+       }
+
+       mutex_lock(&stream->rw_mutex);
+       stream->last_pos = stream->curr_pos;
+       sst_dsp_inbox_read(
+               hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos));
+       mutex_unlock(&stream->rw_mutex);
+
+       schedule_work(&stream->notify_work);
+
+       return ret;
+}
+
+static int hsw_process_notification(struct sst_hsw *hsw)
+{
+       struct sst_dsp *sst = hsw->dsp;
+       u32 type, header;
+       int handled = 1;
+
+       header = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+       type = msg_get_global_type(header);
+
+       trace_ipc_request("processing -->", header);
+
+       /* FW Ready is a special case */
+       if (!hsw->boot_complete && header & IPC_FW_READY) {
+               hsw_fw_ready(hsw, header);
+               return handled;
+       }
+
+       switch (type) {
+       case IPC_GLB_GET_FW_VERSION:
+       case IPC_GLB_ALLOCATE_STREAM:
+       case IPC_GLB_FREE_STREAM:
+       case IPC_GLB_GET_FW_CAPABILITIES:
+       case IPC_GLB_REQUEST_DUMP:
+       case IPC_GLB_GET_DEVICE_FORMATS:
+       case IPC_GLB_SET_DEVICE_FORMATS:
+       case IPC_GLB_ENTER_DX_STATE:
+       case IPC_GLB_GET_MIXER_STREAM_INFO:
+       case IPC_GLB_MAX_IPC_MESSAGE_TYPE:
+       case IPC_GLB_RESTORE_CONTEXT:
+       case IPC_GLB_SHORT_REPLY:
+               dev_err(hsw->dev, "error: message type %d header 0x%x\n",
+                       type, header);
+               break;
+       case IPC_GLB_STREAM_MESSAGE:
+               handled = hsw_stream_message(hsw, header);
+               break;
+       case IPC_GLB_DEBUG_LOG_MESSAGE:
+               handled = hsw_log_message(hsw, header);
+               break;
+       default:
+               dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n",
+                       type, header);
+               break;
+       }
+
+       return handled;
+}
+
+static irqreturn_t hsw_irq_thread(int irq, void *context)
+{
+       struct sst_dsp *sst = (struct sst_dsp *) context;
+       struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
+       u32 ipcx, ipcd;
+       int handled;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sst->spinlock, flags);
+
+       ipcx = sst_dsp_ipc_msg_rx(hsw->dsp);
+       ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+
+       /* reply message from DSP */
+       if (ipcx & SST_IPCX_DONE) {
+
+               /* Handle Immediate reply from DSP Core */
+               handled = hsw_process_reply(hsw, ipcx);
+
+               if (handled > 0) {
+                       /* clear DONE bit - tell DSP we have completed */
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
+                               SST_IPCX_DONE, 0);
+
+                       /* unmask Done interrupt */
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                               SST_IMRX_DONE, 0);
+               }
+       }
+
+       /* new message from DSP */
+       if (ipcd & SST_IPCD_BUSY) {
+
+               /* Handle Notification and Delayed reply from DSP Core */
+               handled = hsw_process_notification(hsw);
+
+               /* clear BUSY bit and set DONE bit - accept new messages */
+               if (handled > 0) {
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
+                               SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+
+                       /* unmask busy interrupt */
+                       sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+                               SST_IMRX_BUSY, 0);
+               }
+       }
+
+       spin_unlock_irqrestore(&sst->spinlock, flags);
+
+       /* continue to send any remaining messages... */
+       queue_kthread_work(&hsw->kworker, &hsw->kwork);
+
+       return IRQ_HANDLED;
+}
+
+int sst_hsw_fw_get_version(struct sst_hsw *hsw,
+       struct sst_hsw_ipc_fw_version *version)
+{
+       int ret;
+
+       ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION),
+               NULL, 0, version, sizeof(*version));
+       if (ret < 0)
+               dev_err(hsw->dev, "error: get version failed\n");
+
+       return ret;
+}
+
+/* Mixer Controls */
+int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 stage_id, u32 channel)
+{
+       int ret;
+
+       ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel,
+               &stream->mute_volume[channel]);
+       if (ret < 0)
+               return ret;
+
+       ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
+                       stream->reply.stream_hw_id, channel);
+               return ret;
+       }
+
+       stream->mute[channel] = 1;
+       return 0;
+}
+
+int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 stage_id, u32 channel)
+
+{
+       int ret;
+
+       stream->mute[channel] = 0;
+       ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel,
+               stream->mute_volume[channel]);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
+                       stream->reply.stream_hw_id, channel);
+               return ret;
+       }
+
+       return 0;
+}
+
+int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 stage_id, u32 channel, u32 *volume)
+{
+       if (channel > 1)
+               return -EINVAL;
+
+       sst_dsp_read(hsw->dsp, volume,
+               stream->reply.volume_register_address[channel], sizeof(volume));
+
+       return 0;
+}
+
+int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u64 curve_duration,
+       enum sst_hsw_volume_curve curve)
+{
+       /* curve duration in steps of 100ns */
+       stream->vol_req.curve_duration = curve_duration;
+       stream->vol_req.curve_type = curve;
+
+       return 0;
+}
+
+/* stream volume */
+int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
+{
+       struct sst_hsw_ipc_volume_req *req;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("set stream volume", stream->reply.stream_hw_id);
+
+       if (channel > 1)
+               return -EINVAL;
+
+       if (stream->mute[channel]) {
+               stream->mute_volume[channel] = volume;
+               return 0;
+       }
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+       header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
+       header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
+       header |= (stage_id << IPC_STG_ID_SHIFT);
+
+       req = &stream->vol_req;
+       req->channel = channel;
+       req->target_volume = volume;
+
+       ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: set stream volume failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
+{
+       int ret;
+
+       ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel,
+               &hsw->mute_volume[channel]);
+       if (ret < 0)
+               return ret;
+
+       ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
+                       channel);
+               return ret;
+       }
+
+       hsw->mute[channel] = 1;
+       return 0;
+}
+
+int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
+{
+       int ret;
+
+       ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel,
+               hsw->mixer_info.volume_register_address[channel]);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
+                       channel);
+               return ret;
+       }
+
+       hsw->mute[channel] = 0;
+       return 0;
+}
+
+int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 *volume)
+{
+       if (channel > 1)
+               return -EINVAL;
+
+       sst_dsp_read(hsw->dsp, volume,
+               hsw->mixer_info.volume_register_address[channel],
+               sizeof(*volume));
+
+       return 0;
+}
+
+int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
+        u64 curve_duration, enum sst_hsw_volume_curve curve)
+{
+       /* curve duration in steps of 100ns */
+       hsw->curve_duration = curve_duration;
+       hsw->curve_type = curve;
+
+       return 0;
+}
+
+/* global mixer volume */
+int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 volume)
+{
+       struct sst_hsw_ipc_volume_req req;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("set mixer volume", volume);
+
+       /* set both at same time ? */
+       if (channel == 2) {
+               if (hsw->mute[0] && hsw->mute[1]) {
+                       hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
+                       return 0;
+               } else if (hsw->mute[0])
+                       req.channel = 1;
+               else if (hsw->mute[1])
+                       req.channel = 0;
+               else
+                       req.channel = 0xffffffff;
+       } else {
+               /* set only 1 channel */
+               if (hsw->mute[channel]) {
+                       hsw->mute_volume[channel] = volume;
+                       return 0;
+               }
+               req.channel = channel;
+       }
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+       header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT);
+       header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
+       header |= (stage_id << IPC_STG_ID_SHIFT);
+
+       req.curve_duration = hsw->curve_duration;
+       req.curve_type = hsw->curve_type;
+       req.target_volume = volume;
+
+       ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: set mixer volume failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/* Stream API */
+struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
+       u32 (*notify_position)(struct sst_hsw_stream *stream, void *data),
+       void *data)
+{
+       struct sst_hsw_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL)
+               return NULL;
+
+       list_add(&stream->node, &hsw->stream_list);
+       stream->notify_position = notify_position;
+       stream->pdata = data;
+       stream->hsw = hsw;
+       stream->host_id = id;
+
+       /* work to process notification messages */
+       INIT_WORK(&stream->notify_work, hsw_notification_work);
+
+       return stream;
+}
+
+int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+       u32 header;
+       int ret = 0;
+
+       /* dont free DSP streams that are not commited */
+       if (!stream->commited)
+               goto out;
+
+       trace_ipc_request("stream free", stream->host_id);
+
+       stream->free_req.stream_id = stream->reply.stream_hw_id;
+       header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM);
+
+       ret = ipc_tx_message_wait(hsw, header, &stream->free_req,
+               sizeof(stream->free_req), NULL, 0);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: free stream %d failed\n",
+                       stream->free_req.stream_id);
+               return -EAGAIN;
+       }
+
+       trace_hsw_stream_free_req(stream, &stream->free_req);
+
+out:
+       list_del(&stream->node);
+       kfree(stream);
+
+       return ret;
+}
+
+int sst_hsw_stream_set_bits(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set bits\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.bitdepth = bits;
+       return 0;
+}
+
+int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, int channels)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set channels\n");
+               return -EINVAL;
+       }
+
+       /* stereo is only supported atm */
+       if (channels != 2)
+               return -EINVAL;
+
+       stream->request.format.ch_num = channels;
+       return 0;
+}
+
+int sst_hsw_stream_set_rate(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, int rate)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set rate\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.frequency = rate;
+       return 0;
+}
+
+int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 map,
+       enum sst_hsw_channel_config config)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set map\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.map = map;
+       stream->request.format.config = config;
+       return 0;
+}
+
+int sst_hsw_stream_set_style(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, enum sst_hsw_interleaving style)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set style\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.style = style;
+       return 0;
+}
+
+int sst_hsw_stream_set_valid(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 bits)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set valid bits\n");
+               return -EINVAL;
+       }
+
+       stream->request.format.valid_bit = bits;
+       return 0;
+}
+
+/* Stream Configuration */
+int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_stream_path_id path_id,
+       enum sst_hsw_stream_type stream_type,
+       enum sst_hsw_stream_format format_id)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set format\n");
+               return -EINVAL;
+       }
+
+       stream->request.path_id = path_id;
+       stream->request.stream_type = stream_type;
+       stream->request.format_id = format_id;
+
+       trace_hsw_stream_alloc_request(stream, &stream->request);
+
+       return 0;
+}
+
+int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 ring_pt_address, u32 num_pages,
+       u32 ring_size, u32 ring_offset, u32 ring_first_pfn)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for buffer\n");
+               return -EINVAL;
+       }
+
+       stream->request.ringinfo.ring_pt_address = ring_pt_address;
+       stream->request.ringinfo.num_pages = num_pages;
+       stream->request.ringinfo.ring_size = ring_size;
+       stream->request.ringinfo.ring_offset = ring_offset;
+       stream->request.ringinfo.ring_first_pfn = ring_first_pfn;
+
+       trace_hsw_stream_buffer(stream);
+
+       return 0;
+}
+
+int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
+       u32 entry_point)
+{
+       struct sst_hsw_module_map *map = &stream->request.map;
+
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set module\n");
+               return -EINVAL;
+       }
+
+       /* only support initial module atm */
+       map->module_entries_count = 1;
+       map->module_entries[0].module_id = module_id;
+       map->module_entries[0].entry_point = entry_point;
+
+       return 0;
+}
+
+int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 offset, u32 size)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set pmem\n");
+               return -EINVAL;
+       }
+
+       stream->request.persistent_mem.offset = offset;
+       stream->request.persistent_mem.size = size;
+
+       return 0;
+}
+
+int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 offset, u32 size)
+{
+       if (stream->commited) {
+               dev_err(hsw->dev, "error: stream committed for set smem\n");
+               return -EINVAL;
+       }
+
+       stream->request.scratch_mem.offset = offset;
+       stream->request.scratch_mem.size = size;
+
+       return 0;
+}
+
+int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+       struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request;
+       struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("stream alloc", stream->host_id);
+
+       header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
+
+       ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req),
+               reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: stream commit failed\n");
+               return ret;
+       }
+
+       stream->commited = 1;
+       trace_hsw_stream_alloc_reply(stream);
+
+       return 0;
+}
+
+/* Stream Information - these calls could be inline but we want the IPC
+ ABI to be opaque to client PCM drivers to cope with any future ABI changes */
+int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->reply.stream_hw_id;
+}
+
+int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->reply.mixer_hw_id;
+}
+
+u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->reply.read_position_register_address;
+}
+
+u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->reply.presentation_position_register_address;
+}
+
+u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 channel)
+{
+       if (channel >= 2)
+               return 0;
+
+       return stream->reply.peak_meter_register_address[channel];
+}
+
+u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 channel)
+{
+       if (channel >= 2)
+               return 0;
+
+       return stream->reply.volume_register_address[channel];
+}
+
+int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
+{
+       struct sst_hsw_ipc_stream_info_reply *reply;
+       u32 header;
+       int ret;
+
+       reply = &hsw->mixer_info;
+       header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO);
+
+       trace_ipc_request("get global mixer info", 0);
+
+       ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply));
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: get stream info failed\n");
+               return ret;
+       }
+
+       trace_hsw_mixer_info_reply(reply);
+
+       return 0;
+}
+
+/* Send stream command */
+static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type,
+       int stream_id, int wait)
+{
+       u32 header;
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type);
+       header |= (stream_id << IPC_STR_ID_SHIFT);
+
+       if (wait)
+               return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0);
+       else
+               return ipc_tx_message_nowait(hsw, header, NULL, 0);
+}
+
+/* Stream ALSA trigger operations */
+int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait)
+{
+       int ret;
+
+       trace_ipc_request("stream pause", stream->reply.stream_hw_id);
+
+       ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
+               stream->reply.stream_hw_id, wait);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: failed to pause stream %d\n",
+                       stream->reply.stream_hw_id);
+
+       return ret;
+}
+
+int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait)
+{
+       int ret;
+
+       trace_ipc_request("stream resume", stream->reply.stream_hw_id);
+
+       ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
+               stream->reply.stream_hw_id, wait);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: failed to resume stream %d\n",
+                       stream->reply.stream_hw_id);
+
+       return ret;
+}
+
+int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+       int ret, tries = 10;
+
+       /* dont reset streams that are not commited */
+       if (!stream->commited)
+               return 0;
+
+       /* wait for pause to complete before we reset the stream */
+       while (stream->running && tries--)
+               msleep(1);
+       if (!tries) {
+               dev_err(hsw->dev, "error: reset stream %d still running\n",
+                       stream->reply.stream_hw_id);
+               return -EINVAL;
+       }
+
+       trace_ipc_request("stream reset", stream->reply.stream_hw_id);
+
+       ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET,
+               stream->reply.stream_hw_id, 1);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: failed to reset stream %d\n",
+                       stream->reply.stream_hw_id);
+       return ret;
+}
+
+/* Stream pointer positions */
+int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream)
+{
+       return stream->rpos.position;
+}
+
+int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 position)
+{
+       u32 header;
+       int ret;
+
+       trace_stream_write_position(stream->reply.stream_hw_id, position);
+
+       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+       header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
+       header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT);
+       header |= (stage_id << IPC_STG_ID_SHIFT);
+       stream->wpos.position = position;
+
+       ret = ipc_tx_message_nowait(hsw, header, &stream->wpos,
+               sizeof(stream->wpos));
+       if (ret < 0)
+               dev_err(hsw->dev, "error: stream %d set position %d failed\n",
+                       stream->reply.stream_hw_id, position);
+
+       return ret;
+}
+
+/* physical BE config */
+int sst_hsw_device_set_config(struct sst_hsw *hsw,
+       enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
+       enum sst_hsw_device_mode mode, u32 clock_divider)
+{
+       struct sst_hsw_ipc_device_config_req config;
+       u32 header;
+       int ret;
+
+       trace_ipc_request("set device config", dev);
+
+       config.ssp_interface = dev;
+       config.clock_frequency = mclk;
+       config.mode = mode;
+       config.clock_divider = clock_divider;
+
+       trace_hsw_device_config_req(&config);
+
+       header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS);
+
+       ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config),
+               NULL, 0);
+       if (ret < 0)
+               dev_err(hsw->dev, "error: set device formats failed\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_hsw_device_set_config);
+
+/* DX Config */
+int sst_hsw_dx_set_state(struct sst_hsw *hsw,
+       enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx)
+{
+       u32 header, state_;
+       int ret;
+
+       header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE);
+       state_ = state;
+
+       trace_ipc_request("PM enter Dx state", state);
+
+       ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_),
+               dx, sizeof(dx));
+       if (ret < 0) {
+               dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
+               return ret;
+       }
+
+       dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
+               dx->entries_no, state);
+
+       memcpy(&hsw->dx, dx, sizeof(*dx));
+       return 0;
+}
+
+/* Used to save state into hsw->dx_reply */
+int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
+       u32 *offset, u32 *size, u32 *source)
+{
+       struct sst_hsw_ipc_dx_memory_item *dx_mem;
+       struct sst_hsw_ipc_dx_reply *dx_reply;
+       int entry_no;
+
+       dx_reply = &hsw->dx;
+       entry_no = dx_reply->entries_no;
+
+       trace_ipc_request("PM get Dx state", entry_no);
+
+       if (item >= entry_no)
+               return -EINVAL;
+
+       dx_mem = &dx_reply->mem_info[item];
+       *offset = dx_mem->offset;
+       *size = dx_mem->size;
+       *source = dx_mem->source;
+
+       return 0;
+}
+
+static int msg_empty_list_init(struct sst_hsw *hsw)
+{
+       int i;
+
+       hsw->msg = kzalloc(sizeof(struct ipc_message) *
+               IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+       if (hsw->msg == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+               init_waitqueue_head(&hsw->msg[i].waitq);
+               list_add(&hsw->msg[i].list, &hsw->empty_list);
+       }
+
+       return 0;
+}
+
+void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
+       struct sst_module *scratch)
+{
+       hsw->scratch = scratch;
+}
+
+struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
+{
+       return hsw->dsp;
+}
+
+static struct sst_dsp_device hsw_dev = {
+       .thread = hsw_irq_thread,
+       .ops = &haswell_ops,
+};
+
+int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_hsw_ipc_fw_version version;
+       struct sst_hsw *hsw;
+       struct sst_fw *hsw_sst_fw;
+       int ret;
+
+       dev_dbg(dev, "initialising Audio DSP IPC\n");
+
+       hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL);
+       if (hsw == NULL)
+               return -ENOMEM;
+
+       hsw->dev = dev;
+       INIT_LIST_HEAD(&hsw->stream_list);
+       INIT_LIST_HEAD(&hsw->tx_list);
+       INIT_LIST_HEAD(&hsw->rx_list);
+       INIT_LIST_HEAD(&hsw->empty_list);
+       init_waitqueue_head(&hsw->boot_wait);
+       init_waitqueue_head(&hsw->wait_txq);
+
+       ret = msg_empty_list_init(hsw);
+       if (ret < 0)
+               goto list_err;
+
+       /* start the IPC message thread */
+       init_kthread_worker(&hsw->kworker);
+       hsw->tx_thread = kthread_run(kthread_worker_fn,
+                                          &hsw->kworker,
+                                          dev_name(hsw->dev));
+       if (IS_ERR(hsw->tx_thread)) {
+               ret = PTR_ERR(hsw->tx_thread);
+               dev_err(hsw->dev, "error: failed to create message TX task\n");
+               goto list_err;
+       }
+       init_kthread_work(&hsw->kwork, ipc_tx_msgs);
+
+       hsw_dev.thread_context = hsw;
+
+       /* init SST shim */
+       hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
+       if (hsw->dsp == NULL) {
+               ret = -ENODEV;
+               goto list_err;
+       }
+
+       /* keep the DSP in reset state for base FW loading */
+       sst_dsp_reset(hsw->dsp);
+
+       hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
+
+       if (hsw_sst_fw == NULL) {
+               ret = -ENODEV;
+               dev_err(dev, "error: failed to load firmware\n");
+               goto fw_err;
+       }
+
+       /* wait for DSP boot completion */
+       sst_dsp_boot(hsw->dsp);
+       ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
+               msecs_to_jiffies(IPC_BOOT_MSECS));
+       if (ret == 0) {
+               ret = -EIO;
+               dev_err(hsw->dev, "error: ADSP boot timeout\n");
+               goto boot_err;
+       }
+
+       /* get the FW version */
+       sst_hsw_fw_get_version(hsw, &version);
+       dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n",
+               version.type, version.major, version.minor, version.build);
+
+       /* get the globalmixer */
+       ret = sst_hsw_mixer_get_info(hsw);
+       if (ret < 0) {
+               dev_err(hsw->dev, "error: failed to get stream info\n");
+               goto boot_err;
+       }
+
+       pdata->dsp = hsw;
+       return 0;
+
+boot_err:
+       sst_dsp_reset(hsw->dsp);
+       sst_fw_free(hsw_sst_fw);
+fw_err:
+       sst_dsp_free(hsw->dsp);
+       kfree(hsw->msg);
+list_err:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
+
+void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+       struct sst_hsw *hsw = pdata->dsp;
+
+       sst_dsp_reset(hsw->dsp);
+       sst_fw_free_all(hsw->dsp);
+       sst_dsp_free(hsw->dsp);
+       kfree(hsw->scratch);
+       kfree(hsw->msg);
+}
+EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
new file mode 100644 (file)
index 0000000..d517929
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Intel SST Haswell/Broadwell IPC Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SST_HASWELL_IPC_H
+#define __SST_HASWELL_IPC_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#define SST_HSW_NO_CHANNELS            2
+#define SST_HSW_MAX_DX_REGIONS         14
+
+#define SST_HSW_FW_LOG_CONFIG_DWORDS   12
+#define SST_HSW_GLOBAL_LOG             15
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_HSW_IPC_MAX_PAYLOAD_SIZE   400
+#define SST_HSW_MAX_INFO_SIZE          64
+#define SST_HSW_BUILD_HASH_LENGTH      40
+
+struct sst_hsw;
+struct sst_hsw_stream;
+struct sst_hsw_log_stream;
+struct sst_pdata;
+struct sst_module;
+extern struct sst_ops haswell_ops;
+
+/* Stream Allocate Path ID */
+enum sst_hsw_stream_path_id {
+       SST_HSW_STREAM_PATH_SSP0_OUT = 0,
+       SST_HSW_STREAM_PATH_SSP0_IN = 1,
+       SST_HSW_STREAM_PATH_MAX_PATH_ID = 2,
+};
+
+/* Stream Allocate Stream Type */
+enum sst_hsw_stream_type {
+       SST_HSW_STREAM_TYPE_RENDER = 0,
+       SST_HSW_STREAM_TYPE_SYSTEM = 1,
+       SST_HSW_STREAM_TYPE_CAPTURE = 2,
+       SST_HSW_STREAM_TYPE_LOOPBACK = 3,
+       SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4,
+};
+
+/* Stream Allocate Stream Format */
+enum sst_hsw_stream_format {
+       SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0,
+       SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1,
+       SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2,
+       SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3,
+};
+
+/* Device ID */
+enum sst_hsw_device_id {
+       SST_HSW_DEVICE_SSP_0   = 0,
+       SST_HSW_DEVICE_SSP_1   = 1,
+};
+
+/* Device Master Clock Frequency */
+enum sst_hsw_device_mclk {
+       SST_HSW_DEVICE_MCLK_OFF         = 0,
+       SST_HSW_DEVICE_MCLK_FREQ_6_MHZ  = 1,
+       SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2,
+       SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3,
+};
+
+/* Device Clock Master */
+enum sst_hsw_device_mode {
+       SST_HSW_DEVICE_CLOCK_SLAVE   = 0,
+       SST_HSW_DEVICE_CLOCK_MASTER  = 1,
+};
+
+/* DX Power State */
+enum sst_hsw_dx_state {
+       SST_HSW_DX_STATE_D0     = 0,
+       SST_HSW_DX_STATE_D1     = 1,
+       SST_HSW_DX_STATE_D3     = 3,
+       SST_HSW_DX_STATE_MAX    = 3,
+};
+
+/* Audio stream stage IDs */
+enum sst_hsw_fx_stage_id {
+       SST_HSW_STAGE_ID_WAVES = 0,
+       SST_HSW_STAGE_ID_DTS   = 1,
+       SST_HSW_STAGE_ID_DOLBY = 2,
+       SST_HSW_STAGE_ID_BOOST = 3,
+       SST_HSW_STAGE_ID_MAX_FX_ID
+};
+
+/* DX State Type */
+enum sst_hsw_dx_type {
+       SST_HSW_DX_TYPE_FW_IMAGE = 0,
+       SST_HSW_DX_TYPE_MEMORY_DUMP = 1
+};
+
+/* Volume Curve Type*/
+enum sst_hsw_volume_curve {
+       SST_HSW_VOLUME_CURVE_NONE = 0,
+       SST_HSW_VOLUME_CURVE_FADE = 1
+};
+
+/* Sample ordering */
+enum sst_hsw_interleaving {
+       SST_HSW_INTERLEAVING_PER_CHANNEL = 0,
+       SST_HSW_INTERLEAVING_PER_SAMPLE  = 1,
+};
+
+/* Channel indices */
+enum sst_hsw_channel_index {
+       SST_HSW_CHANNEL_LEFT            = 0,
+       SST_HSW_CHANNEL_CENTER          = 1,
+       SST_HSW_CHANNEL_RIGHT           = 2,
+       SST_HSW_CHANNEL_LEFT_SURROUND   = 3,
+       SST_HSW_CHANNEL_CENTER_SURROUND = 3,
+       SST_HSW_CHANNEL_RIGHT_SURROUND  = 4,
+       SST_HSW_CHANNEL_LFE             = 7,
+       SST_HSW_CHANNEL_INVALID         = 0xF,
+};
+
+/* List of supported channel maps. */
+enum sst_hsw_channel_config {
+       SST_HSW_CHANNEL_CONFIG_MONO      = 0, /* mono only. */
+       SST_HSW_CHANNEL_CONFIG_STEREO    = 1, /* L & R. */
+       SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */
+       SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */
+       SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */
+       SST_HSW_CHANNEL_CONFIG_QUATRO    = 5, /* L, R, Ls & Rs; PCM only. */
+       SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */
+       SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */
+       SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */
+       SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */
+       SST_HSW_CHANNEL_CONFIG_INVALID,
+};
+
+/* List of supported bit depths. */
+enum sst_hsw_bitdepth {
+       SST_HSW_DEPTH_8BIT  = 8,
+       SST_HSW_DEPTH_16BIT = 16,
+       SST_HSW_DEPTH_24BIT = 24, /* Default. */
+       SST_HSW_DEPTH_32BIT = 32,
+       SST_HSW_DEPTH_INVALID = 33,
+};
+
+enum sst_hsw_module_id {
+       SST_HSW_MODULE_BASE_FW = 0x0,
+       SST_HSW_MODULE_MP3     = 0x1,
+       SST_HSW_MODULE_AAC_5_1 = 0x2,
+       SST_HSW_MODULE_AAC_2_0 = 0x3,
+       SST_HSW_MODULE_SRC     = 0x4,
+       SST_HSW_MODULE_WAVES   = 0x5,
+       SST_HSW_MODULE_DOLBY   = 0x6,
+       SST_HSW_MODULE_BOOST   = 0x7,
+       SST_HSW_MODULE_LPAL    = 0x8,
+       SST_HSW_MODULE_DTS     = 0x9,
+       SST_HSW_MODULE_PCM_CAPTURE = 0xA,
+       SST_HSW_MODULE_PCM_SYSTEM = 0xB,
+       SST_HSW_MODULE_PCM_REFERENCE = 0xC,
+       SST_HSW_MODULE_PCM = 0xD,
+       SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE,
+       SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF,
+       SST_HSW_MAX_MODULE_ID,
+};
+
+enum sst_hsw_performance_action {
+       SST_HSW_PERF_START = 0,
+       SST_HSW_PERF_STOP = 1,
+};
+
+/* SST firmware module info */
+struct sst_hsw_module_info {
+       u8 name[SST_HSW_MAX_INFO_SIZE];
+       u8 version[SST_HSW_MAX_INFO_SIZE];
+} __attribute__((packed));
+
+/* Module entry point */
+struct sst_hsw_module_entry {
+       enum sst_hsw_module_id module_id;
+       u32 entry_point;
+} __attribute__((packed));
+
+/* Module map - alignement matches DSP */
+struct sst_hsw_module_map {
+       u8 module_entries_count;
+       struct sst_hsw_module_entry module_entries[1];
+} __attribute__((packed));
+
+struct sst_hsw_memory_info {
+       u32 offset;
+       u32 size;
+} __attribute__((packed));
+
+struct sst_hsw_fx_enable {
+       struct sst_hsw_module_map module_map;
+       struct sst_hsw_memory_info persistent_mem;
+} __attribute__((packed));
+
+struct sst_hsw_get_fx_param {
+       u32 parameter_id;
+       u32 param_size;
+} __attribute__((packed));
+
+struct sst_hsw_perf_action {
+       u32 action;
+} __attribute__((packed));
+
+struct sst_hsw_perf_data {
+       u64 timestamp;
+       u64 cycles;
+       u64 datatime;
+} __attribute__((packed));
+
+/* FW version */
+struct sst_hsw_ipc_fw_version {
+       u8 build;
+       u8 minor;
+       u8 major;
+       u8 type;
+       u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH];
+       u32 fw_log_providers_hash;
+} __attribute__((packed));
+
+/* Stream ring info */
+struct sst_hsw_ipc_stream_ring {
+       u32 ring_pt_address;
+       u32 num_pages;
+       u32 ring_size;
+       u32 ring_offset;
+       u32 ring_first_pfn;
+} __attribute__((packed));
+
+/* Debug Dump Log Enable Request */
+struct sst_hsw_ipc_debug_log_enable_req {
+       struct sst_hsw_ipc_stream_ring ringinfo;
+       u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
+} __attribute__((packed));
+
+/* Debug Dump Log Reply */
+struct sst_hsw_ipc_debug_log_reply {
+       u32 log_buffer_begining;
+       u32 log_buffer_size;
+} __attribute__((packed));
+
+/* Stream glitch position */
+struct sst_hsw_ipc_stream_glitch_position {
+       u32 glitch_type;
+       u32 present_pos;
+       u32 write_pos;
+} __attribute__((packed));
+
+/* Stream get position */
+struct sst_hsw_ipc_stream_get_position {
+       u32 position;
+       u32 fw_cycle_count;
+} __attribute__((packed));
+
+/* Stream set position */
+struct sst_hsw_ipc_stream_set_position {
+       u32 position;
+       u32 end_of_buffer;
+} __attribute__((packed));
+
+/* Stream Free Request */
+struct sst_hsw_ipc_stream_free_req {
+       u8 stream_id;
+       u8 reserved[3];
+} __attribute__((packed));
+
+/* Set Volume Request */
+struct sst_hsw_ipc_volume_req {
+       u32 channel;
+       u32 target_volume;
+       u64 curve_duration;
+       u32 curve_type;
+} __attribute__((packed));
+
+/* Device Configuration Request */
+struct sst_hsw_ipc_device_config_req {
+       u32 ssp_interface;
+       u32 clock_frequency;
+       u32 mode;
+       u16 clock_divider;
+       u16 reserved;
+} __attribute__((packed));
+
+/* Audio Data formats */
+struct sst_hsw_audio_data_format_ipc {
+       u32 frequency;
+       u32 bitdepth;
+       u32 map;
+       u32 config;
+       u32 style;
+       u8 ch_num;
+       u8 valid_bit;
+       u8 reserved[2];
+} __attribute__((packed));
+
+/* Stream Allocate Request */
+struct sst_hsw_ipc_stream_alloc_req {
+       u8 path_id;
+       u8 stream_type;
+       u8 format_id;
+       u8 reserved;
+       struct sst_hsw_audio_data_format_ipc format;
+       struct sst_hsw_ipc_stream_ring ringinfo;
+       struct sst_hsw_module_map map;
+       struct sst_hsw_memory_info persistent_mem;
+       struct sst_hsw_memory_info scratch_mem;
+       u32 number_of_notifications;
+} __attribute__((packed));
+
+/* Stream Allocate Reply */
+struct sst_hsw_ipc_stream_alloc_reply {
+       u32 stream_hw_id;
+       u32 mixer_hw_id; // returns rate ????
+       u32 read_position_register_address;
+       u32 presentation_position_register_address;
+       u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
+       u32 volume_register_address[SST_HSW_NO_CHANNELS];
+} __attribute__((packed));
+
+/* Get Mixer Stream Info */
+struct sst_hsw_ipc_stream_info_reply {
+       u32 mixer_hw_id;
+       u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
+       u32 volume_register_address[SST_HSW_NO_CHANNELS];
+} __attribute__((packed));
+
+/* DX State Request */
+struct sst_hsw_ipc_dx_req {
+       u8 state;
+       u8 reserved[3];
+} __attribute__((packed));
+
+/* DX State Reply Memory Info Item */
+struct sst_hsw_ipc_dx_memory_item {
+       u32 offset;
+       u32 size;
+       u32 source;
+} __attribute__((packed));
+
+/* DX State Reply */
+struct sst_hsw_ipc_dx_reply {
+       u32 entries_no;
+       struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS];
+} __attribute__((packed));
+
+struct sst_hsw_ipc_fw_version;
+
+/* SST Init & Free */
+struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length,
+       u32 fw_offset);
+void sst_hsw_free(struct sst_hsw *hsw);
+int sst_hsw_fw_get_version(struct sst_hsw *hsw,
+       struct sst_hsw_ipc_fw_version *version);
+u32 create_channel_map(enum sst_hsw_channel_config config);
+
+/* Stream Mixer Controls - */
+int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 stage_id, u32 channel);
+int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 stage_id, u32 channel);
+
+int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume);
+int sst_hsw_stream_get_volume(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume);
+
+int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u64 curve_duration,
+       enum sst_hsw_volume_curve curve);
+
+/* Global Mixer Controls - */
+int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
+int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
+
+int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 volume);
+int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+       u32 *volume);
+
+int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
+       u64 curve_duration, enum sst_hsw_volume_curve curve);
+
+/* Stream API */
+struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
+       u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data),
+       void *data);
+
+int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+/* Stream Configuration */
+int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_stream_path_id path_id,
+       enum sst_hsw_stream_type stream_type,
+       enum sst_hsw_stream_format format_id);
+
+int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 ring_pt_address, u32 num_pages,
+       u32 ring_size, u32 ring_offset, u32 ring_first_pfn);
+
+int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       u32 bits);
+int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int rate);
+int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_bitdepth bits);
+int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, int channels);
+int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 map,
+       enum sst_hsw_channel_config config);
+int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       enum sst_hsw_interleaving style);
+int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
+       u32 entry_point);
+int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 offset, u32 size);
+int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 offset, u32 size);
+int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 channel);
+u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 channel);
+int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
+
+/* Stream ALSA trigger operations */
+int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait);
+int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+       int wait);
+int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+/* Stream pointer positions */
+int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 *position);
+int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 *position);
+int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, u32 stage_id, u32 position);
+int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream);
+
+/* HW port config */
+int sst_hsw_device_set_config(struct sst_hsw *hsw,
+       enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
+       enum sst_hsw_device_mode mode, u32 clock_divider);
+
+/* DX Config */
+int sst_hsw_dx_set_state(struct sst_hsw *hsw,
+       enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx);
+int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
+       u32 *offset, u32 *size, u32 *source);
+
+/* init */
+int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
+void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
+       struct sst_module *scratch);
+
+#endif
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
new file mode 100644 (file)
index 0000000..0a32dd1
--- /dev/null
@@ -0,0 +1,872 @@
+/*
+ * Intel SST Haswell/Broadwell PCM Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/compress_driver.h>
+
+#include "sst-haswell-ipc.h"
+#include "sst-dsp-priv.h"
+#include "sst-dsp.h"
+
+#define HSW_PCM_COUNT          6
+#define HSW_VOLUME_MAX         0x7FFFFFFF      /* 0dB */
+
+/* simple volume table */
+static const u32 volume_map[] = {
+       HSW_VOLUME_MAX >> 30,
+       HSW_VOLUME_MAX >> 29,
+       HSW_VOLUME_MAX >> 28,
+       HSW_VOLUME_MAX >> 27,
+       HSW_VOLUME_MAX >> 26,
+       HSW_VOLUME_MAX >> 25,
+       HSW_VOLUME_MAX >> 24,
+       HSW_VOLUME_MAX >> 23,
+       HSW_VOLUME_MAX >> 22,
+       HSW_VOLUME_MAX >> 21,
+       HSW_VOLUME_MAX >> 20,
+       HSW_VOLUME_MAX >> 19,
+       HSW_VOLUME_MAX >> 18,
+       HSW_VOLUME_MAX >> 17,
+       HSW_VOLUME_MAX >> 16,
+       HSW_VOLUME_MAX >> 15,
+       HSW_VOLUME_MAX >> 14,
+       HSW_VOLUME_MAX >> 13,
+       HSW_VOLUME_MAX >> 12,
+       HSW_VOLUME_MAX >> 11,
+       HSW_VOLUME_MAX >> 10,
+       HSW_VOLUME_MAX >> 9,
+       HSW_VOLUME_MAX >> 8,
+       HSW_VOLUME_MAX >> 7,
+       HSW_VOLUME_MAX >> 6,
+       HSW_VOLUME_MAX >> 5,
+       HSW_VOLUME_MAX >> 4,
+       HSW_VOLUME_MAX >> 3,
+       HSW_VOLUME_MAX >> 2,
+       HSW_VOLUME_MAX >> 1,
+       HSW_VOLUME_MAX >> 0,
+};
+
+#define HSW_PCM_PERIODS_MAX    64
+#define HSW_PCM_PERIODS_MIN    2
+
+static const struct snd_pcm_hardware hsw_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID |
+                                 SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_PAUSE |
+                                 SNDRV_PCM_INFO_RESUME |
+                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
+       .period_bytes_min       = PAGE_SIZE,
+       .period_bytes_max       = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE,
+       .periods_min            = HSW_PCM_PERIODS_MIN,
+       .periods_max            = HSW_PCM_PERIODS_MAX,
+       .buffer_bytes_max       = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
+};
+
+/* private data for each PCM DSP stream */
+struct hsw_pcm_data {
+       int dai_id;
+       struct sst_hsw_stream *stream;
+       u32 volume[2];
+       struct snd_pcm_substream *substream;
+       struct snd_compr_stream *cstream;
+       unsigned int wpos;
+       struct mutex mutex;
+};
+
+/* private data for the driver */
+struct hsw_priv_data {
+       /* runtime DSP */
+       struct sst_hsw *hsw;
+
+       /* page tables */
+       unsigned char *pcm_pg[HSW_PCM_COUNT][2];
+
+       /* DAI data */
+       struct hsw_pcm_data pcm[HSW_PCM_COUNT];
+};
+
+static inline u32 hsw_mixer_to_ipc(unsigned int value)
+{
+       if (value >= ARRAY_SIZE(volume_map))
+               return volume_map[0];
+       else
+               return volume_map[value];
+}
+
+static inline unsigned int hsw_ipc_to_mixer(u32 value)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
+               if (volume_map[i] >= value)
+                       return i;
+       }
+
+       return i - 1;
+}
+
+static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(platform);
+       struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 volume;
+
+       mutex_lock(&pcm_data->mutex);
+
+       if (!pcm_data->stream) {
+               pcm_data->volume[0] =
+                       hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               pcm_data->volume[1] =
+                       hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+               mutex_unlock(&pcm_data->mutex);
+               return 0;
+       }
+
+       if (ucontrol->value.integer.value[0] ==
+               ucontrol->value.integer.value[1]) {
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume);
+       } else {
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+               sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
+       }
+
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(platform);
+       struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 volume;
+
+       mutex_lock(&pcm_data->mutex);
+
+       if (!pcm_data->stream) {
+               ucontrol->value.integer.value[0] =
+                       hsw_ipc_to_mixer(pcm_data->volume[0]);
+               ucontrol->value.integer.value[1] =
+                       hsw_ipc_to_mixer(pcm_data->volume[1]);
+               mutex_unlock(&pcm_data->mutex);
+               return 0;
+       }
+
+       sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume);
+       ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
+       sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
+       ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+       mutex_unlock(&pcm_data->mutex);
+
+       return 0;
+}
+
+static int hsw_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       u32 volume;
+
+       if (ucontrol->value.integer.value[0] ==
+               ucontrol->value.integer.value[1]) {
+
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_mixer_set_volume(hsw, 0, 2, volume);
+
+       } else {
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+               sst_hsw_mixer_set_volume(hsw, 0, 0, volume);
+
+               volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+               sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
+       }
+
+       return 0;
+}
+
+static int hsw_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+       struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+       struct sst_hsw *hsw = pdata->hsw;
+       unsigned int volume = 0;
+
+       sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
+       ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
+
+       sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
+       ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+
+       return 0;
+}
+
+/* TLV used by both global and stream volumes */
+static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
+
+/* System Pin has no volume control */
+static const struct snd_kcontrol_new hsw_volume_controls[] = {
+       /* Global DSP volume */
+       SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
+               ARRAY_SIZE(volume_map) -1, 0,
+               hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
+       /* Offload 0 volume */
+       SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
+               ARRAY_SIZE(volume_map), 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+       /* Offload 1 volume */
+       SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
+               ARRAY_SIZE(volume_map), 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+       /* Loopback volume */
+       SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8,
+               ARRAY_SIZE(volume_map), 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+       /* Mic Capture volume */
+       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
+               ARRAY_SIZE(volume_map), 0,
+               hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+};
+
+/* Create DMA buffer page table for DSP */
+static int create_adsp_page_table(struct hsw_priv_data *pdata,
+       struct snd_soc_pcm_runtime *rtd,
+       unsigned char *dma_area, size_t size, int pcm, int stream)
+{
+       int i, pages;
+
+       if (size % PAGE_SIZE)
+               pages = (size / PAGE_SIZE) + 1;
+       else
+               pages = size / PAGE_SIZE;
+
+       dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
+               dma_area, size, pages);
+
+       for (i = 0; i < pages; i++) {
+               u32 idx = (((i << 2) + i)) >> 1;
+               u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT;
+               u32 *pg_table;
+
+               dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
+
+               pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx);
+
+               if (i & 1)
+                       *pg_table |= (pfn << 4);
+               else
+                       *pg_table |= pfn;
+       }
+
+       return 0;
+}
+
+/* this may get called several times by oss emulation */
+static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_hsw *hsw = pdata->hsw;
+       struct sst_module *module_data;
+       struct sst_dsp *dsp;
+       enum sst_hsw_stream_type stream_type;
+       enum sst_hsw_stream_path_id path_id;
+       u32 rate, bits, map, pages, module_id;
+       u8 channels;
+       int ret;
+
+       /* stream direction */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
+       else
+               path_id = SST_HSW_STREAM_PATH_SSP0_IN;
+
+       /* DSP stream type depends on DAI ID */
+       switch (rtd->cpu_dai->id) {
+       case 0:
+               stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
+               module_id = SST_HSW_MODULE_PCM_SYSTEM;
+               break;
+       case 1:
+       case 2:
+               stream_type = SST_HSW_STREAM_TYPE_RENDER;
+               module_id = SST_HSW_MODULE_PCM;
+               break;
+       case 3:
+               /* path ID needs to be OUT for loopback */
+               stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
+               path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
+               module_id = SST_HSW_MODULE_PCM_REFERENCE;
+               break;
+       case 4:
+               stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
+               module_id = SST_HSW_MODULE_PCM_CAPTURE;
+               break;
+       default:
+               dev_err(rtd->dev, "error: invalid DAI ID %d\n",
+                       rtd->cpu_dai->id);
+               return -EINVAL;
+       };
+
+       ret = sst_hsw_stream_format(hsw, pcm_data->stream,
+               path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to set format %d\n", ret);
+               return ret;
+       }
+
+       rate = params_rate(params);
+       ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not set rate %d\n", rate);
+               return ret;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bits = SST_HSW_DEPTH_16BIT;
+               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               bits = SST_HSW_DEPTH_24BIT;
+               sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
+               break;
+       default:
+               dev_err(rtd->dev, "error: invalid format %d\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not set bits %d\n", bits);
+               return ret;
+       }
+
+       /* we only support stereo atm */
+       channels = params_channels(params);
+       if (channels != 2) {
+               dev_err(rtd->dev, "error: invalid channels %d\n", channels);
+               return -EINVAL;
+       }
+
+       map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
+       sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
+                       map, SST_HSW_CHANNEL_CONFIG_STEREO);
+
+       ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not set channels %d\n",
+                       channels);
+               return ret;
+       }
+
+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
+                       params_buffer_bytes(params), ret);
+               return ret;
+       }
+
+       ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
+               runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
+       if (ret < 0)
+               return ret;
+
+       sst_hsw_stream_set_style(hsw, pcm_data->stream,
+               SST_HSW_INTERLEAVING_PER_CHANNEL);
+
+       if (runtime->dma_bytes % PAGE_SIZE)
+               pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
+       else
+               pages = runtime->dma_bytes / PAGE_SIZE;
+
+       ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
+               virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
+               pages, runtime->dma_bytes, 0,
+               (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
+               return ret;
+       }
+
+       dsp = sst_hsw_get_dsp(hsw);
+
+       module_data = sst_module_get_from_id(dsp, module_id);
+       if (module_data == NULL) {
+               dev_err(rtd->dev, "error: failed to get module config\n");
+               return -EINVAL;
+       }
+
+       /* we use hardcoded memory offsets atm, will be updated for new FW */
+       if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
+               sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
+                       SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
+               sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
+                       0x449400, 0x4000);
+               sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
+                       0x400000, 0);
+       } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
+               sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
+                       SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);
+
+               sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
+                       module_data->offset, module_data->size);
+               sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
+                       0x44d400, 0x3800);
+
+               sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
+                       module_data->offset, module_data->size);
+               sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
+                       0x400000, 0);
+       }
+
+       ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
+       if (ret < 0) {
+               dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
+               return ret;
+       }
+
+       ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
+       if (ret < 0)
+               dev_err(rtd->dev, "error: failed to pause %d\n", ret);
+
+       return 0;
+}
+
+static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_hsw *hsw = pdata->hsw;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
+{
+       struct hsw_pcm_data *pcm_data = data;
+       struct snd_pcm_substream *substream = pcm_data->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       u32 pos;
+
+       pos = frames_to_bytes(runtime,
+               (runtime->control->appl_ptr % runtime->buffer_size));
+
+       dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+
+       /* let alsa know we have play a period */
+       snd_pcm_period_elapsed(substream);
+       return pos;
+}
+
+static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_hsw *hsw = pdata->hsw;
+       snd_pcm_uframes_t offset;
+
+       offset = bytes_to_frames(runtime,
+               sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+
+       dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
+               frames_to_bytes(runtime, (u32)offset));
+       return offset;
+}
+
+static int hsw_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw *hsw = pdata->hsw;
+
+       pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+
+       mutex_lock(&pcm_data->mutex);
+
+       snd_soc_pcm_set_drvdata(rtd, pcm_data);
+       pcm_data->substream = substream;
+
+       snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
+
+       pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
+               hsw_notify_pointer, pcm_data);
+       if (pcm_data->stream == NULL) {
+               dev_err(rtd->dev, "error: failed to create stream\n");
+               mutex_unlock(&pcm_data->mutex);
+               return -EINVAL;
+       }
+
+       /* Set previous saved volume */
+       sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+                       0, pcm_data->volume[0]);
+       sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+                       1, pcm_data->volume[1]);
+
+       mutex_unlock(&pcm_data->mutex);
+       return 0;
+}
+
+static int hsw_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct sst_hsw *hsw = pdata->hsw;
+       int ret;
+
+       mutex_lock(&pcm_data->mutex);
+       ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret);
+               goto out;
+       }
+
+       ret = sst_hsw_stream_free(hsw, pcm_data->stream);
+       if (ret < 0) {
+               dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
+               goto out;
+       }
+       pcm_data->stream = NULL;
+
+out:
+       mutex_unlock(&pcm_data->mutex);
+       return ret;
+}
+
+static struct snd_pcm_ops hsw_pcm_ops = {
+       .open           = hsw_pcm_open,
+       .close          = hsw_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = hsw_pcm_hw_params,
+       .hw_free        = hsw_pcm_hw_free,
+       .trigger        = hsw_pcm_trigger,
+       .pointer        = hsw_pcm_pointer,
+       .mmap           = snd_pcm_lib_default_mmap,
+};
+
+static void hsw_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret = 0;
+
+       ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                       SNDRV_DMA_TYPE_DEV,
+                       rtd->card->dev,
+                       hsw_pcm_hardware.buffer_bytes_max,
+                       hsw_pcm_hardware.buffer_bytes_max);
+               if (ret) {
+                       dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+#define HSW_FORMATS \
+       (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\
+        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver hsw_dais[] = {
+       {
+               .name  = "System Pin",
+               .playback = {
+                       .stream_name = "System Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               },
+       },
+       {
+               /* PCM */
+               .name  = "Offload0 Pin",
+               .playback = {
+                       .stream_name = "Offload0 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = HSW_FORMATS,
+               },
+       },
+       {
+               /* PCM */
+               .name  = "Offload1 Pin",
+               .playback = {
+                       .stream_name = "Offload1 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = HSW_FORMATS,
+               },
+       },
+       {
+               .name  = "Loopback Pin",
+               .capture = {
+                       .stream_name = "Loopback Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = HSW_FORMATS,
+               },
+       },
+       {
+               .name  = "Capture Pin",
+               .capture = {
+                       .stream_name = "Analog Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = HSW_FORMATS,
+               },
+       },
+};
+
+static const struct snd_soc_dapm_widget widgets[] = {
+
+       /* Backend DAIs  */
+       SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       /* Global Playback Mixer */
+       SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route graph[] = {
+
+       /* Playback Mixer */
+       {"Playback VMixer", NULL, "System Playback"},
+       {"Playback VMixer", NULL, "Offload0 Playback"},
+       {"Playback VMixer", NULL, "Offload1 Playback"},
+
+       {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
+
+       {"Analog Capture", NULL, "SSP0 CODEC IN"},
+};
+
+static int hsw_pcm_probe(struct snd_soc_platform *platform)
+{
+       struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+       struct hsw_priv_data *priv_data;
+       int i;
+
+       if (!pdata)
+               return -ENODEV;
+
+       priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
+       priv_data->hsw = pdata->dsp;
+       snd_soc_platform_set_drvdata(platform, priv_data);
+
+       /* allocate DSP buffer page tables */
+       for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
+
+               mutex_init(&priv_data->pcm[i].mutex);
+
+               /* playback */
+               if (hsw_dais[i].playback.channels_min) {
+                       priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA);
+                       if (priv_data->pcm_pg[i][0] == NULL)
+                               goto err;
+               }
+
+               /* capture */
+               if (hsw_dais[i].capture.channels_min) {
+                       priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA);
+                       if (priv_data->pcm_pg[i][1] == NULL)
+                               goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       for (;i >= 0; i--) {
+               if (hsw_dais[i].playback.channels_min)
+                       kfree(priv_data->pcm_pg[i][0]);
+               if (hsw_dais[i].capture.channels_min)
+                       kfree(priv_data->pcm_pg[i][1]);
+       }
+       return -ENOMEM;
+}
+
+static int hsw_pcm_remove(struct snd_soc_platform *platform)
+{
+       struct hsw_priv_data *priv_data =
+               snd_soc_platform_get_drvdata(platform);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
+               if (hsw_dais[i].playback.channels_min)
+                       kfree(priv_data->pcm_pg[i][0]);
+               if (hsw_dais[i].capture.channels_min)
+                       kfree(priv_data->pcm_pg[i][1]);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_platform_driver hsw_soc_platform = {
+       .probe          = hsw_pcm_probe,
+       .remove         = hsw_pcm_remove,
+       .ops            = &hsw_pcm_ops,
+       .pcm_new        = hsw_pcm_new,
+       .pcm_free       = hsw_pcm_free,
+       .controls       = hsw_volume_controls,
+       .num_controls   = ARRAY_SIZE(hsw_volume_controls),
+       .dapm_widgets   = widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(widgets),
+       .dapm_routes    = graph,
+       .num_dapm_routes        = ARRAY_SIZE(graph),
+};
+
+static const struct snd_soc_component_driver hsw_dai_component = {
+       .name           = "haswell-dai",
+};
+
+static int hsw_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+       int ret;
+
+       ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
+       if (ret < 0)
+               return -ENODEV;
+
+       ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
+       if (ret < 0)
+               goto err_plat;
+
+       ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
+               hsw_dais, ARRAY_SIZE(hsw_dais));
+       if (ret < 0)
+               goto err_comp;
+
+       return 0;
+
+err_comp:
+       snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+       sst_hsw_dsp_free(&pdev->dev, sst_pdata);
+       return 0;
+}
+
+static int hsw_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
+       sst_hsw_dsp_free(&pdev->dev, sst_pdata);
+
+       return 0;
+}
+
+static struct platform_driver hsw_pcm_driver = {
+       .driver = {
+               .name = "haswell-pcm-audio",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = hsw_pcm_dev_probe,
+       .remove = hsw_pcm_dev_remove,
+};
+module_platform_driver(hsw_pcm_driver);
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:haswell-pcm-audio");
diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/sst-mfld-dsp.h
new file mode 100644 (file)
index 0000000..3b63edc
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __SST_MFLD_DSP_H__
+#define __SST_MFLD_DSP_H__
+/*
+ *  sst_mfld_dsp.h - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-12 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+enum sst_codec_types {
+       /*  AUDIO/MUSIC CODEC Type Definitions */
+       SST_CODEC_TYPE_UNKNOWN = 0,
+       SST_CODEC_TYPE_PCM,     /* Pass through Audio codec */
+       SST_CODEC_TYPE_MP3,
+       SST_CODEC_TYPE_MP24,
+       SST_CODEC_TYPE_AAC,
+       SST_CODEC_TYPE_AACP,
+       SST_CODEC_TYPE_eAACP,
+};
+
+enum stream_type {
+       SST_STREAM_TYPE_NONE = 0,
+       SST_STREAM_TYPE_MUSIC = 1,
+};
+
+struct snd_pcm_params {
+       u16 codec;      /* codec type */
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u32 reserved;   /* Bitrate in bits per second */
+       u32 sfreq;      /* Sampling rate in Hz */
+       u8 use_offload_path;
+       u8 reserved2;
+       u16 reserved3;
+       u8 channel_map[8];
+} __packed;
+
+/* MP3 Music Parameters Message */
+struct snd_mp3_params {
+       u16 codec;
+       u8  num_chan;   /* 1=Mono, 2=Stereo     */
+       u8  pcm_wd_sz; /* 16/24 - bit*/
+       u8  crc_check; /* crc_check - disable (0) or enable (1) */
+       u8  reserved1; /* unused*/
+       u16 reserved2;  /* Unused */
+} __packed;
+
+#define AAC_BIT_STREAM_ADTS            0
+#define AAC_BIT_STREAM_ADIF            1
+#define AAC_BIT_STREAM_RAW             2
+
+/* AAC Music Parameters Message */
+struct snd_aac_params {
+       u16 codec;
+       u8 num_chan; /* 1=Mono, 2=Stereo*/
+       u8 pcm_wd_sz; /* 16/24 - bit*/
+       u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
+       u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
+       u16  reser2;
+       u32 externalsr; /*sampling rate of basic AAC raw bit stream*/
+       u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/
+       u8 reser1;
+       u16  reser3;
+} __packed;
+
+/* WMA Music Parameters Message */
+struct snd_wma_params {
+       u16 codec;
+       u8  num_chan;   /* 1=Mono, 2=Stereo */
+       u8  pcm_wd_sz;  /* 16/24 - bit*/
+       u32 brate;      /* Use the hard coded value. */
+       u32 sfreq;      /* Sampling freq eg. 8000, 441000, 48000 */
+       u32 channel_mask;  /* Channel Mask */
+       u16 format_tag; /* Format Tag */
+       u16 block_align;        /* packet size */
+       u16 wma_encode_opt;/* Encoder option */
+       u8 op_align;    /* op align 0- 16 bit, 1- MSB, 2 LSB */
+       u8 reserved;    /* reserved */
+} __packed;
+
+/* Codec params struture */
+union  snd_sst_codec_params {
+       struct snd_pcm_params pcm_params;
+       struct snd_mp3_params mp3_params;
+       struct snd_aac_params aac_params;
+       struct snd_wma_params wma_params;
+} __packed;
+
+/* Address and size info of a frame buffer */
+struct sst_address_info {
+       u32 addr; /* Address at IA */
+       u32 size; /* Size of the buffer */
+};
+
+struct snd_sst_alloc_params_ext {
+       struct sst_address_info  ring_buf_info[8];
+       u8 sg_count;
+       u8 reserved;
+       u16 reserved2;
+       u32 frag_size;  /*Number of samples after which period elapsed
+                                 message is sent valid only if path  = 0*/
+} __packed;
+
+struct snd_sst_stream_params {
+       union snd_sst_codec_params uc;
+} __packed;
+
+struct snd_sst_params {
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       struct snd_sst_stream_params sparams;
+       struct snd_sst_alloc_params_ext aparams;
+};
+
+#endif /* __SST_MFLD_DSP_H__ */
diff --git a/sound/soc/intel/sst-mfld-platform.c b/sound/soc/intel/sst-mfld-platform.c
new file mode 100644 (file)
index 0000000..840306c
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ *  sst_mfld_platform.c - Intel MID Platform driver
+ *
+ *  Copyright (C) 2010-2013 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  Author: Harsha Priya <priya.harsha@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include "sst-mfld-platform.h"
+
+static struct sst_device *sst;
+static DEFINE_MUTEX(sst_lock);
+
+int sst_register_dsp(struct sst_device *dev)
+{
+       if (WARN_ON(!dev))
+               return -EINVAL;
+       if (!try_module_get(dev->dev->driver->owner))
+               return -ENODEV;
+       mutex_lock(&sst_lock);
+       if (sst) {
+               pr_err("we already have a device %s\n", sst->name);
+               module_put(dev->dev->driver->owner);
+               mutex_unlock(&sst_lock);
+               return -EEXIST;
+       }
+       pr_debug("registering device %s\n", dev->name);
+       sst = dev;
+       mutex_unlock(&sst_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_register_dsp);
+
+int sst_unregister_dsp(struct sst_device *dev)
+{
+       if (WARN_ON(!dev))
+               return -EINVAL;
+       if (dev != sst)
+               return -EINVAL;
+
+       mutex_lock(&sst_lock);
+
+       if (!sst) {
+               mutex_unlock(&sst_lock);
+               return -EIO;
+       }
+
+       module_put(sst->dev->driver->owner);
+       pr_debug("unreg %s\n", sst->name);
+       sst = NULL;
+       mutex_unlock(&sst_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_unregister_dsp);
+
+static struct snd_pcm_hardware sst_platform_pcm_hw = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED |
+                       SNDRV_PCM_INFO_DOUBLE |
+                       SNDRV_PCM_INFO_PAUSE |
+                       SNDRV_PCM_INFO_RESUME |
+                       SNDRV_PCM_INFO_MMAP|
+                       SNDRV_PCM_INFO_MMAP_VALID |
+                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                       SNDRV_PCM_INFO_SYNC_START),
+       .buffer_bytes_max = SST_MAX_BUFFER,
+       .period_bytes_min = SST_MIN_PERIOD_BYTES,
+       .period_bytes_max = SST_MAX_PERIOD_BYTES,
+       .periods_min = SST_MIN_PERIODS,
+       .periods_max = SST_MAX_PERIODS,
+       .fifo_size = SST_FIFO_SIZE,
+};
+
+/* MFLD - MSIC */
+static struct snd_soc_dai_driver sst_platform_dai[] = {
+{
+       .name = "Headset-cpu-dai",
+       .id = 0,
+       .playback = {
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 5,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       },
+},
+{
+       .name = "Speaker-cpu-dai",
+       .id = 1,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       },
+},
+{
+       .name = "Vibra1-cpu-dai",
+       .id = 2,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_MONO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       },
+},
+{
+       .name = "Vibra2-cpu-dai",
+       .id = 3,
+       .playback = {
+               .channels_min = SST_MONO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S24_LE,
+       },
+},
+{
+       .name = "Compress-cpu-dai",
+       .compress_dai = 1,
+       .playback = {
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
+};
+
+static const struct snd_soc_component_driver sst_component = {
+       .name           = "sst",
+};
+
+/* helper functions */
+static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
+                                       int state)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&stream->status_lock, flags);
+       stream->stream_status = state;
+       spin_unlock_irqrestore(&stream->status_lock, flags);
+}
+
+static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
+{
+       int state;
+       unsigned long flags;
+
+       spin_lock_irqsave(&stream->status_lock, flags);
+       state = stream->stream_status;
+       spin_unlock_irqrestore(&stream->status_lock, flags);
+       return state;
+}
+
+static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
+                               struct sst_pcm_params *param)
+{
+
+       param->codec = SST_CODEC_TYPE_PCM;
+       param->num_chan = (u8) substream->runtime->channels;
+       param->pcm_wd_sz = substream->runtime->sample_bits;
+       param->reserved = 0;
+       param->sfreq = substream->runtime->rate;
+       param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
+       param->period_count = substream->runtime->period_size;
+       param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
+       pr_debug("period_cnt = %d\n", param->period_count);
+       pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
+}
+
+static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream =
+                       substream->runtime->private_data;
+       struct sst_pcm_params param = {0};
+       struct sst_stream_params str_params = {0};
+       int ret_val;
+
+       /* set codec params and inform SST driver the same */
+       sst_fill_pcm_params(substream, &param);
+       substream->runtime->dma_area = substream->dma_buffer.area;
+       str_params.sparams = param;
+       str_params.codec =  param.codec;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               str_params.ops = STREAM_OPS_PLAYBACK;
+               str_params.device_type = substream->pcm->device + 1;
+               pr_debug("Playbck stream,Device %d\n",
+                                       substream->pcm->device);
+       } else {
+               str_params.ops = STREAM_OPS_CAPTURE;
+               str_params.device_type = SND_SST_DEVICE_CAPTURE;
+               pr_debug("Capture stream,Device %d\n",
+                                       substream->pcm->device);
+       }
+       ret_val = stream->ops->open(&str_params);
+       pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
+       if (ret_val < 0)
+               return ret_val;
+
+       stream->stream_info.str_id = ret_val;
+       pr_debug("str id :  %d\n", stream->stream_info.str_id);
+       return ret_val;
+}
+
+static void sst_period_elapsed(void *mad_substream)
+{
+       struct snd_pcm_substream *substream = mad_substream;
+       struct sst_runtime_stream *stream;
+       int status;
+
+       if (!substream || !substream->runtime)
+               return;
+       stream = substream->runtime->private_data;
+       if (!stream)
+               return;
+       status = sst_get_stream_status(stream);
+       if (status != SST_PLATFORM_RUNNING)
+               return;
+       snd_pcm_period_elapsed(substream);
+}
+
+static int sst_platform_init_stream(struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream =
+                       substream->runtime->private_data;
+       int ret_val;
+
+       pr_debug("setting buffer ptr param\n");
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       stream->stream_info.period_elapsed = sst_period_elapsed;
+       stream->stream_info.mad_substream = substream;
+       stream->stream_info.buffer_ptr = 0;
+       stream->stream_info.sfreq = substream->runtime->rate;
+       ret_val = stream->ops->device_control(
+                       SST_SND_STREAM_INIT, &stream->stream_info);
+       if (ret_val)
+               pr_err("control_set ret error %d\n", ret_val);
+       return ret_val;
+
+}
+/* end -- helper functions */
+
+static int sst_platform_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct sst_runtime_stream *stream;
+       int ret_val;
+
+       pr_debug("sst_platform_open called\n");
+
+       snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw);
+       ret_val = snd_pcm_hw_constraint_integer(runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret_val < 0)
+               return ret_val;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+       spin_lock_init(&stream->status_lock);
+
+       /* get the sst ops */
+       mutex_lock(&sst_lock);
+       if (!sst) {
+               pr_err("no device available to run\n");
+               mutex_unlock(&sst_lock);
+               kfree(stream);
+               return -ENODEV;
+       }
+       if (!try_module_get(sst->dev->driver->owner)) {
+               mutex_unlock(&sst_lock);
+               kfree(stream);
+               return -ENODEV;
+       }
+       stream->ops = sst->ops;
+       mutex_unlock(&sst_lock);
+
+       stream->stream_info.str_id = 0;
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       stream->stream_info.mad_substream = substream;
+       /* allocate memory for SST API set */
+       runtime->private_data = stream;
+
+       return 0;
+}
+
+static int sst_platform_close(struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       pr_debug("sst_platform_close called\n");
+       stream = substream->runtime->private_data;
+       str_id = stream->stream_info.str_id;
+       if (str_id)
+               ret_val = stream->ops->close(str_id);
+       module_put(sst->dev->driver->owner);
+       kfree(stream);
+       return ret_val;
+}
+
+static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       pr_debug("sst_platform_pcm_prepare called\n");
+       stream = substream->runtime->private_data;
+       str_id = stream->stream_info.str_id;
+       if (stream->stream_info.str_id) {
+               ret_val = stream->ops->device_control(
+                               SST_SND_DROP, &str_id);
+               return ret_val;
+       }
+
+       ret_val = sst_platform_alloc_stream(substream);
+       if (ret_val < 0)
+               return ret_val;
+       snprintf(substream->pcm->id, sizeof(substream->pcm->id),
+                       "%d", stream->stream_info.str_id);
+
+       ret_val = sst_platform_init_stream(substream);
+       if (ret_val)
+               return ret_val;
+       substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+       return ret_val;
+}
+
+static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
+                                       int cmd)
+{
+       int ret_val = 0, str_id;
+       struct sst_runtime_stream *stream;
+       int str_cmd, status;
+
+       pr_debug("sst_platform_pcm_trigger called\n");
+       stream = substream->runtime->private_data;
+       str_id = stream->stream_info.str_id;
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               pr_debug("sst: Trigger Start\n");
+               str_cmd = SST_SND_START;
+               status = SST_PLATFORM_RUNNING;
+               stream->stream_info.mad_substream = substream;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               pr_debug("sst: in stop\n");
+               str_cmd = SST_SND_DROP;
+               status = SST_PLATFORM_DROPPED;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               pr_debug("sst: in pause\n");
+               str_cmd = SST_SND_PAUSE;
+               status = SST_PLATFORM_PAUSED;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               pr_debug("sst: in pause release\n");
+               str_cmd = SST_SND_RESUME;
+               status = SST_PLATFORM_RUNNING;
+               break;
+       default:
+               return -EINVAL;
+       }
+       ret_val = stream->ops->device_control(str_cmd, &str_id);
+       if (!ret_val)
+               sst_set_stream_status(stream, status);
+
+       return ret_val;
+}
+
+
+static snd_pcm_uframes_t sst_platform_pcm_pointer
+                       (struct snd_pcm_substream *substream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val, status;
+       struct pcm_stream_info *str_info;
+
+       stream = substream->runtime->private_data;
+       status = sst_get_stream_status(stream);
+       if (status == SST_PLATFORM_INIT)
+               return 0;
+       str_info = &stream->stream_info;
+       ret_val = stream->ops->device_control(
+                               SST_SND_BUFFER_POINTER, str_info);
+       if (ret_val) {
+               pr_err("sst: error code = %d\n", ret_val);
+               return ret_val;
+       }
+       return stream->stream_info.buffer_ptr;
+}
+
+static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+
+       return 0;
+}
+
+static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static struct snd_pcm_ops sst_platform_ops = {
+       .open = sst_platform_open,
+       .close = sst_platform_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .prepare = sst_platform_pcm_prepare,
+       .trigger = sst_platform_pcm_trigger,
+       .pointer = sst_platform_pcm_pointer,
+       .hw_params = sst_platform_pcm_hw_params,
+       .hw_free = sst_platform_pcm_hw_free,
+};
+
+static void sst_pcm_free(struct snd_pcm *pcm)
+{
+       pr_debug("sst_pcm_free called\n");
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       int retval = 0;
+
+       pr_debug("sst_pcm_new called\n");
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
+                       SNDRV_DMA_TYPE_CONTINUOUS,
+                       snd_dma_continuous_data(GFP_KERNEL),
+                       SST_MIN_BUFFER, SST_MAX_BUFFER);
+               if (retval) {
+                       pr_err("dma buffer allocationf fail\n");
+                       return retval;
+               }
+       }
+       return retval;
+}
+
+/* compress stream operations */
+static void sst_compr_fragment_elapsed(void *arg)
+{
+       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+       pr_debug("fragment elapsed by driver\n");
+       if (cstream)
+               snd_compr_fragment_elapsed(cstream);
+}
+
+static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+{
+
+       int ret_val = 0;
+       struct snd_compr_runtime *runtime = cstream->runtime;
+       struct sst_runtime_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+
+       spin_lock_init(&stream->status_lock);
+
+       /* get the sst ops */
+       if (!sst || !try_module_get(sst->dev->driver->owner)) {
+               pr_err("no device available to run\n");
+               ret_val = -ENODEV;
+               goto out_ops;
+       }
+       stream->compr_ops = sst->compr_ops;
+
+       stream->id = 0;
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       runtime->private_data = stream;
+       return 0;
+out_ops:
+       kfree(stream);
+       return ret_val;
+}
+
+static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       stream = cstream->runtime->private_data;
+       /*need to check*/
+       str_id = stream->id;
+       if (str_id)
+               ret_val = stream->compr_ops->close(str_id);
+       module_put(sst->dev->driver->owner);
+       kfree(stream);
+       pr_debug("%s: %d\n", __func__, ret_val);
+       return 0;
+}
+
+static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
+                                       struct snd_compr_params *params)
+{
+       struct sst_runtime_stream *stream;
+       int retval;
+       struct snd_sst_params str_params;
+       struct sst_compress_cb cb;
+
+       stream = cstream->runtime->private_data;
+       /* construct fw structure for this*/
+       memset(&str_params, 0, sizeof(str_params));
+
+       str_params.ops = STREAM_OPS_PLAYBACK;
+       str_params.stream_type = SST_STREAM_TYPE_MUSIC;
+       str_params.device_type = SND_SST_DEVICE_COMPRESS;
+
+       switch (params->codec.id) {
+       case SND_AUDIOCODEC_MP3: {
+               str_params.codec = SST_CODEC_TYPE_MP3;
+               str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
+               str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
+               str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
+               break;
+       }
+
+       case SND_AUDIOCODEC_AAC: {
+               str_params.codec = SST_CODEC_TYPE_AAC;
+               str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
+               str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
+               str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
+               if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
+                       str_params.sparams.uc.aac_params.bs_format =
+                                                       AAC_BIT_STREAM_ADTS;
+               else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
+                       str_params.sparams.uc.aac_params.bs_format =
+                                                       AAC_BIT_STREAM_RAW;
+               else {
+                       pr_err("Undefined format%d\n", params->codec.format);
+                       return -EINVAL;
+               }
+               str_params.sparams.uc.aac_params.externalsr =
+                                               params->codec.sample_rate;
+               break;
+       }
+
+       default:
+               pr_err("codec not supported, id =%d\n", params->codec.id);
+               return -EINVAL;
+       }
+
+       str_params.aparams.ring_buf_info[0].addr  =
+                                       virt_to_phys(cstream->runtime->buffer);
+       str_params.aparams.ring_buf_info[0].size =
+                                       cstream->runtime->buffer_size;
+       str_params.aparams.sg_count = 1;
+       str_params.aparams.frag_size = cstream->runtime->fragment_size;
+
+       cb.param = cstream;
+       cb.compr_cb = sst_compr_fragment_elapsed;
+
+       retval = stream->compr_ops->open(&str_params, &cb);
+       if (retval < 0) {
+               pr_err("stream allocation failed %d\n", retval);
+               return retval;
+       }
+
+       stream->id = retval;
+       return 0;
+}
+
+static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->control(cmd, stream->id);
+}
+
+static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
+                                       struct snd_compr_tstamp *tstamp)
+{
+       struct sst_runtime_stream *stream;
+
+       stream  = cstream->runtime->private_data;
+       stream->compr_ops->tstamp(stream->id, tstamp);
+       tstamp->byte_offset = tstamp->copied_total %
+                                (u32)cstream->runtime->buffer_size;
+       pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+       return 0;
+}
+
+static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
+                                       size_t bytes)
+{
+       struct sst_runtime_stream *stream;
+
+       stream  = cstream->runtime->private_data;
+       stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+       stream->bytes_written += bytes;
+
+       return 0;
+}
+
+static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
+                                       struct snd_compr_caps *caps)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->get_caps(caps);
+}
+
+static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+                                       struct snd_compr_codec_caps *codec)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->get_codec_caps(codec);
+}
+
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+                                       struct snd_compr_metadata *metadata)
+{
+       struct sst_runtime_stream *stream  =
+                cstream->runtime->private_data;
+
+       return stream->compr_ops->set_metadata(stream->id, metadata);
+}
+
+static struct snd_compr_ops sst_platform_compr_ops = {
+
+       .open = sst_platform_compr_open,
+       .free = sst_platform_compr_free,
+       .set_params = sst_platform_compr_set_params,
+       .set_metadata = sst_platform_compr_set_metadata,
+       .trigger = sst_platform_compr_trigger,
+       .pointer = sst_platform_compr_pointer,
+       .ack = sst_platform_compr_ack,
+       .get_caps = sst_platform_compr_get_caps,
+       .get_codec_caps = sst_platform_compr_get_codec_caps,
+};
+
+static struct snd_soc_platform_driver sst_soc_platform_drv = {
+       .ops            = &sst_platform_ops,
+       .compr_ops      = &sst_platform_compr_ops,
+       .pcm_new        = sst_pcm_new,
+       .pcm_free       = sst_pcm_free,
+};
+
+static int sst_platform_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       pr_debug("sst_platform_probe called\n");
+       sst = NULL;
+       ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
+       if (ret) {
+               pr_err("registering soc platform failed\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_component(&pdev->dev, &sst_component,
+                               sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
+       if (ret) {
+               pr_err("registering cpu dais failed\n");
+               snd_soc_unregister_platform(&pdev->dev);
+       }
+       return ret;
+}
+
+static int sst_platform_remove(struct platform_device *pdev)
+{
+
+       snd_soc_unregister_component(&pdev->dev);
+       snd_soc_unregister_platform(&pdev->dev);
+       pr_debug("sst_platform_remove success\n");
+       return 0;
+}
+
+static struct platform_driver sst_platform_driver = {
+       .driver         = {
+               .name           = "sst-mfld-platform",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = sst_platform_probe,
+       .remove         = sst_platform_remove,
+};
+
+module_platform_driver(sst_platform_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sst-mfld-platform");
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
new file mode 100644 (file)
index 0000000..0c4e2dd
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  sst_mfld_platform.h - Intel MID Platform driver header file
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  Author: Harsha Priya <priya.harsha@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#ifndef __SST_PLATFORMDRV_H__
+#define __SST_PLATFORMDRV_H__
+
+#include "sst-mfld-dsp.h"
+
+#define SST_MONO               1
+#define SST_STEREO             2
+#define SST_MAX_CAP            5
+
+#define SST_MAX_BUFFER         (800*1024)
+#define SST_MIN_BUFFER         (800*1024)
+#define SST_MIN_PERIOD_BYTES   32
+#define SST_MAX_PERIOD_BYTES   SST_MAX_BUFFER
+#define SST_MIN_PERIODS                2
+#define SST_MAX_PERIODS                (1024*2)
+#define SST_FIFO_SIZE          0
+
+struct pcm_stream_info {
+       int str_id;
+       void *mad_substream;
+       void (*period_elapsed) (void *mad_substream);
+       unsigned long long buffer_ptr;
+       int sfreq;
+};
+
+enum sst_drv_status {
+       SST_PLATFORM_INIT = 1,
+       SST_PLATFORM_STARTED,
+       SST_PLATFORM_RUNNING,
+       SST_PLATFORM_PAUSED,
+       SST_PLATFORM_DROPPED,
+};
+
+enum sst_controls {
+       SST_SND_ALLOC =                 0x00,
+       SST_SND_PAUSE =                 0x01,
+       SST_SND_RESUME =                0x02,
+       SST_SND_DROP =                  0x03,
+       SST_SND_FREE =                  0x04,
+       SST_SND_BUFFER_POINTER =        0x05,
+       SST_SND_STREAM_INIT =           0x06,
+       SST_SND_START    =              0x07,
+       SST_MAX_CONTROLS =              0x07,
+};
+
+enum sst_stream_ops {
+       STREAM_OPS_PLAYBACK = 0,
+       STREAM_OPS_CAPTURE,
+};
+
+enum sst_audio_device_type {
+       SND_SST_DEVICE_HEADSET = 1,
+       SND_SST_DEVICE_IHF,
+       SND_SST_DEVICE_VIBRA,
+       SND_SST_DEVICE_HAPTIC,
+       SND_SST_DEVICE_CAPTURE,
+       SND_SST_DEVICE_COMPRESS,
+};
+
+/* PCM Parameters */
+struct sst_pcm_params {
+       u16 codec;      /* codec type */
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u32 reserved;   /* Bitrate in bits per second */
+       u32 sfreq;      /* Sampling rate in Hz */
+       u32 ring_buffer_size;
+       u32 period_count;       /* period elapsed in samples*/
+       u32 ring_buffer_addr;
+};
+
+struct sst_stream_params {
+       u32 result;
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       struct sst_pcm_params sparams;
+};
+
+struct sst_compress_cb {
+       void *param;
+       void (*compr_cb)(void *param);
+};
+
+struct compress_sst_ops {
+       const char *name;
+       int (*open) (struct snd_sst_params *str_params,
+                       struct sst_compress_cb *cb);
+       int (*control) (unsigned int cmd, unsigned int str_id);
+       int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
+       int (*ack) (unsigned int str_id, unsigned long bytes);
+       int (*close) (unsigned int str_id);
+       int (*get_caps) (struct snd_compr_caps *caps);
+       int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
+       int (*set_metadata) (unsigned int str_id,
+                       struct snd_compr_metadata *mdata);
+
+};
+
+struct sst_ops {
+       int (*open) (struct sst_stream_params *str_param);
+       int (*device_control) (int cmd, void *arg);
+       int (*close) (unsigned int str_id);
+};
+
+struct sst_runtime_stream {
+       int     stream_status;
+       unsigned int id;
+       size_t bytes_written;
+       struct pcm_stream_info stream_info;
+       struct sst_ops *ops;
+       struct compress_sst_ops *compr_ops;
+       spinlock_t      status_lock;
+};
+
+struct sst_device {
+       char *name;
+       struct device *dev;
+       struct sst_ops *ops;
+       struct compress_sst_ops *compr_ops;
+};
+
+int sst_register_dsp(struct sst_device *sst);
+int sst_unregister_dsp(struct sst_device *sst);
+#endif
diff --git a/sound/soc/intel/sst_dsp.h b/sound/soc/intel/sst_dsp.h
deleted file mode 100644 (file)
index 0fce1de..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef __SST_DSP_H__
-#define __SST_DSP_H__
-/*
- *  sst_dsp.h - Intel SST Driver for audio engine
- *
- *  Copyright (C) 2008-12 Intel Corporation
- *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-enum sst_codec_types {
-       /*  AUDIO/MUSIC CODEC Type Definitions */
-       SST_CODEC_TYPE_UNKNOWN = 0,
-       SST_CODEC_TYPE_PCM,     /* Pass through Audio codec */
-       SST_CODEC_TYPE_MP3,
-       SST_CODEC_TYPE_MP24,
-       SST_CODEC_TYPE_AAC,
-       SST_CODEC_TYPE_AACP,
-       SST_CODEC_TYPE_eAACP,
-};
-
-enum stream_type {
-       SST_STREAM_TYPE_NONE = 0,
-       SST_STREAM_TYPE_MUSIC = 1,
-};
-
-struct snd_pcm_params {
-       u16 codec;      /* codec type */
-       u8 num_chan;    /* 1=Mono, 2=Stereo */
-       u8 pcm_wd_sz;   /* 16/24 - bit*/
-       u32 reserved;   /* Bitrate in bits per second */
-       u32 sfreq;      /* Sampling rate in Hz */
-       u8 use_offload_path;
-       u8 reserved2;
-       u16 reserved3;
-       u8 channel_map[8];
-} __packed;
-
-/* MP3 Music Parameters Message */
-struct snd_mp3_params {
-       u16 codec;
-       u8  num_chan;   /* 1=Mono, 2=Stereo     */
-       u8  pcm_wd_sz; /* 16/24 - bit*/
-       u8  crc_check; /* crc_check - disable (0) or enable (1) */
-       u8  reserved1; /* unused*/
-       u16 reserved2;  /* Unused */
-} __packed;
-
-#define AAC_BIT_STREAM_ADTS            0
-#define AAC_BIT_STREAM_ADIF            1
-#define AAC_BIT_STREAM_RAW             2
-
-/* AAC Music Parameters Message */
-struct snd_aac_params {
-       u16 codec;
-       u8 num_chan; /* 1=Mono, 2=Stereo*/
-       u8 pcm_wd_sz; /* 16/24 - bit*/
-       u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
-       u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
-       u16  reser2;
-       u32 externalsr; /*sampling rate of basic AAC raw bit stream*/
-       u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/
-       u8 reser1;
-       u16  reser3;
-} __packed;
-
-/* WMA Music Parameters Message */
-struct snd_wma_params {
-       u16 codec;
-       u8  num_chan;   /* 1=Mono, 2=Stereo */
-       u8  pcm_wd_sz;  /* 16/24 - bit*/
-       u32 brate;      /* Use the hard coded value. */
-       u32 sfreq;      /* Sampling freq eg. 8000, 441000, 48000 */
-       u32 channel_mask;  /* Channel Mask */
-       u16 format_tag; /* Format Tag */
-       u16 block_align;        /* packet size */
-       u16 wma_encode_opt;/* Encoder option */
-       u8 op_align;    /* op align 0- 16 bit, 1- MSB, 2 LSB */
-       u8 reserved;    /* reserved */
-} __packed;
-
-/* Codec params struture */
-union  snd_sst_codec_params {
-       struct snd_pcm_params pcm_params;
-       struct snd_mp3_params mp3_params;
-       struct snd_aac_params aac_params;
-       struct snd_wma_params wma_params;
-} __packed;
-
-/* Address and size info of a frame buffer */
-struct sst_address_info {
-       u32 addr; /* Address at IA */
-       u32 size; /* Size of the buffer */
-};
-
-struct snd_sst_alloc_params_ext {
-       struct sst_address_info  ring_buf_info[8];
-       u8 sg_count;
-       u8 reserved;
-       u16 reserved2;
-       u32 frag_size;  /*Number of samples after which period elapsed
-                                 message is sent valid only if path  = 0*/
-} __packed;
-
-struct snd_sst_stream_params {
-       union snd_sst_codec_params uc;
-} __packed;
-
-struct snd_sst_params {
-       u32 stream_id;
-       u8 codec;
-       u8 ops;
-       u8 stream_type;
-       u8 device_type;
-       struct snd_sst_stream_params sparams;
-       struct snd_sst_alloc_params_ext aparams;
-};
-
-#endif /* __SST_DSP_H__ */
diff --git a/sound/soc/intel/sst_platform.c b/sound/soc/intel/sst_platform.c
deleted file mode 100644 (file)
index f465a81..0000000
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- *  sst_platform.c - Intel MID Platform driver
- *
- *  Copyright (C) 2010-2013 Intel Corp
- *  Author: Vinod Koul <vinod.koul@intel.com>
- *  Author: Harsha Priya <priya.harsha@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/compress_driver.h>
-#include "sst_platform.h"
-
-static struct sst_device *sst;
-static DEFINE_MUTEX(sst_lock);
-
-int sst_register_dsp(struct sst_device *dev)
-{
-       if (WARN_ON(!dev))
-               return -EINVAL;
-       if (!try_module_get(dev->dev->driver->owner))
-               return -ENODEV;
-       mutex_lock(&sst_lock);
-       if (sst) {
-               pr_err("we already have a device %s\n", sst->name);
-               module_put(dev->dev->driver->owner);
-               mutex_unlock(&sst_lock);
-               return -EEXIST;
-       }
-       pr_debug("registering device %s\n", dev->name);
-       sst = dev;
-       mutex_unlock(&sst_lock);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_register_dsp);
-
-int sst_unregister_dsp(struct sst_device *dev)
-{
-       if (WARN_ON(!dev))
-               return -EINVAL;
-       if (dev != sst)
-               return -EINVAL;
-
-       mutex_lock(&sst_lock);
-
-       if (!sst) {
-               mutex_unlock(&sst_lock);
-               return -EIO;
-       }
-
-       module_put(sst->dev->driver->owner);
-       pr_debug("unreg %s\n", sst->name);
-       sst = NULL;
-       mutex_unlock(&sst_lock);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_unregister_dsp);
-
-static struct snd_pcm_hardware sst_platform_pcm_hw = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED |
-                       SNDRV_PCM_INFO_DOUBLE |
-                       SNDRV_PCM_INFO_PAUSE |
-                       SNDRV_PCM_INFO_RESUME |
-                       SNDRV_PCM_INFO_MMAP|
-                       SNDRV_PCM_INFO_MMAP_VALID |
-                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                       SNDRV_PCM_INFO_SYNC_START),
-       .buffer_bytes_max = SST_MAX_BUFFER,
-       .period_bytes_min = SST_MIN_PERIOD_BYTES,
-       .period_bytes_max = SST_MAX_PERIOD_BYTES,
-       .periods_min = SST_MIN_PERIODS,
-       .periods_max = SST_MAX_PERIODS,
-       .fifo_size = SST_FIFO_SIZE,
-};
-
-/* MFLD - MSIC */
-static struct snd_soc_dai_driver sst_platform_dai[] = {
-{
-       .name = "Headset-cpu-dai",
-       .id = 0,
-       .playback = {
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S24_LE,
-       },
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 5,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S24_LE,
-       },
-},
-{
-       .name = "Speaker-cpu-dai",
-       .id = 1,
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S24_LE,
-       },
-},
-{
-       .name = "Vibra1-cpu-dai",
-       .id = 2,
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_MONO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S24_LE,
-       },
-},
-{
-       .name = "Vibra2-cpu-dai",
-       .id = 3,
-       .playback = {
-               .channels_min = SST_MONO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S24_LE,
-       },
-},
-{
-       .name = "Compress-cpu-dai",
-       .compress_dai = 1,
-       .playback = {
-               .channels_min = SST_STEREO,
-               .channels_max = SST_STEREO,
-               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-},
-};
-
-static const struct snd_soc_component_driver sst_component = {
-       .name           = "sst",
-};
-
-/* helper functions */
-static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
-                                       int state)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&stream->status_lock, flags);
-       stream->stream_status = state;
-       spin_unlock_irqrestore(&stream->status_lock, flags);
-}
-
-static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
-{
-       int state;
-       unsigned long flags;
-
-       spin_lock_irqsave(&stream->status_lock, flags);
-       state = stream->stream_status;
-       spin_unlock_irqrestore(&stream->status_lock, flags);
-       return state;
-}
-
-static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
-                               struct sst_pcm_params *param)
-{
-
-       param->codec = SST_CODEC_TYPE_PCM;
-       param->num_chan = (u8) substream->runtime->channels;
-       param->pcm_wd_sz = substream->runtime->sample_bits;
-       param->reserved = 0;
-       param->sfreq = substream->runtime->rate;
-       param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
-       param->period_count = substream->runtime->period_size;
-       param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
-       pr_debug("period_cnt = %d\n", param->period_count);
-       pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
-}
-
-static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream =
-                       substream->runtime->private_data;
-       struct sst_pcm_params param = {0};
-       struct sst_stream_params str_params = {0};
-       int ret_val;
-
-       /* set codec params and inform SST driver the same */
-       sst_fill_pcm_params(substream, &param);
-       substream->runtime->dma_area = substream->dma_buffer.area;
-       str_params.sparams = param;
-       str_params.codec =  param.codec;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               str_params.ops = STREAM_OPS_PLAYBACK;
-               str_params.device_type = substream->pcm->device + 1;
-               pr_debug("Playbck stream,Device %d\n",
-                                       substream->pcm->device);
-       } else {
-               str_params.ops = STREAM_OPS_CAPTURE;
-               str_params.device_type = SND_SST_DEVICE_CAPTURE;
-               pr_debug("Capture stream,Device %d\n",
-                                       substream->pcm->device);
-       }
-       ret_val = stream->ops->open(&str_params);
-       pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
-       if (ret_val < 0)
-               return ret_val;
-
-       stream->stream_info.str_id = ret_val;
-       pr_debug("str id :  %d\n", stream->stream_info.str_id);
-       return ret_val;
-}
-
-static void sst_period_elapsed(void *mad_substream)
-{
-       struct snd_pcm_substream *substream = mad_substream;
-       struct sst_runtime_stream *stream;
-       int status;
-
-       if (!substream || !substream->runtime)
-               return;
-       stream = substream->runtime->private_data;
-       if (!stream)
-               return;
-       status = sst_get_stream_status(stream);
-       if (status != SST_PLATFORM_RUNNING)
-               return;
-       snd_pcm_period_elapsed(substream);
-}
-
-static int sst_platform_init_stream(struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream =
-                       substream->runtime->private_data;
-       int ret_val;
-
-       pr_debug("setting buffer ptr param\n");
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       stream->stream_info.period_elapsed = sst_period_elapsed;
-       stream->stream_info.mad_substream = substream;
-       stream->stream_info.buffer_ptr = 0;
-       stream->stream_info.sfreq = substream->runtime->rate;
-       ret_val = stream->ops->device_control(
-                       SST_SND_STREAM_INIT, &stream->stream_info);
-       if (ret_val)
-               pr_err("control_set ret error %d\n", ret_val);
-       return ret_val;
-
-}
-/* end -- helper functions */
-
-static int sst_platform_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sst_runtime_stream *stream;
-       int ret_val;
-
-       pr_debug("sst_platform_open called\n");
-
-       snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw);
-       ret_val = snd_pcm_hw_constraint_integer(runtime,
-                                               SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret_val < 0)
-               return ret_val;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (!stream)
-               return -ENOMEM;
-       spin_lock_init(&stream->status_lock);
-
-       /* get the sst ops */
-       mutex_lock(&sst_lock);
-       if (!sst) {
-               pr_err("no device available to run\n");
-               mutex_unlock(&sst_lock);
-               kfree(stream);
-               return -ENODEV;
-       }
-       if (!try_module_get(sst->dev->driver->owner)) {
-               mutex_unlock(&sst_lock);
-               kfree(stream);
-               return -ENODEV;
-       }
-       stream->ops = sst->ops;
-       mutex_unlock(&sst_lock);
-
-       stream->stream_info.str_id = 0;
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       stream->stream_info.mad_substream = substream;
-       /* allocate memory for SST API set */
-       runtime->private_data = stream;
-
-       return 0;
-}
-
-static int sst_platform_close(struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val = 0, str_id;
-
-       pr_debug("sst_platform_close called\n");
-       stream = substream->runtime->private_data;
-       str_id = stream->stream_info.str_id;
-       if (str_id)
-               ret_val = stream->ops->close(str_id);
-       module_put(sst->dev->driver->owner);
-       kfree(stream);
-       return ret_val;
-}
-
-static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val = 0, str_id;
-
-       pr_debug("sst_platform_pcm_prepare called\n");
-       stream = substream->runtime->private_data;
-       str_id = stream->stream_info.str_id;
-       if (stream->stream_info.str_id) {
-               ret_val = stream->ops->device_control(
-                               SST_SND_DROP, &str_id);
-               return ret_val;
-       }
-
-       ret_val = sst_platform_alloc_stream(substream);
-       if (ret_val < 0)
-               return ret_val;
-       snprintf(substream->pcm->id, sizeof(substream->pcm->id),
-                       "%d", stream->stream_info.str_id);
-
-       ret_val = sst_platform_init_stream(substream);
-       if (ret_val)
-               return ret_val;
-       substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
-       return ret_val;
-}
-
-static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
-                                       int cmd)
-{
-       int ret_val = 0, str_id;
-       struct sst_runtime_stream *stream;
-       int str_cmd, status;
-
-       pr_debug("sst_platform_pcm_trigger called\n");
-       stream = substream->runtime->private_data;
-       str_id = stream->stream_info.str_id;
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               pr_debug("sst: Trigger Start\n");
-               str_cmd = SST_SND_START;
-               status = SST_PLATFORM_RUNNING;
-               stream->stream_info.mad_substream = substream;
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               pr_debug("sst: in stop\n");
-               str_cmd = SST_SND_DROP;
-               status = SST_PLATFORM_DROPPED;
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               pr_debug("sst: in pause\n");
-               str_cmd = SST_SND_PAUSE;
-               status = SST_PLATFORM_PAUSED;
-               break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               pr_debug("sst: in pause release\n");
-               str_cmd = SST_SND_RESUME;
-               status = SST_PLATFORM_RUNNING;
-               break;
-       default:
-               return -EINVAL;
-       }
-       ret_val = stream->ops->device_control(str_cmd, &str_id);
-       if (!ret_val)
-               sst_set_stream_status(stream, status);
-
-       return ret_val;
-}
-
-
-static snd_pcm_uframes_t sst_platform_pcm_pointer
-                       (struct snd_pcm_substream *substream)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val, status;
-       struct pcm_stream_info *str_info;
-
-       stream = substream->runtime->private_data;
-       status = sst_get_stream_status(stream);
-       if (status == SST_PLATFORM_INIT)
-               return 0;
-       str_info = &stream->stream_info;
-       ret_val = stream->ops->device_control(
-                               SST_SND_BUFFER_POINTER, str_info);
-       if (ret_val) {
-               pr_err("sst: error code = %d\n", ret_val);
-               return ret_val;
-       }
-       return stream->stream_info.buffer_ptr;
-}
-
-static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
-{
-       snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-       memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
-
-       return 0;
-}
-
-static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static struct snd_pcm_ops sst_platform_ops = {
-       .open = sst_platform_open,
-       .close = sst_platform_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .prepare = sst_platform_pcm_prepare,
-       .trigger = sst_platform_pcm_trigger,
-       .pointer = sst_platform_pcm_pointer,
-       .hw_params = sst_platform_pcm_hw_params,
-       .hw_free = sst_platform_pcm_hw_free,
-};
-
-static void sst_pcm_free(struct snd_pcm *pcm)
-{
-       pr_debug("sst_pcm_free called\n");
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
-static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_pcm *pcm = rtd->pcm;
-       int retval = 0;
-
-       pr_debug("sst_pcm_new called\n");
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
-                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
-                       SNDRV_DMA_TYPE_CONTINUOUS,
-                       snd_dma_continuous_data(GFP_KERNEL),
-                       SST_MIN_BUFFER, SST_MAX_BUFFER);
-               if (retval) {
-                       pr_err("dma buffer allocationf fail\n");
-                       return retval;
-               }
-       }
-       return retval;
-}
-
-/* compress stream operations */
-static void sst_compr_fragment_elapsed(void *arg)
-{
-       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
-
-       pr_debug("fragment elapsed by driver\n");
-       if (cstream)
-               snd_compr_fragment_elapsed(cstream);
-}
-
-static int sst_platform_compr_open(struct snd_compr_stream *cstream)
-{
-
-       int ret_val = 0;
-       struct snd_compr_runtime *runtime = cstream->runtime;
-       struct sst_runtime_stream *stream;
-
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (!stream)
-               return -ENOMEM;
-
-       spin_lock_init(&stream->status_lock);
-
-       /* get the sst ops */
-       if (!sst || !try_module_get(sst->dev->driver->owner)) {
-               pr_err("no device available to run\n");
-               ret_val = -ENODEV;
-               goto out_ops;
-       }
-       stream->compr_ops = sst->compr_ops;
-
-       stream->id = 0;
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       runtime->private_data = stream;
-       return 0;
-out_ops:
-       kfree(stream);
-       return ret_val;
-}
-
-static int sst_platform_compr_free(struct snd_compr_stream *cstream)
-{
-       struct sst_runtime_stream *stream;
-       int ret_val = 0, str_id;
-
-       stream = cstream->runtime->private_data;
-       /*need to check*/
-       str_id = stream->id;
-       if (str_id)
-               ret_val = stream->compr_ops->close(str_id);
-       module_put(sst->dev->driver->owner);
-       kfree(stream);
-       pr_debug("%s: %d\n", __func__, ret_val);
-       return 0;
-}
-
-static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
-                                       struct snd_compr_params *params)
-{
-       struct sst_runtime_stream *stream;
-       int retval;
-       struct snd_sst_params str_params;
-       struct sst_compress_cb cb;
-
-       stream = cstream->runtime->private_data;
-       /* construct fw structure for this*/
-       memset(&str_params, 0, sizeof(str_params));
-
-       str_params.ops = STREAM_OPS_PLAYBACK;
-       str_params.stream_type = SST_STREAM_TYPE_MUSIC;
-       str_params.device_type = SND_SST_DEVICE_COMPRESS;
-
-       switch (params->codec.id) {
-       case SND_AUDIOCODEC_MP3: {
-               str_params.codec = SST_CODEC_TYPE_MP3;
-               str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
-               str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
-               str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
-               break;
-       }
-
-       case SND_AUDIOCODEC_AAC: {
-               str_params.codec = SST_CODEC_TYPE_AAC;
-               str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
-               str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
-               str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
-               if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
-                       str_params.sparams.uc.aac_params.bs_format =
-                                                       AAC_BIT_STREAM_ADTS;
-               else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
-                       str_params.sparams.uc.aac_params.bs_format =
-                                                       AAC_BIT_STREAM_RAW;
-               else {
-                       pr_err("Undefined format%d\n", params->codec.format);
-                       return -EINVAL;
-               }
-               str_params.sparams.uc.aac_params.externalsr =
-                                               params->codec.sample_rate;
-               break;
-       }
-
-       default:
-               pr_err("codec not supported, id =%d\n", params->codec.id);
-               return -EINVAL;
-       }
-
-       str_params.aparams.ring_buf_info[0].addr  =
-                                       virt_to_phys(cstream->runtime->buffer);
-       str_params.aparams.ring_buf_info[0].size =
-                                       cstream->runtime->buffer_size;
-       str_params.aparams.sg_count = 1;
-       str_params.aparams.frag_size = cstream->runtime->fragment_size;
-
-       cb.param = cstream;
-       cb.compr_cb = sst_compr_fragment_elapsed;
-
-       retval = stream->compr_ops->open(&str_params, &cb);
-       if (retval < 0) {
-               pr_err("stream allocation failed %d\n", retval);
-               return retval;
-       }
-
-       stream->id = retval;
-       return 0;
-}
-
-static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
-{
-       struct sst_runtime_stream *stream =
-               cstream->runtime->private_data;
-
-       return stream->compr_ops->control(cmd, stream->id);
-}
-
-static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
-                                       struct snd_compr_tstamp *tstamp)
-{
-       struct sst_runtime_stream *stream;
-
-       stream  = cstream->runtime->private_data;
-       stream->compr_ops->tstamp(stream->id, tstamp);
-       tstamp->byte_offset = tstamp->copied_total %
-                                (u32)cstream->runtime->buffer_size;
-       pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
-       return 0;
-}
-
-static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
-                                       size_t bytes)
-{
-       struct sst_runtime_stream *stream;
-
-       stream  = cstream->runtime->private_data;
-       stream->compr_ops->ack(stream->id, (unsigned long)bytes);
-       stream->bytes_written += bytes;
-
-       return 0;
-}
-
-static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
-                                       struct snd_compr_caps *caps)
-{
-       struct sst_runtime_stream *stream =
-               cstream->runtime->private_data;
-
-       return stream->compr_ops->get_caps(caps);
-}
-
-static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
-                                       struct snd_compr_codec_caps *codec)
-{
-       struct sst_runtime_stream *stream =
-               cstream->runtime->private_data;
-
-       return stream->compr_ops->get_codec_caps(codec);
-}
-
-static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
-                                       struct snd_compr_metadata *metadata)
-{
-       struct sst_runtime_stream *stream  =
-                cstream->runtime->private_data;
-
-       return stream->compr_ops->set_metadata(stream->id, metadata);
-}
-
-static struct snd_compr_ops sst_platform_compr_ops = {
-
-       .open = sst_platform_compr_open,
-       .free = sst_platform_compr_free,
-       .set_params = sst_platform_compr_set_params,
-       .set_metadata = sst_platform_compr_set_metadata,
-       .trigger = sst_platform_compr_trigger,
-       .pointer = sst_platform_compr_pointer,
-       .ack = sst_platform_compr_ack,
-       .get_caps = sst_platform_compr_get_caps,
-       .get_codec_caps = sst_platform_compr_get_codec_caps,
-};
-
-static struct snd_soc_platform_driver sst_soc_platform_drv = {
-       .ops            = &sst_platform_ops,
-       .compr_ops      = &sst_platform_compr_ops,
-       .pcm_new        = sst_pcm_new,
-       .pcm_free       = sst_pcm_free,
-};
-
-static int sst_platform_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       pr_debug("sst_platform_probe called\n");
-       sst = NULL;
-       ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
-       if (ret) {
-               pr_err("registering soc platform failed\n");
-               return ret;
-       }
-
-       ret = snd_soc_register_component(&pdev->dev, &sst_component,
-                               sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
-       if (ret) {
-               pr_err("registering cpu dais failed\n");
-               snd_soc_unregister_platform(&pdev->dev);
-       }
-       return ret;
-}
-
-static int sst_platform_remove(struct platform_device *pdev)
-{
-
-       snd_soc_unregister_component(&pdev->dev);
-       snd_soc_unregister_platform(&pdev->dev);
-       pr_debug("sst_platform_remove success\n");
-       return 0;
-}
-
-static struct platform_driver sst_platform_driver = {
-       .driver         = {
-               .name           = "sst-platform",
-               .owner          = THIS_MODULE,
-       },
-       .probe          = sst_platform_probe,
-       .remove         = sst_platform_remove,
-};
-
-module_platform_driver(sst_platform_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sst-platform");
diff --git a/sound/soc/intel/sst_platform.h b/sound/soc/intel/sst_platform.h
deleted file mode 100644 (file)
index bee64fb..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *  sst_platform.h - Intel MID Platform driver header file
- *
- *  Copyright (C) 2010 Intel Corp
- *  Author: Vinod Koul <vinod.koul@intel.com>
- *  Author: Harsha Priya <priya.harsha@intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
- */
-
-#ifndef __SST_PLATFORMDRV_H__
-#define __SST_PLATFORMDRV_H__
-
-#include "sst_dsp.h"
-
-#define SST_MONO               1
-#define SST_STEREO             2
-#define SST_MAX_CAP            5
-
-#define SST_MAX_BUFFER         (800*1024)
-#define SST_MIN_BUFFER         (800*1024)
-#define SST_MIN_PERIOD_BYTES   32
-#define SST_MAX_PERIOD_BYTES   SST_MAX_BUFFER
-#define SST_MIN_PERIODS                2
-#define SST_MAX_PERIODS                (1024*2)
-#define SST_FIFO_SIZE          0
-
-struct pcm_stream_info {
-       int str_id;
-       void *mad_substream;
-       void (*period_elapsed) (void *mad_substream);
-       unsigned long long buffer_ptr;
-       int sfreq;
-};
-
-enum sst_drv_status {
-       SST_PLATFORM_INIT = 1,
-       SST_PLATFORM_STARTED,
-       SST_PLATFORM_RUNNING,
-       SST_PLATFORM_PAUSED,
-       SST_PLATFORM_DROPPED,
-};
-
-enum sst_controls {
-       SST_SND_ALLOC =                 0x00,
-       SST_SND_PAUSE =                 0x01,
-       SST_SND_RESUME =                0x02,
-       SST_SND_DROP =                  0x03,
-       SST_SND_FREE =                  0x04,
-       SST_SND_BUFFER_POINTER =        0x05,
-       SST_SND_STREAM_INIT =           0x06,
-       SST_SND_START    =              0x07,
-       SST_MAX_CONTROLS =              0x07,
-};
-
-enum sst_stream_ops {
-       STREAM_OPS_PLAYBACK = 0,
-       STREAM_OPS_CAPTURE,
-};
-
-enum sst_audio_device_type {
-       SND_SST_DEVICE_HEADSET = 1,
-       SND_SST_DEVICE_IHF,
-       SND_SST_DEVICE_VIBRA,
-       SND_SST_DEVICE_HAPTIC,
-       SND_SST_DEVICE_CAPTURE,
-       SND_SST_DEVICE_COMPRESS,
-};
-
-/* PCM Parameters */
-struct sst_pcm_params {
-       u16 codec;      /* codec type */
-       u8 num_chan;    /* 1=Mono, 2=Stereo */
-       u8 pcm_wd_sz;   /* 16/24 - bit*/
-       u32 reserved;   /* Bitrate in bits per second */
-       u32 sfreq;      /* Sampling rate in Hz */
-       u32 ring_buffer_size;
-       u32 period_count;       /* period elapsed in samples*/
-       u32 ring_buffer_addr;
-};
-
-struct sst_stream_params {
-       u32 result;
-       u32 stream_id;
-       u8 codec;
-       u8 ops;
-       u8 stream_type;
-       u8 device_type;
-       struct sst_pcm_params sparams;
-};
-
-struct sst_compress_cb {
-       void *param;
-       void (*compr_cb)(void *param);
-};
-
-struct compress_sst_ops {
-       const char *name;
-       int (*open) (struct snd_sst_params *str_params,
-                       struct sst_compress_cb *cb);
-       int (*control) (unsigned int cmd, unsigned int str_id);
-       int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
-       int (*ack) (unsigned int str_id, unsigned long bytes);
-       int (*close) (unsigned int str_id);
-       int (*get_caps) (struct snd_compr_caps *caps);
-       int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
-       int (*set_metadata) (unsigned int str_id,
-                       struct snd_compr_metadata *mdata);
-
-};
-
-struct sst_ops {
-       int (*open) (struct sst_stream_params *str_param);
-       int (*device_control) (int cmd, void *arg);
-       int (*close) (unsigned int str_id);
-};
-
-struct sst_runtime_stream {
-       int     stream_status;
-       unsigned int id;
-       size_t bytes_written;
-       struct pcm_stream_info stream_info;
-       struct sst_ops *ops;
-       struct compress_sst_ops *compr_ops;
-       spinlock_t      status_lock;
-};
-
-struct sst_device {
-       char *name;
-       struct device *dev;
-       struct sst_ops *ops;
-       struct compress_sst_ops *compr_ops;
-};
-
-int sst_register_dsp(struct sst_device *sst);
-int sst_unregister_dsp(struct sst_device *sst);
-#endif
index 78ed4a42ad217e904a40591afb500019ec3a017b..49f8437665dea5d326833a4aff3ad506c6c02d56 100644 (file)
@@ -1,11 +1,20 @@
 config SND_KIRKWOOD_SOC
        tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
-       depends on ARCH_KIRKWOOD || ARCH_DOVE || COMPILE_TEST
+       depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
        help
          Say Y or M if you want to add support for codecs attached to
          the Kirkwood I2S interface. You will also need to select the
          audio interfaces to support below.
 
+config SND_KIRKWOOD_SOC_ARMADA370_DB
+       tristate "SoC Audio support for Armada 370 DB"
+       depends on SND_KIRKWOOD_SOC && (ARCH_MVEBU || COMPILE_TEST) && I2C
+       select SND_SOC_CS42L51
+       select SND_SOC_SPDIF
+       help
+         Say Y if you want to add support for SoC audio on
+         the Armada 370 Development Board.
+
 config SND_KIRKWOOD_SOC_OPENRD
        tristate "SoC Audio support for Kirkwood Openrd Client"
        depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST)
index 9e781385cb88be80d8b4eb3da2b2090ca92f3a15..7c1d8fe09e6b6a6d465729904a0bbe7773d05fdb 100644 (file)
@@ -4,6 +4,8 @@ obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
 
 snd-soc-openrd-objs := kirkwood-openrd.o
 snd-soc-t5325-objs := kirkwood-t5325.o
+snd-soc-armada-370-db-objs := armada-370-db.o
 
+obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o
 obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
 obj-$(CONFIG_SND_KIRKWOOD_SOC_T5325) += snd-soc-t5325.o
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
new file mode 100644 (file)
index 0000000..c443338
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <linux/of.h>
+#include <linux/platform_data/asoc-kirkwood.h>
+#include "../codecs/cs42l51.h"
+
+static int a370db_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;
+       unsigned int freq;
+
+       switch (params_rate(params)) {
+       default:
+       case 44100:
+               freq = 11289600;
+               break;
+       case 48000:
+               freq = 12288000;
+               break;
+       case 96000:
+               freq = 24576000;
+               break;
+       }
+
+       return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+}
+
+static struct snd_soc_ops a370db_ops = {
+       .hw_params = a370db_hw_params,
+};
+
+static const struct snd_soc_dapm_widget a370db_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Out Jack", NULL),
+       SND_SOC_DAPM_LINE("In Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route a370db_route[] = {
+       { "Out Jack",   NULL,   "HPL" },
+       { "Out Jack",   NULL,   "HPR" },
+       { "AIN1L",      NULL,   "In Jack" },
+       { "AIN1L",      NULL,   "In Jack" },
+};
+
+static struct snd_soc_dai_link a370db_dai[] = {
+{
+       .name = "CS42L51",
+       .stream_name = "analog",
+       .cpu_dai_name = "i2s",
+       .codec_dai_name = "cs42l51-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+       .ops = &a370db_ops,
+},
+{
+       .name = "S/PDIF out",
+       .stream_name = "spdif-out",
+       .cpu_dai_name = "spdif",
+       .codec_dai_name = "dit-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+},
+{
+       .name = "S/PDIF in",
+       .stream_name = "spdif-in",
+       .cpu_dai_name = "spdif",
+       .codec_dai_name = "dir-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+},
+};
+
+static struct snd_soc_card a370db = {
+       .name = "a370db",
+       .owner = THIS_MODULE,
+       .dai_link = a370db_dai,
+       .num_links = ARRAY_SIZE(a370db_dai),
+       .dapm_widgets = a370db_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(a370db_dapm_widgets),
+       .dapm_routes = a370db_route,
+       .num_dapm_routes = ARRAY_SIZE(a370db_route),
+};
+
+static int a370db_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &a370db;
+
+       card->dev = &pdev->dev;
+
+       a370db_dai[0].cpu_of_node =
+               of_parse_phandle(pdev->dev.of_node,
+                                "marvell,audio-controller", 0);
+       a370db_dai[0].platform_of_node = a370db_dai[0].cpu_of_node;
+
+       a370db_dai[0].codec_of_node =
+               of_parse_phandle(pdev->dev.of_node,
+                                "marvell,audio-codec", 0);
+
+       a370db_dai[1].cpu_of_node = a370db_dai[0].cpu_of_node;
+       a370db_dai[1].platform_of_node = a370db_dai[0].cpu_of_node;
+
+       a370db_dai[1].codec_of_node =
+               of_parse_phandle(pdev->dev.of_node,
+                                "marvell,audio-codec", 1);
+
+       a370db_dai[2].cpu_of_node = a370db_dai[0].cpu_of_node;
+       a370db_dai[2].platform_of_node = a370db_dai[0].cpu_of_node;
+
+       a370db_dai[2].codec_of_node =
+               of_parse_phandle(pdev->dev.of_node,
+                                "marvell,audio-codec", 2);
+
+       return devm_snd_soc_register_card(card->dev, card);
+}
+
+static const struct of_device_id a370db_dt_ids[] = {
+       { .compatible = "marvell,a370db-audio" },
+       { },
+};
+
+static struct platform_driver a370db_driver = {
+       .driver         = {
+               .name   = "a370db-audio",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(a370db_dt_ids),
+       },
+       .probe          = a370db_probe,
+};
+
+module_platform_driver(a370db_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("ALSA SoC a370db audio client");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:a370db-audio");
index 3920a5e8125f886e15caa6607fed9e84a32950cd..9f842222e79802e2628a826ac536a506a069d8c0 100644 (file)
@@ -633,6 +633,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 static struct of_device_id mvebu_audio_of_match[] = {
        { .compatible = "marvell,kirkwood-audio" },
        { .compatible = "marvell,dove-audio" },
+       { .compatible = "marvell,armada370-audio" },
        { }
 };
 MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
index 22ad9c5654b5ebea99b6aecbc0b4271af62ef3e1..e00659351a4e2279a539a0a26a1117fa196419bb 100644 (file)
@@ -58,7 +58,7 @@ config SND_OMAP_SOC_OSK5912
        tristate "SoC Audio support for omap osk5912"
        depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
        select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TLV320AIC23
+       select SND_SOC_TLV320AIC23_I2C
        help
          Say Y if you want to add support for SoC audio on osk5912.
 
@@ -66,7 +66,7 @@ config SND_OMAP_SOC_AM3517EVM
        tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
        depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
        select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TLV320AIC23
+       select SND_SOC_TLV320AIC23_I2C
        help
          Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
          EVM.
index 629446482a917267706c76982863577a426da11c..56a5219c0a00587fc412caf76927adf4d11799a5 100644 (file)
@@ -103,60 +103,62 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
        if (!codec->hw_write)
                return -EUNATCH;
 
-       if (ucontrol->value.enumerated.item[0] >= control->max)
+       if (ucontrol->value.enumerated.item[0] >= control->items)
                return -EINVAL;
 
-       mutex_lock(&codec->mutex);
+       snd_soc_dapm_mutex_lock(dapm);
 
        /* Translate selection to bitmap */
        pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]];
 
        /* Setup pins after corresponding bits if changed */
        pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
+
        if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(dapm, "Mouthpiece");
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece");
                else
-                       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
        }
        pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
        if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(dapm, "Earpiece");
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
                else
-                       snd_soc_dapm_disable_pin(dapm, "Earpiece");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece");
        }
        pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
        if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(dapm, "Microphone");
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
                else
-                       snd_soc_dapm_disable_pin(dapm, "Microphone");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone");
        }
        pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
        if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(dapm, "Speaker");
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
                else
-                       snd_soc_dapm_disable_pin(dapm, "Speaker");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
        }
        pin = !!(pins & (1 << AMS_DELTA_AGC));
        if (pin != ams_delta_audio_agc) {
                ams_delta_audio_agc = pin;
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(dapm, "AGCIN");
+                       snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN");
                else
-                       snd_soc_dapm_disable_pin(dapm, "AGCIN");
+                       snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
        }
+
        if (changed)
-               snd_soc_dapm_sync(dapm);
+               snd_soc_dapm_sync_unlocked(dapm);
 
-       mutex_unlock(&codec->mutex);
+       snd_soc_dapm_mutex_unlock(dapm);
 
        return changed;
 }
@@ -194,13 +196,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const struct soc_enum ams_delta_audio_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode),
-                                               ams_delta_audio_mode),
-};
+static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
+                                     ams_delta_audio_mode);
 
 static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
-       SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0],
+       SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
                        ams_delta_get_audio_mode, ams_delta_set_audio_mode),
 };
 
@@ -315,12 +315,17 @@ static void cx81801_close(struct tty_struct *tty)
        v253_ops.close(tty);
 
        /* Revert back to default audio input/output constellation */
-       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
-       snd_soc_dapm_enable_pin(dapm, "Earpiece");
-       snd_soc_dapm_enable_pin(dapm, "Microphone");
-       snd_soc_dapm_disable_pin(dapm, "Speaker");
-       snd_soc_dapm_disable_pin(dapm, "AGCIN");
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_mutex_lock(dapm);
+
+       snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
+       snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
+       snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+       snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 /* Line discipline .hangup() */
index 3fde9e402710f2bb16baf80b605da42772df69a0..fd4d9c809e50a45b1b36168add18352e343992fe 100644 (file)
@@ -68,26 +68,30 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm)
                break;
        }
 
+       snd_soc_dapm_mutex_lock(dapm);
+
        if (n810_spk_func)
-               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
 
        if (hp)
-               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
        else
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
        if (line1l)
-               snd_soc_dapm_enable_pin(dapm, "LINE1L");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L");
        else
-               snd_soc_dapm_disable_pin(dapm, "LINE1L");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L");
 
        if (n810_dmic_func)
-               snd_soc_dapm_enable_pin(dapm, "DMic");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
        else
-               snd_soc_dapm_disable_pin(dapm, "DMic");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
+
+       snd_soc_dapm_sync_unlocked(dapm);
 
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 static int n810_startup(struct snd_pcm_substream *substream)
@@ -305,7 +309,9 @@ static int __init n810_soc_init(void)
        int err;
        struct device *dev;
 
-       if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
+       if (!of_have_populated_dt() ||
+           (!of_machine_is_compatible("nokia,n810") &&
+            !of_machine_is_compatible("nokia,n810-wimax")))
                return -ENODEV;
 
        n810_snd_device = platform_device_alloc("soc-audio", -1);
index ebb13906b3a0b41b4d3c20509c613378da5ae248..024dafc3e2981b752c6d9526a35644f984076f61 100644 (file)
@@ -203,8 +203,7 @@ static const struct snd_soc_dapm_route dmic_audio_map[] = {
 
 static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
 
        return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
                                ARRAY_SIZE(dmic_audio_map));
index 611179c3bca48c4ca0e9128f3ab5016766373e44..7fb3d4b103701c5a38a6bf25d4dc75b2fa32543c 100644 (file)
@@ -74,26 +74,30 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
                break;
        }
 
+       snd_soc_dapm_mutex_lock(dapm);
+
        if (rx51_spk_func)
-               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
        if (rx51_dmic_func)
-               snd_soc_dapm_enable_pin(dapm, "DMic");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
        else
-               snd_soc_dapm_disable_pin(dapm, "DMic");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
        if (hp)
-               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
        else
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
        if (hs)
-               snd_soc_dapm_enable_pin(dapm, "HS Mic");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
        else
-               snd_soc_dapm_disable_pin(dapm, "HS Mic");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
 
        gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
 
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 static int rx51_startup(struct snd_pcm_substream *substream)
index 1853d41034bfa0c17d752f6191e4346e1cc06725..5a88136aa800bc827db543543aa018f701002d14 100644 (file)
@@ -47,64 +47,63 @@ static int corgi_spk_func;
 
 static void corgi_ext_control(struct snd_soc_dapm_context *dapm)
 {
+       snd_soc_dapm_mutex_lock(dapm);
+
        /* set up jack connection */
        switch (corgi_jack_func) {
        case CORGI_HP:
                /* set = unmute headphone */
                gpio_set_value(CORGI_GPIO_MUTE_L, 1);
                gpio_set_value(CORGI_GPIO_MUTE_R, 1);
-               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
-               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
                break;
        case CORGI_MIC:
                /* reset = mute headphone */
                gpio_set_value(CORGI_GPIO_MUTE_L, 0);
                gpio_set_value(CORGI_GPIO_MUTE_R, 0);
-               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
                break;
        case CORGI_LINE:
                gpio_set_value(CORGI_GPIO_MUTE_L, 0);
                gpio_set_value(CORGI_GPIO_MUTE_R, 0);
-               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_enable_pin(dapm, "Line Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
                break;
        case CORGI_HEADSET:
                gpio_set_value(CORGI_GPIO_MUTE_L, 0);
                gpio_set_value(CORGI_GPIO_MUTE_R, 1);
-               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_enable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
                break;
        }
 
        if (corgi_spk_func == CORGI_SPK_ON)
-               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
 
        /* signal a DAPM event */
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 static int corgi_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&codec->mutex);
 
        /* check the jack status at stream startup */
-       corgi_ext_control(&codec->dapm);
-
-       mutex_unlock(&codec->mutex);
+       corgi_ext_control(&rtd->card->dapm);
 
        return 0;
 }
index 44b5c09d296be62889649c5157dd098d12013deb..c29fedab2f49abb225a67c07e2e8659826aec7a1 100644 (file)
@@ -103,11 +103,6 @@ static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "PCBEEP");
        snd_soc_dapm_nc_pin(dapm, "MIC2");
 
-       snd_soc_dapm_new_controls(dapm, e740_dapm_widgets,
-                                       ARRAY_SIZE(e740_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -136,6 +131,11 @@ static struct snd_soc_card e740 = {
        .owner = THIS_MODULE,
        .dai_link = e740_dai,
        .num_links = ARRAY_SIZE(e740_dai),
+
+       .dapm_widgets = e740_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct gpio e740_audio_gpios[] = {
index c34e447eb9911202ca5b6fbcaa78704f1103468a..ee36aba88063aa7db6cd498dbb6a3341e3f3ea47 100644 (file)
@@ -85,11 +85,6 @@ static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "PCBEEP");
        snd_soc_dapm_nc_pin(dapm, "MIC2");
 
-       snd_soc_dapm_new_controls(dapm, e750_dapm_widgets,
-                                       ARRAY_SIZE(e750_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -119,6 +114,11 @@ static struct snd_soc_card e750 = {
        .owner = THIS_MODULE,
        .dai_link = e750_dai,
        .num_links = ARRAY_SIZE(e750_dai),
+
+       .dapm_widgets = e750_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct gpio e750_audio_gpios[] = {
index 3137f800b43f139a2c41adcfb3edc7981aae347a..24c2078ce70b2a97e05d7b63fa7d1a98da8498a3 100644 (file)
@@ -71,19 +71,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2", NULL, "Mic (Internal2)"},
 };
 
-static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, e800_dapm_widgets,
-                                       ARRAY_SIZE(e800_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static struct snd_soc_dai_link e800_dai[] = {
        {
                .name = "AC97",
@@ -92,7 +79,6 @@ static struct snd_soc_dai_link e800_dai[] = {
                .codec_dai_name = "wm9712-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9712-codec",
-               .init = e800_ac97_init,
        },
        {
                .name = "AC97 Aux",
@@ -109,6 +95,11 @@ static struct snd_soc_card e800 = {
        .owner = THIS_MODULE,
        .dai_link = e800_dai,
        .num_links = ARRAY_SIZE(e800_dai),
+
+       .dapm_widgets = e800_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(e800_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct gpio e800_audio_gpios[] = {
index aace19e0fe2c217f734dbd0164b4d242a93be1d1..259e048681c0fd4bdfc1d4e67c3b3b804fe73504 100644 (file)
@@ -41,44 +41,42 @@ static int magician_hp_switch;
 static int magician_spk_switch = 1;
 static int magician_in_sel = MAGICIAN_MIC;
 
-static void magician_ext_control(struct snd_soc_codec *codec)
+static void magician_ext_control(struct snd_soc_dapm_context *dapm)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_mutex_lock(dapm);
 
        if (magician_spk_switch)
-               snd_soc_dapm_enable_pin(dapm, "Speaker");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
        else
-               snd_soc_dapm_disable_pin(dapm, "Speaker");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
        if (magician_hp_switch)
-               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
        else
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
 
        switch (magician_in_sel) {
        case MAGICIAN_MIC:
-               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
-               snd_soc_dapm_enable_pin(dapm, "Call Mic");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic");
                break;
        case MAGICIAN_MIC_EXT:
-               snd_soc_dapm_disable_pin(dapm, "Call Mic");
-               snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic");
                break;
        }
 
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 static int magician_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&codec->mutex);
 
        /* check the jack status at stream startup */
-       magician_ext_control(codec);
-
-       mutex_unlock(&codec->mutex);
+       magician_ext_control(&rtd->card->dapm);
 
        return 0;
 }
@@ -277,13 +275,13 @@ static int magician_get_hp(struct snd_kcontrol *kcontrol,
 static int magician_set_hp(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);
 
        if (magician_hp_switch == ucontrol->value.integer.value[0])
                return 0;
 
        magician_hp_switch = ucontrol->value.integer.value[0];
-       magician_ext_control(codec);
+       magician_ext_control(&card->dapm);
        return 1;
 }
 
@@ -297,13 +295,13 @@ static int magician_get_spk(struct snd_kcontrol *kcontrol,
 static int magician_set_spk(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);
 
        if (magician_spk_switch == ucontrol->value.integer.value[0])
                return 0;
 
        magician_spk_switch = ucontrol->value.integer.value[0];
-       magician_ext_control(codec);
+       magician_ext_control(&card->dapm);
        return 1;
 }
 
@@ -400,7 +398,6 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        /* NC codec pins */
        snd_soc_dapm_nc_pin(dapm, "VOUTLHP");
@@ -410,19 +407,6 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "VINL");
        snd_soc_dapm_nc_pin(dapm, "VINR");
 
-       /* Add magician specific controls */
-       err = snd_soc_add_codec_controls(codec, uda1380_magician_controls,
-                               ARRAY_SIZE(uda1380_magician_controls));
-       if (err < 0)
-               return err;
-
-       /* Add magician specific widgets */
-       snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
-                                 ARRAY_SIZE(uda1380_dapm_widgets));
-
-       /* Set up magician specific audio path interconnects */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -456,6 +440,12 @@ static struct snd_soc_card snd_soc_card_magician = {
        .dai_link = magician_dai,
        .num_links = ARRAY_SIZE(magician_dai),
 
+       .controls = uda1380_magician_controls,
+       .num_controls = ARRAY_SIZE(uda1380_magician_controls),
+       .dapm_widgets = uda1380_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct platform_device *magician_snd_device;
index 160c5245448f1e32303b240e47ab1e4616c25325..595eee341e90b6910d60348fdae5e970e0854fa6 100644 (file)
@@ -127,16 +127,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        unsigned short reg;
 
-       /* Add mioa701 specific widgets */
-       snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets,
-                                 ARRAY_SIZE(mioa701_dapm_widgets));
-
-       /* Set up mioa701 specific audio path audio_mapnects */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        /* Prepare GPIO8 for rear speaker amplifier */
        reg = codec->driver->read(codec, AC97_GPIO_CFG);
        codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
@@ -145,12 +137,6 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
        reg = codec->driver->read(codec, AC97_3D_CONTROL);
        codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
 
-       snd_soc_dapm_enable_pin(dapm, "Front Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Rear Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Front Mic");
-       snd_soc_dapm_enable_pin(dapm, "GSM Line In");
-       snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
-
        return 0;
 }
 
@@ -183,6 +169,11 @@ static struct snd_soc_card mioa701 = {
        .owner = THIS_MODULE,
        .dai_link = mioa701_dai,
        .num_links = ARRAY_SIZE(mioa701_dai),
+
+       .dapm_widgets = mioa701_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static int mioa701_wm9713_probe(struct platform_device *pdev)
index c93e138d8dc3403f538c193d2bc1fc52794d9ad6..c6bdc6c0eff6007f1180d3908b3437600fc6446d 100644 (file)
@@ -74,14 +74,9 @@ static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
 static int poodle_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&codec->mutex);
 
        /* check the jack status at stream startup */
-       poodle_ext_control(&codec->dapm);
-
-       mutex_unlock(&codec->mutex);
+       poodle_ext_control(&rtd->card->dapm);
 
        return 0;
 }
index fc052d8247ff245aa6b5baead314ac893e77930c..1373b017a9514f379bf8f111afad10ddac640d6f 100644 (file)
@@ -46,74 +46,74 @@ static int spitz_mic_gpio;
 
 static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
 {
+       snd_soc_dapm_mutex_lock(dapm);
+
        if (spitz_spk_func == SPITZ_SPK_ON)
-               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
 
        /* set up jack connection */
        switch (spitz_jack_func) {
        case SPITZ_HP:
                /* enable and unmute hp jack, disable mic bias */
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
-               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
-               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 1);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
                break;
        case SPITZ_MIC:
                /* enable mic jack and bias, mute hp */
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
-               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
                break;
        case SPITZ_LINE:
                /* enable line jack, disable mic bias and mute hp */
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
-               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_enable_pin(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
                break;
        case SPITZ_HEADSET:
                /* enable and unmute headset jack enable mic bias, mute L hp */
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
-               snd_soc_dapm_enable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
                break;
        case SPITZ_HP_OFF:
 
                /* jack removed, everything off */
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
-               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
-               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
                break;
        }
-       snd_soc_dapm_sync(dapm);
+
+       snd_soc_dapm_sync_unlocked(dapm);
+
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 static int spitz_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&codec->mutex);
 
        /* check the jack status at stream startup */
-       spitz_ext_control(&codec->dapm);
-
-       mutex_unlock(&codec->mutex);
+       spitz_ext_control(&rtd->card->dapm);
 
        return 0;
 }
index 1d9c2ed223bc089b233b748485c7b5a2e387ee49..4a956d1cb26960a23bb77eea839908d608b56677 100644 (file)
 static int tosa_jack_func;
 static int tosa_spk_func;
 
-static void tosa_ext_control(struct snd_soc_codec *codec)
+static void tosa_ext_control(struct snd_soc_dapm_context *dapm)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_mutex_lock(dapm);
 
        /* set up jack connection */
        switch (tosa_jack_func) {
        case TOSA_HP:
-               snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
-               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
                break;
        case TOSA_MIC_INT:
-               snd_soc_dapm_enable_pin(dapm, "Mic (Internal)");
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Mic (Internal)");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
                break;
        case TOSA_HEADSET:
-               snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
-               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
-               snd_soc_dapm_enable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
                break;
        }
 
        if (tosa_spk_func == TOSA_SPK_ON)
-               snd_soc_dapm_enable_pin(dapm, "Speaker");
+               snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
        else
-               snd_soc_dapm_disable_pin(dapm, "Speaker");
+               snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+
+       snd_soc_dapm_sync_unlocked(dapm);
 
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_mutex_unlock(dapm);
 }
 
 static int tosa_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-
-       mutex_lock(&codec->mutex);
 
        /* check the jack status at stream startup */
-       tosa_ext_control(codec);
-
-       mutex_unlock(&codec->mutex);
+       tosa_ext_control(&rtd->card->dapm);
 
        return 0;
 }
@@ -104,13 +102,13 @@ static int tosa_get_jack(struct snd_kcontrol *kcontrol,
 static int tosa_set_jack(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);
 
        if (tosa_jack_func == ucontrol->value.integer.value[0])
                return 0;
 
        tosa_jack_func = ucontrol->value.integer.value[0];
-       tosa_ext_control(codec);
+       tosa_ext_control(&card->dapm);
        return 1;
 }
 
@@ -124,13 +122,13 @@ static int tosa_get_spk(struct snd_kcontrol *kcontrol,
 static int tosa_set_spk(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);
 
        if (tosa_spk_func == ucontrol->value.integer.value[0])
                return 0;
 
        tosa_spk_func = ucontrol->value.integer.value[0];
-       tosa_ext_control(codec);
+       tosa_ext_control(&card->dapm);
        return 1;
 }
 
@@ -191,24 +189,10 @@ static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        snd_soc_dapm_nc_pin(dapm, "OUT3");
        snd_soc_dapm_nc_pin(dapm, "MONOOUT");
 
-       /* add tosa specific controls */
-       err = snd_soc_add_codec_controls(codec, tosa_controls,
-                               ARRAY_SIZE(tosa_controls));
-       if (err < 0)
-               return err;
-
-       /* add tosa specific widgets */
-       snd_soc_dapm_new_controls(dapm, tosa_dapm_widgets,
-                                 ARRAY_SIZE(tosa_dapm_widgets));
-
-       /* set up tosa specific audio path audio_map */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -239,6 +223,13 @@ static struct snd_soc_card tosa = {
        .owner = THIS_MODULE,
        .dai_link = tosa_dai,
        .num_links = ARRAY_SIZE(tosa_dai),
+
+       .controls = tosa_controls,
+       .num_controls = ARRAY_SIZE(tosa_controls),
+       .dapm_widgets = tosa_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static int tosa_probe(struct platform_device *pdev)
index db8aadf8932dbc9e319975d474bd17a47884a2c7..23bf991e95d53fa282f3b8e6dfbd2e9e2eeada21 100644 (file)
@@ -71,22 +71,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
        if (clk_pout)
                snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
                                    clk_get_rate(pout), 0);
 
-       snd_soc_dapm_new_controls(dapm, zylonite_dapm_widgets,
-                                 ARRAY_SIZE(zylonite_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       /* Static setup for now */
-       snd_soc_dapm_enable_pin(dapm, "Headphone");
-       snd_soc_dapm_enable_pin(dapm, "Headset Earpiece");
-
        return 0;
 }
 
@@ -256,6 +244,11 @@ static struct snd_soc_card zylonite = {
        .resume_pre = &zylonite_resume_pre,
        .dai_link = zylonite_dai,
        .num_links = ARRAY_SIZE(zylonite_dai),
+
+       .dapm_widgets = zylonite_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(zylonite_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct platform_device *zylonite_snd_ac97_device;
index 945e8abdc10fbf9579a1f89bd9a6a0610980256f..0b21d1dc80c1be2844fcf8e9024007b1d879159d 100644 (file)
@@ -104,8 +104,8 @@ static int output_type_get(struct snd_kcontrol *kcontrol,
 static int output_type_put(struct snd_kcontrol *kcontrol,
                           struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = kcontrol->private_data;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_card *card = kcontrol->private_data;
+       struct snd_soc_dapm_context *dapm = &card->dapm;
        unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
        char *differential = "Audio Out Differential";
        char *stereo = "Audio Out Stereo";
@@ -137,13 +137,7 @@ static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* Add s6105 specific widgets */
-       snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
-                                 ARRAY_SIZE(aic3x_dapm_widgets));
-
-       /* Set up s6105 specific audio path audio_map */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+       struct snd_soc_card *card = rtd->card;
 
        /* not present */
        snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
@@ -157,17 +151,10 @@ static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "RLOUT");
        snd_soc_dapm_nc_pin(dapm, "HPRCOM");
 
-       /* always connected */
-       snd_soc_dapm_enable_pin(dapm, "Audio In");
-
        /* must correspond to audio_out_mux.private_value initializer */
-       snd_soc_dapm_disable_pin(dapm, "Audio Out Differential");
-       snd_soc_dapm_sync(dapm);
-       snd_soc_dapm_enable_pin(dapm, "Audio Out Stereo");
-
-       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_disable_pin(&card->dapm, "Audio Out Differential");
 
-       snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&audio_out_mux, codec));
+       snd_ctl_add(card->snd_card, snd_ctl_new1(&audio_out_mux, card));
 
        return 0;
 }
@@ -190,6 +177,11 @@ static struct snd_soc_card snd_soc_card_s6105 = {
        .owner = THIS_MODULE,
        .dai_link = &s6105_dai,
        .num_links = 1,
+
+       .dapm_widgets = aic3x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct s6000_snd_platform_data s6105_snd_data __initdata = {
index 3507574003913b5023f66853a50bec809d6187bf..f2e289180e466ef0a9d673eea33f7ab0aaca1bd3 100644 (file)
@@ -117,7 +117,7 @@ config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
        tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
        depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
        select SND_S3C24XX_I2S
-       select SND_SOC_TLV320AIC23
+       select SND_SOC_TLV320AIC23_I2C
        select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
index fbced589d0778af46b92e3198534116767be3706..88b09e022503d94f6774dcfbc2822a2e054a0800 100644 (file)
@@ -66,10 +66,6 @@ static int h1940_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       runtime->hw.rate_min = hw_rates.list[0];
-       runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
-       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-
        return snd_pcm_hw_constraint_list(runtime, 0,
                                        SNDRV_PCM_HW_PARAM_RATE,
                                        &hw_rates);
@@ -94,7 +90,7 @@ static int h1940_hw_params(struct snd_pcm_substream *substream,
                        div++;
                break;
        default:
-               dev_err(&rtd->dev, "%s: rate %d is not supported\n",
+               dev_err(rtd->dev, "%s: rate %d is not supported\n",
                        __func__, rate);
                return -EINVAL;
        }
@@ -181,7 +177,6 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
        snd_soc_dapm_enable_pin(dapm, "Speaker");
index 98a04c11202df7562475f4dd88bd4742f00492f3..b0800337b79e04dca84587f4091f8fd0989015ef 100644 (file)
@@ -192,44 +192,6 @@ static struct snd_soc_ops neo1973_voice_ops = {
        .hw_free = neo1973_voice_hw_free,
 };
 
-/* Shared routes and controls */
-
-static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
-       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
-       SND_SOC_DAPM_LINE("GSM Line In", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Handset Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
-       /* Connections to the GSM Module */
-       {"GSM Line Out", NULL, "MONO1"},
-       {"GSM Line Out", NULL, "MONO2"},
-       {"RXP", NULL, "GSM Line In"},
-       {"RXN", NULL, "GSM Line In"},
-
-       /* Connections to Headset */
-       {"MIC1", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Headset Mic"},
-
-       /* Call Mic */
-       {"MIC2", NULL, "Mic Bias"},
-       {"MIC2N", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Handset Mic"},
-
-       /* Connect the ALC pins */
-       {"ACIN", NULL, "ACOP"},
-};
-
-static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
-       SOC_DAPM_PIN_SWITCH("GSM Line Out"),
-       SOC_DAPM_PIN_SWITCH("GSM Line In"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Handset Mic"),
-};
-
-/* GTA02 specific routes and controls */
-
 static int gta02_speaker_enabled;
 
 static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
@@ -257,7 +219,34 @@ static int lm4853_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
+static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line In", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Handset Mic", NULL),
+       SND_SOC_DAPM_SPK("Handset Spk", NULL),
+       SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
+};
+
+static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
+       /* Connections to the GSM Module */
+       {"GSM Line Out", NULL, "MONO1"},
+       {"GSM Line Out", NULL, "MONO2"},
+       {"RXP", NULL, "GSM Line In"},
+       {"RXN", NULL, "GSM Line In"},
+
+       /* Connections to Headset */
+       {"MIC1", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Headset Mic"},
+
+       /* Call Mic */
+       {"MIC2", NULL, "Mic Bias"},
+       {"MIC2N", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Handset Mic"},
+
+       /* Connect the ALC pins */
+       {"ACIN", NULL, "ACOP"},
+
        /* Connections to the amp */
        {"Stereo Out", NULL, "LOUT1"},
        {"Stereo Out", NULL, "ROUT1"},
@@ -267,7 +256,11 @@ static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
        {"Handset Spk", NULL, "ROUT2"},
 };
 
-static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
+static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
+       SOC_DAPM_PIN_SWITCH("GSM Line Out"),
+       SOC_DAPM_PIN_SWITCH("GSM Line In"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Handset Mic"),
        SOC_DAPM_PIN_SWITCH("Handset Spk"),
        SOC_DAPM_PIN_SWITCH("Stereo Out"),
 
@@ -276,86 +269,32 @@ static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
                lm4853_set_spk),
 };
 
-static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Handset Spk", NULL),
-       SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
-};
-
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets,
-                       ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets));
-       if (ret)
-               return ret;
-
-       ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes,
-                       ARRAY_SIZE(neo1973_gta02_routes));
-       if (ret)
-               return ret;
-
-       ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls,
-                       ARRAY_SIZE(neo1973_gta02_wm8753_controls));
-       if (ret)
-               return ret;
-
-       snd_soc_dapm_disable_pin(dapm, "Stereo Out");
-       snd_soc_dapm_disable_pin(dapm, "Handset Spk");
-       snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
-       snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
-
-       return 0;
-}
-
 static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
+       struct snd_soc_card *card = rtd->card;
 
        /* set up NC codec pins */
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "OUT4");
-       snd_soc_dapm_nc_pin(dapm, "LINE1");
-       snd_soc_dapm_nc_pin(dapm, "LINE2");
-
-       /* Add neo1973 specific widgets */
-       ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets,
-                       ARRAY_SIZE(neo1973_wm8753_dapm_widgets));
-       if (ret)
-               return ret;
-
-       /* add neo1973 specific controls */
-       ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls,
-                       ARRAY_SIZE(neo1973_wm8753_controls));
-       if (ret)
-               return ret;
-
-       /* set up neo1973 specific audio routes */
-       ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes,
-                       ARRAY_SIZE(neo1973_wm8753_routes));
-       if (ret)
-               return ret;
+       snd_soc_dapm_nc_pin(&codec->dapm, "OUT3");
+       snd_soc_dapm_nc_pin(&codec->dapm, "OUT4");
+       snd_soc_dapm_nc_pin(&codec->dapm, "LINE1");
+       snd_soc_dapm_nc_pin(&codec->dapm, "LINE2");
 
        /* set endpoints to default off mode */
-       snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
-       snd_soc_dapm_disable_pin(dapm, "GSM Line In");
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic");
-       snd_soc_dapm_disable_pin(dapm, "Handset Mic");
+       snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out");
+       snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In");
+       snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic");
+       snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic");
+       snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out");
+       snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk");
 
        /* allow audio paths from the GSM modem to run during suspend */
-       snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
-       snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
-       snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
-       snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
-
-       if (machine_is_neo1973_gta02()) {
-               ret = neo1973_gta02_wm8753_init(codec);
-               if (ret)
-                       return ret;
-       }
+       snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk");
 
        return 0;
 }
@@ -409,6 +348,13 @@ static struct snd_soc_card neo1973 = {
        .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
        .codec_conf = neo1973_codec_conf,
        .num_configs = ARRAY_SIZE(neo1973_codec_conf),
+
+       .controls = neo1973_wm8753_controls,
+       .num_controls = ARRAY_SIZE(neo1973_wm8753_controls),
+       .dapm_widgets = neo1973_wm8753_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
+       .dapm_routes = neo1973_wm8753_routes,
+       .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
 };
 
 static struct platform_device *neo1973_snd_device;
index 06ebdc061770d546ad997d9f301b4ee3706d77ed..2982d9e7f268f4ba4f8105e0016a9375721034b4 100644 (file)
@@ -131,10 +131,6 @@ static int rx1950_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       runtime->hw.rate_min = hw_rates.list[0];
-       runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
-       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-
        return snd_pcm_hw_constraint_list(runtime, 0,
                                        SNDRV_PCM_HW_PARAM_RATE,
                                        &hw_rates);
@@ -226,7 +222,6 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
        snd_soc_dapm_enable_pin(dapm, "Speaker");
index d38ae98e2f32c27e0118ee21c3685f2d4c95fb9d..682eb4f7ba0c61257ade6e96691ceafcb4d023a5 100644 (file)
@@ -202,7 +202,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
 
 static struct platform_driver smdk_audio_driver = {
        .driver         = {
-               .name   = "smdk-audio-wm8894",
+               .name   = "smdk-audio-wm8994",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(samsung_wm8994_of_match),
                .pm     = &snd_soc_pm_ops,
index f21ff608a8199dd09f70b19b0bf92070a86fd28f..1807b75ccc12d0544d79e538173a2dc47e55ed1a 100644 (file)
@@ -44,6 +44,8 @@ static int tobermory_set_bias_level(struct snd_soc_card *card,
                                                     SND_SOC_CLOCK_IN);
                        if (ret < 0) {
                                pr_err("Failed to set SYSCLK: %d\n", ret);
+                               snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                                   0, 0, 0);
                                return ret;
                        }
                }
index 1967f44e7cd4d18fd078a71c52c3f0faf472b95f..710a079a7377db8f9cf55422648242496fd97d07 100644 (file)
@@ -1711,9 +1711,9 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               fsi->clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
+               fsi->clk_master = 1; /* codec is slave, cpu is master */
                break;
        default:
                return -EINVAL;
index 5014a884afeebff8fdf168a76dd90d33e2387bbf..c58c2529f10345d01745d919124c0634a70d7deb 100644 (file)
@@ -136,19 +136,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        { "Mic Bias", NULL, "External Microphone" },
 };
 
-static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, migor_dapm_widgets,
-                                 ARRAY_SIZE(migor_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 /* migor digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link migor_dai = {
        .name = "wm8978",
@@ -158,7 +145,6 @@ static struct snd_soc_dai_link migor_dai = {
        .platform_name = "siu-pcm-audio",
        .codec_name = "wm8978.0-001a",
        .ops = &migor_dai_ops,
-       .init = migor_dai_init,
 };
 
 /* migor audio machine driver */
@@ -167,6 +153,11 @@ static struct snd_soc_card snd_soc_migor = {
        .owner = THIS_MODULE,
        .dai_link = &migor_dai,
        .num_links = 1,
+
+       .dapm_widgets = migor_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
 };
 
 static struct platform_device *migor_snd_device;
index 0ff492df7929836004e366617ac77c0547f1a342..7d0051ced83831201a70f4ffa8ddb0965b3963fb 100644 (file)
@@ -1,2 +1,2 @@
-snd-soc-rcar-objs      := core.o gen.o scu.o adg.o ssi.o
+snd-soc-rcar-objs      := core.o gen.o src.o adg.o ssi.o
 obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
\ No newline at end of file
index a53235c4d1b0dcc971d81ed04884e1636b80932a..69c44269ebdb960545dd1cbfa5e18e7fde08d843 100644 (file)
@@ -25,15 +25,165 @@ struct rsnd_adg {
 };
 
 #define for_each_rsnd_clk(pos, adg, i)         \
-       for (i = 0, (pos) = adg->clk[i];        \
-            i < CLKMAX;                        \
-            i++, (pos) = adg->clk[i])
+       for (i = 0;                             \
+            (i < CLKMAX) &&                    \
+            ((pos) = adg->clk[i]);             \
+            i++)
 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
 
-static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
-                                        struct rsnd_mod *mod,
-                                        unsigned int src_rate,
-                                        unsigned int dst_rate)
+
+static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       int id = rsnd_mod_id(mod);
+       int ws = id;
+
+       if (rsnd_ssi_is_pin_sharing(rsnd_ssi_mod_get(priv, id))) {
+               switch (id) {
+               case 1:
+               case 2:
+                       ws = 0;
+                       break;
+               case 4:
+                       ws = 3;
+                       break;
+               case 8:
+                       ws = 7;
+                       break;
+               }
+       }
+
+       return (0x6 + ws) << 8;
+}
+
+static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
+                                       struct rsnd_mod *mod,
+                                       struct rsnd_dai_stream *io,
+                                       u32 timsel)
+{
+       int is_play = rsnd_dai_is_play(rdai, io);
+       int id = rsnd_mod_id(mod);
+       int shift = (id % 2) ? 16 : 0;
+       u32 mask, ws;
+       u32 in, out;
+
+       ws = rsnd_adg_ssi_ws_timing_gen2(io);
+
+       in  = (is_play) ? timsel : ws;
+       out = (is_play) ? ws     : timsel;
+
+       in   = in       << shift;
+       out  = out      << shift;
+       mask = 0xffff   << shift;
+
+       switch (id / 2) {
+       case 0:
+               rsnd_mod_bset(mod, SRCIN_TIMSEL0,  mask, in);
+               rsnd_mod_bset(mod, SRCOUT_TIMSEL0, mask, out);
+               break;
+       case 1:
+               rsnd_mod_bset(mod, SRCIN_TIMSEL1,  mask, in);
+               rsnd_mod_bset(mod, SRCOUT_TIMSEL1, mask, out);
+               break;
+       case 2:
+               rsnd_mod_bset(mod, SRCIN_TIMSEL2,  mask, in);
+               rsnd_mod_bset(mod, SRCOUT_TIMSEL2, mask, out);
+               break;
+       case 3:
+               rsnd_mod_bset(mod, SRCIN_TIMSEL3,  mask, in);
+               rsnd_mod_bset(mod, SRCOUT_TIMSEL3, mask, out);
+               break;
+       case 4:
+               rsnd_mod_bset(mod, SRCIN_TIMSEL4,  mask, in);
+               rsnd_mod_bset(mod, SRCOUT_TIMSEL4, mask, out);
+               break;
+       }
+
+       return 0;
+}
+
+int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
+                                 struct rsnd_dai *rdai,
+                                 struct rsnd_dai_stream *io,
+                                 unsigned int src_rate,
+                                 unsigned int dst_rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int idx, sel, div, step, ret;
+       u32 val, en;
+       unsigned int min, diff;
+       unsigned int sel_rate [] = {
+               clk_get_rate(adg->clk[CLKA]),   /* 0000: CLKA */
+               clk_get_rate(adg->clk[CLKB]),   /* 0001: CLKB */
+               clk_get_rate(adg->clk[CLKC]),   /* 0010: CLKC */
+               adg->rbga_rate_for_441khz_div_6,/* 0011: RBGA */
+               adg->rbgb_rate_for_48khz_div_6, /* 0100: RBGB */
+       };
+
+       min = ~0;
+       val = 0;
+       en = 0;
+       for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
+               idx = 0;
+               step = 2;
+
+               if (!sel_rate[sel])
+                       continue;
+
+               for (div = 2; div <= 98304; div += step) {
+                       diff = abs(src_rate - sel_rate[sel] / div);
+                       if (min > diff) {
+                               val = (sel << 8) | idx;
+                               min = diff;
+                               en = 1 << (sel + 1); /* fixme */
+                       }
+
+                       /*
+                        * step of 0_0000 / 0_0001 / 0_1101
+                        * are out of order
+                        */
+                       if ((idx > 2) && (idx % 2))
+                               step *= 2;
+                       if (idx == 0x1c) {
+                               div += step;
+                               step *= 2;
+                       }
+                       idx++;
+               }
+       }
+
+       if (min == ~0) {
+               dev_err(dev, "no Input clock\n");
+               return -EIO;
+       }
+
+       ret = rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+       if (ret < 0) {
+               dev_err(dev, "timsel error\n");
+               return ret;
+       }
+
+       rsnd_mod_bset(mod, DIV_EN, en, en);
+
+       return 0;
+}
+
+int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
+                                    struct rsnd_dai *rdai,
+                                    struct rsnd_dai_stream *io)
+{
+       u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
+
+       return rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+}
+
+int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
+                                 struct rsnd_mod *mod,
+                                 unsigned int src_rate,
+                                 unsigned int dst_rate)
 {
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -91,18 +241,6 @@ find_rate:
        return 0;
 }
 
-int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
-                            struct rsnd_mod *mod,
-                            unsigned int src_rate,
-                            unsigned int dst_rate)
-{
-       if (rsnd_is_gen1(priv))
-               return rsnd_adg_set_convert_clk_gen1(priv, mod,
-                                                    src_rate, dst_rate);
-
-       return -EINVAL;
-}
-
 static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
 {
        int id = rsnd_mod_id(mod);
@@ -254,13 +392,14 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
 }
 
 int rsnd_adg_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv)
 {
        struct rsnd_adg *adg;
        struct device *dev = rsnd_priv_to_dev(priv);
-       struct clk *clk;
+       struct clk *clk, *clk_orig;
        int i;
+       bool use_old_style = false;
 
        adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
        if (!adg) {
@@ -268,10 +407,39 @@ int rsnd_adg_probe(struct platform_device *pdev,
                return -ENOMEM;
        }
 
-       adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
-       adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
-       adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
-       adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
+       clk_orig        = devm_clk_get(dev, NULL);
+       adg->clk[CLKA]  = devm_clk_get(dev, "clk_a");
+       adg->clk[CLKB]  = devm_clk_get(dev, "clk_b");
+       adg->clk[CLKC]  = devm_clk_get(dev, "clk_c");
+       adg->clk[CLKI]  = devm_clk_get(dev, "clk_i");
+
+       /*
+        * It request device dependent audio clock.
+        * But above all clks will indicate rsnd module clock
+        * if platform doesn't it
+        */
+       for_each_rsnd_clk(clk, adg, i) {
+               if (clk_orig == clk) {
+                       dev_warn(dev,
+                                "doesn't have device dependent clock, use independent clock\n");
+                       use_old_style = true;
+                       break;
+               }
+       }
+
+       /*
+        * note:
+        * these exist in order to keep compatible with
+        * platform which has device independent audio clock,
+        * but will be removed soon
+        */
+       if (use_old_style) {
+               adg->clk[CLKA] = devm_clk_get(NULL, "audio_clk_a");
+               adg->clk[CLKB] = devm_clk_get(NULL, "audio_clk_b");
+               adg->clk[CLKC] = devm_clk_get(NULL, "audio_clk_c");
+               adg->clk[CLKI] = devm_clk_get(NULL, "audio_clk_internal");
+       }
+
        for_each_rsnd_clk(clk, adg, i) {
                if (IS_ERR(clk)) {
                        dev_err(dev, "Audio clock failed\n");
@@ -287,14 +455,3 @@ int rsnd_adg_probe(struct platform_device *pdev,
 
        return 0;
 }
-
-void rsnd_adg_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg = priv->adg;
-       struct clk *clk;
-       int i;
-
-       for_each_rsnd_clk(clk, adg, i)
-               clk_put(clk);
-}
index 743de5e3b1e1ed4cba8f5dcfce3a5d3cfd9471bf..215b668166be6c50d01963cac2ef62598cf6f7b2 100644 (file)
  *   |  +- ssi[2]
  *   |  ...
  *   |
- *   | ** these control scu
+ *   | ** these control src
  *   |
- *   +- scu
+ *   +- src
  *      |
- *      +- scu[0]
- *      +- scu[1]
- *      +- scu[2]
+ *      +- src[0]
+ *      +- src[1]
+ *      +- src[2]
  *      ...
  *
  *
 #define RSND_RATES SNDRV_PCM_RATE_8000_96000
 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
+static struct rsnd_of_data rsnd_of_data_gen1 = {
+       .flags = RSND_GEN1,
+};
+
+static struct rsnd_of_data rsnd_of_data_gen2 = {
+       .flags = RSND_GEN2,
+};
+
+static struct of_device_id rsnd_of_match[] = {
+       { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
+       { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rsnd_of_match);
+
 /*
  *     rsnd_platform functions
  */
        (!(priv->info->func) ? 0 :              \
         priv->info->func(param))
 
+#define rsnd_is_enable_path(io, name) \
+       ((io)->info ? (io)->info->name : NULL)
+#define rsnd_info_id(priv, io, name) \
+       ((io)->info->name - priv->info->name##_info)
+
 /*
  *     rsnd_mod functions
  */
@@ -121,17 +141,19 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
 void rsnd_mod_init(struct rsnd_priv *priv,
                   struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
+                  enum rsnd_mod_type type,
                   int id)
 {
        mod->priv       = priv;
        mod->id         = id;
        mod->ops        = ops;
-       INIT_LIST_HEAD(&mod->list);
+       mod->type       = type;
 }
 
 /*
  *     rsnd_dma functions
  */
+static void __rsnd_dma_start(struct rsnd_dma *dma);
 static void rsnd_dma_continue(struct rsnd_dma *dma)
 {
        /* push next A or B plane */
@@ -142,8 +164,9 @@ static void rsnd_dma_continue(struct rsnd_dma *dma)
 void rsnd_dma_start(struct rsnd_dma *dma)
 {
        /* push both A and B plane*/
+       dma->offset = 0;
        dma->submit_loop = 2;
-       schedule_work(&dma->work);
+       __rsnd_dma_start(dma);
 }
 
 void rsnd_dma_stop(struct rsnd_dma *dma)
@@ -156,12 +179,26 @@ void rsnd_dma_stop(struct rsnd_dma *dma)
 static void rsnd_dma_complete(void *data)
 {
        struct rsnd_dma *dma = (struct rsnd_dma *)data;
-       struct rsnd_priv *priv = dma->priv;
+       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma));
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        unsigned long flags;
 
        rsnd_lock(priv, flags);
 
-       dma->complete(dma);
+       /*
+        * Renesas sound Gen1 needs 1 DMAC,
+        * Gen2 needs 2 DMAC.
+        * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
+        * But, Audio-DMAC-peri-peri doesn't have interrupt,
+        * and this driver is assuming that here.
+        *
+        * If Audio-DMAC-peri-peri has interrpt,
+        * rsnd_dai_pointer_update() will be called twice,
+        * ant it will breaks io->byte_pos
+        */
+
+       rsnd_dai_pointer_update(io, io->byte_per_period);
 
        if (dma->submit_loop)
                rsnd_dma_continue(dma);
@@ -169,20 +206,23 @@ static void rsnd_dma_complete(void *data)
        rsnd_unlock(priv, flags);
 }
 
-static void rsnd_dma_do_work(struct work_struct *work)
+static void __rsnd_dma_start(struct rsnd_dma *dma)
 {
-       struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
-       struct rsnd_priv *priv = dma->priv;
+       struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_async_tx_descriptor *desc;
        dma_addr_t buf;
-       size_t len;
+       size_t len = io->byte_per_period;
        int i;
 
        for (i = 0; i < dma->submit_loop; i++) {
 
-               if (dma->inquiry(dma, &buf, &len) < 0)
-                       return;
+               buf = runtime->dma_addr +
+                       rsnd_dai_pointer_offset(io, dma->offset + len);
+               dma->offset = len;
 
                desc = dmaengine_prep_slave_single(
                        dma->chan, buf, len, dma->dir,
@@ -204,16 +244,20 @@ static void rsnd_dma_do_work(struct work_struct *work)
        }
 }
 
+static void rsnd_dma_do_work(struct work_struct *work)
+{
+       struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
+
+       __rsnd_dma_start(dma);
+}
+
 int rsnd_dma_available(struct rsnd_dma *dma)
 {
        return !!dma->chan;
 }
 
 int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
-                 int is_play, int id,
-                 int (*inquiry)(struct rsnd_dma *dma,
-                                 dma_addr_t *buf, int *len),
-                 int (*complete)(struct rsnd_dma *dma))
+                 int is_play, int id)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_slave_config cfg;
@@ -246,9 +290,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
                goto rsnd_dma_init_err;
 
        dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-       dma->priv = priv;
-       dma->inquiry = inquiry;
-       dma->complete = complete;
        INIT_WORK(&dma->work, rsnd_dma_do_work);
 
        return 0;
@@ -271,26 +312,42 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,
 /*
  *     rsnd_dai functions
  */
-#define rsnd_dai_call(rdai, io, fn)                    \
-({                                                     \
-       struct rsnd_mod *mod, *n;                       \
-       int ret = 0;                                    \
-       for_each_rsnd_mod(mod, n, io) {                 \
-               ret = rsnd_mod_call(mod, fn, rdai, io); \
-               if (ret < 0)                            \
-                       break;                          \
-       }                                               \
-       ret;                                            \
+#define __rsnd_mod_call(mod, func, rdai, io)                   \
+({                                                             \
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
+       struct device *dev = rsnd_priv_to_dev(priv);            \
+       dev_dbg(dev, "%s [%d] %s\n",                            \
+               rsnd_mod_name(mod), rsnd_mod_id(mod), #func);   \
+       (mod)->ops->func(mod, rdai, io);                        \
+})
+
+#define rsnd_mod_call(mod, func, rdai, io)     \
+       (!(mod) ? -ENODEV :                     \
+        !((mod)->ops->func) ? 0 :              \
+        __rsnd_mod_call(mod, func, (rdai), (io)))
+
+#define rsnd_dai_call(rdai, io, fn)                            \
+({                                                             \
+       struct rsnd_mod *mod;                                   \
+       int ret = 0, i;                                         \
+       for (i = 0; i < RSND_MOD_MAX; i++) {                    \
+               mod = (io)->mod[i];                             \
+               if (!mod)                                       \
+                       continue;                               \
+               ret = rsnd_mod_call(mod, fn, (rdai), (io));     \
+               if (ret < 0)                                    \
+                       break;                                  \
+       }                                                       \
+       ret;                                                    \
 })
 
-int rsnd_dai_connect(struct rsnd_dai *rdai,
-                    struct rsnd_mod *mod,
-                    struct rsnd_dai_stream *io)
+static int rsnd_dai_connect(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io)
 {
        if (!mod)
                return -EIO;
 
-       if (!list_empty(&mod->list)) {
+       if (io->mod[mod->type]) {
                struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
                struct device *dev = rsnd_priv_to_dev(priv);
 
@@ -300,14 +357,8 @@ int rsnd_dai_connect(struct rsnd_dai *rdai,
                return -EIO;
        }
 
-       list_add_tail(&mod->list, &io->head);
-
-       return 0;
-}
-
-int rsnd_dai_disconnect(struct rsnd_mod *mod)
-{
-       list_del_init(&mod->list);
+       io->mod[mod->type] = mod;
+       mod->io = io;
 
        return 0;
 }
@@ -316,7 +367,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
 {
        int id = rdai - priv->rdai;
 
-       if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
                return -EINVAL;
 
        return id;
@@ -324,7 +375,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
 
 struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
 {
-       if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
                return NULL;
 
        return priv->rdai + id;
@@ -382,10 +433,6 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       if (!list_empty(&io->head))
-               return -EIO;
-
-       INIT_LIST_HEAD(&io->head);
        io->substream           = substream;
        io->byte_pos            = 0;
        io->period_pos          = 0;
@@ -440,10 +487,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_gen_path_init(priv, rdai, io);
-               if (ret < 0)
-                       goto dai_trigger_end;
-
                ret = rsnd_dai_call(rdai, io, init);
                if (ret < 0)
                        goto dai_trigger_end;
@@ -461,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_gen_path_exit(priv, rdai, io);
-               if (ret < 0)
-                       goto dai_trigger_end;
-
                ret = rsnd_platform_call(priv, dai, stop, ssi_id);
                if (ret < 0)
                        goto dai_trigger_end;
@@ -486,10 +525,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               rdai->clk_master = 1;
+               rdai->clk_master = 0;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
-               rdai->clk_master = 0;
+               rdai->clk_master = 1; /* codec is slave, cpu is master */
                break;
        default:
                return -EINVAL;
@@ -540,24 +579,174 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        .set_fmt        = rsnd_soc_dai_set_fmt,
 };
 
+static int rsnd_path_init(struct rsnd_priv *priv,
+                         struct rsnd_dai *rdai,
+                         struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod;
+       struct rsnd_dai_platform_info *dai_info = rdai->info;
+       int ret;
+       int ssi_id = -1;
+       int src_id = -1;
+
+       /*
+        * Gen1 is created by SRU/SSI, and this SRU is base module of
+        * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
+        *
+        * Easy image is..
+        *      Gen1 SRU = Gen2 SCU + SSIU + etc
+        *
+        * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
+        * using fixed path.
+        */
+       if (dai_info) {
+               if (rsnd_is_enable_path(io, ssi))
+                       ssi_id = rsnd_info_id(priv, io, ssi);
+               if (rsnd_is_enable_path(io, src))
+                       src_id = rsnd_info_id(priv, io, src);
+       } else {
+               /* get SSI's ID */
+               mod = rsnd_ssi_mod_get_frm_dai(priv,
+                                              rsnd_dai_id(priv, rdai),
+                                              rsnd_dai_is_play(rdai, io));
+               if (!mod)
+                       return 0;
+               ssi_id = src_id = rsnd_mod_id(mod);
+       }
+
+       ret = 0;
+
+       /* SRC */
+       if (src_id >= 0) {
+               mod = rsnd_src_mod_get(priv, src_id);
+               ret = rsnd_dai_connect(mod, io);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* SSI */
+       if (ssi_id >= 0) {
+               mod = rsnd_ssi_mod_get(priv, ssi_id);
+               ret = rsnd_dai_connect(mod, io);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static void rsnd_of_parse_dai(struct platform_device *pdev,
+                             const struct rsnd_of_data *of_data,
+                             struct rsnd_priv *priv)
+{
+       struct device_node *dai_node,   *dai_np;
+       struct device_node *ssi_node,   *ssi_np;
+       struct device_node *src_node,   *src_np;
+       struct device_node *playback, *capture;
+       struct rsnd_dai_platform_info *dai_info;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = &pdev->dev;
+       int nr, i;
+       int dai_i, ssi_i, src_i;
+
+       if (!of_data)
+               return;
+
+       dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
+       if (!dai_node)
+               return;
+
+       nr = of_get_child_count(dai_node);
+       if (!nr)
+               return;
+
+       dai_info = devm_kzalloc(dev,
+                               sizeof(struct rsnd_dai_platform_info) * nr,
+                               GFP_KERNEL);
+       if (!dai_info) {
+               dev_err(dev, "dai info allocation error\n");
+               return;
+       }
+
+       info->dai_info_nr       = nr;
+       info->dai_info          = dai_info;
+
+       ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+       src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+
+#define mod_parse(name)                                                        \
+if (name##_node) {                                                     \
+       struct rsnd_##name##_platform_info *name##_info;                \
+                                                                       \
+       name##_i = 0;                                                   \
+       for_each_child_of_node(name##_node, name##_np) {                \
+               name##_info = info->name##_info + name##_i;             \
+                                                                       \
+               if (name##_np == playback)                              \
+                       dai_info->playback.name = name##_info;          \
+               if (name##_np == capture)                               \
+                       dai_info->capture.name = name##_info;           \
+                                                                       \
+               name##_i++;                                             \
+       }                                                               \
+}
+
+       /*
+        * parse all dai
+        */
+       dai_i = 0;
+       for_each_child_of_node(dai_node, dai_np) {
+               dai_info = info->dai_info + dai_i;
+
+               for (i = 0;; i++) {
+
+                       playback = of_parse_phandle(dai_np, "playback", i);
+                       capture  = of_parse_phandle(dai_np, "capture", i);
+
+                       if (!playback && !capture)
+                               break;
+
+                       mod_parse(ssi);
+                       mod_parse(src);
+
+                       if (playback)
+                               of_node_put(playback);
+                       if (capture)
+                               of_node_put(capture);
+               }
+
+               dai_i++;
+       }
+}
+
 static int rsnd_dai_probe(struct platform_device *pdev,
-                         struct rcar_snd_info *info,
+                         const struct rsnd_of_data *of_data,
                          struct rsnd_priv *priv)
 {
        struct snd_soc_dai_driver *drv;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct rsnd_dai *rdai;
        struct rsnd_mod *pmod, *cmod;
        struct device *dev = rsnd_priv_to_dev(priv);
        int dai_nr;
        int i;
 
-       /* get max dai nr */
-       for (dai_nr = 0; dai_nr < 32; dai_nr++) {
-               pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
-               cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
+       rsnd_of_parse_dai(pdev, of_data, priv);
 
-               if (!pmod && !cmod)
-                       break;
+       /*
+        * dai_nr should be set via dai_info_nr,
+        * but allow it to keeping compatible
+        */
+       dai_nr = info->dai_info_nr;
+       if (!dai_nr) {
+               /* get max dai nr */
+               for (dai_nr = 0; dai_nr < 32; dai_nr++) {
+                       pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
+                       cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
+
+                       if (!pmod && !cmod)
+                               break;
+               }
        }
 
        if (!dai_nr) {
@@ -572,7 +761,13 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       priv->rdai_nr   = dai_nr;
+       priv->daidrv    = drv;
+       priv->rdai      = rdai;
+
        for (i = 0; i < dai_nr; i++) {
+               if (info->dai_info)
+                       rdai[i].info = &info->dai_info[i];
 
                pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
                cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
@@ -580,9 +775,6 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                /*
                 *      init rsnd_dai
                 */
-               INIT_LIST_HEAD(&rdai[i].playback.head);
-               INIT_LIST_HEAD(&rdai[i].capture.head);
-
                snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
 
                /*
@@ -595,12 +787,20 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].playback.formats         = RSND_FMTS;
                        drv[i].playback.channels_min    = 2;
                        drv[i].playback.channels_max    = 2;
+
+                       if (info->dai_info)
+                               rdai[i].playback.info = &info->dai_info[i].playback;
+                       rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
                }
                if (cmod) {
                        drv[i].capture.rates            = RSND_RATES;
                        drv[i].capture.formats          = RSND_FMTS;
                        drv[i].capture.channels_min     = 2;
                        drv[i].capture.channels_max     = 2;
+
+                       if (info->dai_info)
+                               rdai[i].capture.info = &info->dai_info[i].capture;
+                       rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
                }
 
                dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
@@ -608,18 +808,9 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        cmod ? "capture" : "  --   ");
        }
 
-       priv->dai_nr    = dai_nr;
-       priv->daidrv    = drv;
-       priv->rdai      = rdai;
-
        return 0;
 }
 
-static void rsnd_dai_remove(struct platform_device *pdev,
-                         struct rsnd_priv *priv)
-{
-}
-
 /*
  *             pcm ops
  */
@@ -713,9 +904,30 @@ static int rsnd_probe(struct platform_device *pdev)
        struct rcar_snd_info *info;
        struct rsnd_priv *priv;
        struct device *dev = &pdev->dev;
-       int ret;
+       struct rsnd_dai *rdai;
+       const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
+       const struct rsnd_of_data *of_data;
+       int (*probe_func[])(struct platform_device *pdev,
+                           const struct rsnd_of_data *of_data,
+                           struct rsnd_priv *priv) = {
+               rsnd_gen_probe,
+               rsnd_ssi_probe,
+               rsnd_src_probe,
+               rsnd_adg_probe,
+               rsnd_dai_probe,
+       };
+       int ret, i;
+
+       info = NULL;
+       of_data = NULL;
+       if (of_id) {
+               info = devm_kzalloc(&pdev->dev,
+                                   sizeof(struct rcar_snd_info), GFP_KERNEL);
+               of_data = of_id->data;
+       } else {
+               info = pdev->dev.platform_data;
+       }
 
-       info = pdev->dev.platform_data;
        if (!info) {
                dev_err(dev, "driver needs R-Car sound information\n");
                return -ENODEV;
@@ -737,25 +949,21 @@ static int rsnd_probe(struct platform_device *pdev)
        /*
         *      init each module
         */
-       ret = rsnd_gen_probe(pdev, info, priv);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_scu_probe(pdev, info, priv);
-       if (ret < 0)
-               return ret;
+       for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
+               ret = probe_func[i](pdev, of_data, priv);
+               if (ret)
+                       return ret;
+       }
 
-       ret = rsnd_adg_probe(pdev, info, priv);
-       if (ret < 0)
-               return ret;
+       for_each_rsnd_dai(rdai, priv, i) {
+               ret = rsnd_dai_call(rdai, &rdai->playback, probe);
+               if (ret)
+                       return ret;
 
-       ret = rsnd_ssi_probe(pdev, info, priv);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_dai_probe(pdev, info, priv);
-       if (ret < 0)
-               return ret;
+               ret = rsnd_dai_call(rdai, &rdai->capture, probe);
+               if (ret)
+                       return ret;
+       }
 
        /*
         *      asoc register
@@ -767,7 +975,7 @@ static int rsnd_probe(struct platform_device *pdev)
        }
 
        ret = snd_soc_register_component(dev, &rsnd_soc_component,
-                                        priv->daidrv, rsnd_dai_nr(priv));
+                                        priv->daidrv, rsnd_rdai_nr(priv));
        if (ret < 0) {
                dev_err(dev, "cannot snd dai register\n");
                goto exit_snd_soc;
@@ -789,17 +997,20 @@ exit_snd_soc:
 static int rsnd_remove(struct platform_device *pdev)
 {
        struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
+       struct rsnd_dai *rdai;
+       int ret, i;
 
        pm_runtime_disable(&pdev->dev);
 
-       /*
-        *      remove each module
-        */
-       rsnd_ssi_remove(pdev, priv);
-       rsnd_adg_remove(pdev, priv);
-       rsnd_scu_remove(pdev, priv);
-       rsnd_dai_remove(pdev, priv);
-       rsnd_gen_remove(pdev, priv);
+       for_each_rsnd_dai(rdai, priv, i) {
+               ret = rsnd_dai_call(rdai, &rdai->playback, remove);
+               if (ret)
+                       return ret;
+
+               ret = rsnd_dai_call(rdai, &rdai->capture, remove);
+               if (ret)
+                       return ret;
+       }
 
        return 0;
 }
@@ -807,6 +1018,7 @@ static int rsnd_remove(struct platform_device *pdev)
 static struct platform_driver rsnd_driver = {
        .driver = {
                .name   = "rcar_sound",
+               .of_match_table = rsnd_of_match,
        },
        .probe          = rsnd_probe,
        .remove         = rsnd_remove,
index add088bd4b2aa7163b98f5faab7bd84b52a77fff..50a1ef3eb1c6e243e7c749824c23acbd447fb9e5 100644 (file)
@@ -155,62 +155,6 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
        return 0;
 }
 
-int rsnd_gen_path_init(struct rsnd_priv *priv,
-                      struct rsnd_dai *rdai,
-                      struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *mod;
-       int ret;
-       int id;
-
-       /*
-        * Gen1 is created by SRU/SSI, and this SRU is base module of
-        * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
-        *
-        * Easy image is..
-        *      Gen1 SRU = Gen2 SCU + SSIU + etc
-        *
-        * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
-        * using fixed path.
-        *
-        * Then, SSI id = SCU id here
-        */
-
-       /* get SSI's ID */
-       mod = rsnd_ssi_mod_get_frm_dai(priv,
-                                      rsnd_dai_id(priv, rdai),
-                                      rsnd_dai_is_play(rdai, io));
-       id = rsnd_mod_id(mod);
-
-       /* SSI */
-       mod = rsnd_ssi_mod_get(priv, id);
-       ret = rsnd_dai_connect(rdai, mod, io);
-       if (ret < 0)
-               return ret;
-
-       /* SCU */
-       mod = rsnd_scu_mod_get(priv, id);
-       ret = rsnd_dai_connect(rdai, mod, io);
-
-       return ret;
-}
-
-int rsnd_gen_path_exit(struct rsnd_priv *priv,
-                      struct rsnd_dai *rdai,
-                      struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *mod, *n;
-       int ret = 0;
-
-       /*
-        * remove all mod from rdai
-        */
-       for_each_rsnd_mod(mod, n, io)
-               ret |= rsnd_dai_disconnect(mod);
-
-       return ret;
-}
-
 /*
  *             Gen2
  */
@@ -229,14 +173,40 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
                RSND_GEN2_S_REG(gen, SSIU,      SSI_MODE0,      0x800),
                RSND_GEN2_S_REG(gen, SSIU,      SSI_MODE1,      0x804),
                /* FIXME: it needs SSI_MODE2/3 in the future */
+               RSND_GEN2_M_REG(gen, SSIU,      SSI_BUSIF_MODE, 0x0,    0x80),
+               RSND_GEN2_M_REG(gen, SSIU,      SSI_BUSIF_ADINR,0x4,    0x80),
+               RSND_GEN2_M_REG(gen, SSIU,      SSI_CTRL,       0x10,   0x80),
                RSND_GEN2_M_REG(gen, SSIU,      INT_ENABLE,     0x18,   0x80),
 
+               RSND_GEN2_M_REG(gen, SCU,       SRC_BUSIF_MODE, 0x0,    0x20),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_ROUTE_MODE0,0xc,    0x20),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_CTRL,       0x10,   0x20),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_SWRSR,      0x200,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_SRCIR,      0x204,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_ADINR,      0x214,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_IFSCR,      0x21c,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_IFSVR,      0x220,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_SRCCR,      0x224,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_BSDSR,      0x22c,  0x40),
+               RSND_GEN2_M_REG(gen, SCU,       SRC_BSISR,      0x238,  0x40),
+
                RSND_GEN2_S_REG(gen, ADG,       BRRA,           0x00),
                RSND_GEN2_S_REG(gen, ADG,       BRRB,           0x04),
                RSND_GEN2_S_REG(gen, ADG,       SSICKR,         0x08),
                RSND_GEN2_S_REG(gen, ADG,       AUDIO_CLK_SEL0, 0x0c),
                RSND_GEN2_S_REG(gen, ADG,       AUDIO_CLK_SEL1, 0x10),
                RSND_GEN2_S_REG(gen, ADG,       AUDIO_CLK_SEL2, 0x14),
+               RSND_GEN2_S_REG(gen, ADG,       DIV_EN,         0x30),
+               RSND_GEN2_S_REG(gen, ADG,       SRCIN_TIMSEL0,  0x34),
+               RSND_GEN2_S_REG(gen, ADG,       SRCIN_TIMSEL1,  0x38),
+               RSND_GEN2_S_REG(gen, ADG,       SRCIN_TIMSEL2,  0x3c),
+               RSND_GEN2_S_REG(gen, ADG,       SRCIN_TIMSEL3,  0x40),
+               RSND_GEN2_S_REG(gen, ADG,       SRCIN_TIMSEL4,  0x44),
+               RSND_GEN2_S_REG(gen, ADG,       SRCOUT_TIMSEL0, 0x48),
+               RSND_GEN2_S_REG(gen, ADG,       SRCOUT_TIMSEL1, 0x4c),
+               RSND_GEN2_S_REG(gen, ADG,       SRCOUT_TIMSEL2, 0x50),
+               RSND_GEN2_S_REG(gen, ADG,       SRCOUT_TIMSEL3, 0x54),
+               RSND_GEN2_S_REG(gen, ADG,       SRCOUT_TIMSEL4, 0x58),
 
                RSND_GEN2_M_REG(gen, SSI,       SSICR,          0x00,   0x40),
                RSND_GEN2_M_REG(gen, SSI,       SSISR,          0x04,   0x40),
@@ -249,7 +219,6 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
 }
 
 static int rsnd_gen2_probe(struct platform_device *pdev,
-                          struct rcar_snd_info *info,
                           struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -283,7 +252,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                return ret;
 
        dev_dbg(dev, "Gen2 device probed\n");
-       dev_dbg(dev, "SRU  : %08x => %p\n", scu_res->start,
+       dev_dbg(dev, "SCU  : %08x => %p\n", scu_res->start,
                gen->base[RSND_GEN2_SCU]);
        dev_dbg(dev, "ADG  : %08x => %p\n", adg_res->start,
                gen->base[RSND_GEN2_ADG]);
@@ -317,7 +286,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
                RSND_GEN1_S_REG(gen, SRU,       SRC_ROUTE_CTRL, 0xc0),
                RSND_GEN1_S_REG(gen, SRU,       SSI_MODE0,      0xD0),
                RSND_GEN1_S_REG(gen, SRU,       SSI_MODE1,      0xD4),
-               RSND_GEN1_M_REG(gen, SRU,       BUSIF_MODE,     0x20,   0x4),
+               RSND_GEN1_M_REG(gen, SRU,       SRC_BUSIF_MODE, 0x20,   0x4),
                RSND_GEN1_M_REG(gen, SRU,       SRC_ROUTE_MODE0,0x50,   0x8),
                RSND_GEN1_M_REG(gen, SRU,       SRC_SWRSR,      0x200,  0x40),
                RSND_GEN1_M_REG(gen, SRU,       SRC_SRCIR,      0x204,  0x40),
@@ -347,7 +316,6 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
 }
 
 static int rsnd_gen1_probe(struct platform_device *pdev,
-                          struct rcar_snd_info *info,
                           struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -391,14 +359,28 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
 /*
  *             Gen
  */
+static void rsnd_of_parse_gen(struct platform_device *pdev,
+                             const struct rsnd_of_data *of_data,
+                             struct rsnd_priv *priv)
+{
+       struct rcar_snd_info *info = priv->info;
+
+       if (!of_data)
+               return;
+
+       info->flags = of_data->flags;
+}
+
 int rsnd_gen_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_gen *gen;
        int ret;
 
+       rsnd_of_parse_gen(pdev, of_data, priv);
+
        gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
        if (!gen) {
                dev_err(dev, "GEN allocate failed\n");
@@ -409,17 +391,12 @@ int rsnd_gen_probe(struct platform_device *pdev,
 
        ret = -ENODEV;
        if (rsnd_is_gen1(priv))
-               ret = rsnd_gen1_probe(pdev, info, priv);
+               ret = rsnd_gen1_probe(pdev, priv);
        else if (rsnd_is_gen2(priv))
-               ret = rsnd_gen2_probe(pdev, info, priv);
+               ret = rsnd_gen2_probe(pdev, priv);
 
        if (ret < 0)
                dev_err(dev, "unknown generation R-Car sound device\n");
 
        return ret;
 }
-
-void rsnd_gen_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
-{
-}
index 4ca66cd899c87415e263219c400fea5ce4e51df0..619d198c7d2e821355bdd7cd1d1d15210ae1f219 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/sh_dma.h>
 #include <linux/workqueue.h>
 #include <sound/rcar_snd.h>
  */
 enum rsnd_reg {
        /* SRU/SCU/SSIU */
-       RSND_REG_SRC_ROUTE_SEL,         /* for Gen1 */
-       RSND_REG_SRC_TMG_SEL0,          /* for Gen1 */
-       RSND_REG_SRC_TMG_SEL1,          /* for Gen1 */
-       RSND_REG_SRC_TMG_SEL2,          /* for Gen1 */
-       RSND_REG_SRC_ROUTE_CTRL,        /* for Gen1 */
        RSND_REG_SSI_MODE0,
        RSND_REG_SSI_MODE1,
-       RSND_REG_BUSIF_MODE,
-       RSND_REG_INT_ENABLE,            /* for Gen2 */
+       RSND_REG_SRC_BUSIF_MODE,
        RSND_REG_SRC_ROUTE_MODE0,
        RSND_REG_SRC_SWRSR,
        RSND_REG_SRC_SRCIR,
@@ -48,7 +44,6 @@ enum rsnd_reg {
        RSND_REG_SRC_IFSCR,
        RSND_REG_SRC_IFSVR,
        RSND_REG_SRC_SRCCR,
-       RSND_REG_SRC_MNFSR,
 
        /* ADG */
        RSND_REG_BRRA,
@@ -56,10 +51,6 @@ enum rsnd_reg {
        RSND_REG_SSICKR,
        RSND_REG_AUDIO_CLK_SEL0,
        RSND_REG_AUDIO_CLK_SEL1,
-       RSND_REG_AUDIO_CLK_SEL2,
-       RSND_REG_AUDIO_CLK_SEL3,        /* for Gen1 */
-       RSND_REG_AUDIO_CLK_SEL4,        /* for Gen1 */
-       RSND_REG_AUDIO_CLK_SEL5,        /* for Gen1 */
 
        /* SSI */
        RSND_REG_SSICR,
@@ -68,9 +59,63 @@ enum rsnd_reg {
        RSND_REG_SSIRDR,
        RSND_REG_SSIWSR,
 
+       /* SHARE see below */
+       RSND_REG_SHARE01,
+       RSND_REG_SHARE02,
+       RSND_REG_SHARE03,
+       RSND_REG_SHARE04,
+       RSND_REG_SHARE05,
+       RSND_REG_SHARE06,
+       RSND_REG_SHARE07,
+       RSND_REG_SHARE08,
+       RSND_REG_SHARE09,
+       RSND_REG_SHARE10,
+       RSND_REG_SHARE11,
+       RSND_REG_SHARE12,
+       RSND_REG_SHARE13,
+       RSND_REG_SHARE14,
+       RSND_REG_SHARE15,
+       RSND_REG_SHARE16,
+       RSND_REG_SHARE17,
+       RSND_REG_SHARE18,
+       RSND_REG_SHARE19,
+
        RSND_REG_MAX,
 };
 
+/* Gen1 only */
+#define RSND_REG_SRC_ROUTE_SEL         RSND_REG_SHARE01
+#define RSND_REG_SRC_TMG_SEL0          RSND_REG_SHARE02
+#define RSND_REG_SRC_TMG_SEL1          RSND_REG_SHARE03
+#define RSND_REG_SRC_TMG_SEL2          RSND_REG_SHARE04
+#define RSND_REG_SRC_ROUTE_CTRL                RSND_REG_SHARE05
+#define RSND_REG_SRC_MNFSR             RSND_REG_SHARE06
+#define RSND_REG_AUDIO_CLK_SEL3                RSND_REG_SHARE07
+#define RSND_REG_AUDIO_CLK_SEL4                RSND_REG_SHARE08
+#define RSND_REG_AUDIO_CLK_SEL5                RSND_REG_SHARE09
+
+/* Gen2 only */
+#define RSND_REG_SRC_CTRL              RSND_REG_SHARE01
+#define RSND_REG_SSI_CTRL              RSND_REG_SHARE02
+#define RSND_REG_SSI_BUSIF_MODE                RSND_REG_SHARE03
+#define RSND_REG_SSI_BUSIF_ADINR       RSND_REG_SHARE04
+#define RSND_REG_INT_ENABLE            RSND_REG_SHARE05
+#define RSND_REG_SRC_BSDSR             RSND_REG_SHARE06
+#define RSND_REG_SRC_BSISR             RSND_REG_SHARE07
+#define RSND_REG_DIV_EN                        RSND_REG_SHARE08
+#define RSND_REG_SRCIN_TIMSEL0         RSND_REG_SHARE09
+#define RSND_REG_SRCIN_TIMSEL1         RSND_REG_SHARE10
+#define RSND_REG_SRCIN_TIMSEL2         RSND_REG_SHARE11
+#define RSND_REG_SRCIN_TIMSEL3         RSND_REG_SHARE12
+#define RSND_REG_SRCIN_TIMSEL4         RSND_REG_SHARE13
+#define RSND_REG_SRCOUT_TIMSEL0                RSND_REG_SHARE14
+#define RSND_REG_SRCOUT_TIMSEL1                RSND_REG_SHARE15
+#define RSND_REG_SRCOUT_TIMSEL2                RSND_REG_SHARE16
+#define RSND_REG_SRCOUT_TIMSEL3                RSND_REG_SHARE17
+#define RSND_REG_SRCOUT_TIMSEL4                RSND_REG_SHARE18
+#define RSND_REG_AUDIO_CLK_SEL2                RSND_REG_SHARE19
+
+struct rsnd_of_data;
 struct rsnd_priv;
 struct rsnd_mod;
 struct rsnd_dai;
@@ -96,24 +141,20 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
  *     R-Car DMA
  */
 struct rsnd_dma {
-       struct rsnd_priv        *priv;
        struct sh_dmae_slave    slave;
        struct work_struct      work;
        struct dma_chan         *chan;
        enum dma_data_direction dir;
-       int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len);
-       int (*complete)(struct rsnd_dma *dma);
 
        int submit_loop;
+       int offset; /* it cares A/B plane */
 };
 
 void rsnd_dma_start(struct rsnd_dma *dma);
 void rsnd_dma_stop(struct rsnd_dma *dma);
 int rsnd_dma_available(struct rsnd_dma *dma);
 int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
-       int is_play, int id,
-       int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len),
-       int (*complete)(struct rsnd_dma *dma));
+       int is_play, int id);
 void  rsnd_dma_quit(struct rsnd_priv *priv,
                    struct rsnd_dma *dma);
 
@@ -121,9 +162,20 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,
 /*
  *     R-Car sound mod
  */
+enum rsnd_mod_type {
+       RSND_MOD_SRC = 0,
+       RSND_MOD_SSI,
+       RSND_MOD_MAX,
+};
 
 struct rsnd_mod_ops {
        char *name;
+       int (*probe)(struct rsnd_mod *mod,
+                    struct rsnd_dai *rdai,
+                    struct rsnd_dai_stream *io);
+       int (*remove)(struct rsnd_mod *mod,
+                     struct rsnd_dai *rdai,
+                     struct rsnd_dai_stream *io);
        int (*init)(struct rsnd_mod *mod,
                    struct rsnd_dai *rdai,
                    struct rsnd_dai_stream *io);
@@ -138,28 +190,26 @@ struct rsnd_mod_ops {
                    struct rsnd_dai_stream *io);
 };
 
+struct rsnd_dai_stream;
 struct rsnd_mod {
        int id;
+       enum rsnd_mod_type type;
        struct rsnd_priv *priv;
        struct rsnd_mod_ops *ops;
-       struct list_head list; /* connect to rsnd_dai playback/capture */
        struct rsnd_dma dma;
+       struct rsnd_dai_stream *io;
 };
 
 #define rsnd_mod_to_priv(mod) ((mod)->priv)
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
 #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
+#define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
-#define for_each_rsnd_mod(pos, n, io)  \
-       list_for_each_entry_safe(pos, n, &(io)->head, list)
-#define rsnd_mod_call(mod, func, rdai, io)     \
-       (!(mod) ? -ENODEV :                     \
-        !((mod)->ops->func) ? 0 :              \
-        (mod)->ops->func(mod, rdai, io))
 
 void rsnd_mod_init(struct rsnd_priv *priv,
                   struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
+                  enum rsnd_mod_type type,
                   int id);
 char *rsnd_mod_name(struct rsnd_mod *mod);
 
@@ -168,13 +218,16 @@ char *rsnd_mod_name(struct rsnd_mod *mod);
  */
 #define RSND_DAI_NAME_SIZE     16
 struct rsnd_dai_stream {
-       struct list_head head; /* head of rsnd_mod list */
        struct snd_pcm_substream *substream;
+       struct rsnd_mod *mod[RSND_MOD_MAX];
+       struct rsnd_dai_path_info *info; /* rcar_snd.h */
        int byte_pos;
        int period_pos;
        int byte_per_period;
        int next_period_byte;
 };
+#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
+#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
 
 struct rsnd_dai {
        char name[RSND_DAI_NAME_SIZE];
@@ -189,16 +242,14 @@ struct rsnd_dai {
        unsigned int data_alignment:1;
 };
 
-#define rsnd_dai_nr(priv) ((priv)->dai_nr)
+#define rsnd_rdai_nr(priv) ((priv)->rdai_nr)
 #define for_each_rsnd_dai(rdai, priv, i)               \
-       for (i = 0, (rdai) = rsnd_dai_get(priv, i);     \
-            i < rsnd_dai_nr(priv);                     \
-            i++, (rdai) = rsnd_dai_get(priv, i))
+       for (i = 0;                                     \
+            (i < rsnd_rdai_nr(priv)) &&                \
+            ((rdai) = rsnd_dai_get(priv, i));          \
+            i++)
 
 struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
-int rsnd_dai_disconnect(struct rsnd_mod *mod);
-int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
-                    struct rsnd_dai_stream *io);
 int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
 int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
 #define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
@@ -206,21 +257,14 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
 
 void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+#define rsnd_dai_is_clk_master(rdai) ((rdai)->clk_master)
 
 /*
  *     R-Car Gen1/Gen2
  */
 int rsnd_gen_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
-void rsnd_gen_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv);
-int rsnd_gen_path_init(struct rsnd_priv *priv,
-                      struct rsnd_dai *rdai,
-                      struct rsnd_dai_stream *io);
-int rsnd_gen_path_exit(struct rsnd_priv *priv,
-                      struct rsnd_dai *rdai,
-                      struct rsnd_dai_stream *io);
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
                               struct rsnd_mod *mod,
                               enum rsnd_reg reg);
@@ -233,18 +277,28 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
 int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
 int rsnd_adg_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
-void rsnd_adg_remove(struct platform_device *pdev,
-                  struct rsnd_priv *priv);
-int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
-                            struct rsnd_mod *mod,
-                            unsigned int src_rate,
-                            unsigned int dst_rate);
+int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
+                                 struct rsnd_mod *mod,
+                                 unsigned int src_rate,
+                                 unsigned int dst_rate);
+int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
+                                 struct rsnd_dai *rdai,
+                                 struct rsnd_dai_stream *io,
+                                 unsigned int src_rate,
+                                 unsigned int dst_rate);
+int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
+                                    struct rsnd_dai *rdai,
+                                    struct rsnd_dai_stream *io);
 
 /*
  *     R-Car sound priv
  */
+struct rsnd_of_data {
+       u32 flags;
+};
+
 struct rsnd_priv {
 
        struct device *dev;
@@ -257,10 +311,10 @@ struct rsnd_priv {
        void *gen;
 
        /*
-        * below value will be filled on rsnd_scu_probe()
+        * below value will be filled on rsnd_src_probe()
         */
-       void *scu;
-       int scu_nr;
+       void *src;
+       int src_nr;
 
        /*
         * below value will be filled on rsnd_adg_probe()
@@ -270,46 +324,64 @@ struct rsnd_priv {
        /*
         * below value will be filled on rsnd_ssi_probe()
         */
-       void *ssiu;
+       void *ssi;
+       int ssi_nr;
 
        /*
         * below value will be filled on rsnd_dai_probe()
         */
        struct snd_soc_dai_driver *daidrv;
        struct rsnd_dai *rdai;
-       int dai_nr;
+       int rdai_nr;
 };
 
 #define rsnd_priv_to_dev(priv) ((priv)->dev)
+#define rsnd_priv_to_info(priv)        ((priv)->info)
 #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
 #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
 
+#define rsnd_info_is_playback(priv, type)                              \
+({                                                                     \
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);           \
+       int i, is_play = 0;                                             \
+       for (i = 0; i < info->dai_info_nr; i++) {                       \
+               if (info->dai_info[i].playback.type == (type)->info) {  \
+                       is_play = 1;                                    \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       is_play;                                                        \
+})
+
 /*
- *     R-Car SCU
+ *     R-Car SRC
  */
-int rsnd_scu_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
+int rsnd_src_probe(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
-void rsnd_scu_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
-bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod);
-unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
-                                  struct rsnd_mod *ssi_mod,
+struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
+unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
+                                  struct rsnd_dai_stream *io,
                                   struct snd_pcm_runtime *runtime);
+int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
+                          struct rsnd_dai *rdai,
+                          struct rsnd_dai_stream *io);
+int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
+                           struct rsnd_dai *rdai,
+                           struct rsnd_dai_stream *io);
 
-#define rsnd_scu_nr(priv) ((priv)->scu_nr)
+#define rsnd_src_nr(priv) ((priv)->src_nr)
 
 /*
  *     R-Car SSI
  */
 int rsnd_ssi_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
-                  struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
                                          int dai_id, int is_play);
+int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
+int rsnd_ssi_is_play(struct rsnd_mod *mod);
 
 #endif
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
deleted file mode 100644 (file)
index 9bb08bb..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Renesas R-Car SCU support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "rsnd.h"
-
-struct rsnd_scu {
-       struct rsnd_scu_platform_info *info; /* rcar_snd.h */
-       struct rsnd_mod mod;
-       struct clk *clk;
-};
-
-#define rsnd_scu_mode_flags(p) ((p)->info->flags)
-#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate)
-
-#define RSND_SCU_NAME_SIZE 16
-
-/*
- * ADINR
- */
-#define OTBL_24                (0 << 16)
-#define OTBL_22                (2 << 16)
-#define OTBL_20                (4 << 16)
-#define OTBL_18                (6 << 16)
-#define OTBL_16                (8 << 16)
-
-/*
- *             image of SRC (Sampling Rate Converter)
- *
- * 96kHz   <-> +-----+ 48kHz   +-----+  48kHz  +-------+
- * 48kHz   <-> | SRC | <------>        | SSI | <-----> | codec |
- * 44.1kHz <-> +-----+         +-----+         +-------+
- * ...
- *
- */
-
-#define rsnd_mod_to_scu(_mod)  \
-       container_of((_mod), struct rsnd_scu, mod)
-
-#define for_each_rsnd_scu(pos, priv, i)                                        \
-       for ((i) = 0;                                                   \
-            ((i) < rsnd_scu_nr(priv)) &&                               \
-                    ((pos) = (struct rsnd_scu *)(priv)->scu + i);      \
-            i++)
-
-/* Gen1 only */
-static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv,
-                             struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai,
-                             struct rsnd_dai_stream *io)
-{
-       struct scu_route_config {
-               u32 mask;
-               int shift;
-       } routes[] = {
-               { 0xF,  0, }, /* 0 */
-               { 0xF,  4, }, /* 1 */
-               { 0xF,  8, }, /* 2 */
-               { 0x7, 12, }, /* 3 */
-               { 0x7, 16, }, /* 4 */
-               { 0x7, 20, }, /* 5 */
-               { 0x7, 24, }, /* 6 */
-               { 0x3, 28, }, /* 7 */
-               { 0x3, 30, }, /* 8 */
-       };
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-       u32 mask;
-       u32 val;
-       int shift;
-       int id;
-
-       /*
-        * Gen1 only
-        */
-       if (!rsnd_is_gen1(priv))
-               return 0;
-
-       id = rsnd_mod_id(mod);
-       if (id < 0 || id >= ARRAY_SIZE(routes))
-               return -EIO;
-
-       /*
-        * SRC_ROUTE_SELECT
-        */
-       val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
-       val = val               << routes[id].shift;
-       mask = routes[id].mask  << routes[id].shift;
-
-       rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
-
-       /*
-        * SRC_TIMING_SELECT
-        */
-       shift   = (id % 4) * 8;
-       mask    = 0x1F << shift;
-
-       /*
-        * ADG is used as source clock if SRC was used,
-        * then, SSI WS is used as destination clock.
-        * SSI WS is used as source clock if SRC is not used
-        * (when playback, source/destination become reverse when capture)
-        */
-       if (rsnd_scu_convert_rate(scu)) /* use ADG */
-               val = 0;
-       else if (8 == id)               /* use SSI WS, but SRU8 is special */
-               val = id << shift;
-       else                            /* use SSI WS */
-               val = (id + 1) << shift;
-
-       switch (id / 4) {
-       case 0:
-               rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
-               break;
-       case 1:
-               rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
-               break;
-       case 2:
-               rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
-               break;
-       }
-
-       return 0;
-}
-
-unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
-                                  struct rsnd_mod *ssi_mod,
-                                  struct snd_pcm_runtime *runtime)
-{
-       struct rsnd_scu *scu;
-       unsigned int rate;
-
-       /* this function is assuming SSI id = SCU id here */
-       scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
-
-       /*
-        * return convert rate if SRC is used,
-        * otherwise, return runtime->rate as usual
-        */
-       rate = rsnd_scu_convert_rate(scu);
-       if (!rate)
-               rate = runtime->rate;
-
-       return rate;
-}
-
-static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv,
-                             struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai,
-                             struct rsnd_dai_stream *io)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-       u32 convert_rate = rsnd_scu_convert_rate(scu);
-       u32 adinr = runtime->channels;
-
-       /* set/clear soft reset */
-       rsnd_mod_write(mod, SRC_SWRSR, 0);
-       rsnd_mod_write(mod, SRC_SWRSR, 1);
-
-       /* Initialize the operation of the SRC internal circuits */
-       rsnd_mod_write(mod, SRC_SRCIR, 1);
-
-       /* Set channel number and output bit length */
-       switch (runtime->sample_bits) {
-       case 16:
-               adinr |= OTBL_16;
-               break;
-       case 32:
-               adinr |= OTBL_24;
-               break;
-       default:
-               return -EIO;
-       }
-       rsnd_mod_write(mod, SRC_ADINR, adinr);
-
-       if (convert_rate) {
-               u32 fsrate = 0x0400000 / convert_rate * runtime->rate;
-               int ret;
-
-               /* Enable the initial value of IFS */
-               rsnd_mod_write(mod, SRC_IFSCR, 1);
-
-               /* Set initial value of IFS */
-               rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-
-               /* Select SRC mode (fixed value) */
-               rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
-
-               /* Set the restriction value of the FS ratio (98%) */
-               rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98);
-
-               if (rsnd_is_gen1(priv)) {
-                       /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
-               }
-
-               /* set convert clock */
-               ret = rsnd_adg_set_convert_clk(priv, mod,
-                                              runtime->rate,
-                                              convert_rate);
-               if (ret < 0)
-                       return ret;
-       }
-
-       /* Cancel the initialization and operate the SRC function */
-       rsnd_mod_write(mod, SRC_SRCIR, 0);
-
-       /* use DMA transfer */
-       rsnd_mod_write(mod, BUSIF_MODE, 1);
-
-       return 0;
-}
-
-static int rsnd_scu_transfer_start(struct rsnd_priv *priv,
-                                  struct rsnd_mod *mod,
-                                  struct rsnd_dai *rdai,
-                                  struct rsnd_dai_stream *io)
-{
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-       int id = rsnd_mod_id(mod);
-       u32 val;
-
-       if (rsnd_is_gen1(priv)) {
-               val = (1 << id);
-               rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val);
-       }
-
-       if (rsnd_scu_convert_rate(scu))
-               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
-
-       return 0;
-}
-
-static int rsnd_scu_transfer_stop(struct rsnd_priv *priv,
-                                 struct rsnd_mod *mod,
-                                 struct rsnd_dai *rdai,
-                                 struct rsnd_dai_stream *io)
-{
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-       int id = rsnd_mod_id(mod);
-       u32 mask;
-
-       if (rsnd_is_gen1(priv)) {
-               mask = (1 << id);
-               rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0);
-       }
-
-       if (rsnd_scu_convert_rate(scu))
-               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
-
-       return 0;
-}
-
-bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod)
-{
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-       u32 flags = rsnd_scu_mode_flags(scu);
-
-       return !!(flags & RSND_SCU_USE_HPBIF);
-}
-
-static int rsnd_scu_start(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai,
-                         struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int ret;
-
-       /*
-        * SCU will be used if it has RSND_SCU_USE_HPBIF flags
-        */
-       if (!rsnd_scu_hpbif_is_enable(mod)) {
-               /* it use PIO transter */
-               dev_dbg(dev, "%s%d is not used\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-               return 0;
-       }
-
-       clk_enable(scu->clk);
-
-       /* it use DMA transter */
-
-       ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_scu_transfer_start(priv, mod, rdai, io);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
-       return 0;
-}
-
-static int rsnd_scu_stop(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai,
-                         struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-
-       if (!rsnd_scu_hpbif_is_enable(mod))
-               return 0;
-
-       rsnd_scu_transfer_stop(priv, mod, rdai, io);
-
-       clk_disable(scu->clk);
-
-       return 0;
-}
-
-static struct rsnd_mod_ops rsnd_scu_ops = {
-       .name   = "scu",
-       .start  = rsnd_scu_start,
-       .stop   = rsnd_scu_stop,
-};
-
-struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_scu_nr(priv)))
-               id = 0;
-
-       return &((struct rsnd_scu *)(priv->scu) + id)->mod;
-}
-
-int rsnd_scu_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
-                  struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_scu *scu;
-       struct clk *clk;
-       char name[RSND_SCU_NAME_SIZE];
-       int i, nr;
-
-       /*
-        * init SCU
-        */
-       nr      = info->scu_info_nr;
-       scu     = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
-       if (!scu) {
-               dev_err(dev, "SCU allocate failed\n");
-               return -ENOMEM;
-       }
-
-       priv->scu_nr    = nr;
-       priv->scu       = scu;
-
-       for_each_rsnd_scu(scu, priv, i) {
-               snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i);
-
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
-
-               rsnd_mod_init(priv, &scu->mod,
-                             &rsnd_scu_ops, i);
-               scu->info = &info->scu_info[i];
-               scu->clk = clk;
-
-               dev_dbg(dev, "SCU%d probed\n", i);
-       }
-       dev_dbg(dev, "scu probed\n");
-
-       return 0;
-}
-
-void rsnd_scu_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
-{
-}
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
new file mode 100644 (file)
index 0000000..6232b7d
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Renesas R-Car SRC support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_src {
+       struct rsnd_src_platform_info *info; /* rcar_snd.h */
+       struct rsnd_mod mod;
+       struct clk *clk;
+};
+
+#define RSND_SRC_NAME_SIZE 16
+
+/*
+ * ADINR
+ */
+#define OTBL_24                (0 << 16)
+#define OTBL_22                (2 << 16)
+#define OTBL_20                (4 << 16)
+#define OTBL_18                (6 << 16)
+#define OTBL_16                (8 << 16)
+
+#define rsnd_src_mode_flags(p) ((p)->info->flags)
+#define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
+#define rsnd_mod_to_src(_mod)                          \
+       container_of((_mod), struct rsnd_src, mod)
+#define rsnd_src_hpbif_is_enable(src)  \
+       (rsnd_src_mode_flags(src) & RSND_SCU_USE_HPBIF)
+#define rsnd_src_dma_available(src) \
+       rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod))
+
+#define for_each_rsnd_src(pos, priv, i)                                \
+       for ((i) = 0;                                           \
+            ((i) < rsnd_src_nr(priv)) &&                       \
+            ((pos) = (struct rsnd_src *)(priv)->src + i);      \
+            i++)
+
+
+/*
+ *             image of SRC (Sampling Rate Converter)
+ *
+ * 96kHz   <-> +-----+ 48kHz   +-----+  48kHz  +-------+
+ * 48kHz   <-> | SRC | <------>        | SSI | <-----> | codec |
+ * 44.1kHz <-> +-----+         +-----+         +-------+
+ * ...
+ *
+ */
+
+/*
+ * src.c is caring...
+ *
+ * Gen1
+ *
+ * [mem] -> [SRU] -> [SSI]
+ *        |--------|
+ *
+ * Gen2
+ *
+ * [mem] -> [SRC] -> [SSIU] -> [SSI]
+ *        |-----------------|
+ */
+
+/*
+ *     How to use SRC bypass mode for debugging
+ *
+ * SRC has bypass mode, and it is useful for debugging.
+ * In Gen2 case,
+ * SRCm_MODE controls whether SRC is used or not
+ * SSI_MODE0 controls whether SSIU which receives SRC data
+ * is used or not.
+ * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC,
+ * but SRC bypass mode needs SSI_MODE0 only.
+ *
+ * This driver request
+ * struct rsnd_src_platform_info {
+ *     u32 flags;
+ *     u32 convert_rate;
+ * }
+ *
+ * rsnd_src_hpbif_is_enable() will be true
+ * if flags had RSND_SRC_USE_HPBIF,
+ * and it controls whether SSIU is used or not.
+ *
+ * rsnd_src_convert_rate() indicates
+ * above convert_rate, and it controls
+ * whether SRC is used or not.
+ *
+ * ex) doesn't use SRC
+ * struct rsnd_src_platform_info info = {
+ *     .flags = 0,
+ *     .convert_rate = 0,
+ * };
+ *
+ * ex) uses SRC
+ * struct rsnd_src_platform_info info = {
+ *     .flags = RSND_SRC_USE_HPBIF,
+ *     .convert_rate = 48000,
+ * };
+ *
+ * ex) uses SRC bypass mode
+ * struct rsnd_src_platform_info info = {
+ *     .flags = RSND_SRC_USE_HPBIF,
+ *     .convert_rate = 0,
+ * };
+ *
+ */
+
+/*
+ *             Gen1/Gen2 common functions
+ */
+int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
+                          struct rsnd_dai *rdai,
+                          struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       int ssi_id = rsnd_mod_id(ssi_mod);
+       int has_src = 0;
+
+       /*
+        * SSI_MODE0
+        */
+       if (info->dai_info) {
+               has_src = !!src_mod;
+       } else {
+               struct rsnd_src *src = rsnd_mod_to_src(src_mod);
+               has_src = rsnd_src_hpbif_is_enable(src);
+       }
+
+       rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
+                     has_src ? 0 : (1 << ssi_id));
+
+       /*
+        * SSI_MODE1
+        */
+       if (rsnd_ssi_is_pin_sharing(ssi_mod)) {
+               int shift = -1;
+               switch (ssi_id) {
+               case 1:
+                       shift = 0;
+                       break;
+               case 2:
+                       shift = 2;
+                       break;
+               case 4:
+                       shift = 16;
+                       break;
+               }
+
+               if (shift >= 0)
+                       rsnd_mod_bset(ssi_mod, SSI_MODE1,
+                                     0x3 << shift,
+                                     rsnd_dai_is_clk_master(rdai) ?
+                                     0x2 << shift : 0x1 << shift);
+       }
+
+       return 0;
+}
+
+int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
+                           struct rsnd_dai *rdai,
+                           struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+       /* enable PIO interrupt if Gen2 */
+       if (rsnd_is_gen2(priv))
+               rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000);
+
+       return 0;
+}
+
+unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
+                                  struct rsnd_dai_stream *io,
+                                  struct snd_pcm_runtime *runtime)
+{
+       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+       struct rsnd_src *src;
+       unsigned int rate = 0;
+
+       if (src_mod) {
+               src = rsnd_mod_to_src(src_mod);
+
+               /*
+                * return convert rate if SRC is used,
+                * otherwise, return runtime->rate as usual
+                */
+               rate = rsnd_src_convert_rate(src);
+       }
+
+       if (!rate)
+               rate = runtime->rate;
+
+       return rate;
+}
+
+static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
+                                    struct rsnd_dai *rdai,
+                                    struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 adinr = runtime->channels;
+       u32 fsrate = 0;
+
+       if (convert_rate)
+               fsrate = 0x0400000 / convert_rate * runtime->rate;
+
+       /* set/clear soft reset */
+       rsnd_mod_write(mod, SRC_SWRSR, 0);
+       rsnd_mod_write(mod, SRC_SWRSR, 1);
+
+       /*
+        * Initialize the operation of the SRC internal circuits
+        * see rsnd_src_start()
+        */
+       rsnd_mod_write(mod, SRC_SRCIR, 1);
+
+       /* Set channel number and output bit length */
+       switch (runtime->sample_bits) {
+       case 16:
+               adinr |= OTBL_16;
+               break;
+       case 32:
+               adinr |= OTBL_24;
+               break;
+       default:
+               return -EIO;
+       }
+       rsnd_mod_write(mod, SRC_ADINR, adinr);
+
+       /* Enable the initial value of IFS */
+       if (fsrate) {
+               rsnd_mod_write(mod, SRC_IFSCR, 1);
+
+               /* Set initial value of IFS */
+               rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+       }
+
+       /* use DMA transfer */
+       rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
+
+       return 0;
+}
+
+static int rsnd_src_init(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       clk_enable(src->clk);
+
+       return 0;
+}
+
+static int rsnd_src_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       clk_disable(src->clk);
+
+       return 0;
+}
+
+static int rsnd_src_start(struct rsnd_mod *mod,
+                         struct rsnd_dai *rdai,
+                         struct rsnd_dai_stream *io)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       /*
+        * Cancel the initialization and operate the SRC function
+        * see rsnd_src_set_convert_rate()
+        */
+       rsnd_mod_write(mod, SRC_SRCIR, 0);
+
+       if (rsnd_src_convert_rate(src))
+               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+
+       return 0;
+}
+
+
+static int rsnd_src_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       if (rsnd_src_convert_rate(src))
+               rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_src_non_ops = {
+       .name   = "src (non)",
+};
+
+/*
+ *             Gen1 functions
+ */
+static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
+                                  struct rsnd_dai *rdai,
+                                  struct rsnd_dai_stream *io)
+{
+       struct src_route_config {
+               u32 mask;
+               int shift;
+       } routes[] = {
+               { 0xF,  0, }, /* 0 */
+               { 0xF,  4, }, /* 1 */
+               { 0xF,  8, }, /* 2 */
+               { 0x7, 12, }, /* 3 */
+               { 0x7, 16, }, /* 4 */
+               { 0x7, 20, }, /* 5 */
+               { 0x7, 24, }, /* 6 */
+               { 0x3, 28, }, /* 7 */
+               { 0x3, 30, }, /* 8 */
+       };
+       u32 mask;
+       u32 val;
+       int id;
+
+       id = rsnd_mod_id(mod);
+       if (id < 0 || id >= ARRAY_SIZE(routes))
+               return -EIO;
+
+       /*
+        * SRC_ROUTE_SELECT
+        */
+       val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
+       val = val               << routes[id].shift;
+       mask = routes[id].mask  << routes[id].shift;
+
+       rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
+
+       return 0;
+}
+
+static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
+                                           struct rsnd_dai *rdai,
+                                           struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 convert_rate = rsnd_src_convert_rate(src);
+       u32 mask;
+       u32 val;
+       int shift;
+       int id = rsnd_mod_id(mod);
+       int ret;
+
+       /*
+        * SRC_TIMING_SELECT
+        */
+       shift   = (id % 4) * 8;
+       mask    = 0x1F << shift;
+
+       /*
+        * ADG is used as source clock if SRC was used,
+        * then, SSI WS is used as destination clock.
+        * SSI WS is used as source clock if SRC is not used
+        * (when playback, source/destination become reverse when capture)
+        */
+       ret = 0;
+       if (convert_rate) {
+               /* use ADG */
+               val = 0;
+               ret = rsnd_adg_set_convert_clk_gen1(priv, mod,
+                                                   runtime->rate,
+                                                   convert_rate);
+       } else if (8 == id) {
+               /* use SSI WS, but SRU8 is special */
+               val = id << shift;
+       } else {
+               /* use SSI WS */
+               val = (id + 1) << shift;
+       }
+
+       if (ret < 0)
+               return ret;
+
+       switch (id / 4) {
+       case 0:
+               rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
+               break;
+       case 1:
+               rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
+               break;
+       case 2:
+               rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
+               break;
+       }
+
+       return 0;
+}
+
+static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
+                                         struct rsnd_dai *rdai,
+                                         struct rsnd_dai_stream *io)
+{
+       int ret;
+
+       ret = rsnd_src_set_convert_rate(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       /* Select SRC mode (fixed value) */
+       rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
+
+       /* Set the restriction value of the FS ratio (98%) */
+       rsnd_mod_write(mod, SRC_MNFSR,
+                      rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
+
+       /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
+
+       return 0;
+}
+
+static int rsnd_src_init_gen1(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       int ret;
+
+       ret = rsnd_src_init(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_src_set_route_gen1(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_src_set_convert_rate_gen1(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_src_set_convert_timing_gen1(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rsnd_src_start_gen1(struct rsnd_mod *mod,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       int id = rsnd_mod_id(mod);
+
+       rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
+
+       return rsnd_src_start(mod, rdai, io);
+}
+
+static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       int id = rsnd_mod_id(mod);
+
+       rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
+
+       return rsnd_src_stop(mod, rdai, io);
+}
+
+static struct rsnd_mod_ops rsnd_src_gen1_ops = {
+       .name   = "sru (gen1)",
+       .init   = rsnd_src_init_gen1,
+       .quit   = rsnd_src_quit,
+       .start  = rsnd_src_start_gen1,
+       .stop   = rsnd_src_stop_gen1,
+};
+
+/*
+ *             Gen2 functions
+ */
+static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
+                                         struct rsnd_dai *rdai,
+                                         struct rsnd_dai_stream *io)
+{
+       int ret;
+
+       ret = rsnd_src_set_convert_rate(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR));
+       rsnd_mod_write(mod, SSI_BUSIF_MODE,  rsnd_mod_read(mod, SRC_BUSIF_MODE));
+
+       rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
+
+       rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
+       rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
+
+       return 0;
+}
+
+static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
+                                           struct rsnd_dai *rdai,
+                                           struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 convert_rate = rsnd_src_convert_rate(src);
+       int ret;
+
+       if (convert_rate)
+               ret = rsnd_adg_set_convert_clk_gen2(mod, rdai, io,
+                                                   runtime->rate,
+                                                   convert_rate);
+       else
+               ret = rsnd_adg_set_convert_timing_gen2(mod, rdai, io);
+
+       return ret;
+}
+
+static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct rsnd_mod *ssi = rsnd_ssi_mod_get(priv, rsnd_mod_id(mod));
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int ret;
+       int is_play;
+
+       if (info->dai_info)
+               is_play = rsnd_info_is_playback(priv, src);
+       else
+               is_play = rsnd_ssi_is_play(ssi);
+
+       ret = rsnd_dma_init(priv,
+                           rsnd_mod_to_dma(mod),
+                           is_play,
+                           src->info->dma_id);
+       if (ret < 0)
+               dev_err(dev, "SRC DMA failed\n");
+
+       return ret;
+}
+
+static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
+                               struct rsnd_dai *rdai,
+                               struct rsnd_dai_stream *io)
+{
+       rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+
+       return 0;
+}
+
+static int rsnd_src_init_gen2(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       int ret;
+
+       ret = rsnd_src_init(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_src_set_convert_rate_gen2(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_src_set_convert_timing_gen2(mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rsnd_src_start_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
+
+       rsnd_mod_write(mod, SSI_CTRL, 0x1);
+       rsnd_mod_write(mod, SRC_CTRL, 0x11);
+
+       return rsnd_src_start(mod, rdai, io);
+}
+
+static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       rsnd_mod_write(mod, SSI_CTRL, 0);
+       rsnd_mod_write(mod, SRC_CTRL, 0);
+
+       rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
+
+       return rsnd_src_stop(mod, rdai, io);
+}
+
+static struct rsnd_mod_ops rsnd_src_gen2_ops = {
+       .name   = "src (gen2)",
+       .probe  = rsnd_src_probe_gen2,
+       .remove = rsnd_src_remove_gen2,
+       .init   = rsnd_src_init_gen2,
+       .quit   = rsnd_src_quit,
+       .start  = rsnd_src_start_gen2,
+       .stop   = rsnd_src_stop_gen2,
+};
+
+struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
+               id = 0;
+
+       return &((struct rsnd_src *)(priv->src) + id)->mod;
+}
+
+static void rsnd_of_parse_src(struct platform_device *pdev,
+                             const struct rsnd_of_data *of_data,
+                             struct rsnd_priv *priv)
+{
+       struct device_node *src_node;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct rsnd_src_platform_info *src_info;
+       struct device *dev = &pdev->dev;
+       int nr;
+
+       if (!of_data)
+               return;
+
+       src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+       if (!src_node)
+               return;
+
+       nr = of_get_child_count(src_node);
+       if (!nr)
+               return;
+
+       src_info = devm_kzalloc(dev,
+                               sizeof(struct rsnd_src_platform_info) * nr,
+                               GFP_KERNEL);
+       if (!src_info) {
+               dev_err(dev, "src info allocation error\n");
+               return;
+       }
+
+       info->src_info          = src_info;
+       info->src_info_nr       = nr;
+}
+
+int rsnd_src_probe(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
+                  struct rsnd_priv *priv)
+{
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_src *src;
+       struct rsnd_mod_ops *ops;
+       struct clk *clk;
+       char name[RSND_SRC_NAME_SIZE];
+       int i, nr;
+
+       rsnd_of_parse_src(pdev, of_data, priv);
+
+       /*
+        * init SRC
+        */
+       nr      = info->src_info_nr;
+       if (!nr)
+               return 0;
+
+       src     = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
+       if (!src) {
+               dev_err(dev, "SRC allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->src_nr    = nr;
+       priv->src       = src;
+
+       for_each_rsnd_src(src, priv, i) {
+               snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       snprintf(name, RSND_SRC_NAME_SIZE, "scu.%d", i);
+                       clk = devm_clk_get(dev, name);
+               }
+
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+
+               src->info = &info->src_info[i];
+               src->clk = clk;
+
+               ops = &rsnd_src_non_ops;
+               if (rsnd_src_hpbif_is_enable(src)) {
+                       if (rsnd_is_gen1(priv))
+                               ops = &rsnd_src_gen1_ops;
+                       if (rsnd_is_gen2(priv))
+                               ops = &rsnd_src_gen2_ops;
+               }
+
+               rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i);
+
+               dev_dbg(dev, "SRC%d probed\n", i);
+       }
+
+       return 0;
+}
index 4b8cf7ca9d19fb016b971cf9f0f1ddeb74fbb954..4b7e20603dd7be8032198291ee08ed9b95de88dd 100644 (file)
@@ -64,108 +64,29 @@ struct rsnd_ssi {
        struct rsnd_mod mod;
 
        struct rsnd_dai *rdai;
-       struct rsnd_dai_stream *io;
        u32 cr_own;
        u32 cr_clk;
        u32 cr_etc;
        int err;
-       int dma_offset;
        unsigned int usrcnt;
        unsigned int rate;
 };
 
-struct rsnd_ssiu {
-       u32 ssi_mode0;
-       u32 ssi_mode1;
-
-       int ssi_nr;
-       struct rsnd_ssi *ssi;
-};
-
 #define for_each_rsnd_ssi(pos, priv, i)                                        \
        for (i = 0;                                                     \
             (i < rsnd_ssi_nr(priv)) &&                                 \
-               ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
+               ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i));         \
             i++)
 
-#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
+#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
 #define rsnd_dma_to_ssi(dma)  rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
 #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
 #define rsnd_ssi_dma_available(ssi) \
        rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
 #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
-#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
 #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
 #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
-#define rsnd_ssi_to_ssiu(ssi)\
-       (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
-
-static void rsnd_ssi_mode_set(struct rsnd_priv *priv,
-                             struct rsnd_dai *rdai,
-                             struct rsnd_ssi *ssi)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mod *scu;
-       struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
-       int id = rsnd_mod_id(&ssi->mod);
-       u32 flags;
-       u32 val;
-
-       scu   = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod));
-
-       /*
-        * SSI_MODE0
-        */
-
-       /* see also BUSIF_MODE */
-       if (rsnd_scu_hpbif_is_enable(scu)) {
-               ssiu->ssi_mode0 &= ~(1 << id);
-               dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id);
-       } else {
-               ssiu->ssi_mode0 |= (1 << id);
-               dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id);
-       }
-
-       /*
-        * SSI_MODE1
-        */
-#define ssi_parent_set(p, sync, adg, ext)              \
-       do {                                            \
-               ssi->parent = ssiu->ssi + p;            \
-               if (rsnd_rdai_is_clk_master(rdai))      \
-                       val = adg;                      \
-               else                                    \
-                       val = ext;                      \
-               if (flags & RSND_SSI_SYNC)              \
-                       val |= sync;                    \
-       } while (0)
-
-       flags = rsnd_ssi_mode_flags(ssi);
-       if (flags & RSND_SSI_CLK_PIN_SHARE) {
-
-               val = 0;
-               switch (id) {
-               case 1:
-                       ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
-                       break;
-               case 2:
-                       ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
-                       break;
-               case 4:
-                       ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
-                       break;
-               case 8:
-                       ssi_parent_set(7, 0, 0, 0);
-                       break;
-               }
-
-               ssiu->ssi_mode1 |= val;
-       }
-
-       rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
-       rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
-}
 
 static void rsnd_ssi_status_check(struct rsnd_mod *mod,
                                  u32 bit)
@@ -200,7 +121,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
                1, 2, 4, 8, 16, 6, 12,
        };
        unsigned int main_rate;
-       unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime);
+       unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);
 
        /*
         * Find best clock, and try to start ADG
@@ -252,7 +173,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
        if (0 == ssi->usrcnt) {
                clk_enable(ssi->clk);
 
-               if (rsnd_rdai_is_clk_master(rdai)) {
+               if (rsnd_dai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
                                rsnd_ssi_hw_start(ssi->parent, rdai, io);
                        else
@@ -302,7 +223,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
                rsnd_mod_write(&ssi->mod, SSICR, cr);   /* disabled all */
                rsnd_ssi_status_check(&ssi->mod, IIRQ);
 
-               if (rsnd_rdai_is_clk_master(rdai)) {
+               if (rsnd_dai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
                                rsnd_ssi_hw_stop(ssi->parent, rdai);
                        else
@@ -323,8 +244,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 cr;
 
@@ -365,13 +284,10 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
         * set ssi parameter
         */
        ssi->rdai       = rdai;
-       ssi->io         = io;
        ssi->cr_own     = cr;
        ssi->err        = -1; /* ignore 1st error */
 
-       rsnd_ssi_mode_set(priv, rdai, ssi);
-
-       dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+       rsnd_src_ssi_mode_init(mod, rdai, io);
 
        return 0;
 }
@@ -384,13 +300,10 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
-       dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
        if (ssi->err > 0)
                dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
 
        ssi->rdai       = NULL;
-       ssi->io         = NULL;
        ssi->cr_own     = 0;
        ssi->err        = 0;
 
@@ -414,8 +327,9 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
 {
        struct rsnd_ssi *ssi = data;
-       struct rsnd_dai_stream *io = ssi->io;
-       u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+       struct rsnd_mod *mod = &ssi->mod;
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       u32 status = rsnd_mod_read(mod, SSISR);
        irqreturn_t ret = IRQ_NONE;
 
        if (io && (status & DIRQ)) {
@@ -432,9 +346,9 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
                 * see rsnd_ssi_init()
                 */
                if (rsnd_dai_is_play(rdai, io))
-                       rsnd_mod_write(&ssi->mod, SSITDR, *buf);
+                       rsnd_mod_write(mod, SSITDR, *buf);
                else
-                       *buf = rsnd_mod_read(&ssi->mod, SSIRDR);
+                       *buf = rsnd_mod_read(mod, SSIRDR);
 
                rsnd_dai_pointer_update(io, sizeof(*buf));
 
@@ -444,25 +358,39 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
        return ret;
 }
 
-static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
                              struct rsnd_dai *rdai,
                              struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       int irq = ssi->info->pio_irq;
+       int ret;
+
+       ret = devm_request_irq(dev, irq,
+                              rsnd_ssi_pio_interrupt,
+                              IRQF_SHARED,
+                              dev_name(dev), ssi);
+       if (ret)
+               dev_err(dev, "SSI request interrupt failed\n");
+
+       return ret;
+}
+
+static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
        /* enable PIO IRQ */
        ssi->cr_etc = UIEN | OIEN | DIEN;
 
-       /* enable PIO interrupt if gen2 */
-       if (rsnd_is_gen2(priv))
-               rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000);
+       rsnd_src_enable_ssi_irq(mod, rdai, io);
 
        rsnd_ssi_hw_start(ssi, rdai, io);
 
-       dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
        return 0;
 }
 
@@ -470,12 +398,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
                             struct rsnd_dai *rdai,
                             struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
        ssi->cr_etc = 0;
 
        rsnd_ssi_hw_stop(ssi, rdai);
@@ -485,35 +409,46 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
 
 static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
        .name   = "ssi (pio)",
+       .probe  = rsnd_ssi_pio_probe,
        .init   = rsnd_ssi_init,
        .quit   = rsnd_ssi_quit,
        .start  = rsnd_ssi_pio_start,
        .stop   = rsnd_ssi_pio_stop,
 };
 
-static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len)
+static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
+                         struct rsnd_dai *rdai,
+                         struct rsnd_dai_stream *io)
 {
-       struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
-       struct rsnd_dai_stream *io = ssi->io;
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int dma_id = ssi->info->dma_id;
+       int is_play;
+       int ret;
 
-       *len = io->byte_per_period;
-       *buf = runtime->dma_addr +
-               rsnd_dai_pointer_offset(io, ssi->dma_offset + *len);
-       ssi->dma_offset = *len; /* it cares A/B plane */
+       if (info->dai_info)
+               is_play = rsnd_info_is_playback(priv, ssi);
+       else
+               is_play = rsnd_ssi_is_play(&ssi->mod);
 
-       return 0;
-}
+       ret = rsnd_dma_init(
+               priv, rsnd_mod_to_dma(mod),
+               is_play,
+               dma_id);
 
-static int rsnd_ssi_dma_complete(struct rsnd_dma *dma)
-{
-       struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
-       struct rsnd_dai_stream *io = ssi->io;
-       u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+       if (ret < 0)
+               dev_err(dev, "SSI DMA failed\n");
 
-       rsnd_ssi_record_error(ssi, status);
+       return ret;
+}
 
-       rsnd_dai_pointer_update(ssi->io, io->byte_per_period);
+static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
 
        return 0;
 }
@@ -527,14 +462,13 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
 
        /* enable DMA transfer */
        ssi->cr_etc = DMEN;
-       ssi->dma_offset = 0;
 
        rsnd_dma_start(dma);
 
        rsnd_ssi_hw_start(ssi, ssi->rdai, io);
 
        /* enable WS continue */
-       if (rsnd_rdai_is_clk_master(rdai))
+       if (rsnd_dai_is_clk_master(rdai))
                rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
 
        return 0;
@@ -549,6 +483,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
 
        ssi->cr_etc = 0;
 
+       rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
+
        rsnd_ssi_hw_stop(ssi, rdai);
 
        rsnd_dma_stop(dma);
@@ -558,6 +494,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
 
 static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
        .name   = "ssi (dma)",
+       .probe  = rsnd_ssi_dma_probe,
+       .remove = rsnd_ssi_dma_remove,
        .init   = rsnd_ssi_init,
        .quit   = rsnd_ssi_quit,
        .start  = rsnd_ssi_dma_start,
@@ -567,24 +505,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
 /*
  *             Non SSI
  */
-static int rsnd_ssi_non(struct rsnd_mod *mod,
-                       struct rsnd_dai *rdai,
-                       struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       return 0;
-}
-
 static struct rsnd_mod_ops rsnd_ssi_non_ops = {
        .name   = "ssi (non)",
-       .init   = rsnd_ssi_non,
-       .quit   = rsnd_ssi_non,
-       .start  = rsnd_ssi_non,
-       .stop   = rsnd_ssi_non,
 };
 
 /*
@@ -593,16 +515,30 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = {
 struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
                                          int dai_id, int is_play)
 {
+       struct rsnd_dai_platform_info *dai_info = NULL;
+       struct rsnd_dai_path_info *path_info = NULL;
+       struct rsnd_ssi_platform_info *target_info = NULL;
        struct rsnd_ssi *ssi;
        int i, has_play;
 
+       if (priv->rdai)
+               dai_info = priv->rdai[dai_id].info;
+       if (dai_info)
+               path_info = (is_play) ? &dai_info->playback : &dai_info->capture;
+       if (path_info)
+               target_info = path_info->ssi;
+
        is_play = !!is_play;
 
        for_each_rsnd_ssi(ssi, priv, i) {
+               if (target_info == ssi->info)
+                       return &ssi->mod;
+
+               /* for compatible */
                if (rsnd_ssi_dai_id(ssi) != dai_id)
                        continue;
 
-               has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
+               has_play = rsnd_ssi_is_play(&ssi->mod);
 
                if (is_play == has_play)
                        return &ssi->mod;
@@ -616,36 +552,122 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
                id = 0;
 
-       return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
+       return &((struct rsnd_ssi *)(priv->ssi) + id)->mod;
+}
+
+int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
+}
+
+int rsnd_ssi_is_play(struct rsnd_mod *mod)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
+}
+
+static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
+{
+       if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
+               return;
+
+       switch (rsnd_mod_id(&ssi->mod)) {
+       case 1:
+       case 2:
+               ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
+               break;
+       case 4:
+               ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3));
+               break;
+       case 8:
+               ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7));
+               break;
+       }
+}
+
+
+static void rsnd_of_parse_ssi(struct platform_device *pdev,
+                             const struct rsnd_of_data *of_data,
+                             struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct device_node *np;
+       struct rsnd_ssi_platform_info *ssi_info;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = &pdev->dev;
+       int nr, i;
+
+       if (!of_data)
+               return;
+
+       node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+       if (!node)
+               return;
+
+       nr = of_get_child_count(node);
+       if (!nr)
+               return;
+
+       ssi_info = devm_kzalloc(dev,
+                               sizeof(struct rsnd_ssi_platform_info) * nr,
+                               GFP_KERNEL);
+       if (!ssi_info) {
+               dev_err(dev, "ssi info allocation error\n");
+               return;
+       }
+
+       info->ssi_info          = ssi_info;
+       info->ssi_info_nr       = nr;
+
+       i = -1;
+       for_each_child_of_node(node, np) {
+               i++;
+
+               ssi_info = info->ssi_info + i;
+
+               /*
+                * pin settings
+                */
+               if (of_get_property(np, "shared-pin", NULL))
+                       ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
+
+               /*
+                * irq
+                */
+               ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
+       }
 }
 
 int rsnd_ssi_probe(struct platform_device *pdev,
-                  struct rcar_snd_info *info,
+                  const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv)
 {
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct rsnd_ssi_platform_info *pinfo;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_mod_ops *ops;
        struct clk *clk;
-       struct rsnd_ssiu *ssiu;
        struct rsnd_ssi *ssi;
        char name[RSND_SSI_NAME_SIZE];
-       int i, nr, ret;
+       int i, nr;
+
+       rsnd_of_parse_ssi(pdev, of_data, priv);
 
        /*
         *      init SSI
         */
        nr      = info->ssi_info_nr;
-       ssiu    = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
-                              GFP_KERNEL);
-       if (!ssiu) {
+       ssi     = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
+       if (!ssi) {
                dev_err(dev, "SSI allocate failed\n");
                return -ENOMEM;
        }
 
-       priv->ssiu      = ssiu;
-       ssiu->ssi       = (struct rsnd_ssi *)(ssiu + 1);
-       ssiu->ssi_nr    = nr;
+       priv->ssi       = ssi;
+       priv->ssi_nr    = nr;
 
        for_each_rsnd_ssi(ssi, priv, i) {
                pinfo = &info->ssi_info[i];
@@ -660,61 +682,15 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                ssi->clk        = clk;
 
                ops = &rsnd_ssi_non_ops;
+               if (pinfo->dma_id > 0)
+                       ops = &rsnd_ssi_dma_ops;
+               else if (rsnd_ssi_pio_available(ssi))
+                       ops = &rsnd_ssi_pio_ops;
 
-               /*
-                * SSI DMA case
-                */
-               if (pinfo->dma_id > 0) {
-                       ret = rsnd_dma_init(
-                               priv, rsnd_mod_to_dma(&ssi->mod),
-                               (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY),
-                               pinfo->dma_id,
-                               rsnd_ssi_dma_inquiry,
-                               rsnd_ssi_dma_complete);
-                       if (ret < 0)
-                               dev_info(dev, "SSI DMA failed. try PIO transter\n");
-                       else
-                               ops     = &rsnd_ssi_dma_ops;
-
-                       dev_dbg(dev, "SSI%d use DMA transfer\n", i);
-               }
-
-               /*
-                * SSI PIO case
-                */
-               if (!rsnd_ssi_dma_available(ssi) &&
-                    rsnd_ssi_pio_available(ssi)) {
-                       ret = devm_request_irq(dev, pinfo->pio_irq,
-                                              &rsnd_ssi_pio_interrupt,
-                                              IRQF_SHARED,
-                                              dev_name(dev), ssi);
-                       if (ret) {
-                               dev_err(dev, "SSI request interrupt failed\n");
-                               return ret;
-                       }
-
-                       ops     = &rsnd_ssi_pio_ops;
-
-                       dev_dbg(dev, "SSI%d use PIO transfer\n", i);
-               }
+               rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i);
 
-               rsnd_mod_init(priv, &ssi->mod, ops, i);
+               rsnd_ssi_parent_clk_setup(priv, ssi);
        }
 
-       dev_dbg(dev, "ssi probed\n");
-
        return 0;
 }
-
-void rsnd_ssi_remove(struct platform_device *pdev,
-                  struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi;
-       int i;
-
-       for_each_rsnd_ssi(ssi, priv, i) {
-               if (rsnd_ssi_dma_available(ssi))
-                       rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
-       }
-
-}
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
new file mode 100644 (file)
index 0000000..89e8942
--- /dev/null
@@ -0,0 +1,14 @@
+config SND_SOC_SIRF
+       tristate "SoC Audio for the SiRF SoC chips"
+       depends on ARCH_SIRF || COMPILE_TEST
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_SIRF_AUDIO
+       tristate "SoC Audio support for SiRF internal audio codec"
+       depends on SND_SOC_SIRF
+       select SND_SOC_SIRF_AUDIO_CODEC
+       select SND_SOC_SIRF_AUDIO_PORT
+
+config SND_SOC_SIRF_AUDIO_PORT
+       select REGMAP_MMIO
+       tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
new file mode 100644 (file)
index 0000000..913b932
--- /dev/null
@@ -0,0 +1,5 @@
+snd-soc-sirf-audio-objs := sirf-audio.o
+snd-soc-sirf-audio-port-objs := sirf-audio-port.o
+
+obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o
+obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c
new file mode 100644 (file)
index 0000000..b04a53f
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * SiRF Audio port driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio-port.h"
+
+struct sirf_audio_port {
+       struct regmap *regmap;
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
+};
+
+static void sirf_audio_port_tx_enable(struct sirf_audio_port *port)
+{
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+       regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
+       regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+               AUDIO_FIFO_START, AUDIO_FIFO_START);
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
+               IC_TX_ENABLE, IC_TX_ENABLE);
+}
+
+static void sirf_audio_port_tx_disable(struct sirf_audio_port *port)
+{
+       regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
+               IC_TX_ENABLE, ~IC_TX_ENABLE);
+}
+
+static void sirf_audio_port_rx_enable(struct sirf_audio_port *port,
+       int channels)
+{
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+               AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+       regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
+       regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+               AUDIO_FIFO_START, AUDIO_FIFO_START);
+       if (channels == 1)
+               regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
+                       IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
+       else
+               regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
+                       IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
+}
+
+static void sirf_audio_port_rx_disable(struct sirf_audio_port *port)
+{
+       regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
+                       IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
+}
+
+static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
+{
+       struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
+       snd_soc_dai_init_dma_data(dai, &port->playback_dma_data,
+                       &port->capture_dma_data);
+       return 0;
+}
+
+static int sirf_audio_port_trigger(struct snd_pcm_substream *substream, int cmd,
+       struct snd_soc_dai *dai)
+{
+       struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
+       int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (playback)
+                       sirf_audio_port_tx_disable(port);
+               else
+                       sirf_audio_port_rx_disable(port);
+               break;
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (playback)
+                       sirf_audio_port_tx_enable(port);
+               else
+                       sirf_audio_port_rx_enable(port,
+                               substream->runtime->channels);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = {
+       .trigger = sirf_audio_port_trigger,
+};
+
+static struct snd_soc_dai_driver sirf_audio_port_dai = {
+       .probe = sirf_audio_port_dai_probe,
+       .name = "sirf-audio-port",
+       .id = 0,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &sirf_audio_port_dai_ops,
+};
+
+static const struct snd_soc_component_driver sirf_audio_port_component = {
+       .name       = "sirf-audio-port",
+};
+
+static const struct regmap_config sirf_audio_port_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
+       .cache_type = REGCACHE_NONE,
+};
+
+static int sirf_audio_port_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct sirf_audio_port *port;
+       void __iomem *base;
+       struct resource *mem_res;
+
+       port = devm_kzalloc(&pdev->dev,
+                       sizeof(struct sirf_audio_port), GFP_KERNEL);
+       if (!port)
+               return -ENOMEM;
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       base = devm_ioremap(&pdev->dev, mem_res->start,
+                       resource_size(mem_res));
+       if (base == NULL)
+               return -ENOMEM;
+
+       port->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                           &sirf_audio_port_regmap_config);
+       if (IS_ERR(port->regmap))
+               return PTR_ERR(port->regmap);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &sirf_audio_port_component, &sirf_audio_port_dai, 1);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, port);
+       return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+}
+
+static const struct of_device_id sirf_audio_port_of_match[] = {
+       { .compatible = "sirf,audio-port", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match);
+
+static struct platform_driver sirf_audio_port_driver = {
+       .driver = {
+               .name = "sirf-audio-port",
+               .owner = THIS_MODULE,
+               .of_match_table = sirf_audio_port_of_match,
+       },
+       .probe = sirf_audio_port_probe,
+};
+
+module_platform_driver(sirf_audio_port_driver);
+
+MODULE_DESCRIPTION("SiRF Audio Port driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-audio-port.h b/sound/soc/sirf/sirf-audio-port.h
new file mode 100644 (file)
index 0000000..f32dc54
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SiRF Audio port controllers define
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_AUDIO_PORT_H
+#define _SIRF_AUDIO_PORT_H
+
+#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK     0x3F
+#define AUDIO_PORT_TX_FIFO_SC_OFFSET    0
+#define AUDIO_PORT_TX_FIFO_LC_OFFSET    10
+#define AUDIO_PORT_TX_FIFO_HC_OFFSET    20
+
+#define TX_FIFO_SC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_TX_FIFO_HC_OFFSET)
+
+#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK     0x0F
+#define AUDIO_PORT_RX_FIFO_SC_OFFSET    0
+#define AUDIO_PORT_RX_FIFO_LC_OFFSET    10
+#define AUDIO_PORT_RX_FIFO_HC_OFFSET    20
+
+#define RX_FIFO_SC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+                               << AUDIO_PORT_RX_FIFO_HC_OFFSET)
+#define AUDIO_PORT_IC_CODEC_TX_CTRL            (0x00F4)
+#define AUDIO_PORT_IC_CODEC_RX_CTRL            (0x00F8)
+
+#define AUDIO_PORT_IC_TXFIFO_OP                        (0x00FC)
+#define AUDIO_PORT_IC_TXFIFO_LEV_CHK           (0x0100)
+#define AUDIO_PORT_IC_TXFIFO_STS               (0x0104)
+#define AUDIO_PORT_IC_TXFIFO_INT               (0x0108)
+#define AUDIO_PORT_IC_TXFIFO_INT_MSK           (0x010C)
+
+#define AUDIO_PORT_IC_RXFIFO_OP                        (0x0110)
+#define AUDIO_PORT_IC_RXFIFO_LEV_CHK           (0x0114)
+#define AUDIO_PORT_IC_RXFIFO_STS               (0x0118)
+#define AUDIO_PORT_IC_RXFIFO_INT               (0x011C)
+#define AUDIO_PORT_IC_RXFIFO_INT_MSK           (0x0120)
+
+#define AUDIO_FIFO_START               (1 << 0)
+#define AUDIO_FIFO_RESET               (1 << 1)
+
+#define AUDIO_FIFO_FULL                        (1 << 0)
+#define AUDIO_FIFO_EMPTY               (1 << 1)
+#define AUDIO_FIFO_OFLOW               (1 << 2)
+#define AUDIO_FIFO_UFLOW               (1 << 3)
+
+#define IC_TX_ENABLE           (0x03)
+#define IC_RX_ENABLE_MONO      (0x01)
+#define IC_RX_ENABLE_STEREO    (0x03)
+
+#endif /*__SIRF_AUDIO_PORT_H*/
diff --git a/sound/soc/sirf/sirf-audio.c b/sound/soc/sirf/sirf-audio.c
new file mode 100644 (file)
index 0000000..ecef510
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * SiRF audio card driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+struct sirf_audio_card {
+       unsigned int            gpio_hp_pa;
+       unsigned int            gpio_spk_pa;
+};
+
+static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *ctrl, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
+       int on = !SND_SOC_DAPM_EVENT_OFF(event);
+       if (gpio_is_valid(sirf_audio_card->gpio_hp_pa))
+               gpio_set_value(sirf_audio_card->gpio_hp_pa, on);
+       return 0;
+}
+
+static int sirf_audio_spk_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *ctrl, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
+       int on = !SND_SOC_DAPM_EVENT_OFF(event);
+
+       if (gpio_is_valid(sirf_audio_card->gpio_spk_pa))
+               gpio_set_value(sirf_audio_card->gpio_spk_pa, on);
+
+       return 0;
+}
+static const struct snd_soc_dapm_widget sirf_audio_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Hp", sirf_audio_hp_event),
+       SND_SOC_DAPM_SPK("Ext Spk", sirf_audio_spk_event),
+       SND_SOC_DAPM_MIC("Ext Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       {"Hp", NULL, "HPOUTL"},
+       {"Hp", NULL, "HPOUTR"},
+       {"Ext Spk", NULL, "SPKOUT"},
+       {"MICIN1", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Ext Mic"},
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link sirf_audio_dai_link[] = {
+       {
+               .name = "SiRF audio card",
+               .stream_name = "SiRF audio HiFi",
+               .codec_dai_name = "sirf-audio-codec",
+       },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_sirf_audio_card = {
+       .name = "SiRF audio card",
+       .owner = THIS_MODULE,
+       .dai_link = sirf_audio_dai_link,
+       .num_links = ARRAY_SIZE(sirf_audio_dai_link),
+       .dapm_widgets = sirf_audio_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets),
+       .dapm_routes = intercon,
+       .num_dapm_routes = ARRAY_SIZE(intercon),
+};
+
+static int sirf_audio_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_sirf_audio_card;
+       struct sirf_audio_card *sirf_audio_card;
+       int ret;
+
+       sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card),
+                       GFP_KERNEL);
+       if (sirf_audio_card == NULL)
+               return -ENOMEM;
+
+       sirf_audio_dai_link[0].cpu_of_node =
+               of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
+       sirf_audio_dai_link[0].platform_of_node =
+               of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
+       sirf_audio_dai_link[0].codec_of_node =
+               of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0);
+       sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node,
+                       "spk-pa-gpios", 0);
+       sirf_audio_card->gpio_hp_pa =  of_get_named_gpio(pdev->dev.of_node,
+                       "hp-pa-gpios", 0);
+       if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) {
+               ret = devm_gpio_request_one(&pdev->dev,
+                               sirf_audio_card->gpio_spk_pa,
+                               GPIOF_OUT_INIT_LOW, "SPA_PA_SD");
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Failed to request GPIO_%d for reset: %d\n",
+                               sirf_audio_card->gpio_spk_pa, ret);
+                       return ret;
+               }
+       }
+       if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) {
+               ret = devm_gpio_request_one(&pdev->dev,
+                               sirf_audio_card->gpio_hp_pa,
+                               GPIOF_OUT_INIT_LOW, "HP_PA_SD");
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Failed to request GPIO_%d for reset: %d\n",
+                               sirf_audio_card->gpio_hp_pa, ret);
+                       return ret;
+               }
+       }
+
+       card->dev = &pdev->dev;
+       snd_soc_card_set_drvdata(card, sirf_audio_card);
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret)
+               dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+       return ret;
+}
+
+static const struct of_device_id sirf_audio_of_match[] = {
+       {.compatible = "sirf,sirf-audio-card", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_of_match);
+
+static struct platform_driver sirf_audio_driver = {
+       .driver = {
+               .name = "sirf-audio-card",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = sirf_audio_of_match,
+       },
+       .probe = sirf_audio_probe,
+};
+module_platform_driver(sirf_audio_driver);
+
+MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>");
+MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver");
+MODULE_LICENSE("GPL v2");
index 375dc6dfba4e8be704a52cd5a1c7e0780321d2e5..bfed3e4c45ffa708910e580bf02359a7b6b3c509 100644 (file)
@@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
 {
        dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n",
                        codec->name);
-       if (!codec->reg_cache)
-               return 0;
+
        kfree(codec->reg_cache);
        codec->reg_cache = NULL;
        return 0;
@@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
                return -EINVAL;
 
        mutex_lock(&codec->cache_rw_mutex);
-       *value = snd_soc_get_cache_val(codec->reg_cache, reg,
-                                      codec->driver->reg_word_size);
+       if (!ZERO_OR_NULL_PTR(codec->reg_cache))
+               *value = snd_soc_get_cache_val(codec->reg_cache, reg,
+                                              codec->driver->reg_word_size);
        mutex_unlock(&codec->cache_rw_mutex);
 
        return 0;
@@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
                        unsigned int reg, unsigned int value)
 {
        mutex_lock(&codec->cache_rw_mutex);
-       snd_soc_set_cache_val(codec->reg_cache, reg, value,
-                             codec->driver->reg_word_size);
+       if (!ZERO_OR_NULL_PTR(codec->reg_cache))
+               snd_soc_set_cache_val(codec->reg_cache, reg, value,
+                                     codec->driver->reg_word_size);
        mutex_unlock(&codec->cache_rw_mutex);
 
        return 0;
index 5e9690c85d8f5c9afc248830ce6007d0890f19dc..91083e6a6b3814c37112f2bbd6996a68f0adb782 100644 (file)
@@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
                }
        }
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
-               cpu_dai->playback_active++;
-               codec_dai->playback_active++;
-       } else {
-               cpu_dai->capture_active++;
-               codec_dai->capture_active++;
-       }
-
-       cpu_dai->active++;
-       codec_dai->active++;
-       rtd->codec->active++;
+       snd_soc_runtime_activate(rtd, cstream->direction);
 
        mutex_unlock(&rtd->pcm_mutex);
 
@@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
        struct snd_soc_platform *platform = fe->platform;
-       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
-       struct snd_soc_dai *codec_dai = fe->codec_dai;
        struct snd_soc_dpcm *dpcm;
        struct snd_soc_dapm_widget_list *list;
        int stream;
@@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
-               cpu_dai->playback_active++;
-               codec_dai->playback_active++;
-       } else {
-               cpu_dai->capture_active++;
-               codec_dai->capture_active++;
-       }
-
-       cpu_dai->active++;
-       codec_dai->active++;
-       fe->codec->active++;
+       snd_soc_runtime_activate(fe, stream);
 
        mutex_unlock(&fe->card->mutex);
 
@@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = rtd->codec;
+       int stream;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
-               cpu_dai->playback_active--;
-               codec_dai->playback_active--;
-       } else {
-               cpu_dai->capture_active--;
-               codec_dai->capture_active--;
-       }
+       if (cstream->direction == SND_COMPRESS_PLAYBACK)
+               stream = SNDRV_PCM_STREAM_PLAYBACK;
+       else
+               stream = SNDRV_PCM_STREAM_CAPTURE;
 
-       snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+       snd_soc_runtime_deactivate(rtd, stream);
 
-       cpu_dai->active--;
-       codec_dai->active--;
-       codec->active--;
+       snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
 
        if (!cpu_dai->active)
                cpu_dai->rate = 0;
@@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
        cpu_dai->runtime = NULL;
 
        if (cstream->direction == SND_COMPRESS_PLAYBACK) {
-               if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
-                   rtd->dai_link->ignore_pmdown_time) {
+               if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
                        snd_soc_dapm_stream_event(rtd,
                                        SNDRV_PCM_STREAM_PLAYBACK,
                                        SND_SOC_DAPM_STREAM_STOP);
@@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_soc_platform *platform = fe->platform;
-       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
-       struct snd_soc_dai *codec_dai = fe->codec_dai;
        struct snd_soc_dpcm *dpcm;
        int stream, ret;
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
-       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+       if (cstream->direction == SND_COMPRESS_PLAYBACK)
                stream = SNDRV_PCM_STREAM_PLAYBACK;
-               cpu_dai->playback_active--;
-               codec_dai->playback_active--;
-       } else {
+       else
                stream = SNDRV_PCM_STREAM_CAPTURE;
-               cpu_dai->capture_active--;
-               codec_dai->capture_active--;
-       }
 
-       cpu_dai->active--;
-       codec_dai->active--;
-       fe->codec->active--;
+       snd_soc_runtime_deactivate(fe, stream);
 
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 
index fe1df50805a3035ea455d40771c55d4cb4f6585d..051c006281f5c2c003583f7104c9ec02dc886dfc 100644 (file)
@@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
 static LIST_HEAD(component_list);
@@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
 {
        char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        ssize_t len, ret = 0;
+       struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 
        if (!buf)
                return -ENOMEM;
 
-       list_for_each_entry(dai, &dai_list, list) {
-               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
-               if (len >= 0)
-                       ret += len;
-               if (ret > PAGE_SIZE) {
-                       ret = PAGE_SIZE;
-                       break;
+       list_for_each_entry(component, &component_list, list) {
+               list_for_each_entry(dai, &component->dai_list, list) {
+                       len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                               dai->name);
+                       if (len >= 0)
+                               ret += len;
+                       if (ret > PAGE_SIZE) {
+                               ret = PAGE_SIZE;
+                               break;
+                       }
                }
        }
 
@@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_component *component;
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
        struct snd_soc_dai *codec_dai, *cpu_dai;
@@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
 
        /* Find CPU DAI from registered DAIs*/
-       list_for_each_entry(cpu_dai, &dai_list, list) {
+       list_for_each_entry(component, &component_list, list) {
                if (dai_link->cpu_of_node &&
-                   (cpu_dai->dev->of_node != dai_link->cpu_of_node))
+                       component->dev->of_node != dai_link->cpu_of_node)
                        continue;
                if (dai_link->cpu_name &&
-                   strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
-                       continue;
-               if (dai_link->cpu_dai_name &&
-                   strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+                       strcmp(dev_name(component->dev), dai_link->cpu_name))
                        continue;
+               list_for_each_entry(cpu_dai, &component->dai_list, list) {
+                       if (dai_link->cpu_dai_name &&
+                               strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+                               continue;
 
-               rtd->cpu_dai = cpu_dai;
+                       rtd->cpu_dai = cpu_dai;
+               }
        }
 
        if (!rtd->cpu_dai) {
@@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                 * CODEC found, so find CODEC DAI from registered DAIs from
                 * this CODEC
                 */
-               list_for_each_entry(codec_dai, &dai_list, list) {
-                       if (codec->dev == codec_dai->dev &&
-                               !strcmp(codec_dai->name,
-                                       dai_link->codec_dai_name)) {
-
+               list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
+                       if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
                                rtd->codec_dai = codec_dai;
+                               break;
                        }
                }
 
@@ -1128,15 +1132,21 @@ static int soc_probe_codec(struct snd_soc_card *card,
                                          driver->num_dapm_widgets);
 
        /* Create DAPM widgets for each DAI stream */
-       list_for_each_entry(dai, &dai_list, list) {
-               if (dai->dev != codec->dev)
-                       continue;
-
+       list_for_each_entry(dai, &codec->component.dai_list, list)
                snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
-       }
 
        codec->dapm.idle_bias_off = driver->idle_bias_off;
 
+       if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
+               /* Set the default I/O up try regmap */
+               ret = snd_soc_codec_set_cache_io(codec, NULL);
+               if (ret < 0) {
+                       dev_err(codec->dev,
+                               "Failed to set cache I/O: %d\n", ret);
+                       goto err_probe;
+               }
+       }
+
        if (driver->probe) {
                ret = driver->probe(codec);
                if (ret < 0) {
@@ -1150,10 +1160,6 @@ static int soc_probe_codec(struct snd_soc_card *card,
                        codec->name);
        }
 
-       /* If the driver didn't set I/O up try regmap */
-       if (!codec->write && dev_get_regmap(codec->dev, NULL))
-               snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-
        if (driver->controls)
                snd_soc_add_codec_controls(codec, driver->controls,
                                     driver->num_controls);
@@ -1180,6 +1186,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
 {
        int ret = 0;
        const struct snd_soc_platform_driver *driver = platform->driver;
+       struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 
        platform->card = card;
@@ -1195,11 +1202,11 @@ static int soc_probe_platform(struct snd_soc_card *card,
                        driver->dapm_widgets, driver->num_dapm_widgets);
 
        /* Create DAPM widgets for each DAI stream */
-       list_for_each_entry(dai, &dai_list, list) {
-               if (dai->dev != platform->dev)
+       list_for_each_entry(component, &component_list, list) {
+               if (component->dev != platform->dev)
                        continue;
-
-               snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+               list_for_each_entry(dai, &component->dai_list, list)
+                       snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
        }
 
        platform->dapm.idle_bias_off = 1;
@@ -1246,7 +1253,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
        struct snd_soc_dai_link *dai_link = NULL;
        struct snd_soc_aux_dev *aux_dev = NULL;
        struct snd_soc_pcm_runtime *rtd;
-       const char *temp, *name;
+       const char *name;
        int ret = 0;
 
        if (!dailess) {
@@ -1260,10 +1267,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
        }
        rtd->card = card;
 
-       /* machine controls, routes and widgets are not prefixed */
-       temp = codec->name_prefix;
-       codec->name_prefix = NULL;
-
        /* do machine specific initialization */
        if (!dailess && dai_link->init)
                ret = dai_link->init(rtd);
@@ -1273,7 +1276,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
                dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);
                return ret;
        }
-       codec->name_prefix = temp;
 
        /* register the rtd device */
        rtd->codec = codec;
@@ -1654,7 +1656,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        }
 
        /* card bind complete so register a sound card */
-       ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+       ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        card->owner, 0, &card->snd_card);
        if (ret < 0) {
                dev_err(card->dev,
@@ -1662,7 +1664,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                        card->name, ret);
                goto base_error;
        }
-       card->snd_card->dev = card->dev;
 
        card->dapm.bias_level = SND_SOC_BIAS_OFF;
        card->dapm.dev = card->dev;
@@ -2571,10 +2572,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
-       uinfo->value.enumerated.items = e->max;
+       uinfo->value.enumerated.items = e->items;
 
-       if (uinfo->value.enumerated.item > e->max - 1)
-               uinfo->value.enumerated.item = e->max - 1;
+       if (uinfo->value.enumerated.item >= e->items)
+               uinfo->value.enumerated.item = e->items - 1;
        strlcpy(uinfo->value.enumerated.name,
                e->texts[uinfo->value.enumerated.item],
                sizeof(uinfo->value.enumerated.name));
@@ -2596,14 +2597,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val;
+       unsigned int val, item;
+       unsigned int reg_val;
 
-       val = snd_soc_read(codec, e->reg);
-       ucontrol->value.enumerated.item[0]
-               = (val >> e->shift_l) & e->mask;
-       if (e->shift_l != e->shift_r)
-               ucontrol->value.enumerated.item[1] =
-                       (val >> e->shift_r) & e->mask;
+       reg_val = snd_soc_read(codec, e->reg);
+       val = (reg_val >> e->shift_l) & e->mask;
+       item = snd_soc_enum_val_to_item(e, val);
+       ucontrol->value.enumerated.item[0] = item;
+       if (e->shift_l != e->shift_r) {
+               val = (reg_val >> e->shift_l) & e->mask;
+               item = snd_soc_enum_val_to_item(e, val);
+               ucontrol->value.enumerated.item[1] = item;
+       }
 
        return 0;
 }
@@ -2623,17 +2628,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int *item = ucontrol->value.enumerated.item;
        unsigned int val;
        unsigned int mask;
 
-       if (ucontrol->value.enumerated.item[0] > e->max - 1)
+       if (item[0] >= e->items)
                return -EINVAL;
-       val = ucontrol->value.enumerated.item[0] << e->shift_l;
+       val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
        mask = e->mask << e->shift_l;
        if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->max - 1)
+               if (item[1] >= e->items)
                        return -EINVAL;
-               val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+               val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
                mask |= e->mask << e->shift_r;
        }
 
@@ -2642,78 +2648,46 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
 EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
 
 /**
- * snd_soc_get_value_enum_double - semi enumerated double mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a double semi enumerated mixer.
+ * snd_soc_read_signed - Read a codec register and interprete as signed value
+ * @codec: codec
+ * @reg: Register to read
+ * @mask: Mask to use after shifting the register value
+ * @shift: Right shift of register value
+ * @sign_bit: Bit that describes if a number is negative or not.
  *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
+ * This functions reads a codec register. The register value is shifted right
+ * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
+ * the given registervalue into a signed integer if sign_bit is non-zero.
  *
- * Returns 0 for success.
+ * Returns the register value as signed int.
  */
-int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
+static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
+               unsigned int mask, unsigned int shift, unsigned int sign_bit)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int reg_val, val, mux;
+       int ret;
+       unsigned int val;
 
-       reg_val = snd_soc_read(codec, e->reg);
-       val = (reg_val >> e->shift_l) & e->mask;
-       for (mux = 0; mux < e->max; mux++) {
-               if (val == e->values[mux])
-                       break;
-       }
-       ucontrol->value.enumerated.item[0] = mux;
-       if (e->shift_l != e->shift_r) {
-               val = (reg_val >> e->shift_r) & e->mask;
-               for (mux = 0; mux < e->max; mux++) {
-                       if (val == e->values[mux])
-                               break;
-               }
-               ucontrol->value.enumerated.item[1] = mux;
-       }
+       val = (snd_soc_read(codec, reg) >> shift) & mask;
 
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
+       if (!sign_bit)
+               return val;
 
-/**
- * snd_soc_put_value_enum_double - semi enumerated double mixer put callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a double semi enumerated mixer.
- *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val;
-       unsigned int mask;
+       /* non-negative number */
+       if (!(val & BIT(sign_bit)))
+               return val;
 
-       if (ucontrol->value.enumerated.item[0] > e->max - 1)
-               return -EINVAL;
-       val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
-       mask = e->mask << e->shift_l;
-       if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->max - 1)
-                       return -EINVAL;
-               val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
-               mask |= e->mask << e->shift_r;
-       }
+       ret = val;
 
-       return snd_soc_update_bits_locked(codec, e->reg, mask, val);
+       /*
+        * The register most probably does not contain a full-sized int.
+        * Instead we have an arbitrary number of bits in a signed
+        * representation which has to be translated into a full-sized int.
+        * This is done by filling up all bits above the sign-bit.
+        */
+       ret |= ~((int)(BIT(sign_bit) - 1));
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
 
 /**
  * snd_soc_info_volsw - single mixer info callback
@@ -2743,7 +2717,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
 
        uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
        uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = platform_max;
+       uinfo->value.integer.max = platform_max - mc->min;
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -2769,11 +2743,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
        int max = mc->max;
+       int min = mc->min;
+       int sign_bit = mc->sign_bit;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
 
-       ucontrol->value.integer.value[0] =
-               (snd_soc_read(codec, reg) >> shift) & mask;
+       if (sign_bit)
+               mask = BIT(sign_bit + 1) - 1;
+
+       ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask,
+                       shift, sign_bit) - min;
        if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
@@ -2781,10 +2760,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        if (snd_soc_volsw_is_stereo(mc)) {
                if (reg == reg2)
                        ucontrol->value.integer.value[1] =
-                               (snd_soc_read(codec, reg) >> rshift) & mask;
+                               snd_soc_read_signed(codec, reg, mask, rshift,
+                                               sign_bit) - min;
                else
                        ucontrol->value.integer.value[1] =
-                               (snd_soc_read(codec, reg2) >> shift) & mask;
+                               snd_soc_read_signed(codec, reg2, mask, shift,
+                                               sign_bit) - min;
                if (invert)
                        ucontrol->value.integer.value[1] =
                                max - ucontrol->value.integer.value[1];
@@ -2815,20 +2796,25 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        unsigned int shift = mc->shift;
        unsigned int rshift = mc->rshift;
        int max = mc->max;
+       int min = mc->min;
+       unsigned int sign_bit = mc->sign_bit;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
        int err;
-       bool type_2r = 0;
+       bool type_2r = false;
        unsigned int val2 = 0;
        unsigned int val, val_mask;
 
-       val = (ucontrol->value.integer.value[0] & mask);
+       if (sign_bit)
+               mask = BIT(sign_bit + 1) - 1;
+
+       val = ((ucontrol->value.integer.value[0] + min) & mask);
        if (invert)
                val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (snd_soc_volsw_is_stereo(mc)) {
-               val2 = (ucontrol->value.integer.value[1] & mask);
+               val2 = ((ucontrol->value.integer.value[1] + min) & mask);
                if (invert)
                        val2 = max - val2;
                if (reg == reg2) {
@@ -2836,7 +2822,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
                        val |= val2 << rshift;
                } else {
                        val2 = val2 << shift;
-                       type_2r = 1;
+                       type_2r = true;
                }
        }
        err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
@@ -3234,7 +3220,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
        struct soc_bytes *params = (void *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        int ret, len;
-       unsigned int val;
+       unsigned int val, mask;
        void *data;
 
        if (!codec->using_regmap)
@@ -3264,12 +3250,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
                        ((u8 *)data)[0] |= val;
                        break;
                case 2:
-                       ((u16 *)data)[0] &= cpu_to_be16(~params->mask);
-                       ((u16 *)data)[0] |= cpu_to_be16(val);
+                       mask = ~params->mask;
+                       ret = regmap_parse_val(codec->control_data,
+                                                       &mask, &mask);
+                       if (ret != 0)
+                               goto out;
+
+                       ((u16 *)data)[0] &= mask;
+
+                       ret = regmap_parse_val(codec->control_data,
+                                                       &val, &val);
+                       if (ret != 0)
+                               goto out;
+
+                       ((u16 *)data)[0] |= val;
                        break;
                case 4:
-                       ((u32 *)data)[0] &= cpu_to_be32(~params->mask);
-                       ((u32 *)data)[0] |= cpu_to_be32(val);
+                       mask = ~params->mask;
+                       ret = regmap_parse_val(codec->control_data,
+                                                       &mask, &mask);
+                       if (ret != 0)
+                               goto out;
+
+                       ((u32 *)data)[0] &= mask;
+
+                       ret = regmap_parse_val(codec->control_data,
+                                                       &val, &val);
+                       if (ret != 0)
+                               goto out;
+
+                       ((u32 *)data)[0] |= val;
                        break;
                default:
                        ret = -EINVAL;
@@ -3608,6 +3618,30 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 
+/**
+ * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
+ * @slots: Number of slots in use.
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
+ *
+ * Generates the TDM tx and rx slot default masks for DAI.
+ */
+static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
+                                         unsigned int *tx_mask,
+                                         unsigned int *rx_mask)
+{
+       if (*tx_mask || *rx_mask)
+               return 0;
+
+       if (!slots)
+               return -EINVAL;
+
+       *tx_mask = (1 << slots) - 1;
+       *rx_mask = (1 << slots) - 1;
+
+       return 0;
+}
+
 /**
  * snd_soc_dai_set_tdm_slot - configure DAI TDM.
  * @dai: DAI
@@ -3622,11 +3656,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
+       if (dai->driver && dai->driver->ops->xlate_tdm_slot_mask)
+               dai->driver->ops->xlate_tdm_slot_mask(slots,
+                                               &tx_mask, &rx_mask);
+       else
+               snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+
        if (dai->driver && dai->driver->ops->set_tdm_slot)
                return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
                                slots, slot_width);
        else
-               return -EINVAL;
+               return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 
@@ -3882,95 +3922,42 @@ static inline char *fmt_multiple_name(struct device *dev,
 }
 
 /**
- * snd_soc_register_dai - Register a DAI with the ASoC core
+ * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
  *
- * @dai: DAI to register
+ * @component: The component for which the DAIs should be unregistered
  */
-static int snd_soc_register_dai(struct device *dev,
-               struct snd_soc_dai_driver *dai_drv)
+static void snd_soc_unregister_dais(struct snd_soc_component *component)
 {
-       struct snd_soc_codec *codec;
-       struct snd_soc_dai *dai;
+       struct snd_soc_dai *dai, *_dai;
 
-       dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev));
-
-       dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
-       if (dai == NULL)
-               return -ENOMEM;
-
-       /* create DAI component name */
-       dai->name = fmt_single_name(dev, &dai->id);
-       if (dai->name == NULL) {
+       list_for_each_entry_safe(dai, _dai, &component->dai_list, list) {
+               dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
+                       dai->name);
+               list_del(&dai->list);
+               kfree(dai->name);
                kfree(dai);
-               return -ENOMEM;
-       }
-
-       dai->dev = dev;
-       dai->driver = dai_drv;
-       dai->dapm.dev = dev;
-       if (!dai->driver->ops)
-               dai->driver->ops = &null_dai_ops;
-
-       mutex_lock(&client_mutex);
-
-       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);
-                       dai->codec = codec;
-                       break;
-               }
-       }
-
-       if (!dai->codec)
-               dai->dapm.idle_bias_off = 1;
-
-       list_add(&dai->list, &dai_list);
-
-       mutex_unlock(&client_mutex);
-
-       dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
-
-       return 0;
-}
-
-/**
- * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
- *
- * @dai: DAI to unregister
- */
-static void snd_soc_unregister_dai(struct device *dev)
-{
-       struct snd_soc_dai *dai;
-
-       list_for_each_entry(dai, &dai_list, list) {
-               if (dev == dai->dev)
-                       goto found;
        }
-       return;
-
-found:
-       mutex_lock(&client_mutex);
-       list_del(&dai->list);
-       mutex_unlock(&client_mutex);
-
-       dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
-       kfree(dai->name);
-       kfree(dai);
 }
 
 /**
- * snd_soc_register_dais - Register multiple DAIs with the ASoC core
+ * snd_soc_register_dais - Register a DAI with the ASoC core
  *
- * @dai: Array of DAIs to register
+ * @component: The component the DAIs are registered for
+ * @codec: The CODEC that the DAIs are registered for, NULL if the component is
+ *         not a CODEC.
+ * @dai_drv: DAI driver to use for the DAIs
  * @count: Number of DAIs
+ * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
+ *                     parent's name.
  */
-static int snd_soc_register_dais(struct device *dev,
-               struct snd_soc_dai_driver *dai_drv, size_t count)
+static int snd_soc_register_dais(struct snd_soc_component *component,
+       struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv,
+       size_t count, bool legacy_dai_naming)
 {
-       struct snd_soc_codec *codec;
+       struct device *dev = component->dev;
        struct snd_soc_dai *dai;
-       int i, ret = 0;
+       unsigned int i;
+       int ret;
 
        dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
 
@@ -3982,69 +3969,53 @@ static int snd_soc_register_dais(struct device *dev,
                        goto err;
                }
 
-               /* create DAI component name */
-               dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+               /*
+                * Back in the old days when we still had component-less DAIs,
+                * instead of having a static name, component-less DAIs would
+                * inherit the name of the parent device so it is possible to
+                * register multiple instances of the DAI. We still need to keep
+                * the same naming style even though those DAIs are not
+                * component-less anymore.
+                */
+               if (count == 1 && legacy_dai_naming) {
+                       dai->name = fmt_single_name(dev, &dai->id);
+               } else {
+                       dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+                       if (dai_drv[i].id)
+                               dai->id = dai_drv[i].id;
+                       else
+                               dai->id = i;
+               }
                if (dai->name == NULL) {
                        kfree(dai);
-                       ret = -EINVAL;
+                       ret = -ENOMEM;
                        goto err;
                }
 
+               dai->component = component;
+               dai->codec = codec;
                dai->dev = dev;
                dai->driver = &dai_drv[i];
-               if (dai->driver->id)
-                       dai->id = dai->driver->id;
-               else
-                       dai->id = i;
                dai->dapm.dev = dev;
                if (!dai->driver->ops)
                        dai->driver->ops = &null_dai_ops;
 
-               mutex_lock(&client_mutex);
-
-               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);
-                               dai->codec = codec;
-                               break;
-                       }
-               }
-
                if (!dai->codec)
                        dai->dapm.idle_bias_off = 1;
 
-               list_add(&dai->list, &dai_list);
-
-               mutex_unlock(&client_mutex);
+               list_add(&dai->list, &component->dai_list);
 
-               dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name);
+               dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
        }
 
        return 0;
 
 err:
-       for (i--; i >= 0; i--)
-               snd_soc_unregister_dai(dev);
+       snd_soc_unregister_dais(component);
 
        return ret;
 }
 
-/**
- * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
- *
- * @dai: Array of DAIs to unregister
- * @count: Number of DAIs
- */
-static void snd_soc_unregister_dais(struct device *dev, size_t count)
-{
-       int i;
-
-       for (i = 0; i < count; i++)
-               snd_soc_unregister_dai(dev);
-}
-
 /**
  * snd_soc_register_component - Register a component with the ASoC core
  *
@@ -4053,6 +4024,7 @@ static int
 __snd_soc_register_component(struct device *dev,
                             struct snd_soc_component *cmpnt,
                             const struct snd_soc_component_driver *cmpnt_drv,
+                            struct snd_soc_codec *codec,
                             struct snd_soc_dai_driver *dai_drv,
                             int num_dai, bool allow_single_dai)
 {
@@ -4075,20 +4047,10 @@ __snd_soc_register_component(struct device *dev,
        cmpnt->driver   = cmpnt_drv;
        cmpnt->dai_drv  = dai_drv;
        cmpnt->num_dai  = num_dai;
+       INIT_LIST_HEAD(&cmpnt->dai_list);
 
-       /*
-        * snd_soc_register_dai()  uses fmt_single_name(), and
-        * snd_soc_register_dais() uses fmt_multiple_name()
-        * for dai->name which is used for name based matching
-        *
-        * this function is used from cpu/codec.
-        * allow_single_dai flag can ignore "codec" driver reworking
-        * since it had been used snd_soc_register_dais(),
-        */
-       if ((1 == num_dai) && allow_single_dai)
-               ret = snd_soc_register_dai(dev, dai_drv);
-       else
-               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+       ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai,
+               allow_single_dai);
        if (ret < 0) {
                dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
                goto error_component_name;
@@ -4121,7 +4083,9 @@ int snd_soc_register_component(struct device *dev,
                return -ENOMEM;
        }
 
-       return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
+       cmpnt->ignore_pmdown_time = true;
+
+       return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL,
                                            dai_drv, num_dai, true);
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_component);
@@ -4141,7 +4105,7 @@ void snd_soc_unregister_component(struct device *dev)
        return;
 
 found:
-       snd_soc_unregister_dais(dev, cmpnt->num_dai);
+       snd_soc_unregister_dais(cmpnt);
 
        mutex_lock(&client_mutex);
        list_del(&cmpnt->list);
@@ -4319,7 +4283,7 @@ int snd_soc_register_codec(struct device *dev,
        codec->volatile_register = codec_drv->volatile_register;
        codec->readable_register = codec_drv->readable_register;
        codec->writable_register = codec_drv->writable_register;
-       codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
+       codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
@@ -4342,7 +4306,7 @@ int snd_soc_register_codec(struct device *dev,
        /* register component */
        ret = __snd_soc_register_component(dev, &codec->component,
                                           &codec_drv->component_driver,
-                                          dai_drv, num_dai, false);
+                                          codec, dai_drv, num_dai, false);
        if (ret < 0) {
                dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);
                goto fail_codec_name;
@@ -4417,6 +4381,122 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
 
+static const struct snd_soc_dapm_widget simple_widgets[] = {
+       SND_SOC_DAPM_MIC("Microphone", NULL),
+       SND_SOC_DAPM_LINE("Line", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+                                         const char *propname)
+{
+       struct device_node *np = card->dev->of_node;
+       struct snd_soc_dapm_widget *widgets;
+       const char *template, *wname;
+       int i, j, num_widgets, ret;
+
+       num_widgets = of_property_count_strings(np, propname);
+       if (num_widgets < 0) {
+               dev_err(card->dev,
+                       "ASoC: Property '%s' does not exist\n", propname);
+               return -EINVAL;
+       }
+       if (num_widgets & 1) {
+               dev_err(card->dev,
+                       "ASoC: Property '%s' length is not even\n", propname);
+               return -EINVAL;
+       }
+
+       num_widgets /= 2;
+       if (!num_widgets) {
+               dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
+                       propname);
+               return -EINVAL;
+       }
+
+       widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
+                              GFP_KERNEL);
+       if (!widgets) {
+               dev_err(card->dev,
+                       "ASoC: Could not allocate memory for widgets\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < num_widgets; i++) {
+               ret = of_property_read_string_index(np, propname,
+                       2 * i, &template);
+               if (ret) {
+                       dev_err(card->dev,
+                               "ASoC: Property '%s' index %d read error:%d\n",
+                               propname, 2 * i, ret);
+                       return -EINVAL;
+               }
+
+               for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
+                       if (!strncmp(template, simple_widgets[j].name,
+                                    strlen(simple_widgets[j].name))) {
+                               widgets[i] = simple_widgets[j];
+                               break;
+                       }
+               }
+
+               if (j >= ARRAY_SIZE(simple_widgets)) {
+                       dev_err(card->dev,
+                               "ASoC: DAPM widget '%s' is not supported\n",
+                               template);
+                       return -EINVAL;
+               }
+
+               ret = of_property_read_string_index(np, propname,
+                                                   (2 * i) + 1,
+                                                   &wname);
+               if (ret) {
+                       dev_err(card->dev,
+                               "ASoC: Property '%s' index %d read error:%d\n",
+                               propname, (2 * i) + 1, ret);
+                       return -EINVAL;
+               }
+
+               widgets[i].name = wname;
+       }
+
+       card->dapm_widgets = widgets;
+       card->num_dapm_widgets = num_widgets;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
+
+int snd_soc_of_parse_tdm_slot(struct device_node *np,
+                             unsigned int *slots,
+                             unsigned int *slot_width)
+{
+       u32 val;
+       int ret;
+
+       if (of_property_read_bool(np, "dai-tdm-slot-num")) {
+               ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
+               if (ret)
+                       return ret;
+
+               if (slots)
+                       *slots = val;
+       }
+
+       if (of_property_read_bool(np, "dai-tdm-slot-width")) {
+               ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
+               if (ret)
+                       return ret;
+
+               if (slot_width)
+                       *slot_width = val;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
+
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname)
 {
index b9dc6acbba8c55661eb0cf423a02fb9b7dda1c87..c8a780d0d057f43b08e74fc7c6d57f414e8aecde 100644 (file)
@@ -70,8 +70,6 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_aif_out] = 4,
        [snd_soc_dapm_mic] = 5,
        [snd_soc_dapm_mux] = 6,
-       [snd_soc_dapm_virt_mux] = 6,
-       [snd_soc_dapm_value_mux] = 6,
        [snd_soc_dapm_dac] = 7,
        [snd_soc_dapm_switch] = 8,
        [snd_soc_dapm_mixer] = 8,
@@ -102,8 +100,6 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_mic] = 7,
        [snd_soc_dapm_micbias] = 8,
        [snd_soc_dapm_mux] = 9,
-       [snd_soc_dapm_virt_mux] = 9,
-       [snd_soc_dapm_value_mux] = 9,
        [snd_soc_dapm_aif_in] = 10,
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai_in] = 10,
@@ -115,6 +111,12 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_post] = 14,
 };
 
+static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
+{
+       if (dapm->card && dapm->card->instantiated)
+               lockdep_assert_held(&dapm->card->dapm_mutex);
+}
+
 static void pop_wait(u32 pop_time)
 {
        if (pop_time)
@@ -146,15 +148,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
        return !list_empty(&w->dirty);
 }
 
-void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
+static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
 {
+       dapm_assert_locked(w->dapm);
+
        if (!dapm_dirty_widget(w)) {
                dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
                         w->name, reason);
                list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
        }
 }
-EXPORT_SYMBOL_GPL(dapm_mark_dirty);
 
 void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm)
 {
@@ -361,6 +364,8 @@ static void dapm_reset(struct snd_soc_card *card)
 {
        struct snd_soc_dapm_widget *w;
 
+       lockdep_assert_held(&card->dapm_mutex);
+
        memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
 
        list_for_each_entry(w, &card->widgets, list) {
@@ -386,7 +391,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
        return -1;
 }
 
-static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
+static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
+       unsigned int val)
 {
        if (w->codec)
                return snd_soc_write(w->codec, reg, val);
@@ -498,131 +504,40 @@ out:
        return ret;
 }
 
-/* set up initial codec paths */
-static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
-       struct snd_soc_dapm_path *p, int i)
+/* connect mux widget to its interconnecting audio paths */
+static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
+       struct snd_soc_dapm_path *path, const char *control_name,
+       const struct snd_kcontrol_new *kcontrol)
 {
-       switch (w->id) {
-       case snd_soc_dapm_switch:
-       case snd_soc_dapm_mixer:
-       case snd_soc_dapm_mixer_named_ctl: {
-               int val;
-               struct soc_mixer_control *mc = (struct soc_mixer_control *)
-                       w->kcontrol_news[i].private_value;
-               int reg = mc->reg;
-               unsigned int shift = mc->shift;
-               int max = mc->max;
-               unsigned int mask = (1 << fls(max)) - 1;
-               unsigned int invert = mc->invert;
-
-               if (reg != SND_SOC_NOPM) {
-                       soc_widget_read(w, reg, &val);
-                       val = (val >> shift) & mask;
-                       if (invert)
-                               val = max - val;
-                       p->connect = !!val;
-               } else {
-                       p->connect = 0;
-               }
-
-       }
-       break;
-       case snd_soc_dapm_mux: {
-               struct soc_enum *e = (struct soc_enum *)
-                       w->kcontrol_news[i].private_value;
-               int val, item;
-
-               soc_widget_read(w, e->reg, &val);
-               item = (val >> e->shift_l) & e->mask;
-
-               if (item < e->max && !strcmp(p->name, e->texts[item]))
-                       p->connect = 1;
-               else
-                       p->connect = 0;
-       }
-       break;
-       case snd_soc_dapm_virt_mux: {
-               struct soc_enum *e = (struct soc_enum *)
-                       w->kcontrol_news[i].private_value;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int val, item;
+       int i;
 
-               p->connect = 0;
+       if (e->reg != SND_SOC_NOPM) {
+               soc_widget_read(dest, e->reg, &val);
+               val = (val >> e->shift_l) & e->mask;
+               item = snd_soc_enum_val_to_item(e, val);
+       } else {
                /* since a virtual mux has no backing registers to
                 * decide which path to connect, it will try to match
                 * with the first enumeration.  This is to ensure
                 * that the default mux choice (the first) will be
                 * correctly powered up during initialization.
                 */
-               if (!strcmp(p->name, e->texts[0]))
-                       p->connect = 1;
+               item = 0;
        }
-       break;
-       case snd_soc_dapm_value_mux: {
-               struct soc_enum *e = (struct soc_enum *)
-                       w->kcontrol_news[i].private_value;
-               int val, item;
 
-               soc_widget_read(w, e->reg, &val);
-               val = (val >> e->shift_l) & e->mask;
-               for (item = 0; item < e->max; item++) {
-                       if (val == e->values[item])
-                               break;
-               }
-
-               if (item < e->max && !strcmp(p->name, e->texts[item]))
-                       p->connect = 1;
-               else
-                       p->connect = 0;
-       }
-       break;
-       /* does not affect routing - always connected */
-       case snd_soc_dapm_pga:
-       case snd_soc_dapm_out_drv:
-       case snd_soc_dapm_output:
-       case snd_soc_dapm_adc:
-       case snd_soc_dapm_input:
-       case snd_soc_dapm_siggen:
-       case snd_soc_dapm_dac:
-       case snd_soc_dapm_micbias:
-       case snd_soc_dapm_vmid:
-       case snd_soc_dapm_supply:
-       case snd_soc_dapm_regulator_supply:
-       case snd_soc_dapm_clock_supply:
-       case snd_soc_dapm_aif_in:
-       case snd_soc_dapm_aif_out:
-       case snd_soc_dapm_dai_in:
-       case snd_soc_dapm_dai_out:
-       case snd_soc_dapm_hp:
-       case snd_soc_dapm_mic:
-       case snd_soc_dapm_spk:
-       case snd_soc_dapm_line:
-       case snd_soc_dapm_dai_link:
-       case snd_soc_dapm_kcontrol:
-               p->connect = 1;
-       break;
-       /* does affect routing - dynamically connected */
-       case snd_soc_dapm_pre:
-       case snd_soc_dapm_post:
-               p->connect = 0;
-       break;
-       }
-}
-
-/* connect mux widget to its interconnecting audio paths */
-static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
-       struct snd_soc_dapm_path *path, const char *control_name,
-       const struct snd_kcontrol_new *kcontrol)
-{
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       int i;
-
-       for (i = 0; i < e->max; i++) {
+       for (i = 0; i < e->items; i++) {
                if (!(strcmp(control_name, e->texts[i]))) {
                        list_add(&path->list, &dapm->card->paths);
                        list_add(&path->list_sink, &dest->sources);
                        list_add(&path->list_source, &src->sinks);
                        path->name = (char*)e->texts[i];
-                       dapm_set_path_status(dest, path, 0);
+                       if (i == item)
+                               path->connect = 1;
+                       else
+                               path->connect = 0;
                        return 0;
                }
        }
@@ -630,6 +545,30 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
        return -ENODEV;
 }
 
+/* set up initial codec paths */
+static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
+       struct snd_soc_dapm_path *p, int i)
+{
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)
+               w->kcontrol_news[i].private_value;
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       unsigned int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
+       unsigned int val;
+
+       if (reg != SND_SOC_NOPM) {
+               soc_widget_read(w, reg, &val);
+               val = (val >> shift) & mask;
+               if (invert)
+                       val = max - val;
+               p->connect = !!val;
+       } else {
+               p->connect = 0;
+       }
+}
+
 /* connect mixer widget to its interconnecting audio paths */
 static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
@@ -644,7 +583,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
                        list_add(&path->list_sink, &dest->sources);
                        list_add(&path->list_source, &src->sinks);
                        path->name = dest->kcontrol_news[i].name;
-                       dapm_set_path_status(dest, path, i);
+                       dapm_set_mixer_path_status(dest, path, i);
                        return 0;
                }
        }
@@ -723,8 +662,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                                kcname_in_long_name = true;
                                break;
                        case snd_soc_dapm_mux:
-                       case snd_soc_dapm_virt_mux:
-                       case snd_soc_dapm_value_mux:
                                wname_in_long_name = true;
                                kcname_in_long_name = false;
                                break;
@@ -1823,6 +1760,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
        ASYNC_DOMAIN_EXCLUSIVE(async_domain);
        enum snd_soc_bias_level bias;
 
+       lockdep_assert_held(&card->dapm_mutex);
+
        trace_snd_soc_dapm_start(card);
 
        list_for_each_entry(d, &card->dapm_list, list) {
@@ -1897,10 +1836,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
 
        trace_snd_soc_dapm_walk_done(card);
 
-       /* Run all the bias changes in parallel */
-       list_for_each_entry(d, &card->dapm_list, list)
-               async_schedule_domain(dapm_pre_sequence_async, d,
-                                       &async_domain);
+       /* Run card bias changes at first */
+       dapm_pre_sequence_async(&card->dapm, 0);
+       /* Run other bias changes in parallel */
+       list_for_each_entry(d, &card->dapm_list, list) {
+               if (d != &card->dapm)
+                       async_schedule_domain(dapm_pre_sequence_async, d,
+                                               &async_domain);
+       }
        async_synchronize_full_domain(&async_domain);
 
        list_for_each_entry(w, &down_list, power_list) {
@@ -1920,10 +1863,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
        dapm_seq_run(card, &up_list, event, true);
 
        /* Run all the bias changes in parallel */
-       list_for_each_entry(d, &card->dapm_list, list)
-               async_schedule_domain(dapm_post_sequence_async, d,
-                                       &async_domain);
+       list_for_each_entry(d, &card->dapm_list, list) {
+               if (d != &card->dapm)
+                       async_schedule_domain(dapm_post_sequence_async, d,
+                                               &async_domain);
+       }
        async_synchronize_full_domain(&async_domain);
+       /* Run card bias changes at last */
+       dapm_post_sequence_async(&card->dapm, 0);
 
        /* do we need to notify any clients that DAPM event is complete */
        list_for_each_entry(d, &card->dapm_list, list) {
@@ -2110,6 +2057,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card,
        struct snd_soc_dapm_path *path;
        int found = 0;
 
+       lockdep_assert_held(&card->dapm_mutex);
+
        /* find dapm widget path assoc with kcontrol */
        dapm_kcontrol_for_each_path(path, kcontrol) {
                if (!path->name || !e->texts[mux])
@@ -2160,6 +2109,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
        struct snd_soc_dapm_path *path;
        int found = 0;
 
+       lockdep_assert_held(&card->dapm_mutex);
+
        /* find dapm widget path assoc with kcontrol */
        dapm_kcontrol_for_each_path(path, kcontrol) {
                found = 1;
@@ -2325,6 +2276,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
 {
        struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
+       dapm_assert_locked(dapm);
+
        if (!w) {
                dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
                return -EINVAL;
@@ -2341,18 +2294,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
 }
 
 /**
- * snd_soc_dapm_sync - scan and power dapm paths
+ * snd_soc_dapm_sync_unlocked - scan and power dapm paths
  * @dapm: DAPM context
  *
  * Walks all dapm audio paths and powers widgets according to their
  * stream or path usage.
  *
+ * Requires external locking.
+ *
  * Returns 0 for success.
  */
-int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
+int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
 {
-       int ret;
-
        /*
         * Suppress early reports (eg, jacks syncing their state) to avoid
         * silly DAPM runs during card startup.
@@ -2360,8 +2313,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
        if (!dapm->card || !dapm->card->instantiated)
                return 0;
 
+       return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
+
+/**
+ * snd_soc_dapm_sync - scan and power dapm paths
+ * @dapm: DAPM context
+ *
+ * Walks all dapm audio paths and powers widgets according to their
+ * stream or path usage.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
+{
+       int ret;
+
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
+       ret = snd_soc_dapm_sync_unlocked(dapm);
        mutex_unlock(&dapm->card->dapm_mutex);
        return ret;
 }
@@ -2444,8 +2414,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
                path->connect = 1;
                return 0;
        case snd_soc_dapm_mux:
-       case snd_soc_dapm_virt_mux:
-       case snd_soc_dapm_value_mux:
                ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
                        &wsink->kcontrol_news[0]);
                if (ret != 0)
@@ -2772,8 +2740,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
                        dapm_new_mixer(w);
                        break;
                case snd_soc_dapm_mux:
-               case snd_soc_dapm_virt_mux:
-               case snd_soc_dapm_value_mux:
                        dapm_new_mux(w);
                        break;
                case snd_soc_dapm_pga:
@@ -2935,213 +2901,75 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val;
-
-       val = snd_soc_read(codec, e->reg);
-       ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
-       if (e->shift_l != e->shift_r)
-               ucontrol->value.enumerated.item[1] =
-                       (val >> e->shift_r) & e->mask;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
-
-/**
- * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a dapm enumerated double mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-       struct snd_soc_card *card = codec->card;
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val, mux, change;
-       unsigned int mask;
-       struct snd_soc_dapm_update update;
-       int ret = 0;
-
-       if (ucontrol->value.enumerated.item[0] > e->max - 1)
-               return -EINVAL;
-       mux = ucontrol->value.enumerated.item[0];
-       val = mux << e->shift_l;
-       mask = e->mask << e->shift_l;
-       if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->max - 1)
-                       return -EINVAL;
-               val |= ucontrol->value.enumerated.item[1] << e->shift_r;
-               mask |= e->mask << e->shift_r;
-       }
-
-       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
-       change = snd_soc_test_bits(codec, e->reg, mask, val);
-       if (change) {
-               update.kcontrol = kcontrol;
-               update.reg = e->reg;
-               update.mask = mask;
-               update.val = val;
-               card->update = &update;
-
-               ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
-
-               card->update = NULL;
-       }
-
-       mutex_unlock(&card->dapm_mutex);
-
-       if (ret > 0)
-               soc_dpcm_runtime_update(card);
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
-
-/**
- * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
-
-/**
- * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-       struct snd_soc_card *card = codec->card;
-       unsigned int value;
-       struct soc_enum *e =
-               (struct soc_enum *)kcontrol->private_value;
-       int change;
-       int ret = 0;
-
-       if (ucontrol->value.enumerated.item[0] >= e->max)
-               return -EINVAL;
+       unsigned int reg_val, val;
 
-       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
-       value = ucontrol->value.enumerated.item[0];
-       change = dapm_kcontrol_set_value(kcontrol, value);
-       if (change)
-               ret = soc_dapm_mux_update_power(card, kcontrol, value, e);
-
-       mutex_unlock(&card->dapm_mutex);
-
-       if (ret > 0)
-               soc_dpcm_runtime_update(card);
-
-       return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
-
-/**
- * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
- *                                     callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a dapm semi enumerated double mixer control.
- *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int reg_val, val, mux;
+       if (e->reg != SND_SOC_NOPM)
+               reg_val = snd_soc_read(codec, e->reg);
+       else
+               reg_val = dapm_kcontrol_get_value(kcontrol);
 
-       reg_val = snd_soc_read(codec, e->reg);
        val = (reg_val >> e->shift_l) & e->mask;
-       for (mux = 0; mux < e->max; mux++) {
-               if (val == e->values[mux])
-                       break;
-       }
-       ucontrol->value.enumerated.item[0] = mux;
+       ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
        if (e->shift_l != e->shift_r) {
                val = (reg_val >> e->shift_r) & e->mask;
-               for (mux = 0; mux < e->max; mux++) {
-                       if (val == e->values[mux])
-                               break;
-               }
-               ucontrol->value.enumerated.item[1] = mux;
+               val = snd_soc_enum_val_to_item(e, val);
+               ucontrol->value.enumerated.item[1] = val;
        }
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 
 /**
- * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
- *                                     callback
+ * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
  * @kcontrol: mixer control
  * @ucontrol: control element information
  *
- * Callback to set the value of a dapm semi enumerated double mixer control.
- *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
+ * Callback to set the value of a dapm enumerated double mixer control.
  *
  * Returns 0 for success.
  */
-int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val, mux, change;
+       unsigned int *item = ucontrol->value.enumerated.item;
+       unsigned int val, change;
        unsigned int mask;
        struct snd_soc_dapm_update update;
        int ret = 0;
 
-       if (ucontrol->value.enumerated.item[0] > e->max - 1)
+       if (item[0] >= e->items)
                return -EINVAL;
-       mux = ucontrol->value.enumerated.item[0];
-       val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
+
+       val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
        mask = e->mask << e->shift_l;
        if (e->shift_l != e->shift_r) {
-               if (ucontrol->value.enumerated.item[1] > e->max - 1)
+               if (item[1] > e->items)
                        return -EINVAL;
-               val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
+               val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
                mask |= e->mask << e->shift_r;
        }
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(codec, e->reg, mask, val);
+       if (e->reg != SND_SOC_NOPM)
+               change = snd_soc_test_bits(codec, e->reg, mask, val);
+       else
+               change = dapm_kcontrol_set_value(kcontrol, val);
+
        if (change) {
-               update.kcontrol = kcontrol;
-               update.reg = e->reg;
-               update.mask = mask;
-               update.val = val;
-               card->update = &update;
+               if (e->reg != SND_SOC_NOPM) {
+                       update.kcontrol = kcontrol;
+                       update.reg = e->reg;
+                       update.mask = mask;
+                       update.val = val;
+                       card->update = &update;
+               }
 
-               ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
+               ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
 
                card->update = NULL;
        }
@@ -3153,7 +2981,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 
        return change;
 }
-EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 
 /**
  * snd_soc_dapm_info_pin_switch - Info for a pin switch
@@ -3283,8 +3111,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                w->power_check = dapm_generic_check_power;
                break;
        case snd_soc_dapm_mux:
-       case snd_soc_dapm_virt_mux:
-       case snd_soc_dapm_value_mux:
                w->power_check = dapm_generic_check_power;
                break;
        case snd_soc_dapm_dai_out:
@@ -4098,7 +3924,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
-static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
+static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
@@ -4138,14 +3964,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
  */
 void snd_soc_dapm_shutdown(struct snd_soc_card *card)
 {
-       struct snd_soc_codec *codec;
+       struct snd_soc_dapm_context *dapm;
 
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               soc_dapm_shutdown_codec(&codec->dapm);
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
-                       snd_soc_dapm_set_bias_level(&codec->dapm,
-                                                   SND_SOC_BIAS_OFF);
+       list_for_each_entry(dapm, &card->dapm_list, list) {
+               if (dapm != &card->dapm) {
+                       soc_dapm_shutdown_dapm(dapm);
+                       if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
+                               snd_soc_dapm_set_bias_level(dapm,
+                                                           SND_SOC_BIAS_OFF);
+               }
        }
+
+       soc_dapm_shutdown_dapm(&card->dapm);
+       if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               snd_soc_dapm_set_bias_level(&card->dapm,
+                                           SND_SOC_BIAS_OFF);
 }
 
 /* Module information */
index aa886cca3ecf94a8ecf2c360312cd3dc3bcb4184..260efc8466fc352cf70d08663799c7fde0758a2e 100644 (file)
 static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
                    unsigned int value)
 {
-       int ret;
-
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-           reg < codec->driver->reg_cache_size &&
-           !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
        return regmap_write(codec->control_data, reg, value);
 }
 
@@ -46,32 +31,18 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
        int ret;
        unsigned int val;
 
-       if (reg >= codec->driver->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg) ||
-           codec->cache_bypass) {
-               if (codec->cache_only)
-                       return -1;
-
-               ret = regmap_read(codec->control_data, reg, &val);
-               if (ret == 0)
-                       return val;
-               else
-                       return -1;
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
+       ret = regmap_read(codec->control_data, reg, &val);
+       if (ret == 0)
+               return val;
+       else
                return -1;
-       return val;
 }
 
 /**
  * snd_soc_codec_set_cache_io: Set up standard I/O functions.
  *
  * @codec: CODEC to configure.
- * @addr_bits: Number of bits of register address data.
- * @data_bits: Number of bits of data per register.
- * @control: Control bus used.
+ * @map: Register map to write to
  *
  * Register formats are frequently shared between many I2C and SPI
  * devices.  In order to promote code reuse the ASoC core provides
@@ -85,60 +56,36 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
  * volatile registers.
  */
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              int addr_bits, int data_bits,
-                              enum snd_soc_control_type control)
+                              struct regmap *regmap)
 {
-       struct regmap_config config;
        int ret;
 
-       memset(&config, 0, sizeof(config));
-       codec->write = hw_write;
-       codec->read = hw_read;
-
-       config.reg_bits = addr_bits;
-       config.val_bits = data_bits;
+       /* Device has made its own regmap arrangements */
+       if (!regmap)
+               codec->control_data = dev_get_regmap(codec->dev, NULL);
+       else
+               codec->control_data = regmap;
 
-       switch (control) {
-#if IS_ENABLED(CONFIG_REGMAP_I2C)
-       case SND_SOC_I2C:
-               codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),
-                                                     &config);
-               break;
-#endif
+       if (IS_ERR(codec->control_data))
+               return PTR_ERR(codec->control_data);
 
-#if IS_ENABLED(CONFIG_REGMAP_SPI)
-       case SND_SOC_SPI:
-               codec->control_data = regmap_init_spi(to_spi_device(codec->dev),
-                                                     &config);
-               break;
-#endif
-
-       case SND_SOC_REGMAP:
-               /* Device has made its own regmap arrangements */
-               codec->using_regmap = true;
-               if (!codec->control_data)
-                       codec->control_data = dev_get_regmap(codec->dev, NULL);
+       codec->write = hw_write;
+       codec->read = hw_read;
 
-               if (codec->control_data) {
-                       ret = regmap_get_val_bytes(codec->control_data);
-                       /* Errors are legitimate for non-integer byte
-                        * multiples */
-                       if (ret > 0)
-                               codec->val_bytes = ret;
-               }
-               break;
+       ret = regmap_get_val_bytes(codec->control_data);
+       /* Errors are legitimate for non-integer byte
+        * multiples */
+       if (ret > 0)
+               codec->val_bytes = ret;
 
-       default:
-               return -EINVAL;
-       }
+       codec->using_regmap = true;
 
-       return PTR_ERR_OR_ZERO(codec->control_data);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
 #else
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
-                              int addr_bits, int data_bits,
-                              enum snd_soc_control_type control)
+                              struct regmap *regmap)
 {
        return -ENOTSUPP;
 }
index 23d43dac91da2c0d9c6ad8bbf792036483da3fab..b903f822d1b2069062cae422d4a3a5f96f3ca342 100644 (file)
@@ -250,7 +250,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
                report = 0;
 
        if (gpio->jack_status_check)
-               report = gpio->jack_status_check();
+               report = gpio->jack_status_check(gpio->data);
 
        snd_soc_jack_report(jack, report, gpio->report);
 }
@@ -342,7 +342,8 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                gpio_export(gpios[i].gpio, false);
 
                /* Update initial jack status */
-               snd_soc_jack_gpio_detect(&gpios[i]);
+               schedule_delayed_work(&gpios[i].work,
+                                     msecs_to_jiffies(gpios[i].debounce_time));
        }
 
        return 0;
index 47e1ce771e65e0403e1ab743c677083c98452a8c..2cedf09f6d9613c7b34bb22888806fde598052c6 100644 (file)
 
 #define DPCM_MAX_BE_USERS      8
 
+/**
+ * snd_soc_runtime_activate() - Increment active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is activated
+ * @stream: Direction of the PCM stream
+ *
+ * Increments the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is opened.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       lockdep_assert_held(&rtd->pcm_mutex);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               cpu_dai->playback_active++;
+               codec_dai->playback_active++;
+       } else {
+               cpu_dai->capture_active++;
+               codec_dai->capture_active++;
+       }
+
+       cpu_dai->active++;
+       codec_dai->active++;
+       cpu_dai->component->active++;
+       codec_dai->component->active++;
+}
+
+/**
+ * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is deactivated
+ * @stream: Direction of the PCM stream
+ *
+ * Decrements the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is closed.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       lockdep_assert_held(&rtd->pcm_mutex);
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               cpu_dai->playback_active--;
+               codec_dai->playback_active--;
+       } else {
+               cpu_dai->capture_active--;
+               codec_dai->capture_active--;
+       }
+
+       cpu_dai->active--;
+       codec_dai->active--;
+       cpu_dai->component->active--;
+       codec_dai->component->active--;
+}
+
+/**
+ * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
+ * @rtd: The ASoC PCM runtime that should be checked.
+ *
+ * This function checks whether the power down delay should be ignored for a
+ * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
+ * been configured to ignore the delay, or if none of the components benefits
+ * from having the delay.
+ */
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
+{
+       if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
+               return true;
+
+       return rtd->cpu_dai->component->ignore_pmdown_time &&
+                       rtd->codec_dai->component->ignore_pmdown_time;
+}
+
 /**
  * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
  * @substream: the pcm substream
@@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                 runtime->hw.rate_max);
 
 dynamic:
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback_active++;
-               codec_dai->playback_active++;
-       } else {
-               cpu_dai->capture_active++;
-               codec_dai->capture_active++;
-       }
-       cpu_dai->active++;
-       codec_dai->active++;
-       rtd->codec->active++;
+
+       snd_soc_runtime_activate(rtd, substream->stream);
+
        mutex_unlock(&rtd->pcm_mutex);
        return 0;
 
@@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = rtd->codec;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback_active--;
-               codec_dai->playback_active--;
-       } else {
-               cpu_dai->capture_active--;
-               codec_dai->capture_active--;
-       }
-
-       cpu_dai->active--;
-       codec_dai->active--;
-       codec->active--;
+       snd_soc_runtime_deactivate(rtd, substream->stream);
 
        /* clear the corresponding DAIs rate when inactive */
        if (!cpu_dai->active)
@@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        cpu_dai->runtime = NULL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
-                   rtd->dai_link->ignore_pmdown_time) {
+               if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
                        /* powered down playback stream now */
                        snd_soc_dapm_stream_event(rtd,
                                                  SNDRV_PCM_STREAM_PLAYBACK,
index fe99f461aff0bfd97337f663ba2f13eecd626bbb..19cca043e6e46ffa60a31514eaa778f0a4ca46d5 100644 (file)
@@ -213,10 +213,7 @@ static int spdif_digital_mute(struct snd_soc_dai *dai, int mute)
 static int spdif_mute_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 = codec->card;
-       struct snd_soc_pcm_runtime *rtd = card->rtd;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
        struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
 
        ucontrol->value.integer.value[0] = host->saved_params.mute;
@@ -226,10 +223,7 @@ static int spdif_mute_get(struct snd_kcontrol *kcontrol,
 static int spdif_mute_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 = codec->card;
-       struct snd_soc_pcm_runtime *rtd = card->rtd;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
        struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (host->saved_params.mute == ucontrol->value.integer.value[0])
index 9f9c1856f822588b60843765cb4e57ec1eef9176..31198cf7f88d93829c2ccb7c7c5118583250f0b0 100644 (file)
@@ -105,7 +105,7 @@ config SND_SOC_TEGRA_TRIMSLICE
        tristate "SoC Audio support for TrimSlice board"
        depends on SND_SOC_TEGRA && I2C
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
-       select SND_SOC_TLV320AIC23
+       select SND_SOC_TLV320AIC23_I2C
        help
          Say Y or M here if you want to add support for SoC audio on the
          TrimSlice platform.
index cf5e1cfe818d9b6a8c4f980e4d5c9f23dacbe2c6..3b0fa12dbff7ea743b045cffb965f36621865112 100644 (file)
@@ -37,7 +37,6 @@
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
-#include "tegra_asoc_utils.h"
 #include "tegra20_ac97.h"
 
 #define DRV_NAME "tegra20-ac97"
@@ -306,7 +305,7 @@ static const struct regmap_config tegra20_ac97_regmap_config = {
        .readable_reg = tegra20_ac97_wr_rd_reg,
        .volatile_reg = tegra20_ac97_volatile_reg,
        .precious_reg = tegra20_ac97_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_ac97_platform_probe(struct platform_device *pdev)
@@ -376,18 +375,10 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        ac97->playback_dma_data.maxburst = 4;
 
-       ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
-       if (ret)
-               goto err_clk_put;
-
-       ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
-       if (ret)
-               goto err_asoc_utils_fini;
-
        ret = clk_prepare_enable(ac97->clk_ac97);
        if (ret) {
                dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
-               goto err_asoc_utils_fini;
+               goto err;
        }
 
        ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
@@ -419,8 +410,6 @@ err_unregister_component:
        snd_soc_unregister_component(&pdev->dev);
 err_clk_disable_unprepare:
        clk_disable_unprepare(ac97->clk_ac97);
-err_asoc_utils_fini:
-       tegra_asoc_utils_fini(&ac97->util_data);
 err_clk_put:
 err:
        snd_soc_set_ac97_ops(NULL);
@@ -434,8 +423,6 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
        tegra_pcm_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
 
-       tegra_asoc_utils_fini(&ac97->util_data);
-
        clk_disable_unprepare(ac97->clk_ac97);
 
        snd_soc_set_ac97_ops(NULL);
index 4acb3aaba29b746ad8f238fd26a84bf8d77cb6b1..0a39d823edcbea20bf6e5e961b1302a45c0eed3c 100644 (file)
@@ -90,6 +90,5 @@ struct tegra20_ac97 {
        struct regmap *regmap;
        int reset_gpio;
        int sync_gpio;
-       struct tegra_asoc_utils_data util_data;
 };
 #endif /* __TEGRA20_AC97_H__ */
index e72392927bd2ba3b7ca192e4ff75dde96b2488bd..a634f13b3ffc51456ea174c885196fe3dd26f3f2 100644 (file)
@@ -128,7 +128,7 @@ static const struct regmap_config tegra20_das_regmap_config = {
        .max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
        .writeable_reg = tegra20_das_wr_rd_reg,
        .readable_reg = tegra20_das_wr_rd_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_das_probe(struct platform_device *pdev)
index 42c1f6bfaf2e5bb2a4f2df89269be672b26e377c..79a9932ffe6ed49b2a99ba4b66c5b205b9877da4 100644 (file)
@@ -333,7 +333,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = {
        .readable_reg = tegra20_i2s_wr_rd_reg,
        .volatile_reg = tegra20_i2s_volatile_reg,
        .precious_reg = tegra20_i2s_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_i2s_platform_probe(struct platform_device *pdev)
index 8c7c1028e5797dbc9b23ec88b58a4cd840db1c5c..a0ce92400faf9e69331b2fdbf33d854c1b6f469c 100644 (file)
@@ -259,7 +259,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = {
        .readable_reg = tegra20_spdif_wr_rd_reg,
        .volatile_reg = tegra20_spdif_volatile_reg,
        .precious_reg = tegra20_spdif_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static int tegra20_spdif_platform_probe(struct platform_device *pdev)
index d6f4c9940e0c64fee63b1e447ba11b40a5cfc2d1..0db68f49f4d9ba02c05ff71379ade1dd8e98d17c 100644 (file)
@@ -471,7 +471,7 @@ static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
        .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
        .volatile_reg = tegra30_ahub_apbif_volatile_reg,
        .precious_reg = tegra30_ahub_apbif_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -490,7 +490,7 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
        .max_register = LAST_REG(AUDIO_RX),
        .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
        .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static struct tegra30_ahub_soc_data soc_data_tegra30 = {
index 49ad9366add86b008823f6091315d74d78f13aeb..f146c41dd3ecddb5b2d0f471eaa08e1b447235e7 100644 (file)
@@ -357,7 +357,7 @@ static const struct regmap_config tegra30_i2s_regmap_config = {
        .writeable_reg = tegra30_i2s_wr_rd_reg,
        .readable_reg = tegra30_i2s_wr_rd_reg,
        .volatile_reg = tegra30_i2s_volatile_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static const struct tegra30_i2s_soc_data tegra30_i2s_config = {
index 45b57892b6a53564e60434262b56fb0ae16b91df..25a7f8211ecf825bc0c3bd59cf9badcb82f6088a 100644 (file)
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
+#include "tegra_asoc_utils.h"
+
 #define DRV_NAME "tegra-snd-wm9712"
 
 struct tegra_wm9712 {
        struct platform_device *codec;
+       struct tegra_asoc_utils_data util_data;
 };
 
 static const struct snd_soc_dapm_widget tegra_wm9712_dapm_widgets[] = {
@@ -118,15 +121,25 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
 
        tegra_wm9712_dai.platform_of_node = tegra_wm9712_dai.cpu_of_node;
 
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto codec_unregister;
+
+       ret = tegra_asoc_utils_set_ac97_rate(&machine->util_data);
+       if (ret)
+               goto asoc_utils_fini;
+
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
                        ret);
-               goto codec_unregister;
+               goto asoc_utils_fini;
        }
 
        return 0;
 
+asoc_utils_fini:
+       tegra_asoc_utils_fini(&machine->util_data);
 codec_unregister:
        platform_device_del(machine->codec);
 codec_put:
@@ -141,6 +154,8 @@ static int tegra_wm9712_driver_remove(struct platform_device *pdev)
 
        snd_soc_unregister_card(card);
 
+       tegra_asoc_utils_fini(&machine->util_data);
+
        platform_device_unregister(machine->codec);
 
        return 0;
index 174d21fb56e2e326246231b30ce589a90919a9ff..4a85e14334726e43f513a95a0e85e4fd4c5dd2cd 100644 (file)
@@ -1019,8 +1019,8 @@ static int amd7930_sbus_probe(struct platform_device *op)
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev_num], id[dev_num], THIS_MODULE, 0,
-                             &card);
+       err = snd_card_new(&op->dev, index[dev_num], id[dev_num],
+                          THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
index dbb1b625eb2f59b5fd536fc33c0679b054095652..4e91bcaa36649943b430058d434dff5310c88cc3 100644 (file)
@@ -1565,7 +1565,8 @@ static int snd_cs4231_mixer(struct snd_card *card)
 
 static int dev;
 
-static int cs4231_attach_begin(struct snd_card **rcard)
+static int cs4231_attach_begin(struct platform_device *op,
+                              struct snd_card **rcard)
 {
        struct snd_card *card;
        struct snd_cs4231 *chip;
@@ -1581,8 +1582,8 @@ static int cs4231_attach_begin(struct snd_card **rcard)
                return -ENOENT;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_cs4231), &card);
+       err = snd_card_new(&op->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_cs4231), &card);
        if (err < 0)
                return err;
 
@@ -1869,7 +1870,7 @@ static int cs4231_sbus_probe(struct platform_device *op)
        struct snd_card *card;
        int err;
 
-       err = cs4231_attach_begin(&card);
+       err = cs4231_attach_begin(op, &card);
        if (err)
                return err;
 
@@ -2060,7 +2061,7 @@ static int cs4231_ebus_probe(struct platform_device *op)
        struct snd_card *card;
        int err;
 
-       err = cs4231_attach_begin(&card);
+       err = cs4231_attach_begin(op, &card);
        if (err)
                return err;
 
index eee7afcae37510db454f132c65f01ba5c34f776e..be1b1aa96b7ea2bd44d8ab0021a86eacb48a10e8 100644 (file)
@@ -2615,8 +2615,8 @@ static int dbri_probe(struct platform_device *op)
                return -ENODEV;
        }
 
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct snd_dbri), &card);
+       err = snd_card_new(&op->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct snd_dbri), &card);
        if (err < 0)
                return err;
 
index 25c38afaee4900463692c93b4182db82f93b36bd..39522367897caedb4be23f1f92579d31a4d1fe38 100644 (file)
@@ -927,8 +927,6 @@ static int snd_at73c213_dev_init(struct snd_card *card,
        if (retval)
                goto out_snd_dev;
 
-       snd_card_set_dev(card, &spi->dev);
-
        goto out;
 
 out_snd_dev:
@@ -966,8 +964,8 @@ static int snd_at73c213_probe(struct spi_device *spi)
 
        /* Allocate "card" using some unused identifiers. */
        snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);
-       retval = snd_card_create(-1, id, THIS_MODULE,
-                                sizeof(struct snd_at73c213), &card);
+       retval = snd_card_new(&spi->dev, -1, id, THIS_MODULE,
+                             sizeof(struct snd_at73c213), &card);
        if (retval < 0)
                goto out;
 
index 66edc4a7917f9bd08604f85ed98bc988d8e5d9f3..dcddfc354ba683c65a5266a0c448d625371d21b7 100644 (file)
@@ -106,7 +106,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
        }
        if (regidx < 0) {
                mutex_unlock(&register_mutex);
-               snd_printk(KERN_ERR PREFIX "too many cards registered.\n");
+               dev_err(&intf->dev, "too many cards registered.\n");
                return -ENODEV;
        }
        devices[regidx] = device;
@@ -121,20 +121,19 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
 
        /* if we are here, card can be registered in alsa. */
        if (usb_set_interface(device, 0, 0) != 0) {
-               snd_printk(KERN_ERR PREFIX "can't set first interface.\n");
+               dev_err(&intf->dev, "can't set first interface.\n");
                return -EIO;
        }
-       ret = snd_card_create(index[regidx], id[regidx], THIS_MODULE,
-                       sizeof(struct sfire_chip), &card);
+       ret = snd_card_new(&intf->dev, index[regidx], id[regidx],
+                          THIS_MODULE, sizeof(struct sfire_chip), &card);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "cannot create alsa card.\n");
+               dev_err(&intf->dev, "cannot create alsa card.\n");
                return ret;
        }
        strcpy(card->driver, "6FireUSB");
        strcpy(card->shortname, "TerraTec DMX6FireUSB");
        sprintf(card->longname, "%s at %d:%d", card->shortname,
                        device->bus->busnum, device->devnum);
-       snd_card_set_dev(card, &intf->dev);
 
        chip = card->private_data;
        chips[regidx] = chip;
@@ -169,7 +168,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
 
        ret = snd_card_register(card);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "cannot register card.");
+               dev_err(&intf->dev, "cannot register card.");
                usb6fire_chip_destroy(chip);
                return ret;
        }
index 23452ee617e11a5d304fffbd0da3e7bea805e0dc..161215d78d9520a98026574489095b47e6c95f85 100644 (file)
@@ -51,7 +51,7 @@ static void usb6fire_comm_receiver_handler(struct urb *urb)
                urb->status = 0;
                urb->actual_length = 0;
                if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
-                       snd_printk(KERN_WARNING PREFIX
+                       dev_warn(&urb->dev->dev,
                                        "comm data receiver aborted.\n");
        }
 }
@@ -179,7 +179,7 @@ int usb6fire_comm_init(struct sfire_chip *chip)
        if (ret < 0) {
                kfree(rt->receiver_buffer);
                kfree(rt);
-               snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
+               dev_err(&chip->dev->dev, "cannot create comm data receiver.");
                return ret;
        }
        chip->comm = rt;
index f6434c245720416f7fae946e62979a43f4b66333..184e3987ac24b2205709146d4bd8db7be8ed12bd 100644 (file)
@@ -194,7 +194,8 @@ static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
        int changed = 0;
 
        if (ch > 4) {
-               snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+               dev_err(&rt->chip->dev->dev,
+                       "Invalid channel in volume control.");
                return -EINVAL;
        }
 
@@ -222,7 +223,8 @@ static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
        unsigned int ch = kcontrol->private_value;
 
        if (ch > 4) {
-               snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+               dev_err(&rt->chip->dev->dev,
+                       "Invalid channel in volume control.");
                return -EINVAL;
        }
 
@@ -240,7 +242,8 @@ static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
        u8 value = 0;
 
        if (ch > 4) {
-               snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+               dev_err(&rt->chip->dev->dev,
+                       "Invalid channel in volume control.");
                return -EINVAL;
        }
 
@@ -265,7 +268,8 @@ static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
        u8 value = rt->output_mute >> ch;
 
        if (ch > 4) {
-               snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+               dev_err(&rt->chip->dev->dev,
+                       "Invalid channel in volume control.");
                return -EINVAL;
        }
 
@@ -594,14 +598,14 @@ int usb6fire_control_init(struct sfire_chip *chip)
        ret = usb6fire_control_add_virtual(rt, chip->card,
                "Master Playback Volume", vol_elements);
        if (ret) {
-               snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+               dev_err(&chip->dev->dev, "cannot add control.\n");
                kfree(rt);
                return ret;
        }
        ret = usb6fire_control_add_virtual(rt, chip->card,
                "Master Playback Switch", mute_elements);
        if (ret) {
-               snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+               dev_err(&chip->dev->dev, "cannot add control.\n");
                kfree(rt);
                return ret;
        }
@@ -611,7 +615,7 @@ int usb6fire_control_init(struct sfire_chip *chip)
                ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
                if (ret < 0) {
                        kfree(rt);
-                       snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+                       dev_err(&chip->dev->dev, "cannot add control.\n");
                        return ret;
                }
                i++;
index 780bf3f62d2800f3a8f9da7ffc8d011d0a6c3bd2..3b02e54b8f6db7e6e467edb9b4b8c2981c4dc8f1 100644 (file)
@@ -219,16 +219,16 @@ static int usb6fire_fw_ezusb_upload(
        ret = request_firmware(&fw, fwname, &device->dev);
        if (ret < 0) {
                kfree(rec);
-               snd_printk(KERN_ERR PREFIX "error requesting ezusb "
-                               "firmware %s.\n", fwname);
+               dev_err(&intf->dev,
+                       "error requesting ezusb firmware %s.\n", fwname);
                return ret;
        }
        ret = usb6fire_fw_ihex_init(fw, rec);
        if (ret < 0) {
                kfree(rec);
                release_firmware(fw);
-               snd_printk(KERN_ERR PREFIX "error validating ezusb "
-                               "firmware %s.\n", fwname);
+               dev_err(&intf->dev,
+                       "error validating ezusb firmware %s.\n", fwname);
                return ret;
        }
        /* upload firmware image */
@@ -237,8 +237,9 @@ static int usb6fire_fw_ezusb_upload(
        if (ret < 0) {
                kfree(rec);
                release_firmware(fw);
-               snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
-                               "firmware %s: begin message.\n", fwname);
+               dev_err(&intf->dev,
+                       "unable to upload ezusb firmware %s: begin message.\n",
+                       fwname);
                return ret;
        }
 
@@ -248,8 +249,9 @@ static int usb6fire_fw_ezusb_upload(
                if (ret < 0) {
                        kfree(rec);
                        release_firmware(fw);
-                       snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
-                                       "firmware %s: data urb.\n", fwname);
+                       dev_err(&intf->dev,
+                               "unable to upload ezusb firmware %s: data urb.\n",
+                               fwname);
                        return ret;
                }
        }
@@ -260,8 +262,9 @@ static int usb6fire_fw_ezusb_upload(
                ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
                                postdata, postlen);
                if (ret < 0) {
-                       snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
-                                       "firmware %s: post urb.\n", fwname);
+                       dev_err(&intf->dev,
+                               "unable to upload ezusb firmware %s: post urb.\n",
+                               fwname);
                        return ret;
                }
        }
@@ -269,8 +272,9 @@ static int usb6fire_fw_ezusb_upload(
        data = 0x00; /* resume ezusb cpu */
        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
-                               "firmware %s: end message.\n", fwname);
+               dev_err(&intf->dev,
+                       "unable to upload ezusb firmware %s: end message.\n",
+                       fwname);
                return ret;
        }
        return 0;
@@ -292,7 +296,7 @@ static int usb6fire_fw_fpga_upload(
 
        ret = request_firmware(&fw, fwname, &device->dev);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n",
+               dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
                                fwname);
                kfree(buffer);
                return -EIO;
@@ -305,8 +309,8 @@ static int usb6fire_fw_fpga_upload(
        if (ret < 0) {
                kfree(buffer);
                release_firmware(fw);
-               snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
-                               "begin urb.\n");
+               dev_err(&intf->dev,
+                       "unable to upload fpga firmware: begin urb.\n");
                return ret;
        }
 
@@ -318,8 +322,8 @@ static int usb6fire_fw_fpga_upload(
                if (ret < 0) {
                        release_firmware(fw);
                        kfree(buffer);
-                       snd_printk(KERN_ERR PREFIX "unable to upload fpga "
-                                       "firmware: fw urb.\n");
+                       dev_err(&intf->dev,
+                               "unable to upload fpga firmware: fw urb.\n");
                        return ret;
                }
        }
@@ -328,8 +332,8 @@ static int usb6fire_fw_fpga_upload(
 
        ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
-                               "end urb.\n");
+               dev_err(&intf->dev,
+                       "unable to upload fpga firmware: end urb.\n");
                return ret;
        }
        return 0;
@@ -338,7 +342,7 @@ static int usb6fire_fw_fpga_upload(
 /* check, if the firmware version the devices has currently loaded
  * is known by this driver. 'version' needs to have 4 bytes version
  * info data. */
-static int usb6fire_fw_check(u8 *version)
+static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
 {
        int i;
 
@@ -346,7 +350,7 @@ static int usb6fire_fw_check(u8 *version)
                if (!memcmp(version, known_fw_versions + i, 2))
                        return 0;
 
-       snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %4ph. "
+       dev_err(&intf->dev, "invalid fimware version in device: %4ph. "
                        "please reconnect to power. if this failure "
                        "still happens, check your firmware installation.",
                        version);
@@ -364,16 +368,16 @@ int usb6fire_fw_init(struct usb_interface *intf)
 
        ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "unable to receive device "
-                               "firmware state.\n");
+               dev_err(&intf->dev,
+                       "unable to receive device firmware state.\n");
                return ret;
        }
        if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
-               snd_printk(KERN_ERR PREFIX "unknown device firmware state "
-                               "received from device: ");
+               dev_err(&intf->dev,
+                       "unknown device firmware state received from device:");
                for (i = 0; i < 8; i++)
-                       snd_printk("%02x ", buffer[i]);
-               snd_printk("\n");
+                       printk(KERN_CONT "%02x ", buffer[i]);
+               printk(KERN_CONT "\n");
                return -EIO;
        }
        /* do we need fpga loader ezusb firmware? */
@@ -386,7 +390,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
        }
        /* do we need fpga firmware and application ezusb firmware? */
        else if (buffer[3] == 0x02) {
-               ret = usb6fire_fw_check(buffer + 4);
+               ret = usb6fire_fw_check(intf, buffer + 4);
                if (ret < 0)
                        return ret;
                ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
@@ -402,14 +406,14 @@ int usb6fire_fw_init(struct usb_interface *intf)
        }
        /* all fw loaded? */
        else if (buffer[3] == 0x03)
-               return usb6fire_fw_check(buffer + 4);
+               return usb6fire_fw_check(intf, buffer + 4);
        /* unknown data? */
        else {
-               snd_printk(KERN_ERR PREFIX "unknown device firmware state "
-                               "received from device: ");
+               dev_err(&intf->dev,
+                       "unknown device firmware state received from device: ");
                for (i = 0; i < 8; i++)
-                       snd_printk("%02x ", buffer[i]);
-               snd_printk("\n");
+                       printk(KERN_CONT "%02x ", buffer[i]);
+               printk(KERN_CONT "\n");
                return -EIO;
        }
        return 0;
index f3dd7266c391c7f17dae6220ed094f548a1d4507..3d410969553e2da2748b0587416fb5a8e8b41aab 100644 (file)
@@ -41,8 +41,9 @@ static void usb6fire_midi_out_handler(struct urb *urb)
 
                        ret = usb_submit_urb(urb, GFP_ATOMIC);
                        if (ret < 0)
-                               snd_printk(KERN_ERR PREFIX "midi out urb "
-                                               "submit failed: %d\n", ret);
+                               dev_err(&urb->dev->dev,
+                                       "midi out urb submit failed: %d\n",
+                                       ret);
                } else /* no more data to transmit */
                        rt->out = NULL;
        }
@@ -94,8 +95,9 @@ static void usb6fire_midi_out_trigger(
 
                        ret = usb_submit_urb(urb, GFP_ATOMIC);
                        if (ret < 0)
-                               snd_printk(KERN_ERR PREFIX "midi out urb "
-                                               "submit failed: %d\n", ret);
+                               dev_err(&urb->dev->dev,
+                                       "midi out urb submit failed: %d\n",
+                                       ret);
                        else
                                rt->out = alsa_sub;
                }
@@ -181,7 +183,7 @@ int usb6fire_midi_init(struct sfire_chip *chip)
        if (ret < 0) {
                kfree(rt->out_buffer);
                kfree(rt);
-               snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
+               dev_err(&chip->dev->dev, "unable to create midi.\n");
                return ret;
        }
        rt->instance->private_data = rt;
index b5eb97fdc842f79893adc8d359c4e519df82d700..ba40489b2de4fd26ab69ca8d9fc619f36c6e6493 100644 (file)
@@ -79,32 +79,35 @@ static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
        ctrl_rt->usb_streaming = false;
        ret = ctrl_rt->update_streaming(ctrl_rt);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error stopping streaming while "
-                               "setting samplerate %d.\n", rates[rt->rate]);
+               dev_err(&rt->chip->dev->dev,
+                       "error stopping streaming while setting samplerate %d.\n",
+                       rates[rt->rate]);
                return ret;
        }
 
        ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
-                               rates[rt->rate]);
+               dev_err(&rt->chip->dev->dev,
+                       "error setting samplerate %d.\n",
+                       rates[rt->rate]);
                return ret;
        }
 
        ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,
                        false, false);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error initializing channels "
-                               "while setting samplerate %d.\n",
-                               rates[rt->rate]);
+               dev_err(&rt->chip->dev->dev,
+                       "error initializing channels while setting samplerate %d.\n",
+                       rates[rt->rate]);
                return ret;
        }
 
        ctrl_rt->usb_streaming = true;
        ret = ctrl_rt->update_streaming(ctrl_rt);
        if (ret < 0) {
-               snd_printk(KERN_ERR PREFIX "error starting streaming while "
-                               "setting samplerate %d.\n", rates[rt->rate]);
+               dev_err(&rt->chip->dev->dev,
+                       "error starting streaming while setting samplerate %d.\n",
+                       rates[rt->rate]);
                return ret;
        }
 
@@ -124,7 +127,7 @@ static struct pcm_substream *usb6fire_pcm_get_substream(
                return &rt->playback;
        else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE)
                return &rt->capture;
-       snd_printk(KERN_ERR PREFIX "error getting pcm substream slot.\n");
+       dev_err(&rt->chip->dev->dev, "error getting pcm substream slot.\n");
        return NULL;
 }
 
@@ -257,7 +260,7 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
        else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
                dest = (u32 *) (urb->buffer);
        else {
-               snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+               dev_err(&rt->chip->dev->dev, "Unknown sample format.");
                return;
        }
 
@@ -307,8 +310,8 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
                }
 
        if (rt->stream_state == STREAM_DISABLED) {
-               snd_printk(KERN_ERR PREFIX "internal error: "
-                               "stream disabled in in-urb handler.\n");
+               dev_err(&rt->chip->dev->dev,
+                       "internal error: stream disabled in in-urb handler.\n");
                return;
        }
 
@@ -410,7 +413,7 @@ static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)
 
        if (!sub) {
                mutex_unlock(&rt->stream_mutex);
-               snd_printk(KERN_ERR PREFIX "invalid stream type.\n");
+               dev_err(&rt->chip->dev->dev, "invalid stream type.\n");
                return -EINVAL;
        }
 
@@ -481,8 +484,9 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
                                break;
                if (rt->rate == ARRAY_SIZE(rates)) {
                        mutex_unlock(&rt->stream_mutex);
-                       snd_printk("invalid rate %d in prepare.\n",
-                                       alsa_rt->rate);
+                       dev_err(&rt->chip->dev->dev,
+                               "invalid rate %d in prepare.\n",
+                               alsa_rt->rate);
                        return -EINVAL;
                }
 
@@ -494,8 +498,8 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
                ret = usb6fire_pcm_stream_start(rt);
                if (ret) {
                        mutex_unlock(&rt->stream_mutex);
-                       snd_printk(KERN_ERR PREFIX
-                                       "could not start pcm stream.\n");
+                       dev_err(&rt->chip->dev->dev,
+                               "could not start pcm stream.\n");
                        return ret;
                }
        }
@@ -650,7 +654,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
        if (ret < 0) {
                usb6fire_pcm_buffers_destroy(rt);
                kfree(rt);
-               snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
+               dev_err(&chip->dev->dev, "cannot create pcm instance.\n");
                return ret;
        }
 
@@ -662,8 +666,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
        if (ret) {
                usb6fire_pcm_buffers_destroy(rt);
                kfree(rt);
-               snd_printk(KERN_ERR PREFIX
-                               "error preallocating pcm buffers.\n");
+               dev_err(&chip->dev->dev,
+                       "error preallocating pcm buffers.\n");
                return ret;
        }
        rt->instance = pcm;
index bc55f708a696d11a3302e87557fa8dfef15ac5f0..b871ba407e4ec8aa710c5f79a99f2e52fb7741b7 100644 (file)
@@ -418,8 +418,9 @@ static int create_card(struct usb_device *usb_dev,
        if (devnum >= SNDRV_CARDS)
                return -ENODEV;
 
-       err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
-                             sizeof(struct snd_usb_caiaqdev), &card);
+       err = snd_card_new(&intf->dev,
+                          index[devnum], id[devnum], THIS_MODULE,
+                          sizeof(struct snd_usb_caiaqdev), &card);
        if (err < 0)
                return err;
 
@@ -429,7 +430,6 @@ static int create_card(struct usb_device *usb_dev,
        cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
                                  le16_to_cpu(usb_dev->descriptor.idProduct));
        spin_lock_init(&cdev->spinlock);
-       snd_card_set_dev(card, &intf->dev);
 
        *cardp = card;
        return 0;
index d979050e6a6afbc7daf9b65f666c2de10dbb6269..893d5a1afc3ce6bf854a61ef0c3f4f54cc552d0d 100644 (file)
@@ -139,8 +139,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
        struct usb_interface *iface = usb_ifnum_to_if(dev, interface);
 
        if (!iface) {
-               snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
-                          dev->devnum, ctrlif, interface);
+               dev_err(&dev->dev, "%u:%d : does not exist\n",
+                       ctrlif, interface);
                return -EINVAL;
        }
 
@@ -165,8 +165,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
        }
 
        if (usb_interface_claimed(iface)) {
-               snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n",
-                                               dev->devnum, ctrlif, interface);
+               dev_dbg(&dev->dev, "%d:%d: skipping, already claimed\n",
+                       ctrlif, interface);
                return -EINVAL;
        }
 
@@ -176,8 +176,9 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
                int err = snd_usbmidi_create(chip->card, iface,
                                             &chip->midi_list, NULL);
                if (err < 0) {
-                       snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n",
-                                               dev->devnum, ctrlif, interface);
+                       dev_err(&dev->dev,
+                               "%u:%d: cannot create sequencer device\n",
+                               ctrlif, interface);
                        return -EINVAL;
                }
                usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
@@ -188,14 +189,15 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
        if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
             altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
            altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) {
-               snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n",
-                                       dev->devnum, ctrlif, interface, altsd->bInterfaceClass);
+               dev_dbg(&dev->dev,
+                       "%u:%d: skipping non-supported interface %d\n",
+                       ctrlif, interface, altsd->bInterfaceClass);
                /* skip non-supported classes */
                return -EINVAL;
        }
 
        if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
-               snd_printk(KERN_ERR "low speed audio streaming not supported\n");
+               dev_err(&dev->dev, "low speed audio streaming not supported\n");
                return -EINVAL;
        }
 
@@ -228,26 +230,27 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
        protocol = altsd->bInterfaceProtocol;
 
        if (!control_header) {
-               snd_printk(KERN_ERR "cannot find UAC_HEADER\n");
+               dev_err(&dev->dev, "cannot find UAC_HEADER\n");
                return -EINVAL;
        }
 
        switch (protocol) {
        default:
-               snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n",
-                           protocol);
+               dev_warn(&dev->dev,
+                        "unknown interface protocol %#02x, assuming v1\n",
+                        protocol);
                /* fall through */
 
        case UAC_VERSION_1: {
                struct uac1_ac_header_descriptor *h1 = control_header;
 
                if (!h1->bInCollection) {
-                       snd_printk(KERN_INFO "skipping empty audio interface (v1)\n");
+                       dev_info(&dev->dev, "skipping empty audio interface (v1)\n");
                        return -EINVAL;
                }
 
                if (h1->bLength < sizeof(*h1) + h1->bInCollection) {
-                       snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n");
+                       dev_err(&dev->dev, "invalid UAC_HEADER (v1)\n");
                        return -EINVAL;
                }
 
@@ -277,7 +280,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
                }
 
                if (!assoc) {
-                       snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n");
+                       dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n");
                        return -EINVAL;
                }
 
@@ -328,7 +331,8 @@ static void remove_trailing_spaces(char *str)
 /*
  * create a chip instance and set its names.
  */
-static int snd_usb_audio_create(struct usb_device *dev, int idx,
+static int snd_usb_audio_create(struct usb_interface *intf,
+                               struct usb_device *dev, int idx,
                                const struct snd_usb_audio_quirk *quirk,
                                struct snd_usb_audio **rchip)
 {
@@ -350,13 +354,14 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        case USB_SPEED_SUPER:
                break;
        default:
-               snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
+               dev_err(&dev->dev, "unknown device speed %d\n", snd_usb_get_speed(dev));
                return -ENXIO;
        }
 
-       err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+       err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE,
+                          0, &card);
        if (err < 0) {
-               snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+               dev_err(&dev->dev, "cannot create card instance %d\n", idx);
                return err;
        }
 
@@ -497,7 +502,7 @@ snd_usb_audio_probe(struct usb_device *dev,
        for (i = 0; i < SNDRV_CARDS; i++) {
                if (usb_chip[i] && usb_chip[i]->dev == dev) {
                        if (usb_chip[i]->shutdown) {
-                               snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n");
+                               dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");
                                goto __error;
                        }
                        chip = usb_chip[i];
@@ -513,15 +518,15 @@ snd_usb_audio_probe(struct usb_device *dev,
                        if (enable[i] && ! usb_chip[i] &&
                            (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
                            (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
-                               if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
+                               if (snd_usb_audio_create(intf, dev, i, quirk,
+                                                        &chip) < 0) {
                                        goto __error;
                                }
-                               snd_card_set_dev(chip->card, &intf->dev);
                                chip->pm_intf = intf;
                                break;
                        }
                if (!chip) {
-                       printk(KERN_ERR "no available usb audio device\n");
+                       dev_err(&dev->dev, "no available usb audio device\n");
                        goto __error;
                }
        }
@@ -691,12 +696,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
        }
 
        list_for_each_entry(mixer, &chip->mixer_list, list)
-               snd_usb_mixer_inactivate(mixer);
+               snd_usb_mixer_suspend(mixer);
 
        return 0;
 }
 
-static int usb_audio_resume(struct usb_interface *intf)
+static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
 {
        struct snd_usb_audio *chip = usb_get_intfdata(intf);
        struct usb_mixer_interface *mixer;
@@ -711,7 +716,7 @@ static int usb_audio_resume(struct usb_interface *intf)
         * we just notify and restart the mixers
         */
        list_for_each_entry(mixer, &chip->mixer_list, list) {
-               err = snd_usb_mixer_activate(mixer);
+               err = snd_usb_mixer_resume(mixer, reset_resume);
                if (err < 0)
                        goto err_out;
        }
@@ -723,9 +728,20 @@ static int usb_audio_resume(struct usb_interface *intf)
 err_out:
        return err;
 }
+
+static int usb_audio_resume(struct usb_interface *intf)
+{
+       return __usb_audio_resume(intf, false);
+}
+
+static int usb_audio_reset_resume(struct usb_interface *intf)
+{
+       return __usb_audio_resume(intf, true);
+}
 #else
 #define usb_audio_suspend      NULL
 #define usb_audio_resume       NULL
+#define usb_audio_reset_resume NULL
 #endif         /* CONFIG_PM */
 
 static struct usb_device_id usb_audio_ids [] = {
@@ -747,6 +763,7 @@ static struct usb_driver usb_audio_driver = {
        .disconnect =   usb_audio_disconnect,
        .suspend =      usb_audio_suspend,
        .resume =       usb_audio_resume,
+       .reset_resume = usb_audio_reset_resume,
        .id_table =     usb_audio_ids,
        .supports_autosuspend = 1,
 };
index 86f80c60b21f91202c8c17c40d7981c3d7f873f8..03fed6611d9e83d489e2ab66d94320c84eed4c18 100644 (file)
@@ -115,9 +115,9 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
                return ret;
 
        if (ret != sizeof(pin)) {
-               snd_printk(KERN_ERR
-                       "usb-audio:%d: setting selector (id %d) unexpected length %d\n",
-                       chip->dev->devnum, selector_id, ret);
+               usb_audio_err(chip,
+                       "setting selector (id %d) unexpected length %d\n",
+                       selector_id, ret);
                return -EINVAL;
        }
 
@@ -126,9 +126,9 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
                return ret;
 
        if (ret != pin) {
-               snd_printk(KERN_ERR
-                       "usb-audio:%d: setting selector (id %d) to %x failed (current: %d)\n",
-                       chip->dev->devnum, selector_id, pin, ret);
+               usb_audio_err(chip,
+                       "setting selector (id %d) to %x failed (current: %d)\n",
+                       selector_id, pin, ret);
                return -EINVAL;
        }
 
@@ -158,7 +158,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
                              &data, sizeof(data));
 
        if (err < 0) {
-               snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
+               dev_warn(&dev->dev,
+                        "%s(): cannot get clock validity for id %d\n",
                           __func__, source_id);
                return 0;
        }
@@ -177,9 +178,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
        entity_id &= 0xff;
 
        if (test_and_set_bit(entity_id, visited)) {
-               snd_printk(KERN_WARNING
-                       "%s(): recursive clock topology detected, id %d.\n",
-                       __func__, entity_id);
+               usb_audio_warn(chip,
+                        "%s(): recursive clock topology detected, id %d.\n",
+                        __func__, entity_id);
                return -EINVAL;
        }
 
@@ -188,8 +189,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
        if (source) {
                entity_id = source->bClockID;
                if (validate && !uac_clock_source_is_valid(chip, entity_id)) {
-                       snd_printk(KERN_ERR "usb-audio:%d: clock source %d is not valid, cannot use\n",
-                                  chip->dev->devnum, entity_id);
+                       usb_audio_err(chip,
+                               "clock source %d is not valid, cannot use\n",
+                               entity_id);
                        return -ENXIO;
                }
                return entity_id;
@@ -208,7 +210,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
                /* Selector values are one-based */
 
                if (ret > selector->bNrInPins || ret < 1) {
-                       snd_printk(KERN_ERR
+                       usb_audio_err(chip,
                                "%s(): selector reported illegal value, id %d, ret %d\n",
                                __func__, selector->bClockID, ret);
 
@@ -237,9 +239,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
                        if (err < 0)
                                continue;
 
-                       snd_printk(KERN_INFO
-                               "usb-audio:%d: found and selected valid clock source %d\n",
-                               chip->dev->devnum, ret);
+                       usb_audio_info(chip,
+                                "found and selected valid clock source %d\n",
+                                ret);
                        return ret;
                }
 
@@ -296,8 +298,8 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
                                   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
                                   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
                                   data, sizeof(data))) < 0) {
-               snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
-                          dev->devnum, iface, fmt->altsetting, rate, ep);
+               dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n",
+                       iface, fmt->altsetting, rate, ep);
                return err;
        }
 
@@ -305,14 +307,14 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
                                   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
                                   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
                                   data, sizeof(data))) < 0) {
-               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
-                          dev->devnum, iface, fmt->altsetting, ep);
+               dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n",
+                       iface, fmt->altsetting, ep);
                return 0; /* some devices don't support reading */
        }
 
        crate = data[0] | (data[1] << 8) | (data[2] << 16);
        if (crate != rate) {
-               snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+               dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate);
                // runtime->rate = crate;
        }
 
@@ -332,8 +334,8 @@ static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface,
                              snd_usb_ctrl_intf(chip) | (clock << 8),
                              &data, sizeof(data));
        if (err < 0) {
-               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2): err %d\n",
-                          dev->devnum, iface, altsetting, err);
+               dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d\n",
+                        iface, altsetting, err);
                return 0;
        }
 
@@ -369,8 +371,9 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
                                      snd_usb_ctrl_intf(chip) | (clock << 8),
                                      &data, sizeof(data));
                if (err < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n",
-                                  dev->devnum, iface, fmt->altsetting, rate, err);
+                       usb_audio_err(chip,
+                               "%d:%d: cannot set freq %d (v2): err %d\n",
+                               iface, fmt->altsetting, rate, err);
                        return err;
                }
 
@@ -381,14 +384,14 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
 
        if (cur_rate != rate) {
                if (!writeable) {
-                       snd_printk(KERN_WARNING
-                                  "%d:%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
-                                  dev->devnum, iface, fmt->altsetting, rate, cur_rate);
+                       usb_audio_warn(chip,
+                                "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
+                                iface, fmt->altsetting, rate, cur_rate);
                        return -ENXIO;
                }
-               snd_printd(KERN_WARNING
-                          "current rate %d is different from the runtime rate %d\n",
-                          cur_rate, rate);
+               usb_audio_dbg(chip,
+                       "current rate %d is different from the runtime rate %d\n",
+                       cur_rate, rate);
        }
 
        /* Some devices doesn't respond to sample rate changes while the
index 83aabea259d7113d82d94d870bd04ebffd64b633..e70a87e0d9fe6402765afa0741b9f974b1259bec 100644 (file)
@@ -333,8 +333,9 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
 
                err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
                if (err < 0)
-                       snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n",
-                                  ctx->index, err, ctx->urb);
+                       usb_audio_err(ep->chip,
+                               "Unable to submit urb #%d: %d (urb %p)\n",
+                               ctx->index, err, ctx->urb);
                else
                        set_bit(ctx->index, &ep->active_mask);
        }
@@ -387,7 +388,7 @@ static void snd_complete_urb(struct urb *urb)
        if (err == 0)
                return;
 
-       snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
+       usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err);
        //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
 
 exit_clear:
@@ -426,13 +427,14 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
                if (ep->ep_num == ep_num &&
                    ep->iface == alts->desc.bInterfaceNumber &&
                    ep->altsetting == alts->desc.bAlternateSetting) {
-                       snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
+                       usb_audio_dbg(ep->chip,
+                                     "Re-using EP %x in iface %d,%d @%p\n",
                                        ep_num, ep->iface, ep->altsetting, ep);
                        goto __exit_unlock;
                }
        }
 
-       snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n",
+       usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n",
                    is_playback ? "playback" : "capture",
                    type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
                    ep_num);
@@ -496,8 +498,9 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
        } while (time_before(jiffies, end_time));
 
        if (alive)
-               snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
-                                       alive, ep->ep_num);
+               usb_audio_err(ep->chip,
+                       "timeout: still %d active urbs on EP #%x\n",
+                       alive, ep->ep_num);
        clear_bit(EP_FLAG_STOPPING, &ep->flags);
 
        return 0;
@@ -794,8 +797,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
        int err;
 
        if (ep->use_count != 0) {
-               snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
-                          ep->ep_num);
+               usb_audio_warn(ep->chip,
+                        "Unable to change format on ep #%x: already in use\n",
+                        ep->ep_num);
                return -EBUSY;
        }
 
@@ -830,8 +834,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
                err = -EINVAL;
        }
 
-       snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
-                  ep->ep_num, ep->type, ep->nurbs, err);
+       usb_audio_dbg(ep->chip,
+               "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
+               ep->ep_num, ep->type, ep->nurbs, err);
 
        return err;
 }
@@ -906,8 +911,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)
 
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err < 0) {
-                       snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
-                                  i, err, usb_error_string(err));
+                       usb_audio_err(ep->chip,
+                               "cannot submit urb %d, error %d: %s\n",
+                               i, err, usb_error_string(err));
                        goto __error;
                }
                set_bit(i, &ep->active_mask);
index d244fd3703d8382c85989b6934611e418600c728..8bcc87cf5667efbebc164e000f07cae23fc2a4c2 100644 (file)
@@ -74,8 +74,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
        if ((pcm_formats == 0) &&
            (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
                /* some devices don't define this correctly... */
-               snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
-                           chip->dev->devnum, fp->iface, fp->altsetting);
+               usb_audio_info(chip, "%u:%d : format type 0 is detected, processed as PCM\n",
+                       fp->iface, fp->altsetting);
                format = 1 << UAC_FORMAT_TYPE_I_PCM;
        }
        if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
@@ -83,9 +83,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                    sample_width == 24 && sample_bytes == 2)
                        sample_bytes = 3;
                else if (sample_width > sample_bytes * 8) {
-                       snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
-                                  chip->dev->devnum, fp->iface, fp->altsetting,
-                                  sample_width, sample_bytes);
+                       usb_audio_info(chip, "%u:%d : sample bitwidth %d in over sample bytes %d\n",
+                                fp->iface, fp->altsetting,
+                                sample_width, sample_bytes);
                }
                /* check the format byte size */
                switch (sample_bytes) {
@@ -108,9 +108,10 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                        pcm_formats |= SNDRV_PCM_FMTBIT_S32_LE;
                        break;
                default:
-                       snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
-                                  chip->dev->devnum, fp->iface, fp->altsetting,
-                                  sample_width, sample_bytes);
+                       usb_audio_info(chip,
+                                "%u:%d : unsupported sample bitwidth %d in %d bytes\n",
+                                fp->iface, fp->altsetting,
+                                sample_width, sample_bytes);
                        break;
                }
        }
@@ -132,8 +133,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW;
        }
        if (format & ~0x3f) {
-               snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, format);
+               usb_audio_info(chip,
+                        "%u:%d : unsupported format bits %#x\n",
+                        fp->iface, fp->altsetting, format);
        }
 
        pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes);
@@ -158,8 +160,9 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
        int nr_rates = fmt[offset];
 
        if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
-               snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
-                                  chip->dev->devnum, fp->iface, fp->altsetting);
+               usb_audio_err(chip,
+                       "%u:%d : invalid UAC_FORMAT_TYPE desc\n",
+                       fp->iface, fp->altsetting);
                return -EINVAL;
        }
 
@@ -171,7 +174,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
 
                fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
                if (fp->rate_table == NULL) {
-                       snd_printk(KERN_ERR "cannot malloc\n");
+                       usb_audio_err(chip, "cannot malloc\n");
                        return -ENOMEM;
                }
 
@@ -222,7 +225,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
  * get to know how many sample rates we have to expect.
  * Then fp->rate_table can be allocated and filled.
  */
-static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
+static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
+                                       struct audioformat *fp, int nr_triplets,
                                        const unsigned char *data)
 {
        int i, nr_rates = 0;
@@ -261,7 +265,7 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
 
                        nr_rates++;
                        if (nr_rates >= MAX_NR_RATES) {
-                               snd_printk(KERN_ERR "invalid uac2 rates\n");
+                               usb_audio_err(chip, "invalid uac2 rates\n");
                                break;
                        }
 
@@ -287,7 +291,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
        int clock = snd_usb_clock_find_source(chip, fp->clock, false);
 
        if (clock < 0) {
-               snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n",
+               dev_err(&dev->dev,
+                       "%s(): unable to find clock source (clock %d)\n",
                                __func__, clock);
                goto err;
        }
@@ -300,7 +305,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
                              tmp, sizeof(tmp));
 
        if (ret < 0) {
-               snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n",
+               dev_err(&dev->dev,
+                       "%s(): unable to retrieve number of sample rates (clock %d)\n",
                                __func__, clock);
                goto err;
        }
@@ -321,7 +327,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
                              data, data_size);
 
        if (ret < 0) {
-               snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n",
+               dev_err(&dev->dev,
+                       "%s(): unable to retrieve sample rate range (clock %d)\n",
                                __func__, clock);
                ret = -EINVAL;
                goto err_free;
@@ -332,7 +339,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
         * will have to deal with. */
        kfree(fp->rate_table);
        fp->rate_table = NULL;
-       fp->nr_rates = parse_uac2_sample_rate_range(fp, nr_triplets, data);
+       fp->nr_rates = parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);
 
        if (fp->nr_rates == 0) {
                /* SNDRV_PCM_RATE_CONTINUOUS */
@@ -348,7 +355,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
 
        /* Call the triplet parser again, but this time, fp->rate_table is
         * allocated, so the rates will be stored */
-       parse_uac2_sample_rate_range(fp, nr_triplets, data);
+       parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);
 
 err_free:
        kfree(data);
@@ -408,8 +415,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
        }
 
        if (fp->channels < 1) {
-               snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, fp->channels);
+               usb_audio_err(chip,
+                       "%u:%d : invalid channels %d\n",
+                       fp->iface, fp->altsetting, fp->channels);
                return -EINVAL;
        }
 
@@ -435,8 +443,9 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
                fp->formats = SNDRV_PCM_FMTBIT_MPEG;
                break;
        default:
-               snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, format);
+               usb_audio_info(chip,
+                        "%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n",
+                        fp->iface, fp->altsetting, format);
                fp->formats = SNDRV_PCM_FMTBIT_MPEG;
                break;
        }
@@ -449,7 +458,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
                struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
                brate = le16_to_cpu(fmt->wMaxBitRate);
                framesize = le16_to_cpu(fmt->wSamplesPerFrame);
-               snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
+               usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
                fp->frame_size = framesize;
                ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */
                break;
@@ -458,7 +467,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
                struct uac_format_type_ii_ext_descriptor *fmt = _fmt;
                brate = le16_to_cpu(fmt->wMaxBitRate);
                framesize = le16_to_cpu(fmt->wSamplesPerFrame);
-               snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
+               usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
                fp->frame_size = framesize;
                ret = parse_audio_format_rates_v2(chip, fp);
                break;
@@ -484,9 +493,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
                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",
-                          chip->dev->devnum, fp->iface, fp->altsetting,
-                          fmt->bFormatType);
+               usb_audio_info(chip,
+                        "%u:%d : format type %d is not supported yet\n",
+                        fp->iface, fp->altsetting,
+                        fmt->bFormatType);
                return -ENOTSUPP;
        }
        fp->fmt_type = fmt->bFormatType;
index b0dcb3924ce5139df00803072ac36ec4aa460888..2670d646bda91c2f26af878fc177eec1f772007c 100644 (file)
@@ -64,7 +64,8 @@ struct hiface_vendor_quirk {
        u8 extra_freq;
 };
 
-static int hiface_chip_create(struct usb_device *device, int idx,
+static int hiface_chip_create(struct usb_interface *intf,
+                             struct usb_device *device, int idx,
                              const struct hiface_vendor_quirk *quirk,
                              struct hiface_chip **rchip)
 {
@@ -76,7 +77,8 @@ static int hiface_chip_create(struct usb_device *device, int idx,
        *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);
+       ret = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE,
+                          sizeof(*chip), &card);
        if (ret < 0) {
                dev_err(&device->dev, "cannot create alsa card.\n");
                return ret;
@@ -132,12 +134,10 @@ static int hiface_chip_probe(struct usb_interface *intf,
                goto err;
        }
 
-       ret = hiface_chip_create(device, i, quirk, &chip);
+       ret = hiface_chip_create(intf, 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;
index b901f468b67ada579739828b382e165713de324e..9da74d2e8eeec5f40cfbfc80d892f72e79cc4e04 100644 (file)
@@ -191,16 +191,16 @@ static int snd_usbmidi_submit_urb(struct urb* urb, gfp_t flags)
 {
        int err = usb_submit_urb(urb, flags);
        if (err < 0 && err != -ENODEV)
-               snd_printk(KERN_ERR "usb_submit_urb: %d\n", err);
+               dev_err(&urb->dev->dev, "usb_submit_urb: %d\n", err);
        return err;
 }
 
 /*
  * Error handling for URB completion functions.
  */
-static int snd_usbmidi_urb_error(int status)
+static int snd_usbmidi_urb_error(const struct urb *urb)
 {
-       switch (status) {
+       switch (urb->status) {
        /* manually unlinked, or device gone */
        case -ENOENT:
        case -ECONNRESET:
@@ -213,7 +213,7 @@ static int snd_usbmidi_urb_error(int status)
        case -EILSEQ:
                return -EIO;
        default:
-               snd_printk(KERN_ERR "urb status %d\n", status);
+               dev_err(&urb->dev->dev, "urb status %d\n", urb->status);
                return 0; /* continue */
        }
 }
@@ -227,7 +227,7 @@ static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint* ep, int port
        struct usbmidi_in_port* port = &ep->ports[portidx];
 
        if (!port->substream) {
-               snd_printd("unexpected port %d!\n", portidx);
+               dev_dbg(&ep->umidi->dev->dev, "unexpected port %d!\n", portidx);
                return;
        }
        if (!test_bit(port->substream->number, &ep->umidi->input_triggered))
@@ -259,7 +259,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
                ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
                                                   urb->actual_length);
        } else {
-               int err = snd_usbmidi_urb_error(urb->status);
+               int err = snd_usbmidi_urb_error(urb);
                if (err < 0) {
                        if (err != -ENODEV) {
                                ep->error_resubmit = 1;
@@ -289,7 +289,7 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
        }
        spin_unlock(&ep->buffer_lock);
        if (urb->status < 0) {
-               int err = snd_usbmidi_urb_error(urb->status);
+               int err = snd_usbmidi_urb_error(urb);
                if (err < 0) {
                        if (err != -ENODEV)
                                mod_timer(&ep->umidi->error_timer,
@@ -1668,7 +1668,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
 
        struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number);
        if (!substream) {
-               snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number);
+               dev_err(&umidi->dev->dev, "substream %d:%d not found\n", stream, number);
                return;
        }
 
@@ -1717,7 +1717,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi,
                        }
                }
        }
-       snd_printdd(KERN_INFO "created %d output and %d input ports\n",
+       dev_dbg(&umidi->dev->dev, "created %d output and %d input ports\n",
                    out_ports, in_ports);
        return 0;
 }
@@ -1747,10 +1747,11 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
            ms_header->bLength >= 7 &&
            ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
            ms_header->bDescriptorSubtype == UAC_HEADER)
-               snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n",
+               dev_dbg(&umidi->dev->dev, "MIDIStreaming version %02x.%02x\n",
                            ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
        else
-               snd_printk(KERN_WARNING "MIDIStreaming interface descriptor not found\n");
+               dev_warn(&umidi->dev->dev,
+                        "MIDIStreaming interface descriptor not found\n");
 
        epidx = 0;
        for (i = 0; i < intfd->bNumEndpoints; ++i) {
@@ -1767,7 +1768,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
                if (usb_endpoint_dir_out(ep)) {
                        if (endpoints[epidx].out_ep) {
                                if (++epidx >= MIDI_MAX_ENDPOINTS) {
-                                       snd_printk(KERN_WARNING "too many endpoints\n");
+                                       dev_warn(&umidi->dev->dev,
+                                                "too many endpoints\n");
                                        break;
                                }
                        }
@@ -1782,12 +1784,13 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
                                 */
                                endpoints[epidx].out_interval = 1;
                        endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
-                       snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
+                       dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",
                                    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
                } else {
                        if (endpoints[epidx].in_ep) {
                                if (++epidx >= MIDI_MAX_ENDPOINTS) {
-                                       snd_printk(KERN_WARNING "too many endpoints\n");
+                                       dev_warn(&umidi->dev->dev,
+                                                "too many endpoints\n");
                                        break;
                                }
                        }
@@ -1797,7 +1800,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
                        else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)
                                endpoints[epidx].in_interval = 1;
                        endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
-                       snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
+                       dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",
                                    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
                }
        }
@@ -1865,7 +1868,7 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)
            (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
                return;
 
-       snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
+       dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n",
                    intfd->bAlternateSetting);
        usb_set_interface(umidi->dev, intfd->bInterfaceNumber,
                          intfd->bAlternateSetting);
@@ -2047,25 +2050,25 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
         * input bulk endpoints (at indices 1 and 3) which aren't used.
         */
        if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) {
-               snd_printdd(KERN_ERR "not enough endpoints\n");
+               dev_dbg(&umidi->dev->dev, "not enough endpoints\n");
                return -ENOENT;
        }
 
        epd = get_endpoint(hostif, 0);
        if (!usb_endpoint_dir_in(epd) || !usb_endpoint_xfer_int(epd)) {
-               snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n");
+               dev_dbg(&umidi->dev->dev, "endpoint[0] isn't interrupt\n");
                return -ENXIO;
        }
        epd = get_endpoint(hostif, 2);
        if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) {
-               snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");
+               dev_dbg(&umidi->dev->dev, "endpoint[2] isn't bulk output\n");
                return -ENXIO;
        }
        if (endpoint->out_cables > 0x0001) {
                epd = get_endpoint(hostif, 4);
                if (!usb_endpoint_dir_out(epd) ||
                    !usb_endpoint_xfer_bulk(epd)) {
-                       snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n");
+                       dev_dbg(&umidi->dev->dev, "endpoint[4] isn't bulk output\n");
                        return -ENXIO;
                }
        }
@@ -2289,7 +2292,7 @@ int snd_usbmidi_create(struct snd_card *card,
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
        default:
-               snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
+               dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type);
                err = -ENXIO;
                break;
        }
index 509315937f25a7ea7ef389b373b2ac3fd37651a5..a1bab149df4d06ab1ba9fb4c725c19974841eb5d 100644 (file)
@@ -1243,8 +1243,9 @@ static int ua101_probe(struct usb_interface *interface,
                mutex_unlock(&devices_mutex);
                return -ENOENT;
        }
-       err = snd_card_create(index[card_index], id[card_index], THIS_MODULE,
-                             sizeof(*ua), &card);
+       err = snd_card_new(&interface->dev,
+                          index[card_index], id[card_index], THIS_MODULE,
+                          sizeof(*ua), &card);
        if (err < 0) {
                mutex_unlock(&devices_mutex);
                return err;
@@ -1283,8 +1284,6 @@ static int ua101_probe(struct usb_interface *interface,
                }
        }
 
-       snd_card_set_dev(card, &interface->dev);
-
        err = detect_usb_format(ua);
        if (err < 0)
                goto probe_error;
index 44b0ba4feab3bd1b43100feb457e82e290ea26dc..d40a2850e2709f3a60100f707eb650a398fb73f3 100644 (file)
@@ -305,8 +305,9 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
                        goto out;
                }
        }
-       snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
-                   request, validx, idx, cval->val_type);
+       usb_audio_dbg(chip,
+               "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+               request, validx, idx, cval->val_type);
        err = -EINVAL;
 
  out:
@@ -351,8 +352,9 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
 
        if (ret < 0) {
 error:
-               snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
-                          request, validx, idx, cval->val_type);
+               usb_audio_err(chip,
+                       "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+                       request, validx, idx, cval->val_type);
                return ret;
        }
 
@@ -413,7 +415,8 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
        err = get_cur_mix_raw(cval, channel, value);
        if (err < 0) {
                if (!cval->mixer->ignore_ctl_error)
-                       snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n",
+                       usb_audio_dbg(cval->mixer->chip,
+                               "cannot get current value for control %d ch %d: err = %d\n",
                                   cval->control, channel, err);
                return err;
        }
@@ -444,7 +447,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
 
                /* FIXME */
                if (request != UAC_SET_CUR) {
-                       snd_printdd(KERN_WARNING "RANGE setting not yet supported\n");
+                       usb_audio_dbg(chip, "RANGE setting not yet supported\n");
                        return -EINVAL;
                }
 
@@ -470,7 +473,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
                        goto out;
                }
        }
-       snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
+       usb_audio_dbg(chip, "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
                    request, validx, idx, cval->val_type, buf[0], buf[1]);
        err = -EINVAL;
 
@@ -494,7 +497,8 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
                cval->ch_readonly & (1 << (channel - 1));
 
        if (read_only) {
-               snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n",
+               usb_audio_dbg(cval->mixer->chip,
+                             "%s(): channel %d of control %d is read_only\n",
                            __func__, channel, cval->control);
                return 0;
        }
@@ -560,7 +564,7 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
        while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
                kctl->id.index++;
        if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
-               snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
+               usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n", err);
                return err;
        }
        cval->elem_id = &kctl->id;
@@ -807,7 +811,8 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                                  struct snd_kcontrol *kctl)
 {
-       switch (cval->mixer->chip->usb_id) {
+       struct snd_usb_audio *chip = cval->mixer->chip;
+       switch (chip->usb_id) {
        case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
        case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
                if (strcmp(kctl->id.name, "Effect Duration") == 0) {
@@ -839,8 +844,8 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
        case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
        case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
                if (strcmp(kctl->id.name, "Effect Duration") == 0) {
-                       snd_printk(KERN_INFO
-                               "usb-audio: set quirk for FTU Effect Duration\n");
+                       usb_audio_info(chip,
+                                      "set quirk for FTU Effect Duration\n");
                        cval->min = 0x0000;
                        cval->max = 0x7f00;
                        cval->res = 0x0100;
@@ -848,8 +853,8 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                }
                if (strcmp(kctl->id.name, "Effect Volume") == 0 ||
                    strcmp(kctl->id.name, "Effect Feedback Volume") == 0) {
-                       snd_printk(KERN_INFO
-                               "usb-audio: set quirks for FTU Effect Feedback/Volume\n");
+                       usb_audio_info(chip,
+                                      "set quirks for FTU Effect Feedback/Volume\n");
                        cval->min = 0x00;
                        cval->max = 0x7f;
                        break;
@@ -867,7 +872,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
         */
                if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
                    cval->min == -15616) {
-                       snd_printk(KERN_INFO
+                       usb_audio_info(chip,
                                 "set volume quirk for UDA1321/N101 chip\n");
                        cval->max = -256;
                }
@@ -875,7 +880,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
 
        case USB_ID(0x046d, 0x09a4):
                if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
-                       snd_printk(KERN_INFO
+                       usb_audio_info(chip,
                                "set volume quirk for QuickCam E3500\n");
                        cval->min = 6080;
                        cval->max = 8768;
@@ -883,6 +888,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                }
                break;
 
+       case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
        case USB_ID(0x046d, 0x0808):
        case USB_ID(0x046d, 0x0809):
        case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
@@ -895,7 +901,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
         * Proboly there is some logitech magic behind this number --fishor
         */
                if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
-                       snd_printk(KERN_INFO
+                       usb_audio_info(chip,
                                "set resolution quirk: cval->res = 384\n");
                        cval->res = 384;
                }
@@ -931,7 +937,8 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
                }
                if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
                    get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
-                       snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
+                       usb_audio_err(cval->mixer->chip,
+                                     "%d:%d: cannot get min/max values for control %d (id %d)\n",
                                   cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
                        return -EINVAL;
                }
@@ -1195,7 +1202,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
 
        cval = kzalloc(sizeof(*cval), GFP_KERNEL);
        if (! cval) {
-               snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                return;
        }
        cval->mixer = state->mixer;
@@ -1224,7 +1231,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
 
        if (! kctl) {
-               snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                kfree(cval);
                return;
        }
@@ -1298,16 +1305,16 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
         * devices. It will definitively catch all buggy Logitech devices.
         */
        if (range > 384) {
-               snd_printk(KERN_WARNING "usb_audio: Warning! Unlikely big "
+               usb_audio_warn(state->chip, "Warning! Unlikely big "
                           "volume range (=%u), cval->res is probably wrong.",
                           range);
-               snd_printk(KERN_WARNING "usb_audio: [%d] FU [%s] ch = %d, "
+               usb_audio_warn(state->chip, "[%d] FU [%s] ch = %d, "
                           "val = %d/%d/%d", cval->id,
                           kctl->id.name, cval->channels,
                           cval->min, cval->max, cval->res);
        }
 
-       snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
+       usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
        snd_usb_mixer_add_control(state->mixer, kctl);
 }
@@ -1331,16 +1338,17 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
        if (state->mixer->protocol == UAC_VERSION_1) {
                csize = hdr->bControlSize;
                if (!csize) {
-                       snd_printdd(KERN_ERR "usbaudio: unit %u: "
-                                   "invalid bControlSize == 0\n", unitid);
+                       usb_audio_dbg(state->chip,
+                                     "unit %u: invalid bControlSize == 0\n",
+                                     unitid);
                        return -EINVAL;
                }
                channels = (hdr->bLength - 7) / csize - 1;
                bmaControls = hdr->bmaControls;
                if (hdr->bLength < 7 + csize) {
-                       snd_printk(KERN_ERR "usbaudio: unit %u: "
-                                  "invalid UAC_FEATURE_UNIT descriptor\n",
-                                  unitid);
+                       usb_audio_err(state->chip,
+                                     "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+                                     unitid);
                        return -EINVAL;
                }
        } else {
@@ -1349,9 +1357,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
                channels = (hdr->bLength - 6) / 4 - 1;
                bmaControls = ftr->bmaControls;
                if (hdr->bLength < 6 + csize) {
-                       snd_printk(KERN_ERR "usbaudio: unit %u: "
-                                  "invalid UAC_FEATURE_UNIT descriptor\n",
-                                  unitid);
+                       usb_audio_err(state->chip,
+                                     "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+                                     unitid);
                        return -EINVAL;
                }
        }
@@ -1369,14 +1377,14 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
        /* master configuration quirks */
        switch (state->chip->usb_id) {
        case USB_ID(0x08bb, 0x2702):
-               snd_printk(KERN_INFO
-                          "usbmixer: master volume quirk for PCM2702 chip\n");
+               usb_audio_info(state->chip,
+                              "usbmixer: master volume quirk for PCM2702 chip\n");
                /* disable non-functional volume control */
                master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
                break;
        case USB_ID(0x1130, 0xf211):
-               snd_printk(KERN_INFO
-                          "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
+               usb_audio_info(state->chip,
+                              "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
                /* disable non-functional volume control */
                channels = 0;
                break;
@@ -1478,7 +1486,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
 
        kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
        if (! kctl) {
-               snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                kfree(cval);
                return;
        }
@@ -1491,7 +1499,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
                len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
        append_ctl_name(kctl, " Volume");
 
-       snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
+       usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
        snd_usb_mixer_add_control(state->mixer, kctl);
 }
@@ -1508,12 +1516,12 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r
        int pin, ich, err;
 
        if (desc->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) {
-               snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid);
+               usb_audio_err(state->chip, "invalid MIXER UNIT descriptor %d\n", unitid);
                return -EINVAL;
        }
        /* no bmControls field (e.g. Maya44) -> ignore */
        if (desc->bLength <= 10 + input_pins) {
-               snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid);
+               usb_audio_dbg(state->chip, "MU %d has no bmControls field\n", unitid);
                return 0;
        }
 
@@ -1712,7 +1720,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
 
        if (desc->bLength < 13 || desc->bLength < 13 + num_ins ||
            desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {
-               snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid);
+               usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
                return -EINVAL;
        }
 
@@ -1738,7 +1746,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
                        continue;
                cval = kzalloc(sizeof(*cval), GFP_KERNEL);
                if (! cval) {
-                       snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+                       usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                        return -ENOMEM;
                }
                cval->mixer = state->mixer;
@@ -1770,7 +1778,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
 
                kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
                if (! kctl) {
-                       snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+                       usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                        kfree(cval);
                        return -ENOMEM;
                }
@@ -1792,7 +1800,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
                append_ctl_name(kctl, " ");
                append_ctl_name(kctl, valinfo->suffix);
 
-               snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
+               usb_audio_dbg(state->chip,
+                       "[%d] PU [%s] ch = %d, val = %d/%d\n",
                            cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
                if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
                        return err;
@@ -1917,7 +1926,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
        char **namelist;
 
        if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {
-               snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
+               usb_audio_err(state->chip,
+                       "invalid SELECTOR UNIT descriptor %d\n", unitid);
                return -EINVAL;
        }
 
@@ -1935,7 +1945,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
 
        cval = kzalloc(sizeof(*cval), GFP_KERNEL);
        if (! cval) {
-               snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                return -ENOMEM;
        }
        cval->mixer = state->mixer;
@@ -1954,7 +1964,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
 
        namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
        if (! namelist) {
-               snd_printk(KERN_ERR "cannot malloc\n");
+               usb_audio_err(state->chip, "cannot malloc\n");
                kfree(cval);
                return -ENOMEM;
        }
@@ -1964,7 +1974,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
                len = 0;
                namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
                if (! namelist[i]) {
-                       snd_printk(KERN_ERR "cannot malloc\n");
+                       usb_audio_err(state->chip, "cannot malloc\n");
                        while (i--)
                                kfree(namelist[i]);
                        kfree(namelist);
@@ -1981,7 +1991,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
 
        kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
        if (! kctl) {
-               snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
                kfree(namelist);
                kfree(cval);
                return -ENOMEM;
@@ -2009,7 +2019,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
                        append_ctl_name(kctl, " Playback Source");
        }
 
-       snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
+       usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
                    cval->id, kctl->id.name, desc->bNrInPins);
        if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
                return err;
@@ -2031,7 +2041,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
 
        p1 = find_audio_control_unit(state, unitid);
        if (!p1) {
-               snd_printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
+               usb_audio_err(state->chip, "unit %d not found!\n", unitid);
                return -EINVAL;
        }
 
@@ -2061,7 +2071,8 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
        case UAC2_EXTENSION_UNIT_V2:
                return parse_audio_extension_unit(state, unitid, p1);
        default:
-               snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+               usb_audio_err(state->chip,
+                       "unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
                return -EINVAL;
        }
 }
@@ -2209,8 +2220,9 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
        __u8 channel = value & 0xff;
 
        if (channel >= MAX_CHANNELS) {
-               snd_printk(KERN_DEBUG "%s(): bogus channel number %d\n",
-                               __func__, channel);
+               usb_audio_dbg(mixer->chip,
+                       "%s(): bogus channel number %d\n",
+                       __func__, channel);
                return;
        }
 
@@ -2239,8 +2251,9 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
                        break;
 
                default:
-                       snd_printk(KERN_DEBUG "unknown attribute %d in interrupt\n",
-                                               attribute);
+                       usb_audio_dbg(mixer->chip,
+                               "unknown attribute %d in interrupt\n",
+                               attribute);
                        break;
                } /* switch */
        }
@@ -2261,7 +2274,7 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
                for (status = urb->transfer_buffer;
                     len >= sizeof(*status);
                     len -= sizeof(*status), status++) {
-                       snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",
+                       dev_dbg(&urb->dev->dev, "status interrupt: %02x %02x\n",
                                                status->bStatusType,
                                                status->bOriginator);
 
@@ -2299,26 +2312,6 @@ requeue:
        }
 }
 
-/* stop any bus activity of a mixer */
-void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
-{
-       usb_kill_urb(mixer->urb);
-       usb_kill_urb(mixer->rc_urb);
-}
-
-int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
-{
-       int err;
-
-       if (mixer->urb) {
-               err = usb_submit_urb(mixer->urb, GFP_NOIO);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
 /* create the handler for the optional status interrupt endpoint */
 static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
 {
@@ -2393,7 +2386,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
 
        snd_usb_mixer_apply_create_quirk(mixer);
 
-       err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
+       err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops);
        if (err < 0)
                goto _error;
 
@@ -2417,3 +2410,82 @@ void snd_usb_mixer_disconnect(struct list_head *p)
        usb_kill_urb(mixer->urb);
        usb_kill_urb(mixer->rc_urb);
 }
+
+#ifdef CONFIG_PM
+/* stop any bus activity of a mixer */
+static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
+{
+       usb_kill_urb(mixer->urb);
+       usb_kill_urb(mixer->rc_urb);
+}
+
+static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
+{
+       int err;
+
+       if (mixer->urb) {
+               err = usb_submit_urb(mixer->urb, GFP_NOIO);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
+{
+       snd_usb_mixer_inactivate(mixer);
+       return 0;
+}
+
+static int restore_mixer_value(struct usb_mixer_elem_info *cval)
+{
+       int c, err, idx;
+
+       if (cval->cmask) {
+               idx = 0;
+               for (c = 0; c < MAX_CHANNELS; c++) {
+                       if (!(cval->cmask & (1 << c)))
+                               continue;
+                       if (cval->cached & (1 << c)) {
+                               err = set_cur_mix_value(cval, c + 1, idx,
+                                                       cval->cache_val[idx]);
+                               if (err < 0)
+                                       return err;
+                       }
+                       idx++;
+               }
+       } else {
+               /* master */
+               if (cval->cached) {
+                       err = set_cur_mix_value(cval, 0, 0, *cval->cache_val);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
+{
+       struct usb_mixer_elem_info *cval;
+       int id, err;
+
+       /* FIXME: any mixer quirks? */
+
+       if (reset_resume) {
+               /* restore cached mixer values */
+               for (id = 0; id < MAX_ID_ELEMS; id++) {
+                       for (cval = mixer->id_elems[id]; cval;
+                            cval = cval->next_id_elem) {
+                               err = restore_mixer_value(cval);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
+
+       return snd_usb_mixer_activate(mixer);
+}
+#endif
index aab80df201bdde8f6015d9b2451abb0c24efddb7..73b1f649447bdb8de4fdc18e9e0ce89407f10d6c 100644 (file)
@@ -63,8 +63,6 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
 
 int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
                                int request, int validx, int value_set);
-void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
-int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
 
 int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
                              struct snd_kcontrol *kctl);
@@ -72,4 +70,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
 int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
                          unsigned int size, unsigned int __user *_tlv);
 
+#ifdef CONFIG_PM
+int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
+int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
+#endif
+
 #endif /* __USBMIXER_H */
index f4b12c216f1cd55c2db4396746a5abc9f20ed302..f119a41ed9a94986cc1ec1ccd99b1aac3c400260 100644 (file)
@@ -600,8 +600,8 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
        up_read(&mixer->chip->shutdown_rwsem);
 
        if (ret < 0) {
-               snd_printk(KERN_ERR
-                          "unable to issue vendor read request (ret = %d)", ret);
+               dev_err(&dev->dev,
+                       "unable to issue vendor read request (ret = %d)", ret);
                return ret;
        }
 
@@ -631,8 +631,8 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
        up_read(&mixer->chip->shutdown_rwsem);
 
        if (ret < 0) {
-               snd_printk(KERN_ERR
-                          "unable to issue vendor write request (ret = %d)", ret);
+               dev_err(&dev->dev,
+                       "unable to issue vendor write request (ret = %d)", ret);
                return ret;
        }
 
@@ -1699,7 +1699,7 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
                        snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
                break;
        default:
-               snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid);
+               usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid);
                break;
        }
 }
index ca3256d6fde3d1206ffe3fc7313305561438f611..49de5c1284f6c7d4df3cecaa227316fa8dbd830a 100644 (file)
@@ -166,8 +166,8 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
                                   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
                                   UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep,
                                   data, sizeof(data))) < 0) {
-               snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
-                          dev->devnum, iface, ep);
+               usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n",
+                             iface, ep);
                return err;
        }
 
@@ -187,8 +187,8 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
                                   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
                                   UAC2_EP_CS_PITCH << 8, 0,
                                   data, sizeof(data))) < 0) {
-               snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
-                          dev->devnum, iface, fmt->altsetting);
+               usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n",
+                             iface, fmt->altsetting);
                return err;
        }
 
@@ -226,7 +226,7 @@ static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
        if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
                struct snd_usb_endpoint *ep = subs->data_endpoint;
 
-               snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);
+               dev_dbg(&subs->dev->dev, "Starting data EP @%p\n", ep);
 
                ep->data_subs = subs;
                err = snd_usb_endpoint_start(ep, can_sleep);
@@ -247,16 +247,15 @@ static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
                                                subs->sync_endpoint->altsetting);
                        if (err < 0) {
                                clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
-                               snd_printk(KERN_ERR
-                                          "%d:%d:%d: cannot set interface (%d)\n",
-                                          subs->dev->devnum,
+                               dev_err(&subs->dev->dev,
+                                          "%d:%d: cannot set interface (%d)\n",
                                           subs->sync_endpoint->iface,
                                           subs->sync_endpoint->altsetting, err);
                                return -EIO;
                        }
                }
 
-               snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);
+               dev_dbg(&subs->dev->dev, "Starting sync EP @%p\n", ep);
 
                ep->sync_slave = subs->data_endpoint;
                err = snd_usb_endpoint_start(ep, can_sleep);
@@ -410,8 +409,9 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
        if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
            (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
             get_endpoint(alts, 1)->bSynchAddress != 0)) {
-               snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
-                          dev->devnum, fmt->iface, fmt->altsetting,
+               dev_err(&dev->dev,
+                       "%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
+                          fmt->iface, fmt->altsetting,
                           get_endpoint(alts, 1)->bmAttributes,
                           get_endpoint(alts, 1)->bLength,
                           get_endpoint(alts, 1)->bSynchAddress);
@@ -421,8 +421,9 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
        if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
            ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
             (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
-               snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
-                          dev->devnum, fmt->iface, fmt->altsetting,
+               dev_err(&dev->dev,
+                       "%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
+                          fmt->iface, fmt->altsetting,
                           is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
                return -EINVAL;
        }
@@ -469,8 +470,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        if (subs->interface >= 0 && subs->interface != fmt->iface) {
                err = usb_set_interface(subs->dev, subs->interface, 0);
                if (err < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed (%d)\n",
-                               dev->devnum, fmt->iface, fmt->altsetting, err);
+                       dev_err(&dev->dev,
+                               "%d:%d: return to setting 0 failed (%d)\n",
+                               fmt->iface, fmt->altsetting, err);
                        return -EIO;
                }
                subs->interface = -1;
@@ -482,12 +484,13 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
            subs->altset_idx != fmt->altset_idx) {
                err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
                if (err < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed (%d)\n",
-                                  dev->devnum, fmt->iface, fmt->altsetting, err);
+                       dev_err(&dev->dev,
+                               "%d:%d: usb_set_interface failed (%d)\n",
+                               fmt->iface, fmt->altsetting, err);
                        return -EIO;
                }
-               snd_printdd(KERN_INFO "setting usb interface %d:%d\n",
-                               fmt->iface, fmt->altsetting);
+               dev_dbg(&dev->dev, "setting usb interface %d:%d\n",
+                       fmt->iface, fmt->altsetting);
                subs->interface = fmt->iface;
                subs->altset_idx = fmt->altset_idx;
 
@@ -523,20 +526,23 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
  * - Requested PCM format is not supported.
  * - Requested sample rate is not supported.
  */
-static int match_endpoint_audioformats(struct audioformat *fp,
-       struct audioformat *match, int rate,
-       snd_pcm_format_t pcm_format)
+static int match_endpoint_audioformats(struct snd_usb_substream *subs,
+                                      struct audioformat *fp,
+                                      struct audioformat *match, int rate,
+                                      snd_pcm_format_t pcm_format)
 {
        int i;
        int score = 0;
 
        if (fp->channels < 1) {
-               snd_printdd("%s: (fmt @%p) no channels\n", __func__, fp);
+               dev_dbg(&subs->dev->dev,
+                       "%s: (fmt @%p) no channels\n", __func__, fp);
                return 0;
        }
 
        if (!(fp->formats & pcm_format_to_bits(pcm_format))) {
-               snd_printdd("%s: (fmt @%p) no match for format %d\n", __func__,
+               dev_dbg(&subs->dev->dev,
+                       "%s: (fmt @%p) no match for format %d\n", __func__,
                        fp, pcm_format);
                return 0;
        }
@@ -548,7 +554,8 @@ static int match_endpoint_audioformats(struct audioformat *fp,
                }
        }
        if (!score) {
-               snd_printdd("%s: (fmt @%p) no match for rate %d\n", __func__,
+               dev_dbg(&subs->dev->dev,
+                       "%s: (fmt @%p) no match for rate %d\n", __func__,
                        fp, rate);
                return 0;
        }
@@ -556,7 +563,8 @@ static int match_endpoint_audioformats(struct audioformat *fp,
        if (fp->channels == match->channels)
                score++;
 
-       snd_printdd("%s: (fmt @%p) score %d\n", __func__, fp, score);
+       dev_dbg(&subs->dev->dev,
+               "%s: (fmt @%p) score %d\n", __func__, fp, score);
 
        return score;
 }
@@ -587,7 +595,8 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
 
        /* Try to find the best matching audioformat. */
        list_for_each_entry(fp, &sync_subs->fmt_list, list) {
-               int score = match_endpoint_audioformats(fp, subs->cur_audiofmt,
+               int score = match_endpoint_audioformats(subs,
+                                                       fp, subs->cur_audiofmt,
                        subs->cur_rate, subs->pcm_format);
 
                if (score > cur_score) {
@@ -597,7 +606,8 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
        }
 
        if (unlikely(sync_fp == NULL)) {
-               snd_printk(KERN_ERR "%s: no valid audioformat for sync ep %x found\n",
+               dev_err(&subs->dev->dev,
+                       "%s: no valid audioformat for sync ep %x found\n",
                        __func__, sync_subs->ep_num);
                return -EINVAL;
        }
@@ -609,7 +619,8 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
        if (sync_fp->channels != subs->channels) {
                sync_period_bytes = (subs->period_bytes / subs->channels) *
                        sync_fp->channels;
-               snd_printdd("%s: adjusted sync ep period bytes (%d -> %d)\n",
+               dev_dbg(&subs->dev->dev,
+                       "%s: adjusted sync ep period bytes (%d -> %d)\n",
                        __func__, subs->period_bytes, sync_period_bytes);
        }
 
@@ -685,7 +696,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 
        fmt = find_format(subs);
        if (!fmt) {
-               snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
+               dev_dbg(&subs->dev->dev,
+                       "cannot set format: format = %#x, rate = %d, channels = %d\n",
                           subs->pcm_format, subs->cur_rate, subs->channels);
                return -EINVAL;
        }
@@ -742,7 +754,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        int ret;
 
        if (! subs->cur_audiofmt) {
-               snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
+               dev_err(&subs->dev->dev, "no format is specified!\n");
                return -ENXIO;
        }
 
@@ -1235,7 +1247,8 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
        for (i = 0; i < urb->number_of_packets; i++) {
                cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj;
                if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
-                       snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+                       dev_dbg(&subs->dev->dev, "frame %d active: %d\n",
+                               i, urb->iso_frame_desc[i].status);
                        // continue;
                }
                bytes = urb->iso_frame_desc[i].actual_length;
@@ -1245,7 +1258,8 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
                if (bytes % (runtime->sample_bits >> 3) != 0) {
                        int oldbytes = bytes;
                        bytes = frames * stride;
-                       snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+                       dev_warn(&subs->dev->dev,
+                                "Corrected urb data len. %d->%d\n",
                                                        oldbytes, bytes);
                }
                /* update the current pointer */
@@ -1488,7 +1502,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
         * on two reads of a counter updated every ms.
         */
        if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
-               snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
+               dev_dbg(&subs->dev->dev,
+                       "delay: estimated %d, actual %d\n",
                        est_delay, subs->last_delay);
 
        if (!subs->running) {
index 89730707614c3686be440a7d763700e375cd1f81..7c57f2268dd70a67c04c6addc2cf80c281121cda 100644 (file)
@@ -110,7 +110,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
        altsd = get_iface_desc(alts);
        err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
        if (err < 0) {
-               snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
+               usb_audio_err(chip, "cannot setup if %d: error %d\n",
                           altsd->bInterfaceNumber, err);
                return err;
        }
@@ -135,7 +135,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
 
        fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
        if (!fp) {
-               snd_printk(KERN_ERR "cannot memdup\n");
+               usb_audio_err(chip, "cannot memdup\n");
                return -ENOMEM;
        }
        if (fp->nr_rates > MAX_NR_RATES) {
@@ -464,7 +464,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
                fp->rate_max = fp->rate_min = 96000;
                break;
        default:
-               snd_printk(KERN_ERR "unknown sample rate\n");
+               usb_audio_err(chip, "unknown sample rate\n");
                kfree(fp);
                return -ENXIO;
        }
@@ -536,7 +536,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
        if (quirk->type < QUIRK_TYPE_COUNT) {
                return quirk_funcs[quirk->type](chip, iface, driver, quirk);
        } else {
-               snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
+               usb_audio_err(chip, "invalid quirk type %d\n", quirk->type);
                return -ENXIO;
        }
 }
@@ -555,18 +555,21 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
 
        if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
            le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) {
-               snd_printdd("sending Extigy boot sequence...\n");
+               dev_dbg(&dev->dev, "sending Extigy boot sequence...\n");
                /* Send message to force it to reconnect with full interface. */
                err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
                                      0x10, 0x43, 0x0001, 0x000a, NULL, 0);
-               if (err < 0) snd_printdd("error sending boot message: %d\n", err);
+               if (err < 0)
+                       dev_dbg(&dev->dev, "error sending boot message: %d\n", err);
                err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
                                &dev->descriptor, sizeof(dev->descriptor));
                config = dev->actconfig;
-               if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err);
+               if (err < 0)
+                       dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
                err = usb_reset_configuration(dev);
-               if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err);
-               snd_printdd("extigy_boot: new boot length = %d\n",
+               if (err < 0)
+                       dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
+               dev_dbg(&dev->dev, "extigy_boot: new boot length = %d\n",
                            le16_to_cpu(get_cfg_desc(config)->wTotalLength));
                return -ENODEV; /* quit this anyway */
        }
@@ -594,7 +597,7 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
        int err;
 
        if (dev->actconfig->desc.bConfigurationValue == 1) {
-               snd_printk(KERN_INFO "usb-audio: "
+               dev_info(&dev->dev,
                           "Fast Track Pro switching to config #2\n");
                /* This function has to be available by the usb core module.
                 * if it is not avialable the boot quirk has to be left out
@@ -603,14 +606,15 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
                 */
                err = usb_driver_set_configuration(dev, 2);
                if (err < 0)
-                       snd_printdd("error usb_driver_set_configuration: %d\n",
-                                   err);
+                       dev_dbg(&dev->dev,
+                               "error usb_driver_set_configuration: %d\n",
+                               err);
                /* Always return an error, so that we stop creating a device
                   that will just be destroyed and recreated with a new
                   configuration */
                return -ENODEV;
        } else
-               snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n");
+               dev_info(&dev->dev, "Fast Track Pro config OK\n");
 
        return 0;
 }
@@ -779,11 +783,11 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
        fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
 
        if (fwsize != MBOX2_FIRMWARE_SIZE) {
-               snd_printk(KERN_ERR "usb-audio: Invalid firmware size=%d.\n", fwsize);
+               dev_err(&dev->dev, "Invalid firmware size=%d.\n", fwsize);
                return -ENODEV;
        }
 
-       snd_printd("usb-audio: Sending Digidesign Mbox 2 boot sequence...\n");
+       dev_dbg(&dev->dev, "Sending Digidesign Mbox 2 boot sequence...\n");
 
        count = 0;
        bootresponse[0] = MBOX2_BOOT_LOADING;
@@ -794,32 +798,32 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
                        0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012);
                if (bootresponse[0] == MBOX2_BOOT_READY)
                        break;
-               snd_printd("usb-audio: device not ready, resending boot sequence...\n");
+               dev_dbg(&dev->dev, "device not ready, resending boot sequence...\n");
                count++;
        }
 
        if (bootresponse[0] != MBOX2_BOOT_READY) {
-               snd_printk(KERN_ERR "usb-audio: Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
+               dev_err(&dev->dev, "Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
                return -ENODEV;
        }
 
-       snd_printdd("usb-audio: device initialised!\n");
+       dev_dbg(&dev->dev, "device initialised!\n");
 
        err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
                &dev->descriptor, sizeof(dev->descriptor));
        config = dev->actconfig;
        if (err < 0)
-               snd_printd("error usb_get_descriptor: %d\n", err);
+               dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
 
        err = usb_reset_configuration(dev);
        if (err < 0)
-               snd_printd("error usb_reset_configuration: %d\n", err);
-       snd_printdd("mbox2_boot: new boot length = %d\n",
+               dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
+       dev_dbg(&dev->dev, "mbox2_boot: new boot length = %d\n",
                le16_to_cpu(get_cfg_desc(config)->wTotalLength));
 
        mbox2_setup_48_24_magic(dev);
 
-       snd_printk(KERN_INFO "usb-audio: Digidesign Mbox 2: 24bit 48kHz");
+       dev_info(&dev->dev, "Digidesign Mbox 2: 24bit 48kHz");
 
        return 0; /* Successful boot */
 }
@@ -865,7 +869,7 @@ static int quattro_skip_setting_quirk(struct snd_usb_audio *chip,
                                return 1; /* skip this altsetting */
                }
        }
-       snd_printdd(KERN_INFO
+       usb_audio_dbg(chip,
                    "using altsetting %d for interface %d config %d\n",
                    altno, iface, chip->setup);
        return 0; /* keep this altsetting */
@@ -932,7 +936,7 @@ static int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
                        return 1;
        }
 
-       snd_printdd(KERN_INFO
+       usb_audio_dbg(chip,
                    "using altsetting %d for interface %d config %d\n",
                    altno, iface, chip->setup);
        return 0; /* keep this altsetting */
index 2fb71be5e100b0973c0993dbb8ed4da3f35c5cf2..310a3822d2b72b51586a9ee06954ef08667bbeb8 100644 (file)
@@ -411,10 +411,9 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
 
        if (!csep || csep->bLength < 7 ||
            csep->bDescriptorSubtype != UAC_EP_GENERAL) {
-               snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
-                          " class specific endpoint descriptor\n",
-                          chip->dev->devnum, iface_no,
-                          altsd->bAlternateSetting);
+               usb_audio_warn(chip,
+                              "%u:%d : no or invalid class specific endpoint descriptor\n",
+                              iface_no, altsd->bAlternateSetting);
                return 0;
        }
 
@@ -533,8 +532,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                /* get audio formats */
                switch (protocol) {
                default:
-                       snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n",
-                                   dev->devnum, iface_no, altno, protocol);
+                       dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n",
+                               iface_no, altno, protocol);
                        protocol = UAC_VERSION_1;
                        /* fall through */
 
@@ -544,14 +543,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                        struct uac_input_terminal_descriptor *iterm;
 
                        if (!as) {
-                               snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
-                                          dev->devnum, iface_no, altno);
+                               dev_err(&dev->dev,
+                                       "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+                                       iface_no, altno);
                                continue;
                        }
 
                        if (as->bLength < sizeof(*as)) {
-                               snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
-                                          dev->devnum, iface_no, altno);
+                               dev_err(&dev->dev,
+                                       "%u:%d : invalid UAC_AS_GENERAL desc\n",
+                                       iface_no, altno);
                                continue;
                        }
 
@@ -574,14 +575,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                                snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
 
                        if (!as) {
-                               snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
-                                          dev->devnum, iface_no, altno);
+                               dev_err(&dev->dev,
+                                       "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+                                       iface_no, altno);
                                continue;
                        }
 
                        if (as->bLength < sizeof(*as)) {
-                               snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
-                                          dev->devnum, iface_no, altno);
+                               dev_err(&dev->dev,
+                                       "%u:%d : invalid UAC_AS_GENERAL desc\n",
+                                       iface_no, altno);
                                continue;
                        }
 
@@ -607,8 +610,9 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                                break;
                        }
 
-                       snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
-                                  dev->devnum, iface_no, altno, as->bTerminalLink);
+                       dev_err(&dev->dev,
+                               "%u:%d : bogus bTerminalLink %d\n",
+                               iface_no, altno, as->bTerminalLink);
                        continue;
                }
                }
@@ -616,14 +620,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                /* get format type */
                fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
                if (!fmt) {
-                       snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
-                                  dev->devnum, iface_no, altno);
+                       dev_err(&dev->dev,
+                               "%u:%d : no UAC_FORMAT_TYPE desc\n",
+                               iface_no, altno);
                        continue;
                }
                if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
                    ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
-                       snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
-                                  dev->devnum, iface_no, altno);
+                       dev_err(&dev->dev,
+                               "%u:%d : invalid UAC_FORMAT_TYPE desc\n",
+                               iface_no, altno);
                        continue;
                }
 
@@ -644,7 +650,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
 
                fp = kzalloc(sizeof(*fp), GFP_KERNEL);
                if (! fp) {
-                       snd_printk(KERN_ERR "cannot malloc\n");
+                       dev_err(&dev->dev, "cannot malloc\n");
                        return -ENOMEM;
                }
 
@@ -707,7 +713,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                        chconfig = 0;
                fp->chmap = convert_chmap(fp->channels, chconfig, protocol);
 
-               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
+               dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
                err = snd_usb_add_audio_stream(chip, stream, fp);
                if (err < 0) {
                        kfree(fp->rate_table);
index 5d2fe0530745a175c24a9034416a29477be96062..25c4c7e217de603c1f02c5c714833e6f29d92c3b 100644 (file)
@@ -60,6 +60,15 @@ struct snd_usb_audio {
        struct usb_host_interface *ctrl_intf;   /* the audio control interface */
 };
 
+#define usb_audio_err(chip, fmt, args...) \
+       dev_err(&(chip)->dev->dev, fmt, ##args)
+#define usb_audio_warn(chip, fmt, args...) \
+       dev_warn(&(chip)->dev->dev, fmt, ##args)
+#define usb_audio_info(chip, fmt, args...) \
+       dev_info(&(chip)->dev->dev, fmt, ##args)
+#define usb_audio_dbg(chip, fmt, args...) \
+       dev_dbg(&(chip)->dev->dev, fmt, ##args)
+
 /*
  * Information about devices with broken descriptors
  */
index 999550bbad40e66f259d9ed2b044ed478e377d72..cf5dc33f4a6d6d582bea62d239f23b4e08bf750a 100644 (file)
@@ -535,7 +535,9 @@ static void snd_us122l_free(struct snd_card *card)
                snd_us122l_card_used[index] = 0;
 }
 
-static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
+static int usx2y_create_card(struct usb_device *device,
+                            struct usb_interface *intf,
+                            struct snd_card **cardp)
 {
        int             dev;
        struct snd_card *card;
@@ -546,8 +548,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
                        break;
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct us122l), &card);
+       err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct us122l), &card);
        if (err < 0)
                return err;
        snd_us122l_card_used[US122L(card)->card_index = dev] = 1;
@@ -578,11 +580,10 @@ static int us122l_usb_probe(struct usb_interface *intf,
        struct snd_card *card;
        int err;
 
-       err = usx2y_create_card(device, &card);
+       err = usx2y_create_card(device, intf, &card);
        if (err < 0)
                return err;
 
-       snd_card_set_dev(card, &intf->dev);
        if (!us122l_create_card(card)) {
                snd_card_free(card);
                return -EINVAL;
index 5a51b18c50fe9230faabb923219c281b45a47970..91e0e2a4808c99f8d9193342908343875f745fdd 100644 (file)
@@ -332,7 +332,9 @@ static struct usb_device_id snd_usX2Y_usb_id_table[] = {
        { /* terminator */ }
 };
 
-static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
+static int usX2Y_create_card(struct usb_device *device,
+                            struct usb_interface *intf,
+                            struct snd_card **cardp)
 {
        int             dev;
        struct snd_card *       card;
@@ -343,15 +345,15 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
                        break;
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                             sizeof(struct usX2Ydev), &card);
+       err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE,
+                          sizeof(struct usX2Ydev), &card);
        if (err < 0)
                return err;
        snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1;
        card->private_free = snd_usX2Y_card_private_free;
        usX2Y(card)->dev = device;
        init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
-       mutex_init(&usX2Y(card)->prepare_mutex);
+       mutex_init(&usX2Y(card)->pcm_mutex);
        INIT_LIST_HEAD(&usX2Y(card)->midi_list);
        strcpy(card->driver, "USB "NAME_ALLCAPS"");
        sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
@@ -382,10 +384,9 @@ static int usX2Y_usb_probe(struct usb_device *device,
             le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428))
                return -EINVAL;
 
-       err = usX2Y_create_card(device, &card);
+       err = usX2Y_create_card(device, intf, &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, &intf->dev);
        if ((err = usX2Y_hwdep_new(card, device)) < 0  ||
            (err = snd_card_register(card)) < 0) {
                snd_card_free(card);
index e43c0a86441ae600c2725356e1cbf3c27ecb81a3..6ae6b08069389a77b1a68e01b6d78a9b48998e75 100644 (file)
@@ -36,7 +36,7 @@ struct usX2Ydev {
        unsigned int            rate,
                                format;
        int                     chip_status;
-       struct mutex            prepare_mutex;
+       struct mutex            pcm_mutex;
        struct us428ctls_sharedmem      *us428ctls_sharedmem;
        int                     wait_iso_frame;
        wait_queue_head_t       us428ctls_wait_queue_head;
index 6234a51625b1b6a556f252c2fea3a150db1bdbc1..a63330dd1407e721285285a559c8b90adddd74c5 100644 (file)
@@ -752,36 +752,44 @@ static int snd_usX2Y_pcm_hw_params(struct snd_pcm_substream *substream,
        unsigned int            rate = params_rate(hw_params);
        snd_pcm_format_t        format = params_format(hw_params);
        struct snd_card *card = substream->pstr->pcm->card;
-       struct list_head *list;
+       struct usX2Ydev *dev = usX2Y(card);
+       int i;
 
+       mutex_lock(&usX2Y(card)->pcm_mutex);
        snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params);
-       // all pcm substreams off one usX2Y have to operate at the same rate & format
-       list_for_each(list, &card->devices) {
-               struct snd_device *dev;
-               struct snd_pcm *pcm;
-               int s;
-               dev = snd_device(list);
-               if (dev->type != SNDRV_DEV_PCM)
+       /* all pcm substreams off one usX2Y have to operate at the same
+        * rate & format
+        */
+       for (i = 0; i < dev->pcm_devs * 2; i++) {
+               struct snd_usX2Y_substream *subs = dev->subs[i];
+               struct snd_pcm_substream *test_substream;
+
+               if (!subs)
+                       continue;
+               test_substream = subs->pcm_substream;
+               if (!test_substream || test_substream == substream ||
+                   !test_substream->runtime)
                        continue;
-               pcm = dev->device_data;
-               for (s = 0; s < 2; ++s) {
-                       struct snd_pcm_substream *test_substream;
-                       test_substream = pcm->streams[s].substream;
-                       if (test_substream && test_substream != substream  &&
-                           test_substream->runtime &&
-                           ((test_substream->runtime->format &&
-                             test_substream->runtime->format != format) ||
-                            (test_substream->runtime->rate &&
-                             test_substream->runtime->rate != rate)))
-                               return -EINVAL;
+               if ((test_substream->runtime->format &&
+                    test_substream->runtime->format != format) ||
+                   (test_substream->runtime->rate &&
+                    test_substream->runtime->rate != rate)) {
+                       err = -EINVAL;
+                       goto error;
                }
        }
-       if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) {
+
+       err = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (err < 0) {
                snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n",
                           substream, params_buffer_bytes(hw_params), err);
-               return err;
+               goto error;
        }
-       return 0;
+
+ error:
+       mutex_unlock(&usX2Y(card)->pcm_mutex);
+       return err;
 }
 
 /*
@@ -791,7 +799,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_usX2Y_substream *subs = runtime->private_data;
-       mutex_lock(&subs->usX2Y->prepare_mutex);
+       mutex_lock(&subs->usX2Y->pcm_mutex);
        snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
 
        if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -812,7 +820,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)
                        usX2Y_urbs_release(subs);
                }
        }
-       mutex_unlock(&subs->usX2Y->prepare_mutex);
+       mutex_unlock(&subs->usX2Y->pcm_mutex);
        return snd_pcm_lib_free_pages(substream);
 }
 /*
@@ -829,7 +837,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)
        int err = 0;
        snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
 
-       mutex_lock(&usX2Y->prepare_mutex);
+       mutex_lock(&usX2Y->pcm_mutex);
        usX2Y_subs_prepare(subs);
 // Start hardware streams
 // SyncStream first....
@@ -849,7 +857,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)
                err = usX2Y_urbs_start(subs);
 
  up_prepare_mutex:
-       mutex_unlock(&usX2Y->prepare_mutex);
+       mutex_unlock(&usX2Y->pcm_mutex);
        return err;
 }
 
index 814d0e887c62e5c451c3ff7cc4b8f448c3a45007..90766a92e7fdf471e7f109def88bd21ebb50048f 100644 (file)
@@ -358,7 +358,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_usX2Y_substream *subs = runtime->private_data,
                *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
-       mutex_lock(&subs->usX2Y->prepare_mutex);
+       mutex_lock(&subs->usX2Y->pcm_mutex);
        snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
 
        if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -387,7 +387,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
                                usX2Y_usbpcm_urbs_release(cap_subs2);
                }
        }
-       mutex_unlock(&subs->usX2Y->prepare_mutex);
+       mutex_unlock(&subs->usX2Y->pcm_mutex);
        return snd_pcm_lib_free_pages(substream);
 }
 
@@ -493,7 +493,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
                memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
        }
 
-       mutex_lock(&usX2Y->prepare_mutex);
+       mutex_lock(&usX2Y->pcm_mutex);
        usX2Y_subs_prepare(subs);
 // Start hardware streams
 // SyncStream first....
@@ -534,7 +534,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
                usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
 
  up_prepare_mutex:
-       mutex_unlock(&usX2Y->prepare_mutex);
+       mutex_unlock(&usX2Y->pcm_mutex);
        return err;
 }
 
@@ -600,59 +600,30 @@ static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
 };
 
 
-static int usX2Y_pcms_lock_check(struct snd_card *card)
+static int usX2Y_pcms_busy_check(struct snd_card *card)
 {
-       struct list_head *list;
-       struct snd_device *dev;
-       struct snd_pcm *pcm;
-       int err = 0;
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
-               if (dev->type != SNDRV_DEV_PCM)
-                       continue;
-               pcm = dev->device_data;
-               mutex_lock(&pcm->open_mutex);
-       }
-       list_for_each(list, &card->devices) {
-               int s;
-               dev = snd_device(list);
-               if (dev->type != SNDRV_DEV_PCM)
-                       continue;
-               pcm = dev->device_data;
-               for (s = 0; s < 2; ++s) {
-                       struct snd_pcm_substream *substream;
-                       substream = pcm->streams[s].substream;
-                       if (substream && SUBSTREAM_BUSY(substream))
-                               err = -EBUSY;
-               }
-       }
-       return err;
-}
-
+       struct usX2Ydev *dev = usX2Y(card);
+       int i;
 
-static void usX2Y_pcms_unlock(struct snd_card *card)
-{
-       struct list_head *list;
-       struct snd_device *dev;
-       struct snd_pcm *pcm;
-       list_for_each(list, &card->devices) {
-               dev = snd_device(list);
-               if (dev->type != SNDRV_DEV_PCM)
-                       continue;
-               pcm = dev->device_data;
-               mutex_unlock(&pcm->open_mutex);
+       for (i = 0; i < dev->pcm_devs * 2; i++) {
+               struct snd_usX2Y_substream *subs = dev->subs[i];
+               if (subs && subs->pcm_substream &&
+                   SUBSTREAM_BUSY(subs->pcm_substream))
+                       return -EBUSY;
        }
+       return 0;
 }
 
-
 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
 {
-       // we need to be the first 
        struct snd_card *card = hw->card;
-       int err = usX2Y_pcms_lock_check(card);
-       if (0 == err)
+       int err;
+
+       mutex_lock(&usX2Y(card)->pcm_mutex);
+       err = usX2Y_pcms_busy_check(card);
+       if (!err)
                usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
-       usX2Y_pcms_unlock(card);
+       mutex_unlock(&usX2Y(card)->pcm_mutex);
        return err;
 }
 
@@ -660,10 +631,13 @@ static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
 {
        struct snd_card *card = hw->card;
-       int err = usX2Y_pcms_lock_check(card);
-       if (0 == err)
+       int err;
+
+       mutex_lock(&usX2Y(card)->pcm_mutex);
+       err = usX2Y_pcms_busy_check(card);
+       if (!err)
                usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
-       usX2Y_pcms_unlock(card);
+       mutex_unlock(&usX2Y(card)->pcm_mutex);
        return err;
 }
 
index feec3ad5fd09862a66ef64dc3fe647eb07f7a236..bcae806b0c398d5450975ab08001e7a808e376c4 100644 (file)
@@ -7,6 +7,7 @@ help:
        @echo '  cgroup     - cgroup tools'
        @echo '  cpupower   - a tool for all things x86 CPU power'
        @echo '  firewire   - the userspace part of nosy, an IEEE-1394 traffic sniffer'
+       @echo '  hv         - tools used when in Hyper-V clients'
        @echo '  lguest     - a minimal 32-bit x86 hypervisor'
        @echo '  perf       - Linux performance measurement and analysis tool'
        @echo '  selftests  - various kernel selftests'
@@ -40,7 +41,7 @@ acpi: FORCE
 cpupower: FORCE
        $(call descend,power/$@)
 
-cgroup firewire guest usb virtio vm net: FORCE
+cgroup firewire hv guest usb virtio vm net: FORCE
        $(call descend,$@)
 
 libapikfs: FORCE
@@ -64,7 +65,7 @@ acpi_install:
 cpupower_install:
        $(call descend,power/$(@:_install=),install)
 
-cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install net_install:
+cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install:
        $(call descend,$(@:_install=),install)
 
 selftests_install:
@@ -76,7 +77,7 @@ turbostat_install x86_energy_perf_policy_install:
 tmon_install:
        $(call descend,thermal/$(@:_install=),install)
 
-install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \
+install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
                perf_install selftests_install turbostat_install usb_install \
                virtio_install vm_install net_install x86_energy_perf_policy_install \
        tmon
@@ -87,7 +88,7 @@ acpi_clean:
 cpupower_clean:
        $(call descend,power/cpupower,clean)
 
-cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
+cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
        $(call descend,$(@:_clean=),clean)
 
 libapikfs_clean:
@@ -105,7 +106,7 @@ turbostat_clean x86_energy_perf_policy_clean:
 tmon_clean:
        $(call descend,thermal/tmon,clean)
 
-clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \
+clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
                perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \
                vm_clean net_clean x86_energy_perf_policy_clean tmon_clean
 
diff --git a/tools/hv/Makefile b/tools/hv/Makefile
new file mode 100644 (file)
index 0000000..bd22f78
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for Hyper-V tools
+
+CC = $(CROSS_COMPILE)gcc
+PTHREAD_LIBS = -lpthread
+WARNINGS = -Wall -Wextra
+CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
+
+all: hv_kvp_daemon hv_vss_daemon
+%: %.c
+       $(CC) $(CFLAGS) -o $@ $^
+
+clean:
+       $(RM) hv_kvp_daemon hv_vss_daemon
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
new file mode 100644 (file)
index 0000000..4ecc4fd
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * An implementation of host to guest copy functionality for Linux.
+ *
+ * Copyright (C) 2014, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <kys@microsoft.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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ */
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <linux/hyperv.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+static int target_fd;
+static char target_fname[W_MAX_PATH];
+
+static int hv_start_fcopy(struct hv_start_fcopy *smsg)
+{
+       int error = HV_E_FAIL;
+       char *q, *p;
+
+       /*
+        * If possile append a path seperator to the path.
+        */
+       if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
+               strcat((char *)smsg->path_name, "/");
+
+       p = (char *)smsg->path_name;
+       snprintf(target_fname, sizeof(target_fname), "%s/%s",
+               (char *)smsg->path_name, smsg->file_name);
+
+       syslog(LOG_INFO, "Target file name: %s", target_fname);
+       /*
+        * Check to see if the path is already in place; if not,
+        * create if required.
+        */
+       while ((q = strchr(p, '/')) != NULL) {
+               if (q == p) {
+                       p++;
+                       continue;
+               }
+               *q = '\0';
+               if (access((char *)smsg->path_name, F_OK)) {
+                       if (smsg->copy_flags & CREATE_PATH) {
+                               if (mkdir((char *)smsg->path_name, 0755)) {
+                                       syslog(LOG_ERR, "Failed to create %s",
+                                               (char *)smsg->path_name);
+                                       goto done;
+                               }
+                       } else {
+                               syslog(LOG_ERR, "Invalid path: %s",
+                                       (char *)smsg->path_name);
+                               goto done;
+                       }
+               }
+               p = q + 1;
+               *q = '/';
+       }
+
+       if (!access(target_fname, F_OK)) {
+               syslog(LOG_INFO, "File: %s exists", target_fname);
+               if (!smsg->copy_flags & OVER_WRITE)
+                       goto done;
+       }
+
+       target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744);
+       if (target_fd == -1) {
+               syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
+               goto done;
+       }
+
+       error = 0;
+done:
+       return error;
+}
+
+static int hv_copy_data(struct hv_do_fcopy *cpmsg)
+{
+       ssize_t bytes_written;
+
+       bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
+                               cpmsg->offset);
+
+       if (bytes_written != cpmsg->size)
+               return HV_E_FAIL;
+
+       return 0;
+}
+
+static int hv_copy_finished(void)
+{
+       close(target_fd);
+       return 0;
+}
+static int hv_copy_cancel(void)
+{
+       close(target_fd);
+       unlink(target_fname);
+       return 0;
+
+}
+
+int main(void)
+{
+       int fd, fcopy_fd, len;
+       int error;
+       int version = FCOPY_CURRENT_VERSION;
+       char *buffer[4096 * 2];
+       struct hv_fcopy_hdr *in_msg;
+
+       if (daemon(1, 0)) {
+               syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       openlog("HV_FCOPY", 0, LOG_USER);
+       syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
+
+       fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
+
+       if (fcopy_fd < 0) {
+               syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
+                       errno, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       /*
+        * Register with the kernel.
+        */
+       if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
+               syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       while (1) {
+               /*
+                * In this loop we process fcopy messages after the
+                * handshake is complete.
+                */
+               len = pread(fcopy_fd, buffer, (4096 * 2), 0);
+               if (len < 0) {
+                       syslog(LOG_ERR, "pread failed: %s", strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+               in_msg = (struct hv_fcopy_hdr *)buffer;
+
+               switch (in_msg->operation) {
+               case START_FILE_COPY:
+                       error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
+                       break;
+               case WRITE_TO_FILE:
+                       error = hv_copy_data((struct hv_do_fcopy *)in_msg);
+                       break;
+               case COMPLETE_FCOPY:
+                       error = hv_copy_finished();
+                       break;
+               case CANCEL_FCOPY:
+                       error = hv_copy_cancel();
+                       break;
+
+               default:
+                       syslog(LOG_ERR, "Unknown operation: %d",
+                               in_msg->operation);
+
+               }
+
+               if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
+                       syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+       }
+}
index 520de330457106657ab747581f983d23d695e5df..6a213b8cd7b9034ad097d60b2ce5295e458d4054 100644 (file)
@@ -87,6 +87,8 @@ static int vss_operate(int operation)
                        continue;
                if (strcmp(ent->mnt_type, "iso9660") == 0)
                        continue;
+               if (strcmp(ent->mnt_type, "vfat") == 0)
+                       continue;
                if (strcmp(ent->mnt_dir, "/") == 0) {
                        root_seen = 1;
                        continue;
diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h
new file mode 100644 (file)
index 0000000..d026c65
--- /dev/null
@@ -0,0 +1,5 @@
+#include "../../../include/linux/hash.h"
+
+#ifndef _TOOLS_LINUX_HASH_H
+#define _TOOLS_LINUX_HASH_H
+#endif
index ed2f51e11b80f36d63601c7abb1ea32db13566ff..ce00f7ee6455248d92dba7016b2770c824e897f9 100644 (file)
@@ -9,8 +9,10 @@ LIB_H=
 LIB_OBJS=
 
 LIB_H += fs/debugfs.h
+LIB_H += fs/fs.h
 
 LIB_OBJS += $(OUTPUT)fs/debugfs.o
+LIB_OBJS += $(OUTPUT)fs/fs.o
 
 LIBFILE = libapikfs.a
 
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
new file mode 100644 (file)
index 0000000..5b5eb78
--- /dev/null
@@ -0,0 +1,124 @@
+/* TODO merge/factor in debugfs.c here */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/vfs.h>
+
+#include "debugfs.h"
+#include "fs.h"
+
+static const char * const sysfs__fs_known_mountpoints[] = {
+       "/sys",
+       0,
+};
+
+static const char * const procfs__known_mountpoints[] = {
+       "/proc",
+       0,
+};
+
+struct fs {
+       const char              *name;
+       const char * const      *mounts;
+       char                     path[PATH_MAX + 1];
+       bool                     found;
+       long                     magic;
+};
+
+enum {
+       FS__SYSFS  = 0,
+       FS__PROCFS = 1,
+};
+
+static struct fs fs__entries[] = {
+       [FS__SYSFS] = {
+               .name   = "sysfs",
+               .mounts = sysfs__fs_known_mountpoints,
+               .magic  = SYSFS_MAGIC,
+       },
+       [FS__PROCFS] = {
+               .name   = "proc",
+               .mounts = procfs__known_mountpoints,
+               .magic  = PROC_SUPER_MAGIC,
+       },
+};
+
+static bool fs__read_mounts(struct fs *fs)
+{
+       bool found = false;
+       char type[100];
+       FILE *fp;
+
+       fp = fopen("/proc/mounts", "r");
+       if (fp == NULL)
+               return NULL;
+
+       while (!found &&
+              fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
+                     fs->path, type) == 2) {
+
+               if (strcmp(type, fs->name) == 0)
+                       found = true;
+       }
+
+       fclose(fp);
+       return fs->found = found;
+}
+
+static int fs__valid_mount(const char *fs, long magic)
+{
+       struct statfs st_fs;
+
+       if (statfs(fs, &st_fs) < 0)
+               return -ENOENT;
+       else if (st_fs.f_type != magic)
+               return -ENOENT;
+
+       return 0;
+}
+
+static bool fs__check_mounts(struct fs *fs)
+{
+       const char * const *ptr;
+
+       ptr = fs->mounts;
+       while (*ptr) {
+               if (fs__valid_mount(*ptr, fs->magic) == 0) {
+                       fs->found = true;
+                       strcpy(fs->path, *ptr);
+                       return true;
+               }
+               ptr++;
+       }
+
+       return false;
+}
+
+static const char *fs__get_mountpoint(struct fs *fs)
+{
+       if (fs__check_mounts(fs))
+               return fs->path;
+
+       return fs__read_mounts(fs) ? fs->path : NULL;
+}
+
+static const char *fs__mountpoint(int idx)
+{
+       struct fs *fs = &fs__entries[idx];
+
+       if (fs->found)
+               return (const char *)fs->path;
+
+       return fs__get_mountpoint(fs);
+}
+
+#define FS__MOUNTPOINT(name, idx)      \
+const char *name##__mountpoint(void)   \
+{                                      \
+       return fs__mountpoint(idx);     \
+}
+
+FS__MOUNTPOINT(sysfs,  FS__SYSFS);
+FS__MOUNTPOINT(procfs, FS__PROCFS);
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h
new file mode 100644 (file)
index 0000000..cb70495
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __API_FS__
+#define __API_FS__
+
+#ifndef SYSFS_MAGIC
+#define SYSFS_MAGIC            0x62656572
+#endif
+
+#ifndef PROC_SUPER_MAGIC
+#define PROC_SUPER_MAGIC       0x9fa0
+#endif
+
+const char *sysfs__mountpoint(void);
+const char *procfs__mountpoint(void);
+#endif /* __API_FS__ */
index da8b7aa3d3518d1e52532af42974fc2e3981376f..07b0b7542511e9912e830b11885e1212bbf63a76 100644 (file)
@@ -87,8 +87,8 @@ endif # BUILD_SRC
 # We process the rest of the Makefile if this is the final invocation of make
 ifeq ($(skip-makefile),)
 
-srctree                := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
-objtree                := $(CURDIR)
+srctree                := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)))
+objtree                := $(realpath $(CURDIR))
 src            := $(srctree)
 obj            := $(objtree)
 
@@ -112,7 +112,7 @@ export Q VERBOSE
 
 LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION)
 
-INCLUDES = -I. -I/usr/local/include -I./uinclude $(CONFIG_INCLUDES)
+INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES)
 
 # Set compile option CFLAGS if not set elsewhere
 CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
index f8465a811aa554e6510477ac0c733b2eb02bb5f4..23bd69cb5ade7014e8630e87ad89a16e2d95be71 100644 (file)
@@ -418,7 +418,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
 
 __attribute__((constructor)) static void init_preload(void)
 {
-       if (__init_state != done)
+       if (__init_state == done)
                return;
 
 #ifndef __GLIBC__
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h
new file mode 100644 (file)
index 0000000..d82b170
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_HASH_H
+#define __ASM_GENERIC_HASH_H
+
+/* Stub */
+
+#endif /* __ASM_GENERIC_HASH_H */
index 4c99fcb5da2769ef48067b5e6adf05806e758396..042ee8e463c98bf03d9a92e4d18dd3c01ec32162 100644 (file)
@@ -13,4 +13,9 @@ static inline int rcu_is_cpu_idle(void)
        return 1;
 }
 
+static inline bool rcu_is_watching(void)
+{
+       return false;
+}
+
 #endif
index 004cd74734b62b941cf64db1634d2774f70f6e3c..ee577ea03ba50f05a4b14379ddcd17a3f73593c0 100644 (file)
@@ -12,7 +12,7 @@ YACC = bison
 
 all : bpf_jit_disasm bpf_dbg bpf_asm
 
-bpf_jit_disasm : CFLAGS = -Wall -O2
+bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
 bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
 bpf_jit_disasm : bpf_jit_disasm.o
 
index 888d51137fbe61e0dc04546b36a46486a9d9a555..1d78a4064da48218b90b15f8495c3626cf614b2c 100644 (file)
@@ -18,6 +18,10 @@ from it, into perf.data. Perf record options are accepted and are passed through
 "perf mem -t <TYPE> report" displays the result. It invokes perf report with the
 right set of options to display a memory access profile.
 
+Note that on Intel systems the memory latency reported is the use-latency,
+not the pure load (or store latency). Use latency includes any pipeline
+queueing delays in addition to the memory subsystem latency.
+
 OPTIONS
 -------
 <command>...::
index b715cb71592b0299d473eb7b40df77433485d28f..1513935c399b67c6e2158b9041af548edf3e610c 100644 (file)
@@ -136,6 +136,8 @@ Each probe argument follows below syntax.
 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
 
+On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
+
 LINE SYNTAX
 -----------
 Line range is described by following syntax.
index f41572d0dd76125b9ebc4b03fd0beb832192b39d..c0c87c87b60f83d92356e43488c83e6c074cb6e8 100644 (file)
@@ -6,6 +6,7 @@ tools/lib/symbol/kallsyms.c
 tools/lib/symbol/kallsyms.h
 tools/include/asm/bug.h
 tools/include/linux/compiler.h
+tools/include/linux/hash.h
 include/linux/const.h
 include/linux/perf_event.h
 include/linux/rbtree.h
index 7257e7e9e38a5e625f2fa562836ff3793d0275c4..50d875d970c4331f82dccfa35b6ebd980b1e3ea4 100644 (file)
@@ -7,6 +7,8 @@ include config/utilities.mak
 
 # Define V to have a more verbose compile.
 #
+# Define VF to have a more verbose feature check output.
+#
 # Define O to save output files in a separate directory.
 #
 # Define ARCH as name of target architecture if you want cross-builds.
@@ -55,6 +57,9 @@ include config/utilities.mak
 # Define NO_LIBAUDIT if you do not want libaudit support
 #
 # Define NO_LIBBIONIC if you do not want bionic support
+#
+# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
+# for dwarf backtrace post unwind.
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -208,7 +213,7 @@ LIB_H += ../../include/uapi/linux/perf_event.h
 LIB_H += ../../include/linux/rbtree.h
 LIB_H += ../../include/linux/list.h
 LIB_H += ../../include/uapi/linux/const.h
-LIB_H += ../../include/linux/hash.h
+LIB_H += ../include/linux/hash.h
 LIB_H += ../../include/linux/stringify.h
 LIB_H += util/include/linux/bitmap.h
 LIB_H += util/include/linux/bitops.h
@@ -218,9 +223,7 @@ LIB_H += util/include/linux/ctype.h
 LIB_H += util/include/linux/kernel.h
 LIB_H += util/include/linux/list.h
 LIB_H += util/include/linux/export.h
-LIB_H += util/include/linux/magic.h
 LIB_H += util/include/linux/poison.h
-LIB_H += util/include/linux/prefetch.h
 LIB_H += util/include/linux/rbtree.h
 LIB_H += util/include/linux/rbtree_augmented.h
 LIB_H += util/include/linux/string.h
@@ -244,7 +247,6 @@ LIB_H += util/cache.h
 LIB_H += util/callchain.h
 LIB_H += util/build-id.h
 LIB_H += util/debug.h
-LIB_H += util/fs.h
 LIB_H += util/pmu.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
@@ -306,7 +308,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
 LIB_OBJS += $(OUTPUT)util/build-id.o
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
-LIB_OBJS += $(OUTPUT)util/fs.o
 LIB_OBJS += $(OUTPUT)util/pmu.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
@@ -408,6 +409,11 @@ endif
 LIB_OBJS += $(OUTPUT)tests/code-reading.o
 LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
 LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
+ifndef NO_DWARF_UNWIND
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
+endif
+endif
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -420,6 +426,9 @@ BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
 endif
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
+BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o
+BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o
+BUILTIN_OBJS += $(OUTPUT)bench/futex-requeue.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
 BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
@@ -475,8 +484,13 @@ ifndef NO_DWARF
 endif # NO_DWARF
 endif # NO_LIBELF
 
+ifndef NO_LIBDW_DWARF_UNWIND
+  LIB_OBJS += $(OUTPUT)util/unwind-libdw.o
+  LIB_H += util/unwind-libdw.h
+endif
+
 ifndef NO_LIBUNWIND
-  LIB_OBJS += $(OUTPUT)util/unwind.o
+  LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
 endif
 LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
 
@@ -533,6 +547,7 @@ ifeq ($(NO_PERF_REGS),0)
   ifeq ($(ARCH),x86)
     LIB_H += arch/x86/include/perf_regs.h
   endif
+  LIB_OBJS += $(OUTPUT)util/perf_regs.o
 endif
 
 ifndef NO_LIBNUMA
@@ -655,6 +670,9 @@ $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
                -DPYTHON='"$(PYTHON_WORD)"' \
                $<
 
+$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
+
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
@@ -707,9 +725,15 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 # we depend the various files onto their directories.
 DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
 DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
-$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
+# no need to add flex objects, because they depend on bison ones
+DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c
+DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c
+
+OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS)))
+
+$(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES)
 # In the second step, we make a rule to actually create these directories
-$(sort $(dir $(DIRECTORY_DEPS))):
+$(OUTPUT_DIRECTORIES):
        $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
 
 $(LIB_FILE): $(LIB_OBJS)
@@ -886,7 +910,7 @@ config-clean:
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
        $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
        $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
-       $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
+       $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
        $(python-clean)
 
index fe9b61e322a557b063ecc78eccb9a87c8de73dda..67e9b3d38e89209dec2810a9ca229127fd49f17c 100644 (file)
@@ -3,5 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
 ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
 endif
diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
new file mode 100644 (file)
index 0000000..729ed69
--- /dev/null
@@ -0,0 +1,48 @@
+
+#include <errno.h>
+#include <libunwind.h>
+#include "perf_regs.h"
+#include "../../util/unwind.h"
+
+int libunwind__arch_reg_id(int regnum)
+{
+       switch (regnum) {
+       case UNW_ARM_R0:
+               return PERF_REG_ARM_R0;
+       case UNW_ARM_R1:
+               return PERF_REG_ARM_R1;
+       case UNW_ARM_R2:
+               return PERF_REG_ARM_R2;
+       case UNW_ARM_R3:
+               return PERF_REG_ARM_R3;
+       case UNW_ARM_R4:
+               return PERF_REG_ARM_R4;
+       case UNW_ARM_R5:
+               return PERF_REG_ARM_R5;
+       case UNW_ARM_R6:
+               return PERF_REG_ARM_R6;
+       case UNW_ARM_R7:
+               return PERF_REG_ARM_R7;
+       case UNW_ARM_R8:
+               return PERF_REG_ARM_R8;
+       case UNW_ARM_R9:
+               return PERF_REG_ARM_R9;
+       case UNW_ARM_R10:
+               return PERF_REG_ARM_R10;
+       case UNW_ARM_R11:
+               return PERF_REG_ARM_FP;
+       case UNW_ARM_R12:
+               return PERF_REG_ARM_IP;
+       case UNW_ARM_R13:
+               return PERF_REG_ARM_SP;
+       case UNW_ARM_R14:
+               return PERF_REG_ARM_LR;
+       case UNW_ARM_R15:
+               return PERF_REG_ARM_PC;
+       default:
+               pr_err("unwind: invalid reg id %d\n", regnum);
+               return -EINVAL;
+       }
+
+       return -EINVAL;
+}
diff --git a/tools/perf/arch/arm/util/unwind.c b/tools/perf/arch/arm/util/unwind.c
deleted file mode 100644 (file)
index da3dc95..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-
-int unwind__arch_reg_id(int regnum)
-{
-       switch (regnum) {
-       case UNW_ARM_R0:
-               return PERF_REG_ARM_R0;
-       case UNW_ARM_R1:
-               return PERF_REG_ARM_R1;
-       case UNW_ARM_R2:
-               return PERF_REG_ARM_R2;
-       case UNW_ARM_R3:
-               return PERF_REG_ARM_R3;
-       case UNW_ARM_R4:
-               return PERF_REG_ARM_R4;
-       case UNW_ARM_R5:
-               return PERF_REG_ARM_R5;
-       case UNW_ARM_R6:
-               return PERF_REG_ARM_R6;
-       case UNW_ARM_R7:
-               return PERF_REG_ARM_R7;
-       case UNW_ARM_R8:
-               return PERF_REG_ARM_R8;
-       case UNW_ARM_R9:
-               return PERF_REG_ARM_R9;
-       case UNW_ARM_R10:
-               return PERF_REG_ARM_R10;
-       case UNW_ARM_R11:
-               return PERF_REG_ARM_FP;
-       case UNW_ARM_R12:
-               return PERF_REG_ARM_IP;
-       case UNW_ARM_R13:
-               return PERF_REG_ARM_SP;
-       case UNW_ARM_R14:
-               return PERF_REG_ARM_LR;
-       case UNW_ARM_R15:
-               return PERF_REG_ARM_PC;
-       default:
-               pr_err("unwind: invalid reg id %d\n", regnum);
-               return -EINVAL;
-       }
-
-       return -EINVAL;
-}
index 8801fe02f206a93a97d7f7cc8a56094dffa1d05c..1641542e3636693abe587a9aab99d74ccb5b6bb9 100644 (file)
@@ -3,7 +3,14 @@ PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
 ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
+endif
+ifndef NO_LIBDW_DWARF_UNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
+endif
+ifndef NO_DWARF_UNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
index e84ca76aae779ef484df1633b7cff3e35b327ba8..fc819ca34a7eeffd564cace9b9d0baea71ef36ed 100644 (file)
@@ -5,14 +5,20 @@
 #include "../../util/types.h"
 #include <asm/perf_regs.h>
 
+void perf_regs_load(u64 *regs);
+
 #ifndef HAVE_ARCH_X86_64_SUPPORT
 #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_X86_32_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
 #else
 #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
                       (1ULL << PERF_REG_X86_ES) | \
                       (1ULL << PERF_REG_X86_FS) | \
                       (1ULL << PERF_REG_X86_GS))
 #define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
+#define PERF_REGS_MAX PERF_REG_X86_64_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
 #endif
 #define PERF_REG_IP PERF_REG_X86_IP
 #define PERF_REG_SP PERF_REG_X86_SP
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
new file mode 100644 (file)
index 0000000..b602ad9
--- /dev/null
@@ -0,0 +1,59 @@
+#include <string.h>
+#include "perf_regs.h"
+#include "thread.h"
+#include "map.h"
+#include "event.h"
+#include "tests/tests.h"
+
+#define STACK_SIZE 8192
+
+static int sample_ustack(struct perf_sample *sample,
+                        struct thread *thread, u64 *regs)
+{
+       struct stack_dump *stack = &sample->user_stack;
+       struct map *map;
+       unsigned long sp;
+       u64 stack_size, *buf;
+
+       buf = malloc(STACK_SIZE);
+       if (!buf) {
+               pr_debug("failed to allocate sample uregs data\n");
+               return -1;
+       }
+
+       sp = (unsigned long) regs[PERF_REG_X86_SP];
+
+       map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
+       if (!map) {
+               pr_debug("failed to get stack map\n");
+               return -1;
+       }
+
+       stack_size = map->end - sp;
+       stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
+
+       memcpy(buf, (void *) sp, stack_size);
+       stack->data = (char *) buf;
+       stack->size = stack_size;
+       return 0;
+}
+
+int test__arch_unwind_sample(struct perf_sample *sample,
+                            struct thread *thread)
+{
+       struct regs_dump *regs = &sample->user_regs;
+       u64 *buf;
+
+       buf = malloc(sizeof(u64) * PERF_REGS_MAX);
+       if (!buf) {
+               pr_debug("failed to allocate sample uregs data\n");
+               return -1;
+       }
+
+       perf_regs_load(buf);
+       regs->abi  = PERF_SAMPLE_REGS_ABI;
+       regs->regs = buf;
+       regs->mask = PERF_REGS_MASK;
+
+       return sample_ustack(sample, thread, buf);
+}
diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S
new file mode 100644 (file)
index 0000000..99167bf
--- /dev/null
@@ -0,0 +1,92 @@
+
+#include <linux/linkage.h>
+
+#define AX      0
+#define BX      1 * 8
+#define CX      2 * 8
+#define DX      3 * 8
+#define SI      4 * 8
+#define DI      5 * 8
+#define BP      6 * 8
+#define SP      7 * 8
+#define IP      8 * 8
+#define FLAGS   9 * 8
+#define CS     10 * 8
+#define SS     11 * 8
+#define DS     12 * 8
+#define ES     13 * 8
+#define FS     14 * 8
+#define GS     15 * 8
+#define R8     16 * 8
+#define R9     17 * 8
+#define R10    18 * 8
+#define R11    19 * 8
+#define R12    20 * 8
+#define R13    21 * 8
+#define R14    22 * 8
+#define R15    23 * 8
+
+.text
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+ENTRY(perf_regs_load)
+       movq %rax, AX(%rdi)
+       movq %rbx, BX(%rdi)
+       movq %rcx, CX(%rdi)
+       movq %rdx, DX(%rdi)
+       movq %rsi, SI(%rdi)
+       movq %rdi, DI(%rdi)
+       movq %rbp, BP(%rdi)
+
+       leaq 8(%rsp), %rax /* exclude this call.  */
+       movq %rax, SP(%rdi)
+
+       movq 0(%rsp), %rax
+       movq %rax, IP(%rdi)
+
+       movq $0, FLAGS(%rdi)
+       movq $0, CS(%rdi)
+       movq $0, SS(%rdi)
+       movq $0, DS(%rdi)
+       movq $0, ES(%rdi)
+       movq $0, FS(%rdi)
+       movq $0, GS(%rdi)
+
+       movq %r8,  R8(%rdi)
+       movq %r9,  R9(%rdi)
+       movq %r10, R10(%rdi)
+       movq %r11, R11(%rdi)
+       movq %r12, R12(%rdi)
+       movq %r13, R13(%rdi)
+       movq %r14, R14(%rdi)
+       movq %r15, R15(%rdi)
+       ret
+ENDPROC(perf_regs_load)
+#else
+ENTRY(perf_regs_load)
+       push %edi
+       movl 8(%esp), %edi
+       movl %eax, AX(%edi)
+       movl %ebx, BX(%edi)
+       movl %ecx, CX(%edi)
+       movl %edx, DX(%edi)
+       movl %esi, SI(%edi)
+       pop %eax
+       movl %eax, DI(%edi)
+       movl %ebp, BP(%edi)
+
+       leal 4(%esp), %eax /* exclude this call.  */
+       movl %eax, SP(%edi)
+
+       movl 0(%esp), %eax
+       movl %eax, IP(%edi)
+
+       movl $0, FLAGS(%edi)
+       movl $0, CS(%edi)
+       movl $0, SS(%edi)
+       movl $0, DS(%edi)
+       movl $0, ES(%edi)
+       movl $0, FS(%edi)
+       movl $0, GS(%edi)
+       ret
+ENDPROC(perf_regs_load)
+#endif
diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/arch/x86/util/unwind-libdw.c
new file mode 100644 (file)
index 0000000..c4b7217
--- /dev/null
@@ -0,0 +1,51 @@
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+       struct unwind_info *ui = arg;
+       struct regs_dump *user_regs = &ui->sample->user_regs;
+       Dwarf_Word dwarf_regs[17];
+       unsigned nregs;
+
+#define REG(r) ({                                              \
+       Dwarf_Word val = 0;                                     \
+       perf_reg_value(&val, user_regs, PERF_REG_X86_##r);      \
+       val;                                                    \
+})
+
+       if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
+               dwarf_regs[0] = REG(AX);
+               dwarf_regs[1] = REG(CX);
+               dwarf_regs[2] = REG(DX);
+               dwarf_regs[3] = REG(BX);
+               dwarf_regs[4] = REG(SP);
+               dwarf_regs[5] = REG(BP);
+               dwarf_regs[6] = REG(SI);
+               dwarf_regs[7] = REG(DI);
+               dwarf_regs[8] = REG(IP);
+               nregs = 9;
+       } else {
+               dwarf_regs[0]  = REG(AX);
+               dwarf_regs[1]  = REG(DX);
+               dwarf_regs[2]  = REG(CX);
+               dwarf_regs[3]  = REG(BX);
+               dwarf_regs[4]  = REG(SI);
+               dwarf_regs[5]  = REG(DI);
+               dwarf_regs[6]  = REG(BP);
+               dwarf_regs[7]  = REG(SP);
+               dwarf_regs[8]  = REG(R8);
+               dwarf_regs[9]  = REG(R9);
+               dwarf_regs[10] = REG(R10);
+               dwarf_regs[11] = REG(R11);
+               dwarf_regs[12] = REG(R12);
+               dwarf_regs[13] = REG(R13);
+               dwarf_regs[14] = REG(R14);
+               dwarf_regs[15] = REG(R15);
+               dwarf_regs[16] = REG(IP);
+               nregs = 17;
+       }
+
+       return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
+}
diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
new file mode 100644 (file)
index 0000000..3261f68
--- /dev/null
@@ -0,0 +1,111 @@
+
+#include <errno.h>
+#include <libunwind.h>
+#include "perf_regs.h"
+#include "../../util/unwind.h"
+
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+int libunwind__arch_reg_id(int regnum)
+{
+       int id;
+
+       switch (regnum) {
+       case UNW_X86_64_RAX:
+               id = PERF_REG_X86_AX;
+               break;
+       case UNW_X86_64_RDX:
+               id = PERF_REG_X86_DX;
+               break;
+       case UNW_X86_64_RCX:
+               id = PERF_REG_X86_CX;
+               break;
+       case UNW_X86_64_RBX:
+               id = PERF_REG_X86_BX;
+               break;
+       case UNW_X86_64_RSI:
+               id = PERF_REG_X86_SI;
+               break;
+       case UNW_X86_64_RDI:
+               id = PERF_REG_X86_DI;
+               break;
+       case UNW_X86_64_RBP:
+               id = PERF_REG_X86_BP;
+               break;
+       case UNW_X86_64_RSP:
+               id = PERF_REG_X86_SP;
+               break;
+       case UNW_X86_64_R8:
+               id = PERF_REG_X86_R8;
+               break;
+       case UNW_X86_64_R9:
+               id = PERF_REG_X86_R9;
+               break;
+       case UNW_X86_64_R10:
+               id = PERF_REG_X86_R10;
+               break;
+       case UNW_X86_64_R11:
+               id = PERF_REG_X86_R11;
+               break;
+       case UNW_X86_64_R12:
+               id = PERF_REG_X86_R12;
+               break;
+       case UNW_X86_64_R13:
+               id = PERF_REG_X86_R13;
+               break;
+       case UNW_X86_64_R14:
+               id = PERF_REG_X86_R14;
+               break;
+       case UNW_X86_64_R15:
+               id = PERF_REG_X86_R15;
+               break;
+       case UNW_X86_64_RIP:
+               id = PERF_REG_X86_IP;
+               break;
+       default:
+               pr_err("unwind: invalid reg id %d\n", regnum);
+               return -EINVAL;
+       }
+
+       return id;
+}
+#else
+int libunwind__arch_reg_id(int regnum)
+{
+       int id;
+
+       switch (regnum) {
+       case UNW_X86_EAX:
+               id = PERF_REG_X86_AX;
+               break;
+       case UNW_X86_EDX:
+               id = PERF_REG_X86_DX;
+               break;
+       case UNW_X86_ECX:
+               id = PERF_REG_X86_CX;
+               break;
+       case UNW_X86_EBX:
+               id = PERF_REG_X86_BX;
+               break;
+       case UNW_X86_ESI:
+               id = PERF_REG_X86_SI;
+               break;
+       case UNW_X86_EDI:
+               id = PERF_REG_X86_DI;
+               break;
+       case UNW_X86_EBP:
+               id = PERF_REG_X86_BP;
+               break;
+       case UNW_X86_ESP:
+               id = PERF_REG_X86_SP;
+               break;
+       case UNW_X86_EIP:
+               id = PERF_REG_X86_IP;
+               break;
+       default:
+               pr_err("unwind: invalid reg id %d\n", regnum);
+               return -EINVAL;
+       }
+
+       return id;
+}
+#endif /* HAVE_ARCH_X86_64_SUPPORT */
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind.c
deleted file mode 100644 (file)
index 456a88c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-
-#include <errno.h>
-#include <libunwind.h>
-#include "perf_regs.h"
-#include "../../util/unwind.h"
-
-#ifdef HAVE_ARCH_X86_64_SUPPORT
-int unwind__arch_reg_id(int regnum)
-{
-       int id;
-
-       switch (regnum) {
-       case UNW_X86_64_RAX:
-               id = PERF_REG_X86_AX;
-               break;
-       case UNW_X86_64_RDX:
-               id = PERF_REG_X86_DX;
-               break;
-       case UNW_X86_64_RCX:
-               id = PERF_REG_X86_CX;
-               break;
-       case UNW_X86_64_RBX:
-               id = PERF_REG_X86_BX;
-               break;
-       case UNW_X86_64_RSI:
-               id = PERF_REG_X86_SI;
-               break;
-       case UNW_X86_64_RDI:
-               id = PERF_REG_X86_DI;
-               break;
-       case UNW_X86_64_RBP:
-               id = PERF_REG_X86_BP;
-               break;
-       case UNW_X86_64_RSP:
-               id = PERF_REG_X86_SP;
-               break;
-       case UNW_X86_64_R8:
-               id = PERF_REG_X86_R8;
-               break;
-       case UNW_X86_64_R9:
-               id = PERF_REG_X86_R9;
-               break;
-       case UNW_X86_64_R10:
-               id = PERF_REG_X86_R10;
-               break;
-       case UNW_X86_64_R11:
-               id = PERF_REG_X86_R11;
-               break;
-       case UNW_X86_64_R12:
-               id = PERF_REG_X86_R12;
-               break;
-       case UNW_X86_64_R13:
-               id = PERF_REG_X86_R13;
-               break;
-       case UNW_X86_64_R14:
-               id = PERF_REG_X86_R14;
-               break;
-       case UNW_X86_64_R15:
-               id = PERF_REG_X86_R15;
-               break;
-       case UNW_X86_64_RIP:
-               id = PERF_REG_X86_IP;
-               break;
-       default:
-               pr_err("unwind: invalid reg id %d\n", regnum);
-               return -EINVAL;
-       }
-
-       return id;
-}
-#else
-int unwind__arch_reg_id(int regnum)
-{
-       int id;
-
-       switch (regnum) {
-       case UNW_X86_EAX:
-               id = PERF_REG_X86_AX;
-               break;
-       case UNW_X86_EDX:
-               id = PERF_REG_X86_DX;
-               break;
-       case UNW_X86_ECX:
-               id = PERF_REG_X86_CX;
-               break;
-       case UNW_X86_EBX:
-               id = PERF_REG_X86_BX;
-               break;
-       case UNW_X86_ESI:
-               id = PERF_REG_X86_SI;
-               break;
-       case UNW_X86_EDI:
-               id = PERF_REG_X86_DI;
-               break;
-       case UNW_X86_EBP:
-               id = PERF_REG_X86_BP;
-               break;
-       case UNW_X86_ESP:
-               id = PERF_REG_X86_SP;
-               break;
-       case UNW_X86_EIP:
-               id = PERF_REG_X86_IP;
-               break;
-       default:
-               pr_err("unwind: invalid reg id %d\n", regnum);
-               return -EINVAL;
-       }
-
-       return id;
-}
-#endif /* HAVE_ARCH_X86_64_SUPPORT */
index 0fdc85269c4dc4c2bd72220526879a07e76679be..eba46709b279d42244f1ed85265c390e2778b500 100644 (file)
@@ -31,6 +31,9 @@ extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
 extern int bench_mem_memcpy(int argc, const char **argv,
                            const char *prefix __maybe_unused);
 extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
+extern int bench_futex_hash(int argc, const char **argv, const char *prefix);
+extern int bench_futex_wake(int argc, const char **argv, const char *prefix);
+extern int bench_futex_requeue(int argc, const char **argv, const char *prefix);
 
 #define BENCH_FORMAT_DEFAULT_STR       "default"
 #define BENCH_FORMAT_DEFAULT           0
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
new file mode 100644 (file)
index 0000000..a84206e
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2013  Davidlohr Bueso <davidlohr@hp.com>
+ *
+ * futex-hash: Stress the hell out of the Linux kernel futex uaddr hashing.
+ *
+ * This program is particularly useful for measuring the kernel's futex hash
+ * table/function implementation. In order for it to make sense, use with as
+ * many threads and futexes as possible.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/stat.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "futex.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+static unsigned int nthreads = 0;
+static unsigned int nsecs    = 10;
+/* amount of futexes per thread */
+static unsigned int nfutexes = 1024;
+static bool fshared = false, done = false, silent = false;
+
+struct timeval start, end, runtime;
+static pthread_mutex_t thread_lock;
+static unsigned int threads_starting;
+static struct stats throughput_stats;
+static pthread_cond_t thread_parent, thread_worker;
+
+struct worker {
+       int tid;
+       u_int32_t *futex;
+       pthread_t thread;
+       unsigned long ops;
+};
+
+static const struct option options[] = {
+       OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
+       OPT_UINTEGER('r', "runtime", &nsecs,    "Specify runtime (in seconds)"),
+       OPT_UINTEGER('f', "futexes", &nfutexes, "Specify amount of futexes per threads"),
+       OPT_BOOLEAN( 's', "silent",  &silent,   "Silent mode: do not display data/details"),
+       OPT_BOOLEAN( 'S', "shared",  &fshared,  "Use shared futexes instead of private ones"),
+       OPT_END()
+};
+
+static const char * const bench_futex_hash_usage[] = {
+       "perf bench futex hash <options>",
+       NULL
+};
+
+static void *workerfn(void *arg)
+{
+       int ret;
+       unsigned int i;
+       struct worker *w = (struct worker *) arg;
+
+       pthread_mutex_lock(&thread_lock);
+       threads_starting--;
+       if (!threads_starting)
+               pthread_cond_signal(&thread_parent);
+       pthread_cond_wait(&thread_worker, &thread_lock);
+       pthread_mutex_unlock(&thread_lock);
+
+       do {
+               for (i = 0; i < nfutexes; i++, w->ops++) {
+                       /*
+                        * We want the futex calls to fail in order to stress
+                        * the hashing of uaddr and not measure other steps,
+                        * such as internal waitqueue handling, thus enlarging
+                        * the critical region protected by hb->lock.
+                        */
+                       ret = futex_wait(&w->futex[i], 1234, NULL,
+                                        fshared ? 0 : FUTEX_PRIVATE_FLAG);
+                       if (!silent &&
+                           (!ret || errno != EAGAIN || errno != EWOULDBLOCK))
+                               warn("Non-expected futex return call");
+               }
+       }  while (!done);
+
+       return NULL;
+}
+
+static void toggle_done(int sig __maybe_unused,
+                       siginfo_t *info __maybe_unused,
+                       void *uc __maybe_unused)
+{
+       /* inform all threads that we're done for the day */
+       done = true;
+       gettimeofday(&end, NULL);
+       timersub(&end, &start, &runtime);
+}
+
+static void print_summary(void)
+{
+       unsigned long avg = avg_stats(&throughput_stats);
+       double stddev = stddev_stats(&throughput_stats);
+
+       printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
+              !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
+              (int) runtime.tv_sec);
+}
+
+int bench_futex_hash(int argc, const char **argv,
+                    const char *prefix __maybe_unused)
+{
+       int ret = 0;
+       cpu_set_t cpu;
+       struct sigaction act;
+       unsigned int i, ncpus;
+       pthread_attr_t thread_attr;
+       struct worker *worker = NULL;
+
+       argc = parse_options(argc, argv, options, bench_futex_hash_usage, 0);
+       if (argc) {
+               usage_with_options(bench_futex_hash_usage, options);
+               exit(EXIT_FAILURE);
+       }
+
+       ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       sigfillset(&act.sa_mask);
+       act.sa_sigaction = toggle_done;
+       sigaction(SIGINT, &act, NULL);
+
+       if (!nthreads) /* default to the number of CPUs */
+               nthreads = ncpus;
+
+       worker = calloc(nthreads, sizeof(*worker));
+       if (!worker)
+               goto errmem;
+
+       printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
+              getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs);
+
+       init_stats(&throughput_stats);
+       pthread_mutex_init(&thread_lock, NULL);
+       pthread_cond_init(&thread_parent, NULL);
+       pthread_cond_init(&thread_worker, NULL);
+
+       threads_starting = nthreads;
+       pthread_attr_init(&thread_attr);
+       gettimeofday(&start, NULL);
+       for (i = 0; i < nthreads; i++) {
+               worker[i].tid = i;
+               worker[i].futex = calloc(nfutexes, sizeof(*worker[i].futex));
+               if (!worker[i].futex)
+                       goto errmem;
+
+               CPU_ZERO(&cpu);
+               CPU_SET(i % ncpus, &cpu);
+
+               ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu);
+               if (ret)
+                       err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
+
+               ret = pthread_create(&worker[i].thread, &thread_attr, workerfn,
+                                    (void *)(struct worker *) &worker[i]);
+               if (ret)
+                       err(EXIT_FAILURE, "pthread_create");
+
+       }
+       pthread_attr_destroy(&thread_attr);
+
+       pthread_mutex_lock(&thread_lock);
+       while (threads_starting)
+               pthread_cond_wait(&thread_parent, &thread_lock);
+       pthread_cond_broadcast(&thread_worker);
+       pthread_mutex_unlock(&thread_lock);
+
+       sleep(nsecs);
+       toggle_done(0, NULL, NULL);
+
+       for (i = 0; i < nthreads; i++) {
+               ret = pthread_join(worker[i].thread, NULL);
+               if (ret)
+                       err(EXIT_FAILURE, "pthread_join");
+       }
+
+       /* cleanup & report results */
+       pthread_cond_destroy(&thread_parent);
+       pthread_cond_destroy(&thread_worker);
+       pthread_mutex_destroy(&thread_lock);
+
+       for (i = 0; i < nthreads; i++) {
+               unsigned long t = worker[i].ops/runtime.tv_sec;
+               update_stats(&throughput_stats, t);
+               if (!silent) {
+                       if (nfutexes == 1)
+                               printf("[thread %2d] futex: %p [ %ld ops/sec ]\n",
+                                      worker[i].tid, &worker[i].futex[0], t);
+                       else
+                               printf("[thread %2d] futexes: %p ... %p [ %ld ops/sec ]\n",
+                                      worker[i].tid, &worker[i].futex[0],
+                                      &worker[i].futex[nfutexes-1], t);
+               }
+
+               free(worker[i].futex);
+       }
+
+       print_summary();
+
+       free(worker);
+       return ret;
+errmem:
+       err(EXIT_FAILURE, "calloc");
+}
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
new file mode 100644 (file)
index 0000000..a162558
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2013  Davidlohr Bueso <davidlohr@hp.com>
+ *
+ * futex-requeue: Block a bunch of threads on futex1 and requeue them
+ *                on futex2, N at a time.
+ *
+ * This program is particularly useful to measure the latency of nthread
+ * requeues without waking up any tasks -- thus mimicking a regular futex_wait.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/stat.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "futex.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+static u_int32_t futex1 = 0, futex2 = 0;
+
+/*
+ * How many tasks to requeue at a time.
+ * Default to 1 in order to make the kernel work more.
+ */
+static unsigned int nrequeue = 1;
+
+/*
+ * There can be significant variance from run to run,
+ * the more repeats, the more exact the overall avg and
+ * the better idea of the futex latency.
+ */
+static unsigned int repeat = 10;
+
+static pthread_t *worker;
+static bool done = 0, silent = 0;
+static pthread_mutex_t thread_lock;
+static pthread_cond_t thread_parent, thread_worker;
+static struct stats requeuetime_stats, requeued_stats;
+static unsigned int ncpus, threads_starting, nthreads = 0;
+
+static const struct option options[] = {
+       OPT_UINTEGER('t', "threads",  &nthreads, "Specify amount of threads"),
+       OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
+       OPT_UINTEGER('r', "repeat",   &repeat,   "Specify amount of times to repeat the run"),
+       OPT_BOOLEAN( 's', "silent",   &silent,   "Silent mode: do not display data/details"),
+       OPT_END()
+};
+
+static const char * const bench_futex_requeue_usage[] = {
+       "perf bench futex requeue <options>",
+       NULL
+};
+
+static void print_summary(void)
+{
+       double requeuetime_avg = avg_stats(&requeuetime_stats);
+       double requeuetime_stddev = stddev_stats(&requeuetime_stats);
+       unsigned int requeued_avg = avg_stats(&requeued_stats);
+
+       printf("Requeued %d of %d threads in %.4f ms (+-%.2f%%)\n",
+              requeued_avg,
+              nthreads,
+              requeuetime_avg/1e3,
+              rel_stddev_stats(requeuetime_stddev, requeuetime_avg));
+}
+
+static void *workerfn(void *arg __maybe_unused)
+{
+       pthread_mutex_lock(&thread_lock);
+       threads_starting--;
+       if (!threads_starting)
+               pthread_cond_signal(&thread_parent);
+       pthread_cond_wait(&thread_worker, &thread_lock);
+       pthread_mutex_unlock(&thread_lock);
+
+       futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+       return NULL;
+}
+
+static void block_threads(pthread_t *w,
+                         pthread_attr_t thread_attr)
+{
+       cpu_set_t cpu;
+       unsigned int i;
+
+       threads_starting = nthreads;
+
+       /* create and block all threads */
+       for (i = 0; i < nthreads; i++) {
+               CPU_ZERO(&cpu);
+               CPU_SET(i % ncpus, &cpu);
+
+               if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu))
+                       err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
+
+               if (pthread_create(&w[i], &thread_attr, workerfn, NULL))
+                       err(EXIT_FAILURE, "pthread_create");
+       }
+}
+
+static void toggle_done(int sig __maybe_unused,
+                       siginfo_t *info __maybe_unused,
+                       void *uc __maybe_unused)
+{
+       done = true;
+}
+
+int bench_futex_requeue(int argc, const char **argv,
+                       const char *prefix __maybe_unused)
+{
+       int ret = 0;
+       unsigned int i, j;
+       struct sigaction act;
+       pthread_attr_t thread_attr;
+
+       argc = parse_options(argc, argv, options, bench_futex_requeue_usage, 0);
+       if (argc)
+               goto err;
+
+       ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       sigfillset(&act.sa_mask);
+       act.sa_sigaction = toggle_done;
+       sigaction(SIGINT, &act, NULL);
+
+       if (!nthreads)
+               nthreads = ncpus;
+
+       worker = calloc(nthreads, sizeof(*worker));
+       if (!worker)
+               err(EXIT_FAILURE, "calloc");
+
+       printf("Run summary [PID %d]: Requeuing %d threads (from %p to %p), "
+              "%d at a time.\n\n",
+              getpid(), nthreads, &futex1, &futex2, nrequeue);
+
+       init_stats(&requeued_stats);
+       init_stats(&requeuetime_stats);
+       pthread_attr_init(&thread_attr);
+       pthread_mutex_init(&thread_lock, NULL);
+       pthread_cond_init(&thread_parent, NULL);
+       pthread_cond_init(&thread_worker, NULL);
+
+       for (j = 0; j < repeat && !done; j++) {
+               unsigned int nrequeued = 0;
+               struct timeval start, end, runtime;
+
+               /* create, launch & block all threads */
+               block_threads(worker, thread_attr);
+
+               /* make sure all threads are already blocked */
+               pthread_mutex_lock(&thread_lock);
+               while (threads_starting)
+                       pthread_cond_wait(&thread_parent, &thread_lock);
+               pthread_cond_broadcast(&thread_worker);
+               pthread_mutex_unlock(&thread_lock);
+
+               usleep(100000);
+
+               /* Ok, all threads are patiently blocked, start requeueing */
+               gettimeofday(&start, NULL);
+               for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue)
+                       /*
+                        * Do not wakeup any tasks blocked on futex1, allowing
+                        * us to really measure futex_wait functionality.
+                        */
+                       futex_cmp_requeue(&futex1, 0, &futex2, 0, nrequeue,
+                                         FUTEX_PRIVATE_FLAG);
+               gettimeofday(&end, NULL);
+               timersub(&end, &start, &runtime);
+
+               update_stats(&requeued_stats, nrequeued);
+               update_stats(&requeuetime_stats, runtime.tv_usec);
+
+               if (!silent) {
+                       printf("[Run %d]: Requeued %d of %d threads in %.4f ms\n",
+                              j + 1, nrequeued, nthreads, runtime.tv_usec/1e3);
+               }
+
+               /* everybody should be blocked on futex2, wake'em up */
+               nrequeued = futex_wake(&futex2, nthreads, FUTEX_PRIVATE_FLAG);
+               if (nthreads != nrequeued)
+                       warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads);
+
+               for (i = 0; i < nthreads; i++) {
+                       ret = pthread_join(worker[i], NULL);
+                       if (ret)
+                               err(EXIT_FAILURE, "pthread_join");
+               }
+
+       }
+
+       /* cleanup & report results */
+       pthread_cond_destroy(&thread_parent);
+       pthread_cond_destroy(&thread_worker);
+       pthread_mutex_destroy(&thread_lock);
+       pthread_attr_destroy(&thread_attr);
+
+       print_summary();
+
+       free(worker);
+       return ret;
+err:
+       usage_with_options(bench_futex_requeue_usage, options);
+       exit(EXIT_FAILURE);
+}
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
new file mode 100644 (file)
index 0000000..d096169
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2013  Davidlohr Bueso <davidlohr@hp.com>
+ *
+ * futex-wake: Block a bunch of threads on a futex and wake'em up, N at a time.
+ *
+ * This program is particularly useful to measure the latency of nthread wakeups
+ * in non-error situations:  all waiters are queued and all wake calls wakeup
+ * one or more tasks, and thus the waitqueue is never empty.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/stat.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "futex.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+/* all threads will block on the same futex */
+static u_int32_t futex1 = 0;
+
+/*
+ * How many wakeups to do at a time.
+ * Default to 1 in order to make the kernel work more.
+ */
+static unsigned int nwakes = 1;
+
+/*
+ * There can be significant variance from run to run,
+ * the more repeats, the more exact the overall avg and
+ * the better idea of the futex latency.
+ */
+static unsigned int repeat = 10;
+
+pthread_t *worker;
+static bool done = 0, silent = 0;
+static pthread_mutex_t thread_lock;
+static pthread_cond_t thread_parent, thread_worker;
+static struct stats waketime_stats, wakeup_stats;
+static unsigned int ncpus, threads_starting, nthreads = 0;
+
+static const struct option options[] = {
+       OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
+       OPT_UINTEGER('w', "nwakes",  &nwakes,   "Specify amount of threads to wake at once"),
+       OPT_UINTEGER('r', "repeat",  &repeat,   "Specify amount of times to repeat the run"),
+       OPT_BOOLEAN( 's', "silent",  &silent,   "Silent mode: do not display data/details"),
+       OPT_END()
+};
+
+static const char * const bench_futex_wake_usage[] = {
+       "perf bench futex wake <options>",
+       NULL
+};
+
+static void *workerfn(void *arg __maybe_unused)
+{
+       pthread_mutex_lock(&thread_lock);
+       threads_starting--;
+       if (!threads_starting)
+               pthread_cond_signal(&thread_parent);
+       pthread_cond_wait(&thread_worker, &thread_lock);
+       pthread_mutex_unlock(&thread_lock);
+
+       futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+       return NULL;
+}
+
+static void print_summary(void)
+{
+       double waketime_avg = avg_stats(&waketime_stats);
+       double waketime_stddev = stddev_stats(&waketime_stats);
+       unsigned int wakeup_avg = avg_stats(&wakeup_stats);
+
+       printf("Wokeup %d of %d threads in %.4f ms (+-%.2f%%)\n",
+              wakeup_avg,
+              nthreads,
+              waketime_avg/1e3,
+              rel_stddev_stats(waketime_stddev, waketime_avg));
+}
+
+static void block_threads(pthread_t *w,
+                         pthread_attr_t thread_attr)
+{
+       cpu_set_t cpu;
+       unsigned int i;
+
+       threads_starting = nthreads;
+
+       /* create and block all threads */
+       for (i = 0; i < nthreads; i++) {
+               CPU_ZERO(&cpu);
+               CPU_SET(i % ncpus, &cpu);
+
+               if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu))
+                       err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
+
+               if (pthread_create(&w[i], &thread_attr, workerfn, NULL))
+                       err(EXIT_FAILURE, "pthread_create");
+       }
+}
+
+static void toggle_done(int sig __maybe_unused,
+                       siginfo_t *info __maybe_unused,
+                       void *uc __maybe_unused)
+{
+       done = true;
+}
+
+int bench_futex_wake(int argc, const char **argv,
+                    const char *prefix __maybe_unused)
+{
+       int ret = 0;
+       unsigned int i, j;
+       struct sigaction act;
+       pthread_attr_t thread_attr;
+
+       argc = parse_options(argc, argv, options, bench_futex_wake_usage, 0);
+       if (argc) {
+               usage_with_options(bench_futex_wake_usage, options);
+               exit(EXIT_FAILURE);
+       }
+
+       ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       sigfillset(&act.sa_mask);
+       act.sa_sigaction = toggle_done;
+       sigaction(SIGINT, &act, NULL);
+
+       if (!nthreads)
+               nthreads = ncpus;
+
+       worker = calloc(nthreads, sizeof(*worker));
+       if (!worker)
+               err(EXIT_FAILURE, "calloc");
+
+       printf("Run summary [PID %d]: blocking on %d threads (at futex %p), "
+              "waking up %d at a time.\n\n",
+              getpid(), nthreads, &futex1, nwakes);
+
+       init_stats(&wakeup_stats);
+       init_stats(&waketime_stats);
+       pthread_attr_init(&thread_attr);
+       pthread_mutex_init(&thread_lock, NULL);
+       pthread_cond_init(&thread_parent, NULL);
+       pthread_cond_init(&thread_worker, NULL);
+
+       for (j = 0; j < repeat && !done; j++) {
+               unsigned int nwoken = 0;
+               struct timeval start, end, runtime;
+
+               /* create, launch & block all threads */
+               block_threads(worker, thread_attr);
+
+               /* make sure all threads are already blocked */
+               pthread_mutex_lock(&thread_lock);
+               while (threads_starting)
+                       pthread_cond_wait(&thread_parent, &thread_lock);
+               pthread_cond_broadcast(&thread_worker);
+               pthread_mutex_unlock(&thread_lock);
+
+               usleep(100000);
+
+               /* Ok, all threads are patiently blocked, start waking folks up */
+               gettimeofday(&start, NULL);
+               while (nwoken != nthreads)
+                       nwoken += futex_wake(&futex1, nwakes, FUTEX_PRIVATE_FLAG);
+               gettimeofday(&end, NULL);
+               timersub(&end, &start, &runtime);
+
+               update_stats(&wakeup_stats, nwoken);
+               update_stats(&waketime_stats, runtime.tv_usec);
+
+               if (!silent) {
+                       printf("[Run %d]: Wokeup %d of %d threads in %.4f ms\n",
+                              j + 1, nwoken, nthreads, runtime.tv_usec/1e3);
+               }
+
+               for (i = 0; i < nthreads; i++) {
+                       ret = pthread_join(worker[i], NULL);
+                       if (ret)
+                               err(EXIT_FAILURE, "pthread_join");
+               }
+
+       }
+
+       /* cleanup & report results */
+       pthread_cond_destroy(&thread_parent);
+       pthread_cond_destroy(&thread_worker);
+       pthread_mutex_destroy(&thread_lock);
+       pthread_attr_destroy(&thread_attr);
+
+       print_summary();
+
+       free(worker);
+       return ret;
+}
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h
new file mode 100644 (file)
index 0000000..71f2844
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Glibc independent futex library for testing kernel functionality.
+ * Shamelessly stolen from Darren Hart <dvhltc@us.ibm.com>
+ *    http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git/
+ */
+
+#ifndef _FUTEX_H
+#define _FUTEX_H
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <linux/futex.h>
+
+/**
+ * futex() - SYS_futex syscall wrapper
+ * @uaddr:     address of first futex
+ * @op:                futex op code
+ * @val:       typically expected value of uaddr, but varies by op
+ * @timeout:   typically an absolute struct timespec (except where noted
+ *             otherwise). Overloaded by some ops
+ * @uaddr2:    address of second futex for some ops\
+ * @val3:      varies by op
+ * @opflags:   flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
+ *
+ * futex() is used by all the following futex op wrappers. It can also be
+ * used for misuse and abuse testing. Generally, the specific op wrappers
+ * should be used instead. It is a macro instead of an static inline function as
+ * some of the types over overloaded (timeout is used for nr_requeue for
+ * example).
+ *
+ * These argument descriptions are the defaults for all
+ * like-named arguments in the following wrappers except where noted below.
+ */
+#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
+       syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
+
+/**
+ * futex_wait() - block on uaddr with optional timeout
+ * @timeout:   relative timeout
+ */
+static inline int
+futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
+{
+       return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
+}
+
+/**
+ * futex_wake() - wake one or more tasks blocked on uaddr
+ * @nr_wake:   wake up to this many tasks
+ */
+static inline int
+futex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
+{
+       return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
+}
+
+/**
+* futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
+* @nr_wake:        wake up to this many tasks
+* @nr_requeue:        requeue up to this many tasks
+*/
+static inline int
+futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wake,
+                int nr_requeue, int opflags)
+{
+       return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
+                val, opflags);
+}
+
+#endif /* _FUTEX_H */
index d4c83c60b9b29fa7d6249de70e5f0673d2066287..97d86d828190950af7f133c1b8be72550070d3d1 100644 (file)
@@ -1593,6 +1593,7 @@ static void init_params(struct params *p, const char *name, int argc, const char
        p->data_rand_walk               = true;
        p->nr_loops                     = -1;
        p->init_random                  = true;
+       p->run_all                      = argc == 1;
 }
 
 static int run_bench_numa(const char *name, const char **argv)
index e47f90cc7b98cdde57079975bbd5637f3249ce44..1e6e77710545afc472eae5c0f5e5a63f5ec432d1 100644 (file)
@@ -12,6 +12,7 @@
  *  sched ... scheduler and IPC performance
  *  mem   ... memory access performance
  *  numa  ... NUMA scheduling and MM performance
+ *  futex ... Futex performance
  */
 #include "perf.h"
 #include "util/util.h"
@@ -54,6 +55,14 @@ static struct bench mem_benchmarks[] = {
        { NULL,         NULL,                                           NULL                    }
 };
 
+static struct bench futex_benchmarks[] = {
+       { "hash",       "Benchmark for futex hash table",               bench_futex_hash        },
+       { "wake",       "Benchmark for futex wake calls",               bench_futex_wake        },
+       { "requeue",    "Benchmark for futex requeue calls",            bench_futex_requeue     },
+       { "all",        "Test all futex benchmarks",                    NULL                    },
+       { NULL,         NULL,                                           NULL                    }
+};
+
 struct collection {
        const char      *name;
        const char      *summary;
@@ -61,11 +70,12 @@ struct collection {
 };
 
 static struct collection collections[] = {
-       { "sched",      "Scheduler and IPC benchmarks",         sched_benchmarks        },
+       { "sched",      "Scheduler and IPC benchmarks",                 sched_benchmarks        },
        { "mem",        "Memory access benchmarks",                     mem_benchmarks          },
 #ifdef HAVE_LIBNUMA_SUPPORT
        { "numa",       "NUMA scheduling and MM benchmarks",            numa_benchmarks         },
 #endif
+       {"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
        { "all",        "All benchmarks",                               NULL                    },
        { NULL,         NULL,                                           NULL                    }
 };
@@ -76,7 +86,7 @@ static struct collection collections[] = {
 
 /* Iterate over all benchmarks within a collection: */
 #define for_each_bench(coll, bench) \
-       for (bench = coll->benchmarks; bench->name; bench++)
+       for (bench = coll->benchmarks; bench && bench->name; bench++)
 
 static void dump_benchmarks(struct collection *coll)
 {
index a77e31246c00ba1841a0b8447d97a04302f2ea3b..204fffe225320f3aa710d9e50da63de25c9d56a2 100644 (file)
@@ -952,8 +952,8 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
                                 dfmt->header_width, buf);
 }
 
-static int hpp__header(struct perf_hpp_fmt *fmt,
-                      struct perf_hpp *hpp)
+static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                      struct perf_evsel *evsel __maybe_unused)
 {
        struct diff_hpp_fmt *dfmt =
                container_of(fmt, struct diff_hpp_fmt, fmt);
@@ -963,7 +963,8 @@ static int hpp__header(struct perf_hpp_fmt *fmt,
 }
 
 static int hpp__width(struct perf_hpp_fmt *fmt,
-                     struct perf_hpp *hpp __maybe_unused)
+                     struct perf_hpp *hpp __maybe_unused,
+                     struct perf_evsel *evsel __maybe_unused)
 {
        struct diff_hpp_fmt *dfmt =
                container_of(fmt, struct diff_hpp_fmt, fmt);
index b3466018bbd7b514811dd6a5e2bad10ed275eb5b..3a7387551369c97ab38b249ced193cc386c2cabe 100644 (file)
@@ -312,7 +312,6 @@ found:
        sample_sw.period = sample->period;
        sample_sw.time   = sample->time;
        perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
-                                     evsel->attr.sample_regs_user,
                                      evsel->attr.read_format, &sample_sw,
                                      false);
        build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
index a7350519c63f528cfb627d736867742b57b1a2e8..21c164b8f9db2a70a9467e1341fbb6a49a3536a1 100644 (file)
@@ -1691,17 +1691,15 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
                OPT_END()
        };
 
-
-       const char * const kvm_usage[] = {
-               "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
-               NULL
-       };
+       const char *const kvm_subcommands[] = { "top", "record", "report", "diff",
+                                               "buildid-list", "stat", NULL };
+       const char *kvm_usage[] = { NULL, NULL };
 
        perf_host  = 0;
        perf_guest = 1;
 
-       argc = parse_options(argc, argv, kvm_options, kvm_usage,
-                       PARSE_OPT_STOP_AT_NON_OPTION);
+       argc = parse_options_subcommand(argc, argv, kvm_options, kvm_subcommands, kvm_usage,
+                                       PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc)
                usage_with_options(kvm_usage, kvm_options);
 
index 78948882e3de72c9a521f1d3c6d3bff29f2e493d..cdcd4eb3a57df5e48a77a3ba914251c896e0bfc1 100644 (file)
@@ -268,9 +268,9 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
        return 0;
 }
 
-static void init_params(void)
+static int init_params(void)
 {
-       line_range__init(&params.line_range);
+       return line_range__init(&params.line_range);
 }
 
 static void cleanup_params(void)
@@ -515,9 +515,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix)
 {
        int ret;
 
-       init_params();
-       ret = __cmd_probe(argc, argv, prefix);
-       cleanup_params();
+       ret = init_params();
+       if (!ret) {
+               ret = __cmd_probe(argc, argv, prefix);
+               cleanup_params();
+       }
 
        return ret;
 }
index af47531b82ecda73a9233b7c9aef27c70754666a..eb524f91bffe5d9098d582e07050734a1c3e5343 100644 (file)
@@ -649,7 +649,7 @@ error:
        return ret;
 }
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
 static int get_stack_size(char *str, unsigned long *_size)
 {
        char *endptr;
@@ -675,7 +675,7 @@ static int get_stack_size(char *str, unsigned long *_size)
               max_size, str);
        return -1;
 }
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 
 int record_parse_callchain(const char *arg, struct record_opts *opts)
 {
@@ -704,7 +704,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
                                       "needed for -g fp\n");
                        break;
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
                /* Dwarf style */
                } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
                        const unsigned long default_stack_dump_size = 8192;
@@ -720,7 +720,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
                                ret = get_stack_size(tok, &size);
                                opts->stack_dump_size = size;
                        }
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
                } else {
                        pr_err("callchain: Unknown --call-graph option "
                               "value: %s\n", arg);
@@ -735,7 +735,9 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
 
 static void callchain_debug(struct record_opts *opts)
 {
-       pr_debug("callchain: type %d\n", opts->call_graph);
+       static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
+
+       pr_debug("callchain: type %s\n", str[opts->call_graph]);
 
        if (opts->call_graph == CALLCHAIN_DWARF)
                pr_debug("callchain: stack dump size %d\n",
@@ -749,6 +751,8 @@ int record_parse_callchain_opt(const struct option *opt,
        struct record_opts *opts = opt->value;
        int ret;
 
+       opts->call_graph_enabled = !unset;
+
        /* --no-call-graph */
        if (unset) {
                opts->call_graph = CALLCHAIN_NONE;
@@ -769,6 +773,8 @@ int record_callchain_opt(const struct option *opt,
 {
        struct record_opts *opts = opt->value;
 
+       opts->call_graph_enabled = !unset;
+
        if (opts->call_graph == CALLCHAIN_NONE)
                opts->call_graph = CALLCHAIN_FP;
 
@@ -776,6 +782,16 @@ int record_callchain_opt(const struct option *opt,
        return 0;
 }
 
+static int perf_record_config(const char *var, const char *value, void *cb)
+{
+       struct record *rec = cb;
+
+       if (!strcmp(var, "record.call-graph"))
+               return record_parse_callchain(value, &rec->opts);
+
+       return perf_default_config(var, value, cb);
+}
+
 static const char * const record_usage[] = {
        "perf record [<options>] [<command>]",
        "perf record [<options>] -- <command> [<options>]",
@@ -807,7 +823,7 @@ static struct record record = {
 
 #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
 const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
 #else
 const char record_callchain_help[] = CALLCHAIN_HELP "fp";
@@ -907,6 +923,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
        if (rec->evlist == NULL)
                return -ENOMEM;
 
+       perf_config(perf_record_config, rec);
+
        argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target__none(&rec->opts.target))
index 02f985f3a396916ff60e4fcd8123bc109fa0dab4..c8f21137dfd8ad7f80472acf020eab9e3f492bb6 100644 (file)
@@ -75,13 +75,10 @@ static int report__config(const char *var, const char *value, void *cb)
        return perf_default_config(var, value, cb);
 }
 
-static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
-                                     struct perf_sample *sample, struct perf_evsel *evsel,
-                                     union perf_event *event)
+static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
+                                     struct perf_sample *sample, struct perf_evsel *evsel)
 {
-       struct report *rep = container_of(tool, struct report, tool);
        struct symbol *parent = NULL;
-       u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
        struct hist_entry *he;
        struct mem_info *mi, *mx;
        uint64_t cost;
@@ -90,7 +87,7 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
        if (err)
                return err;
 
-       mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
+       mi = sample__resolve_mem(sample, al);
        if (!mi)
                return -ENOMEM;
 
@@ -131,10 +128,9 @@ out:
        return err;
 }
 
-static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
+static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
                                         struct perf_sample *sample, struct perf_evsel *evsel)
 {
-       struct report *rep = container_of(tool, struct report, tool);
        struct symbol *parent = NULL;
        unsigned i;
        struct hist_entry *he;
@@ -144,8 +140,7 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
        if (err)
                return err;
 
-       bi = machine__resolve_bstack(al->machine, al->thread,
-                                    sample->branch_stack);
+       bi = sample__resolve_bstack(sample, al);
        if (!bi)
                return -ENOMEM;
 
@@ -190,10 +185,9 @@ out:
        return err;
 }
 
-static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
+static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
                                  struct addr_location *al, struct perf_sample *sample)
 {
-       struct report *rep = container_of(tool, struct report, tool);
        struct symbol *parent = NULL;
        struct hist_entry *he;
        int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
@@ -237,25 +231,25 @@ static int process_sample_event(struct perf_tool *tool,
                return -1;
        }
 
-       if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
+       if (rep->hide_unresolved && al.sym == NULL)
                return 0;
 
        if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
                return 0;
 
        if (sort__mode == SORT_MODE__BRANCH) {
-               ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
+               ret = report__add_branch_hist_entry(rep, &al, sample, evsel);
                if (ret < 0)
                        pr_debug("problem adding lbr entry, skipping event\n");
        } else if (rep->mem_mode == 1) {
-               ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
+               ret = report__add_mem_hist_entry(rep, &al, sample, evsel);
                if (ret < 0)
                        pr_debug("problem adding mem entry, skipping event\n");
        } else {
                if (al.map != NULL)
                        al.map->dso->hit = 1;
 
-               ret = report__add_hist_entry(tool, evsel, &al, sample);
+               ret = report__add_hist_entry(rep, evsel, &al, sample);
                if (ret < 0)
                        pr_debug("problem incrementing symbol period, skipping event\n");
        }
@@ -934,7 +928,7 @@ repeat:
         * so don't allocate extra space that won't be used in the stdio
         * implementation.
         */
-       if (use_browser == 1 && sort__has_sym) {
+       if (ui__has_annotation()) {
                symbol_conf.priv_size = sizeof(struct annotation);
                machines__set_symbol_filter(&session->machines,
                                            symbol__annotate_init);
index 6a76a07b67890c253fbb1e227e9aaa980b499779..9ac0a495c954e5793ddfe9e0e42ef4ee995bec56 100644 (file)
@@ -1124,7 +1124,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
 
        avg = work_list->total_lat / work_list->nb_atoms;
 
-       printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
+       printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %13.6f s\n",
              (double)work_list->total_runtime / 1e6,
                 work_list->nb_atoms, (double)avg / 1e6,
                 (double)work_list->max_lat / 1e6,
@@ -1527,9 +1527,9 @@ static int perf_sched__lat(struct perf_sched *sched)
 
        perf_sched__sort_lat(sched);
 
-       printf("\n ---------------------------------------------------------------------------------------------------------------\n");
-       printf("  Task                  |   Runtime ms  | Switches | Average delay ms | Maximum delay ms | Maximum delay at     |\n");
-       printf(" ---------------------------------------------------------------------------------------------------------------\n");
+       printf("\n -----------------------------------------------------------------------------------------------------------------\n");
+       printf("  Task                  |   Runtime ms  | Switches | Average delay ms | Maximum delay ms | Maximum delay at       |\n");
+       printf(" -----------------------------------------------------------------------------------------------------------------\n");
 
        next = rb_first(&sched->sorted_atom_root);
 
@@ -1541,7 +1541,7 @@ static int perf_sched__lat(struct perf_sched *sched)
                next = rb_next(next);
        }
 
-       printf(" -----------------------------------------------------------------------------------------\n");
+       printf(" -----------------------------------------------------------------------------------------------------------------\n");
        printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
                (double)sched->all_runtime / 1e6, sched->all_count);
 
index 25526d6eae59f65a4a0405c9186d93b9cd5d3d59..74db2568b867b7996726674edd20539a7820dcc9 100644 (file)
@@ -494,7 +494,7 @@ static const char *cat_backtrace(union perf_event *event,
                        continue;
                }
 
-               tal.filtered = false;
+               tal.filtered = 0;
                thread__find_addr_location(al.thread, machine, cpumode,
                                           MAP__FUNCTION, ip, &tal);
 
@@ -1238,7 +1238,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
        for (i = 0; i < old_power_args_nr; i++)
                *p++ = strdup(old_power_args[i]);
 
-       for (j = 1; j < (unsigned int)argc; j++)
+       for (j = 0; j < (unsigned int)argc; j++)
                *p++ = argv[j];
 
        return cmd_record(rec_argc, rec_argv, NULL);
index 5f989a7d8bc2166e30d6bcbef710015f019ab252..65aaa5bbf7ec75830b9b58afae6c6d66d352a9f7 100644 (file)
@@ -993,6 +993,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
        return record_parse_callchain_opt(opt, arg, unset);
 }
 
+static int perf_top_config(const char *var, const char *value, void *cb)
+{
+       struct perf_top *top = cb;
+
+       if (!strcmp(var, "top.call-graph"))
+               return record_parse_callchain(value, &top->record_opts);
+
+       return perf_default_config(var, value, cb);
+}
+
 static int
 parse_percent_limit(const struct option *opt, const char *arg,
                    int unset __maybe_unused)
@@ -1117,6 +1127,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (top.evlist == NULL)
                return -ENOMEM;
 
+       perf_config(perf_top_config, &top);
+
        argc = parse_options(argc, argv, options, top_usage, 0);
        if (argc)
                usage_with_options(top_usage, options);
index 6aa6fb6f7bd938b7ed7ccc2e7c07511b03a6cee6..f954c26de231d2860cf1b70a5ccb6597629137b8 100644 (file)
@@ -825,7 +825,6 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
        P_SIGNUM(PIPE);
        P_SIGNUM(ALRM);
        P_SIGNUM(TERM);
-       P_SIGNUM(STKFLT);
        P_SIGNUM(CHLD);
        P_SIGNUM(CONT);
        P_SIGNUM(STOP);
@@ -841,6 +840,15 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
        P_SIGNUM(IO);
        P_SIGNUM(PWR);
        P_SIGNUM(SYS);
+#ifdef SIGEMT
+       P_SIGNUM(EMT);
+#endif
+#ifdef SIGSTKFLT
+       P_SIGNUM(STKFLT);
+#endif
+#ifdef SIGSWI
+       P_SIGNUM(SWI);
+#endif
        default: break;
        }
 
index 0331ea2701a380c536facf82b8306729f23d9de3..c23418225c2c806086012b982faf7769f64efd98 100644 (file)
@@ -59,6 +59,18 @@ ifeq ($(NO_PERF_REGS),0)
   CFLAGS += -DHAVE_PERF_REGS_SUPPORT
 endif
 
+ifndef NO_LIBELF
+  # 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
+
+    FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
+    FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
+  endif
+endif
+
 # include ARCH specific config
 -include $(src-perf)/arch/$(ARCH)/Makefile
 
@@ -147,7 +159,35 @@ CORE_FEATURE_TESTS =                       \
        libunwind                       \
        on-exit                         \
        stackprotector-all              \
-       timerfd
+       timerfd                         \
+       libdw-dwarf-unwind
+
+LIB_FEATURE_TESTS =                    \
+       dwarf                           \
+       glibc                           \
+       gtk2                            \
+       libaudit                        \
+       libbfd                          \
+       libelf                          \
+       libnuma                         \
+       libperl                         \
+       libpython                       \
+       libslang                        \
+       libunwind                       \
+       libdw-dwarf-unwind
+
+VF_FEATURE_TESTS =                     \
+       backtrace                       \
+       fortify-source                  \
+       gtk2-infobar                    \
+       libelf-getphdrnum               \
+       libelf-mmap                     \
+       libpython-version               \
+       on-exit                         \
+       stackprotector-all              \
+       timerfd                         \
+       libunwind-debug-frame           \
+       bionic
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
@@ -160,17 +200,6 @@ endef
 
 $(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
 
-#
-# So here we detect whether test-all was rebuilt, to be able
-# to skip the print-out of the long features list if the file
-# existed before and after it was built:
-#
-ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),)
-  test-all-failed := 1
-else
-  test-all-failed := 0
-endif
-
 #
 # Special fast-path for the 'all features are available' case:
 #
@@ -180,15 +209,6 @@ $(call feature_check,all,$(MSG))
 # Just in case the build freshly failed, make sure we print the
 # feature matrix:
 #
-ifeq ($(feature-all), 0)
-  test-all-failed := 1
-endif
-
-ifeq ($(test-all-failed),1)
-  $(info )
-  $(info Auto-detecting system features:)
-endif
-
 ifeq ($(feature-all), 1)
   #
   # test-all.c passed - just set all the core feature flags to 1:
@@ -199,27 +219,6 @@ else
   $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
 endif
 
-#
-# Print the result of the feature test:
-#
-feature_print = $(eval $(feature_print_code)) $(info $(MSG))
-
-define feature_print_code
-  ifeq ($(feature-$(1)), 1)
-    MSG = $(shell printf '...%30s: [ \033[32mon\033[m  ]' $(1))
-  else
-    MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
-  endif
-endef
-
-#
-# Only print out our features if we rebuilt the testcases or if a test failed:
-#
-ifeq ($(test-all-failed), 1)
-  $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
-  $(info )
-endif
-
 ifeq ($(feature-stackprotector-all), 1)
   CFLAGS += -fstack-protector-all
 endif
@@ -264,6 +263,7 @@ ifdef NO_LIBELF
   NO_DWARF := 1
   NO_DEMANGLE := 1
   NO_LIBUNWIND := 1
+  NO_LIBDW_DWARF_UNWIND := 1
 else
   ifeq ($(feature-libelf), 0)
     ifeq ($(feature-glibc), 1)
@@ -282,13 +282,12 @@ 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
+    ifndef NO_LIBDW_DWARF_UNWIND
+      ifneq ($(feature-libdw-dwarf-unwind),1)
+        NO_LIBDW_DWARF_UNWIND := 1
+        msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
+      endif
     endif
-
     ifneq ($(feature-dwarf), 1)
       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
@@ -324,25 +323,51 @@ endif # NO_LIBELF
 
 ifndef NO_LIBUNWIND
   ifneq ($(feature-libunwind), 1)
-    msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
+    msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
     NO_LIBUNWIND := 1
+  endif
+endif
+
+dwarf-post-unwind := 1
+dwarf-post-unwind-text := BUG
+
+# setup DWARF post unwinder
+ifdef NO_LIBUNWIND
+  ifdef NO_LIBDW_DWARF_UNWIND
+    msg := $(warning Disabling post unwind, no support found.);
+    dwarf-post-unwind := 0
   else
-    ifeq ($(ARCH),arm)
-      $(call feature_check,libunwind-debug-frame)
-      ifneq ($(feature-libunwind-debug-frame), 1)
-        msg := $(warning No debug_frame support found in libunwind);
-        CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
-      endif
-    else
-      # non-ARM has no dwarf_find_debug_frame() function:
+    dwarf-post-unwind-text := libdw
+  endif
+else
+  dwarf-post-unwind-text := libunwind
+  # Enable libunwind support by default.
+  ifndef NO_LIBDW_DWARF_UNWIND
+    NO_LIBDW_DWARF_UNWIND := 1
+  endif
+endif
+
+ifeq ($(dwarf-post-unwind),1)
+  CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
+else
+  NO_DWARF_UNWIND := 1
+endif
+
+ifndef NO_LIBUNWIND
+  ifeq ($(ARCH),arm)
+    $(call feature_check,libunwind-debug-frame)
+    ifneq ($(feature-libunwind-debug-frame), 1)
+      msg := $(warning No debug_frame support found in libunwind);
       CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
     endif
-
-    CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
-    EXTLIBS += $(LIBUNWIND_LIBS)
-    CFLAGS += $(LIBUNWIND_CFLAGS)
-    LDFLAGS += $(LIBUNWIND_LDFLAGS)
-  endif # ifneq ($(feature-libunwind), 1)
+  else
+    # non-ARM has no dwarf_find_debug_frame() function:
+    CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+  endif
+  CFLAGS  += -DHAVE_LIBUNWIND_SUPPORT
+  EXTLIBS += $(LIBUNWIND_LIBS)
+  CFLAGS  += $(LIBUNWIND_CFLAGS)
+  LDFLAGS += $(LIBUNWIND_LDFLAGS)
 endif
 
 ifndef NO_LIBAUDIT
@@ -602,3 +627,84 @@ ifdef DESTDIR
 plugindir=$(libdir)/traceevent/plugins
 plugindir_SQ= $(subst ','\'',$(plugindir))
 endif
+
+#
+# Print the result of the feature test:
+#
+feature_print_status = $(eval $(feature_print_status_code)) $(info $(MSG))
+
+define feature_print_status_code
+  ifeq ($(feature-$(1)), 1)
+    MSG = $(shell printf '...%30s: [ \033[32mon\033[m  ]' $(1))
+  else
+    MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
+  endif
+endef
+
+feature_print_var = $(eval $(feature_print_var_code)) $(info $(MSG))
+define feature_print_var_code
+    MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
+endef
+
+feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG))
+define feature_print_text_code
+    MSG = $(shell printf '...%30s: %s' $(1) $(2))
+endef
+
+PERF_FEATURES := $(foreach feat,$(LIB_FEATURE_TESTS),feature-$(feat)($(feature-$(feat))))
+PERF_FEATURES_FILE := $(shell touch $(OUTPUT)PERF-FEATURES; cat $(OUTPUT)PERF-FEATURES)
+
+ifeq ($(dwarf-post-unwind),1)
+  PERF_FEATURES += dwarf-post-unwind($(dwarf-post-unwind-text))
+endif
+
+# The $(display_lib) controls the default detection message
+# output. It's set if:
+# - detected features differes from stored features from
+#   last build (in PERF-FEATURES file)
+# - one of the $(LIB_FEATURE_TESTS) is not detected
+# - VF is enabled
+
+ifneq ("$(PERF_FEATURES)","$(PERF_FEATURES_FILE)")
+  $(shell echo "$(PERF_FEATURES)" > $(OUTPUT)PERF-FEATURES)
+  display_lib := 1
+endif
+
+feature_check = $(eval $(feature_check_code))
+define feature_check_code
+  ifneq ($(feature-$(1)), 1)
+    display_lib := 1
+  endif
+endef
+
+$(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_check,$(feat)))
+
+ifeq ($(VF),1)
+  display_lib := 1
+  display_vf := 1
+endif
+
+ifeq ($(display_lib),1)
+  $(info )
+  $(info Auto-detecting system features:)
+  $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_print_status,$(feat),))
+
+  ifeq ($(dwarf-post-unwind),1)
+    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
+  endif
+endif
+
+ifeq ($(display_vf),1)
+  $(foreach feat,$(VF_FEATURE_TESTS),$(call feature_print_status,$(feat),))
+  $(info )
+  $(call feature_print_var,prefix)
+  $(call feature_print_var,bindir)
+  $(call feature_print_var,libdir)
+  $(call feature_print_var,sysconfdir)
+  $(call feature_print_var,LIBUNWIND_DIR)
+  $(call feature_print_var,LIBDW_DIR)
+endif
+
+ifeq ($(display_lib),1)
+  $(info )
+endif
index 523b7bc1055321051d62562f1f490165ea2872b5..2da103c53f892762b0ad634e1d60669a7c4b5b8a 100644 (file)
@@ -26,7 +26,8 @@ FILES=                                        \
        test-libunwind-debug-frame.bin  \
        test-on-exit.bin                \
        test-stackprotector-all.bin     \
-       test-timerfd.bin
+       test-timerfd.bin                \
+       test-libdw-dwarf-unwind.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -141,6 +142,9 @@ test-backtrace.bin:
 test-timerfd.bin:
        $(BUILD)
 
+test-libdw-dwarf-unwind.bin:
+       $(BUILD)
+
 -include *.d
 
 ###############################
index 9b8a544155bbdf2a628f21f400dda8e65f9d51a7..fc37eb3ca17b9121c60ae47133b540896700756c 100644 (file)
 # include "test-stackprotector-all.c"
 #undef main
 
+#define main main_test_libdw_dwarf_unwind
+# include "test-libdw-dwarf-unwind.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
        main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
        main_test_libnuma();
        main_test_timerfd();
        main_test_stackprotector_all();
+       main_test_libdw_dwarf_unwind();
 
        return 0;
 }
diff --git a/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
new file mode 100644 (file)
index 0000000..f676a3f
--- /dev/null
@@ -0,0 +1,13 @@
+
+#include <elfutils/libdwfl.h>
+
+int main(void)
+{
+       /*
+        * This function is guarded via: __nonnull_attribute__ (1, 2).
+        * Passing '1' as arguments value. This code is never executed,
+        * only compiled.
+        */
+       dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
+       return 0;
+}
index 63a0e6f04a01191fb6e90f7e220280edfa2d4cea..a28dca2582aa63f38fb2997235ab1818a9a45e42 100644 (file)
@@ -18,7 +18,7 @@ underlying hardware counters.
 Performance counters are accessed via special file descriptors.
 There's one file descriptor per virtual counter used.
 
-The special file descriptor is opened via the perf_event_open()
+The special file descriptor is opened via the sys_perf_event_open()
 system call:
 
    int sys_perf_event_open(struct perf_event_attr *hw_event_uptr,
@@ -82,7 +82,7 @@ machine-specific.
 If 'raw_type' is 0, then the 'type' field says what kind of counter
 this is, with the following encoding:
 
-enum perf_event_types {
+enum perf_type_id {
        PERF_TYPE_HARDWARE              = 0,
        PERF_TYPE_SOFTWARE              = 1,
        PERF_TYPE_TRACEPOINT            = 2,
@@ -95,7 +95,7 @@ specified by 'event_id':
  * Generalized performance counter event types, used by the hw_event.event_id
  * parameter of the sys_perf_event_open() syscall:
  */
-enum hw_event_ids {
+enum perf_hw_id {
        /*
         * Common hardware events, generalized by the kernel:
         */
@@ -129,7 +129,7 @@ software events, selected by 'event_id':
  * physical and sw events of the kernel (and allow the profiling of them as
  * well):
  */
-enum sw_event_ids {
+enum perf_sw_ids {
        PERF_COUNT_SW_CPU_CLOCK         = 0,
        PERF_COUNT_SW_TASK_CLOCK        = 1,
        PERF_COUNT_SW_PAGE_FAULTS       = 2,
@@ -230,7 +230,7 @@ these events are recorded in the ring-buffer (see below).
 The 'comm' bit allows tracking of process comm data on process creation.
 This too is recorded in the ring-buffer (see below).
 
-The 'pid' parameter to the perf_event_open() system call allows the
+The 'pid' parameter to the sys_perf_event_open() system call allows the
 counter to be specific to a task:
 
  pid == 0: if the pid parameter is zero, the counter is attached to the
@@ -260,7 +260,7 @@ The 'flags' parameter is currently unused and must be zero.
 
 The 'group_fd' parameter allows counter "groups" to be set up.  A
 counter group has one counter which is the group "leader".  The leader
-is created first, with group_fd = -1 in the perf_event_open call
+is created first, with group_fd = -1 in the sys_perf_event_open call
 that creates it.  The rest of the group members are created
 subsequently, with group_fd giving the fd of the group leader.
 (A single counter on its own is created with group_fd = -1 and is
index 496e2abb54824e3fbcc937e3cfc267ea3bfa82b0..ae3a57694b6bda9937146c25e291ab9a80929ce7 100644 (file)
@@ -123,7 +123,7 @@ __perf_main ()
                __perfcomp_colon "$evts" "$cur"
        # List subcommands for 'perf kvm'
        elif [[ $prev == "kvm" ]]; then
-               subcmds="top record report diff buildid-list stat"
+               subcmds=$($cmd $prev --list-cmds)
                __perfcomp_colon "$subcmds" "$cur"
        # List long option names
        elif [[ $cur == --* ]];  then
index e84fa26bc1bec472e65696b1649656bb4cae3af4..e18a8b5e69531cca4e1fbf889098d779ff14cf4d 100644 (file)
@@ -12,6 +12,9 @@
 #ifndef __NR_perf_event_open
 # define __NR_perf_event_open 336
 #endif
+#ifndef __NR_futex
+# define __NR_futex 240
+#endif
 #endif
 
 #if defined(__x86_64__)
@@ -23,6 +26,9 @@
 #ifndef __NR_perf_event_open
 # define __NR_perf_event_open 298
 #endif
+#ifndef __NR_futex
+# define __NR_futex 202
+#endif
 #endif
 
 #ifdef __powerpc__
@@ -251,12 +257,14 @@ void pthread__unblock_sigwinch(void);
 enum perf_call_graph_mode {
        CALLCHAIN_NONE,
        CALLCHAIN_FP,
-       CALLCHAIN_DWARF
+       CALLCHAIN_DWARF,
+       CALLCHAIN_MAX
 };
 
 struct record_opts {
        struct target target;
        int          call_graph;
+       bool         call_graph_enabled;
        bool         group;
        bool         inherit_stat;
        bool         no_buffering;
index 1e67437fb4cae5c770087432d248591b05baa033..b11bf8a08430b1c37ea4ac0f70ba2f418986508d 100644 (file)
@@ -115,6 +115,14 @@ static struct test {
                .desc = "Test parsing with no sample_id_all bit set",
                .func = test__parse_no_sample_id_all,
        },
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+       {
+               .desc = "Test dwarf unwind",
+               .func = test__dwarf_unwind,
+       },
+#endif
+#endif
        {
                .func = NULL,
        },
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
new file mode 100644 (file)
index 0000000..c059ee8
--- /dev/null
@@ -0,0 +1,144 @@
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "tests.h"
+#include "debug.h"
+#include "machine.h"
+#include "event.h"
+#include "unwind.h"
+#include "perf_regs.h"
+#include "map.h"
+#include "thread.h"
+
+static int mmap_handler(struct perf_tool *tool __maybe_unused,
+                       union perf_event *event,
+                       struct perf_sample *sample __maybe_unused,
+                       struct machine *machine)
+{
+       return machine__process_mmap_event(machine, event, NULL);
+}
+
+static int init_live_machine(struct machine *machine)
+{
+       union perf_event event;
+       pid_t pid = getpid();
+
+       return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
+                                                 mmap_handler, machine, true);
+}
+
+#define MAX_STACK 6
+
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+       unsigned long *cnt = (unsigned long *) arg;
+       char *symbol = entry->sym ? entry->sym->name : NULL;
+       static const char *funcs[MAX_STACK] = {
+               "test__arch_unwind_sample",
+               "unwind_thread",
+               "krava_3",
+               "krava_2",
+               "krava_1",
+               "test__dwarf_unwind"
+       };
+
+       if (*cnt >= MAX_STACK) {
+               pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
+               return -1;
+       }
+
+       if (!symbol) {
+               pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
+                        entry->ip);
+               return -1;
+       }
+
+       pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
+       return strcmp((const char *) symbol, funcs[(*cnt)++]);
+}
+
+__attribute__ ((noinline))
+static int unwind_thread(struct thread *thread, struct machine *machine)
+{
+       struct perf_sample sample;
+       unsigned long cnt = 0;
+       int err = -1;
+
+       memset(&sample, 0, sizeof(sample));
+
+       if (test__arch_unwind_sample(&sample, thread)) {
+               pr_debug("failed to get unwind sample\n");
+               goto out;
+       }
+
+       err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
+                                 &sample, MAX_STACK);
+       if (err)
+               pr_debug("unwind failed\n");
+       else if (cnt != MAX_STACK) {
+               pr_debug("got wrong number of stack entries %lu != %d\n",
+                        cnt, MAX_STACK);
+               err = -1;
+       }
+
+ out:
+       free(sample.user_stack.data);
+       free(sample.user_regs.regs);
+       return err;
+}
+
+__attribute__ ((noinline))
+static int krava_3(struct thread *thread, struct machine *machine)
+{
+       return unwind_thread(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_2(struct thread *thread, struct machine *machine)
+{
+       return krava_3(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_1(struct thread *thread, struct machine *machine)
+{
+       return krava_2(thread, machine);
+}
+
+int test__dwarf_unwind(void)
+{
+       struct machines machines;
+       struct machine *machine;
+       struct thread *thread;
+       int err = -1;
+
+       machines__init(&machines);
+
+       machine = machines__find(&machines, HOST_KERNEL_ID);
+       if (!machine) {
+               pr_err("Could not get machine\n");
+               return -1;
+       }
+
+       if (init_live_machine(machine)) {
+               pr_err("Could not init machine\n");
+               goto out;
+       }
+
+       if (verbose > 1)
+               machine__fprintf(machine, stderr);
+
+       thread = machine__find_thread(machine, getpid(), getpid());
+       if (!thread) {
+               pr_err("Could not get thread\n");
+               goto out;
+       }
+
+       err = krava_1(thread, machine);
+
+ out:
+       machine__delete_threads(machine);
+       machine__exit(machine);
+       machines__exit(&machines);
+       return err;
+}
index 2b6519e0e36f09bdbdeac4865fed851f82a3a1ac..7ccbc7b6ae775e0c2793e77706a0acfaf86f5a27 100644 (file)
@@ -101,6 +101,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
                        .mmap = {
                                .header = { .misc = PERF_RECORD_MISC_USER, },
                                .pid = fake_mmap_info[i].pid,
+                               .tid = fake_mmap_info[i].pid,
                                .start = fake_mmap_info[i].start,
                                .len = 0x1000ULL,
                                .pgoff = 0ULL,
index 00544b8b644b3bf28c97e392955bfcdb36a509fb..5daeae1cb4c01b3a87f4c54ee4018199c12aeeb6 100644 (file)
@@ -27,6 +27,7 @@ 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_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1
 make_no_backtrace   := NO_BACKTRACE=1
 make_no_libnuma     := NO_LIBNUMA=1
 make_no_libaudit    := NO_LIBAUDIT=1
@@ -35,8 +36,9 @@ make_tags           := tags
 make_cscope         := cscope
 make_help           := help
 make_doc            := doc
-make_perf_o         := perf.o
-make_util_map_o     := util/map.o
+make_perf_o           := perf.o
+make_util_map_o       := util/map.o
+make_util_pmu_bison_o := util/pmu-bison.o
 make_install        := install
 make_install_bin    := install-bin
 make_install_doc    := install-doc
@@ -49,6 +51,7 @@ make_install_pdf    := install-pdf
 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
+make_minimal        += NO_LIBDW_DWARF_UNWIND=1
 
 # $(run) contains all available tests
 run := make_pure
@@ -65,6 +68,7 @@ run += make_no_ui
 run += make_no_demangle
 run += make_no_libelf
 run += make_no_libunwind
+run += make_no_libdw_dwarf_unwind
 run += make_no_backtrace
 run += make_no_libnuma
 run += make_no_libaudit
@@ -73,6 +77,7 @@ run += make_help
 run += make_doc
 run += make_perf_o
 run += make_util_map_o
+run += make_util_pmu_bison_o
 run += make_install
 run += make_install_bin
 # FIXME 'install-*' commented out till they're fixed
@@ -113,8 +118,9 @@ 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
+test_make_perf_o           := test -f $(PERF)/perf.o
+test_make_util_map_o       := test -f $(PERF)/util/map.o
+test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o
 
 define test_dest_files
   for file in $(1); do                         \
@@ -167,13 +173,10 @@ test_make_install_info_O := $(test_ok)
 test_make_install_pdf    := $(test_ok)
 test_make_install_pdf_O  := $(test_ok)
 
-# 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_make_python_perf_so_O    := test -f $$TMP_O/python/perf.so
+test_make_perf_o_O            := test -f $$TMP_O/perf.o
+test_make_util_map_o_O        := test -f $$TMP_O/util/map.o
+test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
 
 test_default = test -x $(PERF)/perf
 test = $(if $(test_$1),$(test_$1),$(test_default))
index 4db0ae617d7080cd7c97467a15fbe36d9bcedf30..8605ff5572aeeb402ae8b9c118e5f87439bc70f7 100644 (file)
@@ -2,7 +2,7 @@
 #include "parse-events.h"
 #include "evsel.h"
 #include "evlist.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include <api/fs/debugfs.h>
 #include "tests.h"
 #include <linux/hw_breakpoint.h>
index 1b677202638d087b94903f3f395d9fab8ae15bc7..0014d3c8c21cd47d2868cac66bc65253913e888e 100644 (file)
@@ -22,8 +22,8 @@
 } while (0)
 
 static bool samples_same(const struct perf_sample *s1,
-                        const struct perf_sample *s2, u64 type, u64 regs_user,
-                        u64 read_format)
+                        const struct perf_sample *s2,
+                        u64 type, u64 read_format)
 {
        size_t i;
 
@@ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1,
        }
 
        if (type & PERF_SAMPLE_REGS_USER) {
-               size_t sz = hweight_long(regs_user) * sizeof(u64);
+               size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);
 
+               COMP(user_regs.mask);
                COMP(user_regs.abi);
                if (s1->user_regs.abi &&
                    (!s1->user_regs.regs || !s2->user_regs.regs ||
@@ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
                .branch_stack   = &branch_stack.branch_stack,
                .user_regs      = {
                        .abi    = PERF_SAMPLE_REGS_ABI_64,
+                       .mask   = sample_regs_user,
                        .regs   = user_regs,
                },
                .user_stack     = {
@@ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
                sample.read.one.id    = 99;
        }
 
-       sz = perf_event__sample_event_size(&sample, sample_type,
-                                          sample_regs_user, read_format);
+       sz = perf_event__sample_event_size(&sample, sample_type, read_format);
        bufsz = sz + 4096; /* Add a bit for overrun checking */
        event = malloc(bufsz);
        if (!event) {
@@ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
        event->header.misc = 0;
        event->header.size = sz;
 
-       err = perf_event__synthesize_sample(event, sample_type,
-                                           sample_regs_user, read_format,
+       err = perf_event__synthesize_sample(event, sample_type, read_format,
                                            &sample, false);
        if (err) {
                pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
@@ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
                goto out_free;
        }
 
-       if (!samples_same(&sample, &sample_out, sample_type,
-                         sample_regs_user, read_format)) {
+       if (!samples_same(&sample, &sample_out, sample_type, read_format)) {
                pr_debug("parsing failed for sample_type %#"PRIx64"\n",
                         sample_type);
                goto out_free;
index e0ac713857ba5708fee69a8b1000cd81d9ae0a76..a24795ca002db3a25742ee324fca6bc6d74e8e14 100644 (file)
@@ -40,5 +40,14 @@ int test__code_reading(void);
 int test__sample_parsing(void);
 int test__keep_tracking(void);
 int test__parse_no_sample_id_all(void);
+int test__dwarf_unwind(void);
 
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+struct thread;
+struct perf_sample;
+int test__arch_unwind_sample(struct perf_sample *sample,
+                            struct thread *thread);
+#endif
+#endif
 #endif /* TESTS_H */
index b720b92eba6eb95cc7dd9bd4a57693f0a79d91b9..7ec871af3f6f8c5cc4796f40c14c801aa3ba3943 100644 (file)
@@ -587,95 +587,52 @@ struct hpp_arg {
        bool current_entry;
 };
 
-static int __hpp__color_callchain(struct hpp_arg *arg)
+static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front)
 {
-       if (!symbol_conf.use_callchain)
-               return 0;
-
-       slsmg_printf("%c ", arg->folded_sign);
-       return 2;
-}
-
-static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
-                           u64 (*get_field)(struct hist_entry *),
-                           int (*callchain_cb)(struct hpp_arg *))
-{
-       int ret = 0;
-       double percent = 0.0;
-       struct hists *hists = he->hists;
        struct hpp_arg *arg = hpp->ptr;
 
-       if (hists->stats.total_period)
-               percent = 100.0 * get_field(he) / hists->stats.total_period;
-
-       ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
-
-       if (callchain_cb)
-               ret += callchain_cb(arg);
-
-       ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
-       slsmg_printf("%s", hpp->buf);
-
-       if (symbol_conf.event_group) {
-               int prev_idx, idx_delta;
-               struct perf_evsel *evsel = hists_to_evsel(hists);
-               struct hist_entry *pair;
-               int nr_members = evsel->nr_members;
-
-               if (nr_members <= 1)
-                       goto out;
+       if (arg->current_entry && arg->b->navkeypressed)
+               ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
+       else
+               ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
 
-               prev_idx = perf_evsel__group_idx(evsel);
+       if (front) {
+               if (!symbol_conf.use_callchain)
+                       return 0;
 
-               list_for_each_entry(pair, &he->pairs.head, pairs.node) {
-                       u64 period = get_field(pair);
-                       u64 total = pair->hists->stats.total_period;
+               slsmg_printf("%c ", arg->folded_sign);
+               return 2;
+       }
 
-                       if (!total)
-                               continue;
+       return 0;
+}
 
-                       evsel = hists_to_evsel(pair->hists);
-                       idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
+static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
+{
+       struct hpp_arg *arg = hpp->ptr;
 
-                       while (idx_delta--) {
-                               /*
-                                * zero-fill group members in the middle which
-                                * have no sample
-                                */
-                               ui_browser__set_percent_color(arg->b, 0.0,
-                                                       arg->current_entry);
-                               ret += scnprintf(hpp->buf, hpp->size,
-                                                " %6.2f%%", 0.0);
-                               slsmg_printf("%s", hpp->buf);
-                       }
+       if (!arg->current_entry || !arg->b->navkeypressed)
+               ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
+       return 0;
+}
 
-                       percent = 100.0 * period / total;
-                       ui_browser__set_percent_color(arg->b, percent,
-                                                     arg->current_entry);
-                       ret += scnprintf(hpp->buf, hpp->size,
-                                        " %6.2f%%", percent);
-                       slsmg_printf("%s", hpp->buf);
+static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
+{
+       struct hpp_arg *arg = hpp->ptr;
+       int ret;
+       va_list args;
+       double percent;
 
-                       prev_idx = perf_evsel__group_idx(evsel);
-               }
+       va_start(args, fmt);
+       percent = va_arg(args, double);
+       va_end(args);
 
-               idx_delta = nr_members - prev_idx - 1;
+       ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
 
-               while (idx_delta--) {
-                       /*
-                        * zero-fill group members at last which have no sample
-                        */
-                       ui_browser__set_percent_color(arg->b, 0.0,
-                                                     arg->current_entry);
-                       ret += scnprintf(hpp->buf, hpp->size,
-                                        " %6.2f%%", 0.0);
-                       slsmg_printf("%s", hpp->buf);
-               }
-       }
-out:
-       if (!arg->current_entry || !arg->b->navkeypressed)
-               ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
+       ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
+       slsmg_printf("%s", hpp->buf);
 
+       advance_hpp(hpp, ret);
        return ret;
 }
 
@@ -690,14 +647,15 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
-       return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb);      \
+       return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \
+                         __hpp__slsmg_color_printf, true);             \
 }
 
-__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
-__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
-__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
-__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
-__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
+__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback)
+__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback)
+__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback)
+__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback)
+__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback)
 
 #undef __HPP_COLOR_PERCENT_FN
 
index 5b95c44f34354215ba597c19d736d3e63c559d1e..e395ef9b0ae00494187c089fde8c6b6a7a5259c4 100644 (file)
@@ -8,16 +8,24 @@
 
 #define MAX_COLUMNS                    32
 
-static int __percent_color_snprintf(char *buf, size_t size, double percent)
+static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        int ret = 0;
+       va_list args;
+       double percent;
        const char *markup;
+       char *buf = hpp->buf;
+       size_t size = hpp->size;
+
+       va_start(args, fmt);
+       percent = va_arg(args, double);
+       va_end(args);
 
        markup = perf_gtk__get_percent_color(percent);
        if (markup)
                ret += scnprintf(buf, size, markup);
 
-       ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
+       ret += scnprintf(buf + ret, size - ret, fmt, percent);
 
        if (markup)
                ret += scnprintf(buf + ret, size - ret, "</span>");
@@ -25,66 +33,6 @@ static int __percent_color_snprintf(char *buf, size_t size, double percent)
        return ret;
 }
 
-
-static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
-                           u64 (*get_field)(struct hist_entry *))
-{
-       int ret;
-       double percent = 0.0;
-       struct hists *hists = he->hists;
-       struct perf_evsel *evsel = hists_to_evsel(hists);
-
-       if (hists->stats.total_period)
-               percent = 100.0 * get_field(he) / hists->stats.total_period;
-
-       ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
-
-       if (perf_evsel__is_group_event(evsel)) {
-               int prev_idx, idx_delta;
-               struct hist_entry *pair;
-               int nr_members = evsel->nr_members;
-
-               prev_idx = perf_evsel__group_idx(evsel);
-
-               list_for_each_entry(pair, &he->pairs.head, pairs.node) {
-                       u64 period = get_field(pair);
-                       u64 total = pair->hists->stats.total_period;
-
-                       evsel = hists_to_evsel(pair->hists);
-                       idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
-
-                       while (idx_delta--) {
-                               /*
-                                * zero-fill group members in the middle which
-                                * have no sample
-                                */
-                               ret += __percent_color_snprintf(hpp->buf + ret,
-                                                               hpp->size - ret,
-                                                               0.0);
-                       }
-
-                       percent = 100.0 * period / total;
-                       ret += __percent_color_snprintf(hpp->buf + ret,
-                                                       hpp->size - ret,
-                                                       percent);
-
-                       prev_idx = perf_evsel__group_idx(evsel);
-               }
-
-               idx_delta = nr_members - prev_idx - 1;
-
-               while (idx_delta--) {
-                       /*
-                        * zero-fill group members at last which have no sample
-                        */
-                       ret += __percent_color_snprintf(hpp->buf + ret,
-                                                       hpp->size - ret,
-                                                       0.0);
-               }
-       }
-       return ret;
-}
-
 #define __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
 static u64 he_get_##_field(struct hist_entry *he)                              \
 {                                                                              \
@@ -95,7 +43,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__color_fmt(hpp, he, he_get_##_field);                      \
+       return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%",           \
+                         __percent_color_snprintf, true);                      \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -216,7 +165,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
        struct perf_hpp hpp = {
                .buf            = s,
                .size           = sizeof(s),
-               .ptr            = hists_to_evsel(hists),
        };
 
        nr_cols = 0;
@@ -243,7 +191,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
        col_idx = 0;
 
        perf_hpp__for_each_format(fmt) {
-               fmt->header(fmt, &hpp);
+               fmt->header(fmt, &hpp, hists_to_evsel(hists));
 
                gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
                                                            -1, ltrim(s),
index 78f4c92e9b73c1c55e5699bce4b628f551348beb..0f403b83e9d1c1da19b7be850c7c49ffba0b074d 100644 (file)
@@ -8,16 +8,27 @@
 
 /* hist period print (hpp) functions */
 
-typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
-
-static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-                     u64 (*get_field)(struct hist_entry *),
-                     const char *fmt, hpp_snprint_fn print_fn,
-                     bool fmt_percent)
+#define hpp__call_print_fn(hpp, fn, fmt, ...)                  \
+({                                                             \
+       int __ret = fn(hpp, fmt, ##__VA_ARGS__);                \
+       advance_hpp(hpp, __ret);                                \
+       __ret;                                                  \
+})
+
+int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+              hpp_field_fn get_field, hpp_callback_fn callback,
+              const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent)
 {
-       int ret;
+       int ret = 0;
        struct hists *hists = he->hists;
        struct perf_evsel *evsel = hists_to_evsel(hists);
+       char *buf = hpp->buf;
+       size_t size = hpp->size;
+
+       if (callback) {
+               ret = callback(hpp, true);
+               advance_hpp(hpp, ret);
+       }
 
        if (fmt_percent) {
                double percent = 0.0;
@@ -26,9 +37,9 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                        percent = 100.0 * get_field(he) /
                                  hists->stats.total_period;
 
-               ret = print_fn(hpp->buf, hpp->size, fmt, percent);
+               ret += hpp__call_print_fn(hpp, print_fn, fmt, percent);
        } else
-               ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
+               ret += hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
 
        if (perf_evsel__is_group_event(evsel)) {
                int prev_idx, idx_delta;
@@ -52,16 +63,22 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                                 * zero-fill group members in the middle which
                                 * have no sample
                                 */
-                               ret += print_fn(hpp->buf + ret, hpp->size - ret,
-                                               fmt, 0);
+                               if (fmt_percent) {
+                                       ret += hpp__call_print_fn(hpp, print_fn,
+                                                                 fmt, 0.0);
+                               } else {
+                                       ret += hpp__call_print_fn(hpp, print_fn,
+                                                                 fmt, 0ULL);
+                               }
                        }
 
-                       if (fmt_percent)
-                               ret += print_fn(hpp->buf + ret, hpp->size - ret,
-                                               fmt, 100.0 * period / total);
-                       else
-                               ret += print_fn(hpp->buf + ret, hpp->size - ret,
-                                               fmt, period);
+                       if (fmt_percent) {
+                               ret += hpp__call_print_fn(hpp, print_fn, fmt,
+                                                         100.0 * period / total);
+                       } else {
+                               ret += hpp__call_print_fn(hpp, print_fn, fmt,
+                                                         period);
+                       }
 
                        prev_idx = perf_evsel__group_idx(evsel);
                }
@@ -72,41 +89,87 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                        /*
                         * zero-fill group members at last which have no sample
                         */
-                       ret += print_fn(hpp->buf + ret, hpp->size - ret,
-                                       fmt, 0);
+                       if (fmt_percent) {
+                               ret += hpp__call_print_fn(hpp, print_fn,
+                                                         fmt, 0.0);
+                       } else {
+                               ret += hpp__call_print_fn(hpp, print_fn,
+                                                         fmt, 0ULL);
+                       }
                }
        }
+
+       if (callback) {
+               int __ret = callback(hpp, false);
+
+               advance_hpp(hpp, __ret);
+               ret += __ret;
+       }
+
+       /*
+        * Restore original buf and size as it's where caller expects
+        * the result will be saved.
+        */
+       hpp->buf = buf;
+       hpp->size = size;
+
        return ret;
 }
 
 #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)          \
 static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
-                              struct perf_hpp *hpp)                    \
+                              struct perf_hpp *hpp,                    \
+                              struct perf_evsel *evsel)                \
 {                                                                      \
        int len = _min_width;                                           \
                                                                        \
-       if (symbol_conf.event_group) {                                  \
-               struct perf_evsel *evsel = hpp->ptr;                    \
-                                                                       \
+       if (symbol_conf.event_group)                                    \
                len = max(len, evsel->nr_members * _unit_width);        \
-       }                                                               \
+                                                                       \
        return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);        \
 }
 
 #define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
 static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
-                             struct perf_hpp *hpp __maybe_unused)      \
+                             struct perf_hpp *hpp __maybe_unused,      \
+                             struct perf_evsel *evsel)                 \
 {                                                                      \
        int len = _min_width;                                           \
                                                                        \
-       if (symbol_conf.event_group) {                                  \
-               struct perf_evsel *evsel = hpp->ptr;                    \
-                                                                       \
+       if (symbol_conf.event_group)                                    \
                len = max(len, evsel->nr_members * _unit_width);        \
-       }                                                               \
+                                                                       \
        return len;                                                     \
 }
 
+static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
+{
+       va_list args;
+       ssize_t ssize = hpp->size;
+       double percent;
+       int ret;
+
+       va_start(args, fmt);
+       percent = va_arg(args, double);
+       ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent);
+       va_end(args);
+
+       return (ret >= ssize) ? (ssize - 1) : ret;
+}
+
+static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
+{
+       va_list args;
+       ssize_t ssize = hpp->size;
+       int ret;
+
+       va_start(args, fmt);
+       ret = vsnprintf(hpp->buf, hpp->size, fmt, args);
+       va_end(args);
+
+       return (ret >= ssize) ? (ssize - 1) : ret;
+}
+
 #define __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
 static u64 he_get_##_field(struct hist_entry *he)                              \
 {                                                                              \
@@ -116,8 +179,8 @@ static u64 he_get_##_field(struct hist_entry *he)                           \
 static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         percent_color_snprintf, true);                        \
+       return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%",           \
+                         hpp_color_scnprintf, true);                           \
 }
 
 #define __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
@@ -125,8 +188,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,             \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
        const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
-                         scnprintf, true);                                     \
+       return __hpp__fmt(hpp, he, he_get_##_field, NULL, fmt,                  \
+                         hpp_entry_scnprintf, true);                           \
 }
 
 #define __HPP_ENTRY_RAW_FN(_type, _field)                                      \
@@ -139,7 +202,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,             \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
        const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
-       return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
+       return __hpp__fmt(hpp, he, he_get_raw_##_field, NULL, fmt,              \
+                         hpp_entry_scnprintf, false);                          \
 }
 
 #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)  \
@@ -263,15 +327,13 @@ unsigned int hists__sort_list_width(struct hists *hists)
        struct perf_hpp_fmt *fmt;
        struct sort_entry *se;
        int i = 0, ret = 0;
-       struct perf_hpp dummy_hpp = {
-               .ptr    = hists_to_evsel(hists),
-       };
+       struct perf_hpp dummy_hpp;
 
        perf_hpp__for_each_format(fmt) {
                if (i)
                        ret += 2;
 
-               ret += fmt->width(fmt, &dummy_hpp);
+               ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
        }
 
        list_for_each_entry(se, &hist_entry__sort_list, list)
index 831fbb77d1ff010ab786ff12ee747aaf8873bcbe..d59893edf03130549079a748ffe17440ab8231a9 100644 (file)
@@ -306,12 +306,6 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
        return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
 }
 
-static inline void advance_hpp(struct perf_hpp *hpp, int inc)
-{
-       hpp->buf  += inc;
-       hpp->size -= inc;
-}
-
 static int hist_entry__period_snprintf(struct perf_hpp *hpp,
                                       struct hist_entry *he)
 {
@@ -385,7 +379,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
        struct perf_hpp dummy_hpp = {
                .buf    = bf,
                .size   = sizeof(bf),
-               .ptr    = hists_to_evsel(hists),
        };
        bool first = true;
        size_t linesz;
@@ -404,7 +397,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                else
                        first = false;
 
-               fmt->header(fmt, &dummy_hpp);
+               fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
                fprintf(fp, "%s", bf);
        }
 
@@ -449,7 +442,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                else
                        first = false;
 
-               width = fmt->width(fmt, &dummy_hpp);
+               width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
                for (i = 0; i < width; i++)
                        fprintf(fp, ".");
        }
index 3aa555ff9d89e5d7ede4c6af067170197b9ce0e8..809b4c50beaed3e3a57845919b3a034fe7ab8c9e 100644 (file)
@@ -1236,6 +1236,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
        struct dso *dso = map->dso;
        char *filename;
        const char *d_filename;
+       const char *evsel_name = perf_evsel__name(evsel);
        struct annotation *notes = symbol__annotation(sym);
        struct disasm_line *pos, *queue = NULL;
        u64 start = map__rip_2objdump(map, sym->start);
@@ -1243,7 +1244,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
        int more = 0;
        u64 len;
        int width = 8;
-       int namelen;
+       int namelen, evsel_name_len, graph_dotted_len;
 
        filename = strdup(dso->long_name);
        if (!filename)
@@ -1256,14 +1257,17 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
 
        len = symbol__size(sym);
        namelen = strlen(d_filename);
+       evsel_name_len = strlen(evsel_name);
 
        if (perf_evsel__is_group_event(evsel))
                width *= evsel->nr_members;
 
-       printf(" %-*.*s|        Source code & Disassembly of %s\n",
-              width, width, "Percent", d_filename);
-       printf("-%-*.*s-------------------------------------\n",
-              width+namelen, width+namelen, graph_dotted_line);
+       printf(" %-*.*s|        Source code & Disassembly of %s for %s\n",
+              width, width, "Percent", d_filename, evsel_name);
+
+       graph_dotted_len = width + namelen + evsel_name_len;
+       printf("-%-*.*s-----------------------------------------\n",
+              graph_dotted_len, graph_dotted_len, graph_dotted_line);
 
        if (verbose)
                symbol__annotate_hits(sym, evsel);
index a9b48c42e81eb36e34cce24e091be66437270d44..7fe4994eeb638a63f7b52105ad326afa448915ab 100644 (file)
@@ -1,5 +1,5 @@
 #include "util.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include "../perf.h"
 #include "cpumap.h"
 #include <assert.h>
index 4045d086d9d957823af08d79db4d8407fb9a460f..64453d63b971212ea3c626eb0d57fbefb62ea236 100644 (file)
@@ -45,8 +45,8 @@ int dso__read_binary_type_filename(const struct dso *dso,
                        debuglink--;
                if (*debuglink == '/')
                        debuglink++;
-               filename__read_debuglink(dso->long_name, debuglink,
-                                        size - (debuglink - filename));
+               ret = filename__read_debuglink(dso->long_name, debuglink,
+                                              size - (debuglink - filename));
                }
                break;
        case DSO_BINARY_TYPE__BUILD_ID_CACHE:
index cd7d6f078cddf618e40e709eab6c1d93750e155a..ab06f1c0365542cc35c000ba90d6879b34070ed6 100644 (file)
@@ -102,6 +102,16 @@ struct dso {
        char             name[0];
 };
 
+/* dso__for_each_symbol - iterate over the symbols of given type
+ *
+ * @dso: the 'struct dso *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * @type: the 'enum map_type' type of symbols
+ */
+#define dso__for_each_symbol(dso, pos, n, type)        \
+       symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
+
 static inline void dso__set_loaded(struct dso *dso, enum map_type type)
 {
        dso->loaded |= (1 << type);
index b0f3ca850e9e8ffbf5c1e70b9f04215e545a71ae..9d12aa6dd485336104068aef0f3c40f8436d10b2 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include "event.h"
 #include "debug.h"
+#include "hist.h"
 #include "machine.h"
 #include "sort.h"
 #include "string.h"
@@ -94,14 +95,10 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
 
 static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
                                         union perf_event *event, pid_t pid,
-                                        int full,
                                         perf_event__handler_t process,
                                         struct machine *machine)
 {
-       char filename[PATH_MAX];
        size_t size;
-       DIR *tasks;
-       struct dirent dirent, *next;
        pid_t tgid;
 
        memset(&event->comm, 0, sizeof(event->comm));
@@ -124,55 +121,35 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
        event->comm.header.size = (sizeof(event->comm) -
                                (sizeof(event->comm.comm) - size) +
                                machine->id_hdr_size);
-       if (!full) {
-               event->comm.tid = pid;
+       event->comm.tid = pid;
 
-               if (process(tool, event, &synth_sample, machine) != 0)
-                       return -1;
-
-               goto out;
-       }
-
-       if (machine__is_default_guest(machine))
-               return 0;
-
-       snprintf(filename, sizeof(filename), "%s/proc/%d/task",
-                machine->root_dir, pid);
-
-       tasks = opendir(filename);
-       if (tasks == NULL) {
-               pr_debug("couldn't open %s\n", filename);
-               return 0;
-       }
+       if (process(tool, event, &synth_sample, machine) != 0)
+               return -1;
 
-       while (!readdir_r(tasks, &dirent, &next) && next) {
-               char *end;
-               pid = strtol(dirent.d_name, &end, 10);
-               if (*end)
-                       continue;
+out:
+       return tgid;
+}
 
-               /* already have tgid; jut want to update the comm */
-               (void) perf_event__get_comm_tgid(pid, event->comm.comm,
-                                        sizeof(event->comm.comm));
+static int perf_event__synthesize_fork(struct perf_tool *tool,
+                                      union perf_event *event, pid_t pid,
+                                      pid_t tgid, perf_event__handler_t process,
+                                      struct machine *machine)
+{
+       memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
 
-               size = strlen(event->comm.comm) + 1;
-               size = PERF_ALIGN(size, sizeof(u64));
-               memset(event->comm.comm + size, 0, machine->id_hdr_size);
-               event->comm.header.size = (sizeof(event->comm) -
-                                         (sizeof(event->comm.comm) - size) +
-                                         machine->id_hdr_size);
+       /* this is really a clone event but we use fork to synthesize it */
+       event->fork.ppid = tgid;
+       event->fork.ptid = tgid;
+       event->fork.pid  = tgid;
+       event->fork.tid  = pid;
+       event->fork.header.type = PERF_RECORD_FORK;
 
-               event->comm.tid = pid;
+       event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
 
-               if (process(tool, event, &synth_sample, machine) != 0) {
-                       tgid = -1;
-                       break;
-               }
-       }
+       if (process(tool, event, &synth_sample, machine) != 0)
+               return -1;
 
-       closedir(tasks);
-out:
-       return tgid;
+       return 0;
 }
 
 int perf_event__synthesize_mmap_events(struct perf_tool *tool,
@@ -324,17 +301,71 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
 
 static int __event__synthesize_thread(union perf_event *comm_event,
                                      union perf_event *mmap_event,
+                                     union perf_event *fork_event,
                                      pid_t pid, int full,
                                          perf_event__handler_t process,
                                      struct perf_tool *tool,
                                      struct machine *machine, bool mmap_data)
 {
-       pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
+       char filename[PATH_MAX];
+       DIR *tasks;
+       struct dirent dirent, *next;
+       pid_t tgid;
+
+       /* special case: only send one comm event using passed in pid */
+       if (!full) {
+               tgid = perf_event__synthesize_comm(tool, comm_event, pid,
+                                                  process, machine);
+
+               if (tgid == -1)
+                       return -1;
+
+               return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+                                                         process, machine, mmap_data);
+       }
+
+       if (machine__is_default_guest(machine))
+               return 0;
+
+       snprintf(filename, sizeof(filename), "%s/proc/%d/task",
+                machine->root_dir, pid);
+
+       tasks = opendir(filename);
+       if (tasks == NULL) {
+               pr_debug("couldn't open %s\n", filename);
+               return 0;
+       }
+
+       while (!readdir_r(tasks, &dirent, &next) && next) {
+               char *end;
+               int rc = 0;
+               pid_t _pid;
+
+               _pid = strtol(dirent.d_name, &end, 10);
+               if (*end)
+                       continue;
+
+               tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
+                                                  process, machine);
+               if (tgid == -1)
+                       return -1;
+
+               if (_pid == pid) {
+                       /* process the parent's maps too */
+                       rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+                                               process, machine, mmap_data);
+               } else {
+                       /* only fork the tid's map, to save time */
+                       rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
                                                 process, machine);
-       if (tgid == -1)
-               return -1;
-       return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
-                                                 process, machine, mmap_data);
+               }
+
+               if (rc)
+                       return rc;
+       }
+
+       closedir(tasks);
+       return 0;
 }
 
 int perf_event__synthesize_thread_map(struct perf_tool *tool,
@@ -343,7 +374,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                                      struct machine *machine,
                                      bool mmap_data)
 {
-       union perf_event *comm_event, *mmap_event;
+       union perf_event *comm_event, *mmap_event, *fork_event;
        int err = -1, thread, j;
 
        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -354,9 +385,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
        if (mmap_event == NULL)
                goto out_free_comm;
 
+       fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
+       if (fork_event == NULL)
+               goto out_free_mmap;
+
        err = 0;
        for (thread = 0; thread < threads->nr; ++thread) {
                if (__event__synthesize_thread(comm_event, mmap_event,
+                                              fork_event,
                                               threads->map[thread], 0,
                                               process, tool, machine,
                                               mmap_data)) {
@@ -382,6 +418,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                        /* if not, generate events for it */
                        if (need_leader &&
                            __event__synthesize_thread(comm_event, mmap_event,
+                                                      fork_event,
                                                       comm_event->comm.pid, 0,
                                                       process, tool, machine,
                                                       mmap_data)) {
@@ -390,6 +427,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                        }
                }
        }
+       free(fork_event);
+out_free_mmap:
        free(mmap_event);
 out_free_comm:
        free(comm_event);
@@ -404,9 +443,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        DIR *proc;
        char proc_path[PATH_MAX];
        struct dirent dirent, *next;
-       union perf_event *comm_event, *mmap_event;
+       union perf_event *comm_event, *mmap_event, *fork_event;
        int err = -1;
 
+       if (machine__is_default_guest(machine))
+               return 0;
+
        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
        if (comm_event == NULL)
                goto out;
@@ -415,14 +457,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        if (mmap_event == NULL)
                goto out_free_comm;
 
-       if (machine__is_default_guest(machine))
-               return 0;
+       fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
+       if (fork_event == NULL)
+               goto out_free_mmap;
 
        snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
        proc = opendir(proc_path);
 
        if (proc == NULL)
-               goto out_free_mmap;
+               goto out_free_fork;
 
        while (!readdir_r(proc, &dirent, &next) && next) {
                char *end;
@@ -434,12 +477,14 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
                 * We may race with exiting thread, so don't stop just because
                 * one thread couldn't be synthesized.
                 */
-               __event__synthesize_thread(comm_event, mmap_event, pid, 1,
-                                          process, tool, machine, mmap_data);
+               __event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
+                                          1, process, tool, machine, mmap_data);
        }
 
        err = 0;
        closedir(proc);
+out_free_fork:
+       free(fork_event);
 out_free_mmap:
        free(mmap_event);
 out_free_comm:
@@ -661,7 +706,7 @@ void thread__find_addr_map(struct thread *thread,
        al->thread = thread;
        al->addr = addr;
        al->cpumode = cpumode;
-       al->filtered = false;
+       al->filtered = 0;
 
        if (machine == NULL) {
                al->map = NULL;
@@ -687,11 +732,11 @@ void thread__find_addr_map(struct thread *thread,
                if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
                        cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
                        !perf_guest)
-                       al->filtered = true;
+                       al->filtered |= (1 << HIST_FILTER__GUEST);
                if ((cpumode == PERF_RECORD_MISC_USER ||
                        cpumode == PERF_RECORD_MISC_KERNEL) &&
                        !perf_host)
-                       al->filtered = true;
+                       al->filtered |= (1 << HIST_FILTER__HOST);
 
                return;
        }
@@ -748,9 +793,6 @@ int perf_event__preprocess_sample(const union perf_event *event,
        if (thread == NULL)
                return -1;
 
-       if (thread__is_filtered(thread))
-               goto out_filtered;
-
        dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
        /*
         * Have we already created the kernel maps for this machine?
@@ -768,6 +810,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
        dump_printf(" ...... dso: %s\n",
                    al->map ? al->map->dso->long_name :
                        al->level == 'H' ? "[hypervisor]" : "<not found>");
+
+       if (thread__is_filtered(thread))
+               al->filtered |= (1 << HIST_FILTER__THREAD);
+
        al->sym = NULL;
        al->cpu = sample->cpu;
 
@@ -779,8 +825,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
                                                  dso->short_name) ||
                               (dso->short_name != dso->long_name &&
                                strlist__has_entry(symbol_conf.dso_list,
-                                                  dso->long_name)))))
-                       goto out_filtered;
+                                                  dso->long_name))))) {
+                       al->filtered |= (1 << HIST_FILTER__DSO);
+               }
 
                al->sym = map__find_symbol(al->map, al->addr,
                                           machine->symbol_filter);
@@ -788,12 +835,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
 
        if (symbol_conf.sym_list &&
                (!al->sym || !strlist__has_entry(symbol_conf.sym_list,
-                                               al->sym->name)))
-               goto out_filtered;
-
-       return 0;
+                                               al->sym->name))) {
+               al->filtered |= (1 << HIST_FILTER__SYMBOL);
+       }
 
-out_filtered:
-       al->filtered = true;
        return 0;
 }
index 851fa06f4a427d47b2c2af5ee70e345fda643978..38457d447a13106360fb60d7b93dd3eab5217f50 100644 (file)
@@ -85,6 +85,7 @@ struct sample_event {
 
 struct regs_dump {
        u64 abi;
+       u64 mask;
        u64 *regs;
 };
 
@@ -259,9 +260,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
 const char *perf_event__name(unsigned int id);
 
 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
-                                    u64 sample_regs_user, u64 read_format);
+                                    u64 read_format);
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
-                                 u64 sample_regs_user, u64 read_format,
+                                 u64 read_format,
                                  const struct perf_sample *sample,
                                  bool swapped);
 
index 55407c594b87f1657e8ff06f8e64ee27ba2662c2..5c28d82b76c472d2107e097656a5d45e4f151536 100644 (file)
@@ -500,6 +500,34 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
        return ret;
 }
 
+static void
+perf_evsel__config_callgraph(struct perf_evsel *evsel,
+                            struct record_opts *opts)
+{
+       bool function = perf_evsel__is_function_event(evsel);
+       struct perf_event_attr *attr = &evsel->attr;
+
+       perf_evsel__set_sample_bit(evsel, CALLCHAIN);
+
+       if (opts->call_graph == CALLCHAIN_DWARF) {
+               if (!function) {
+                       perf_evsel__set_sample_bit(evsel, REGS_USER);
+                       perf_evsel__set_sample_bit(evsel, STACK_USER);
+                       attr->sample_regs_user = PERF_REGS_MASK;
+                       attr->sample_stack_user = opts->stack_dump_size;
+                       attr->exclude_callchain_user = 1;
+               } else {
+                       pr_info("Cannot use DWARF unwind for function trace event,"
+                               " falling back to framepointers.\n");
+               }
+       }
+
+       if (function) {
+               pr_info("Disabling user space callchains for function trace event.\n");
+               attr->exclude_callchain_user = 1;
+       }
+}
+
 /*
  * The enable_on_exec/disabled value strategy:
  *
@@ -595,17 +623,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
                attr->mmap_data = track;
        }
 
-       if (opts->call_graph) {
-               perf_evsel__set_sample_bit(evsel, CALLCHAIN);
-
-               if (opts->call_graph == CALLCHAIN_DWARF) {
-                       perf_evsel__set_sample_bit(evsel, REGS_USER);
-                       perf_evsel__set_sample_bit(evsel, STACK_USER);
-                       attr->sample_regs_user = PERF_REGS_MASK;
-                       attr->sample_stack_user = opts->stack_dump_size;
-                       attr->exclude_callchain_user = 1;
-               }
-       }
+       if (opts->call_graph_enabled)
+               perf_evsel__config_callgraph(evsel, opts);
 
        if (target__has_cpu(&opts->target))
                perf_evsel__set_sample_bit(evsel, CPU);
@@ -1004,7 +1023,7 @@ retry_sample_id:
 
                        group_fd = get_group_fd(evsel, cpu, thread);
 retry_open:
-                       pr_debug2("perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx\n",
+                       pr_debug2("sys_perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx\n",
                                  pid, cpus->map[cpu], group_fd, flags);
 
                        FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
@@ -1013,7 +1032,7 @@ retry_open:
                                                                     group_fd, flags);
                        if (FD(evsel, cpu, thread) < 0) {
                                err = -errno;
-                               pr_debug2("perf_event_open failed, error %d\n",
+                               pr_debug2("sys_perf_event_open failed, error %d\n",
                                          err);
                                goto try_fallback;
                        }
@@ -1220,7 +1239,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
        memset(data, 0, sizeof(*data));
        data->cpu = data->pid = data->tid = -1;
        data->stream_id = data->id = data->time = -1ULL;
-       data->period = 1;
+       data->period = evsel->attr.sample_period;
        data->weight = 0;
 
        if (event->header.type != PERF_RECORD_SAMPLE) {
@@ -1396,10 +1415,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
                array++;
 
                if (data->user_regs.abi) {
-                       u64 regs_user = evsel->attr.sample_regs_user;
+                       u64 mask = evsel->attr.sample_regs_user;
 
-                       sz = hweight_long(regs_user) * sizeof(u64);
+                       sz = hweight_long(mask) * sizeof(u64);
                        OVERFLOW_CHECK(array, sz, max_size);
+                       data->user_regs.mask = mask;
                        data->user_regs.regs = (u64 *)array;
                        array = (void *)array + sz;
                }
@@ -1451,7 +1471,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
 }
 
 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
-                                    u64 sample_regs_user, u64 read_format)
+                                    u64 read_format)
 {
        size_t sz, result = sizeof(struct sample_event);
 
@@ -1517,7 +1537,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
        if (type & PERF_SAMPLE_REGS_USER) {
                if (sample->user_regs.abi) {
                        result += sizeof(u64);
-                       sz = hweight_long(sample_regs_user) * sizeof(u64);
+                       sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
                        result += sz;
                } else {
                        result += sizeof(u64);
@@ -1546,7 +1566,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
 }
 
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
-                                 u64 sample_regs_user, u64 read_format,
+                                 u64 read_format,
                                  const struct perf_sample *sample,
                                  bool swapped)
 {
@@ -1687,7 +1707,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
        if (type & PERF_SAMPLE_REGS_USER) {
                if (sample->user_regs.abi) {
                        *array++ = sample->user_regs.abi;
-                       sz = hweight_long(sample_regs_user) * sizeof(u64);
+                       sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
                        memcpy(array, sample->user_regs.regs, sz);
                        array = (void *)array + sz;
                } else {
index f1b325665aae8201b9696b2c3c5a6a64e009ffb7..0c9926cfb292ba2667de9f270fc8103182d857ab 100644 (file)
@@ -315,6 +315,24 @@ static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel)
        return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1;
 }
 
+/**
+ * perf_evsel__is_function_event - Return whether given evsel is a function
+ * trace event
+ *
+ * @evsel - evsel selector to be tested
+ *
+ * Return %true if event is function trace event
+ */
+static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
+{
+#define FUNCTION_EVENT "ftrace:function"
+
+       return evsel->name &&
+              !strncmp(FUNCTION_EVENT, evsel->name, sizeof(FUNCTION_EVENT));
+
+#undef FUNCTION_EVENT
+}
+
 struct perf_attr_details {
        bool freq;
        bool verbose;
diff --git a/tools/perf/util/fs.c b/tools/perf/util/fs.c
deleted file mode 100644 (file)
index f5be1f2..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-
-/* TODO merge/factor into tools/lib/lk/debugfs.c */
-
-#include "util.h"
-#include "util/fs.h"
-
-static const char * const sysfs__fs_known_mountpoints[] = {
-       "/sys",
-       0,
-};
-
-static const char * const procfs__known_mountpoints[] = {
-       "/proc",
-       0,
-};
-
-struct fs {
-       const char              *name;
-       const char * const      *mounts;
-       char                     path[PATH_MAX + 1];
-       bool                     found;
-       long                     magic;
-};
-
-enum {
-       FS__SYSFS  = 0,
-       FS__PROCFS = 1,
-};
-
-static struct fs fs__entries[] = {
-       [FS__SYSFS] = {
-               .name   = "sysfs",
-               .mounts = sysfs__fs_known_mountpoints,
-               .magic  = SYSFS_MAGIC,
-       },
-       [FS__PROCFS] = {
-               .name   = "proc",
-               .mounts = procfs__known_mountpoints,
-               .magic  = PROC_SUPER_MAGIC,
-       },
-};
-
-static bool fs__read_mounts(struct fs *fs)
-{
-       bool found = false;
-       char type[100];
-       FILE *fp;
-
-       fp = fopen("/proc/mounts", "r");
-       if (fp == NULL)
-               return NULL;
-
-       while (!found &&
-              fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
-                     fs->path, type) == 2) {
-
-               if (strcmp(type, fs->name) == 0)
-                       found = true;
-       }
-
-       fclose(fp);
-       return fs->found = found;
-}
-
-static int fs__valid_mount(const char *fs, long magic)
-{
-       struct statfs st_fs;
-
-       if (statfs(fs, &st_fs) < 0)
-               return -ENOENT;
-       else if (st_fs.f_type != magic)
-               return -ENOENT;
-
-       return 0;
-}
-
-static bool fs__check_mounts(struct fs *fs)
-{
-       const char * const *ptr;
-
-       ptr = fs->mounts;
-       while (*ptr) {
-               if (fs__valid_mount(*ptr, fs->magic) == 0) {
-                       fs->found = true;
-                       strcpy(fs->path, *ptr);
-                       return true;
-               }
-               ptr++;
-       }
-
-       return false;
-}
-
-static const char *fs__get_mountpoint(struct fs *fs)
-{
-       if (fs__check_mounts(fs))
-               return fs->path;
-
-       return fs__read_mounts(fs) ? fs->path : NULL;
-}
-
-static const char *fs__mountpoint(int idx)
-{
-       struct fs *fs = &fs__entries[idx];
-
-       if (fs->found)
-               return (const char *)fs->path;
-
-       return fs__get_mountpoint(fs);
-}
-
-#define FS__MOUNTPOINT(name, idx)      \
-const char *name##__mountpoint(void)   \
-{                                      \
-       return fs__mountpoint(idx);     \
-}
-
-FS__MOUNTPOINT(sysfs,  FS__SYSFS);
-FS__MOUNTPOINT(procfs, FS__PROCFS);
diff --git a/tools/perf/util/fs.h b/tools/perf/util/fs.h
deleted file mode 100644 (file)
index 5e09ce1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __PERF_FS
-#define __PERF_FS
-
-const char *sysfs__mountpoint(void);
-const char *procfs__mountpoint(void);
-
-#endif /* __PERF_FS */
index e4e6249b87d4eef1cd89d3df1aa3da022b550f84..f38590d7561b99733c5c32154eb1dee8c9777572 100644 (file)
@@ -13,13 +13,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
 static bool hists__filter_entry_by_symbol(struct hists *hists,
                                          struct hist_entry *he);
 
-enum hist_filter {
-       HIST_FILTER__DSO,
-       HIST_FILTER__THREAD,
-       HIST_FILTER__PARENT,
-       HIST_FILTER__SYMBOL,
-};
-
 struct callchain_param callchain_param = {
        .mode   = CHAIN_GRAPH_REL,
        .min_percent = 0.5,
@@ -290,7 +283,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
                if (he->branch_info) {
                        /*
                         * This branch info is (a part of) allocated from
-                        * machine__resolve_bstack() and will be freed after
+                        * sample__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));
@@ -369,7 +362,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
                        he_stat__add_period(&he->stat, period, weight);
 
                        /*
-                        * This mem info was allocated from machine__resolve_mem
+                        * This mem info was allocated from sample__resolve_mem
                         * and will not be used anymore.
                         */
                        zfree(&entry->mem_info);
@@ -429,7 +422,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                        .weight = weight,
                },
                .parent = sym_parent,
-               .filtered = symbol__parent_filter(sym_parent),
+               .filtered = symbol__parent_filter(sym_parent) | al->filtered,
                .hists  = hists,
                .branch_info = bi,
                .mem_info = mi,
index a59743fa3ef73d3aeb8c5c832a32aa2e04773a4c..1f1f513dfe7fb05f9cf0e77caeab43a327182fa1 100644 (file)
@@ -14,6 +14,15 @@ struct hist_entry;
 struct addr_location;
 struct symbol;
 
+enum hist_filter {
+       HIST_FILTER__DSO,
+       HIST_FILTER__THREAD,
+       HIST_FILTER__PARENT,
+       HIST_FILTER__SYMBOL,
+       HIST_FILTER__GUEST,
+       HIST_FILTER__HOST,
+};
+
 /*
  * The kernel collects the number of events it couldn't send in a stretch and
  * when possible sends this number in a PERF_RECORD_LOST event. The number of
@@ -132,8 +141,10 @@ struct perf_hpp {
 };
 
 struct perf_hpp_fmt {
-       int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
-       int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
+       int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                     struct perf_evsel *evsel);
+       int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                    struct perf_evsel *evsel);
        int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                     struct hist_entry *he);
        int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -166,6 +177,20 @@ void perf_hpp__init(void);
 void perf_hpp__column_register(struct perf_hpp_fmt *format);
 void perf_hpp__column_enable(unsigned col);
 
+typedef u64 (*hpp_field_fn)(struct hist_entry *he);
+typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
+typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
+
+int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+              hpp_field_fn get_field, hpp_callback_fn callback,
+              const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent);
+
+static inline void advance_hpp(struct perf_hpp *hpp, int inc)
+{
+       hpp->buf  += inc;
+       hpp->size -= inc;
+}
+
 static inline size_t perf_hpp__use_color(void)
 {
        return !symbol_conf.field_sep;
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
deleted file mode 100644 (file)
index 201f573..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "../../../../include/linux/hash.h"
-
-#ifndef PERF_HASH_H
-#define PERF_HASH_H
-#endif
index d8c927c868eee79e9dc82d6c24a66f689f75288d..9844c31b7c2bb26c25a71e5a0203800e3a2daa26 100644 (file)
@@ -94,12 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
        return (i >= ssize) ? (ssize - 1) : i;
 }
 
-static inline unsigned long
-simple_strtoul(const char *nptr, char **endptr, int base)
-{
-       return strtoul(nptr, endptr, base);
-}
-
 int eprintf(int level,
            const char *fmt, ...) __attribute__((format(printf, 2, 3)));
 
index 1d928a0ce9972014f435d93646c576bad56ad84b..bfe0a2afd0d28bc736b8ab8ae9c063ca0248a158 100644 (file)
@@ -1,5 +1,4 @@
 #include <linux/kernel.h>
-#include <linux/prefetch.h>
 
 #include "../../../../include/linux/list.h"
 
diff --git a/tools/perf/util/include/linux/magic.h b/tools/perf/util/include/linux/magic.h
deleted file mode 100644 (file)
index 07d63cf..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _PERF_LINUX_MAGIC_H_
-#define _PERF_LINUX_MAGIC_H_
-
-#ifndef DEBUGFS_MAGIC
-#define DEBUGFS_MAGIC          0x64626720
-#endif
-
-#ifndef SYSFS_MAGIC
-#define SYSFS_MAGIC            0x62656572
-#endif
-
-#ifndef PROC_SUPER_MAGIC
-#define PROC_SUPER_MAGIC       0x9fa0
-#endif
-
-#endif
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
deleted file mode 100644 (file)
index 7841e48..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef PERF_LINUX_PREFETCH_H
-#define PERF_LINUX_PREFETCH_H
-
-static inline void prefetch(void *a __attribute__((unused))) { }
-
-#endif
index c872991e0f655ba581443f0f413d81a5b910842f..a53cd0b8c151cdb898d3711c36e5081846813a15 100644 (file)
@@ -327,9 +327,10 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
        return __machine__findnew_thread(machine, pid, tid, true);
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t tid)
+struct thread *machine__find_thread(struct machine *machine, pid_t pid,
+                                   pid_t tid)
 {
-       return __machine__findnew_thread(machine, 0, tid, false);
+       return __machine__findnew_thread(machine, pid, tid, false);
 }
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
@@ -1026,7 +1027,7 @@ int machine__process_mmap2_event(struct machine *machine,
        }
 
        thread = machine__findnew_thread(machine, event->mmap2.pid,
-                                       event->mmap2.pid);
+                                       event->mmap2.tid);
        if (thread == NULL)
                goto out_problem;
 
@@ -1074,7 +1075,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
        }
 
        thread = machine__findnew_thread(machine, event->mmap.pid,
-                                        event->mmap.pid);
+                                        event->mmap.tid);
        if (thread == NULL)
                goto out_problem;
 
@@ -1114,7 +1115,9 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
 int machine__process_fork_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample)
 {
-       struct thread *thread = machine__find_thread(machine, event->fork.tid);
+       struct thread *thread = machine__find_thread(machine,
+                                                    event->fork.pid,
+                                                    event->fork.tid);
        struct thread *parent = machine__findnew_thread(machine,
                                                        event->fork.ppid,
                                                        event->fork.ptid);
@@ -1140,7 +1143,9 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
 int machine__process_exit_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample __maybe_unused)
 {
-       struct thread *thread = machine__find_thread(machine, event->fork.tid);
+       struct thread *thread = machine__find_thread(machine,
+                                                    event->fork.pid,
+                                                    event->fork.tid);
 
        if (dump_trace)
                perf_event__fprintf_task(event, stdout);
@@ -1184,39 +1189,22 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
        return 0;
 }
 
-static const u8 cpumodes[] = {
-       PERF_RECORD_MISC_USER,
-       PERF_RECORD_MISC_KERNEL,
-       PERF_RECORD_MISC_GUEST_USER,
-       PERF_RECORD_MISC_GUEST_KERNEL
-};
-#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
-
 static void ip__resolve_ams(struct machine *machine, struct thread *thread,
                            struct addr_map_symbol *ams,
                            u64 ip)
 {
        struct addr_location al;
-       size_t i;
-       u8 m;
 
        memset(&al, 0, sizeof(al));
+       /*
+        * We cannot use the header.misc hint to determine whether a
+        * branch stack address is user, kernel, guest, hypervisor.
+        * Branches may straddle the kernel/user/hypervisor boundaries.
+        * Thus, we have to try consecutively until we find a match
+        * or else, the symbol is unknown
+        */
+       thread__find_cpumode_addr_location(thread, machine, MAP__FUNCTION, ip, &al);
 
-       for (i = 0; i < NCPUMODES; i++) {
-               m = cpumodes[i];
-               /*
-                * We cannot use the header.misc hint to determine whether a
-                * branch stack address is user, kernel, guest, hypervisor.
-                * Branches may straddle the kernel/user/hypervisor boundaries.
-                * Thus, we have to try consecutively until we find a match
-                * or else, the symbol is unknown
-                */
-               thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
-                               ip, &al);
-               if (al.sym)
-                       goto found;
-       }
-found:
        ams->addr = ip;
        ams->al_addr = al.addr;
        ams->sym = al.sym;
@@ -1238,37 +1226,35 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
        ams->map = al.map;
 }
 
-struct mem_info *machine__resolve_mem(struct machine *machine,
-                                     struct thread *thr,
-                                     struct perf_sample *sample,
-                                     u8 cpumode)
+struct mem_info *sample__resolve_mem(struct perf_sample *sample,
+                                    struct addr_location *al)
 {
        struct mem_info *mi = zalloc(sizeof(*mi));
 
        if (!mi)
                return NULL;
 
-       ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
-       ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
+       ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip);
+       ip__resolve_data(al->machine, al->thread, al->cpumode,
+                        &mi->daddr, sample->addr);
        mi->data_src.val = sample->data_src;
 
        return mi;
 }
 
-struct branch_info *machine__resolve_bstack(struct machine *machine,
-                                           struct thread *thr,
-                                           struct branch_stack *bs)
+struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
+                                          struct addr_location *al)
 {
-       struct branch_info *bi;
        unsigned int i;
+       const struct branch_stack *bs = sample->branch_stack;
+       struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
 
-       bi = calloc(bs->nr, sizeof(struct branch_info));
        if (!bi)
                return NULL;
 
        for (i = 0; i < bs->nr; i++) {
-               ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
-               ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
+               ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to);
+               ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from);
                bi[i].flags = bs->entries[i].flags;
        }
        return bi;
@@ -1326,7 +1312,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
                        continue;
                }
 
-               al.filtered = false;
+               al.filtered = 0;
                thread__find_addr_location(thread, machine, cpumode,
                                           MAP__FUNCTION, ip, &al);
                if (al.sym != NULL) {
@@ -1385,8 +1371,7 @@ int machine__resolve_callchain(struct machine *machine,
                return 0;
 
        return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
-                                  thread, evsel->attr.sample_regs_user,
-                                  sample, max_stack);
+                                  thread, sample, max_stack);
 
 }
 
index f77e91e483dcf769597bfe6c18c7c106436398bf..c8c74a1193983ab6dbc66db56dacdb157a0ba315 100644 (file)
@@ -41,7 +41,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
        return machine->vmlinux_maps[type];
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t tid);
+struct thread *machine__find_thread(struct machine *machine, pid_t pid,
+                                   pid_t tid);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample);
@@ -91,12 +92,10 @@ void machine__delete_dead_threads(struct machine *machine);
 void machine__delete_threads(struct machine *machine);
 void machine__delete(struct machine *machine);
 
-struct branch_info *machine__resolve_bstack(struct machine *machine,
-                                           struct thread *thread,
-                                           struct branch_stack *bs);
-struct mem_info *machine__resolve_mem(struct machine *machine,
-                                     struct thread *thread,
-                                     struct perf_sample *sample, u8 cpumode);
+struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
+                                          struct addr_location *al);
+struct mem_info *sample__resolve_mem(struct perf_sample *sample,
+                                    struct addr_location *al);
 int machine__resolve_callchain(struct machine *machine,
                               struct perf_evsel *evsel,
                               struct thread *thread,
index 257e513205ceb850dbcaf9d6414254ba95a671e5..f00f058afb3b6b510da22c7c04d2f2c4aee3b0e9 100644 (file)
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
 
 struct symbol;
 
+/* map__for_each_symbol - iterate over the symbols in the given map
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * Note: caller must ensure map->dso is not NULL (map is loaded).
+ */
+#define map__for_each_symbol(map, pos, n)      \
+       dso__for_each_symbol(map->dso, pos, n, map->type)
+
 typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
index d22e3f8017dc429a67458bc18457a6de7cd9f778..bf48092983c65fe8cec8bb3ff4662e1b1803b18e 100644 (file)
@@ -407,7 +407,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                if (internal_help && !strcmp(arg + 2, "help"))
                        return usage_with_options_internal(usagestr, options, 0);
                if (!strcmp(arg + 2, "list-opts"))
-                       return PARSE_OPT_LIST;
+                       return PARSE_OPT_LIST_OPTS;
+               if (!strcmp(arg + 2, "list-cmds"))
+                       return PARSE_OPT_LIST_SUBCMDS;
                switch (parse_long_opt(ctx, arg + 2, options)) {
                case -1:
                        return parse_options_usage(usagestr, options, arg + 2, 0);
@@ -433,25 +435,45 @@ int parse_options_end(struct parse_opt_ctx_t *ctx)
        return ctx->cpidx + ctx->argc;
 }
 
-int parse_options(int argc, const char **argv, const struct option *options,
-                 const char * const usagestr[], int flags)
+int parse_options_subcommand(int argc, const char **argv, const struct option *options,
+                       const char *const subcommands[], const char *usagestr[], int flags)
 {
        struct parse_opt_ctx_t ctx;
 
        perf_header__set_cmdline(argc, argv);
 
+       /* build usage string if it's not provided */
+       if (subcommands && !usagestr[0]) {
+               struct strbuf buf = STRBUF_INIT;
+
+               strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
+               for (int i = 0; subcommands[i]; i++) {
+                       if (i)
+                               strbuf_addstr(&buf, "|");
+                       strbuf_addstr(&buf, subcommands[i]);
+               }
+               strbuf_addstr(&buf, "}");
+
+               usagestr[0] = strdup(buf.buf);
+               strbuf_release(&buf);
+       }
+
        parse_options_start(&ctx, argc, argv, flags);
        switch (parse_options_step(&ctx, options, usagestr)) {
        case PARSE_OPT_HELP:
                exit(129);
        case PARSE_OPT_DONE:
                break;
-       case PARSE_OPT_LIST:
+       case PARSE_OPT_LIST_OPTS:
                while (options->type != OPTION_END) {
                        printf("--%s ", options->long_name);
                        options++;
                }
                exit(130);
+       case PARSE_OPT_LIST_SUBCMDS:
+               for (int i = 0; subcommands[i]; i++)
+                       printf("%s ", subcommands[i]);
+               exit(130);
        default: /* PARSE_OPT_UNKNOWN */
                if (ctx.argv[0][1] == '-') {
                        error("unknown option `%s'", ctx.argv[0] + 2);
@@ -464,6 +486,13 @@ int parse_options(int argc, const char **argv, const struct option *options,
        return parse_options_end(&ctx);
 }
 
+int parse_options(int argc, const char **argv, const struct option *options,
+                 const char * const usagestr[], int flags)
+{
+       return parse_options_subcommand(argc, argv, options, NULL,
+                                       (const char **) usagestr, flags);
+}
+
 #define USAGE_OPTS_WIDTH 24
 #define USAGE_GAP         2
 
index cbf0149cf221783aea2aeafd8643900b80e6765d..d8dac8ac5f371403cf23f0ea0953d5db767540d4 100644 (file)
@@ -140,6 +140,11 @@ extern int parse_options(int argc, const char **argv,
                          const struct option *options,
                          const char * const usagestr[], int flags);
 
+extern int parse_options_subcommand(int argc, const char **argv,
+                               const struct option *options,
+                               const char *const subcommands[],
+                               const char *usagestr[], int flags);
+
 extern NORETURN void usage_with_options(const char * const *usagestr,
                                         const struct option *options);
 
@@ -148,7 +153,8 @@ extern NORETURN void usage_with_options(const char * const *usagestr,
 enum {
        PARSE_OPT_HELP = -1,
        PARSE_OPT_DONE,
-       PARSE_OPT_LIST,
+       PARSE_OPT_LIST_OPTS,
+       PARSE_OPT_LIST_SUBCMDS,
        PARSE_OPT_UNKNOWN,
 };
 
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
new file mode 100644 (file)
index 0000000..a3539ef
--- /dev/null
@@ -0,0 +1,19 @@
+#include <errno.h>
+#include "perf_regs.h"
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
+{
+       int i, idx = 0;
+       u64 mask = regs->mask;
+
+       if (!(mask & (1 << id)))
+               return -EINVAL;
+
+       for (i = 0; i < id; i++) {
+               if (mask & (1 << i))
+                       idx++;
+       }
+
+       *valp = regs->regs[idx];
+       return 0;
+}
index a3d42cd749196b83c4c8226bfd069a68cd3a6917..d6e8b6a8d7f38f03632921789281569433826816 100644 (file)
@@ -1,8 +1,14 @@
 #ifndef __PERF_REGS_H
 #define __PERF_REGS_H
 
+#include "types.h"
+#include "event.h"
+
 #ifdef HAVE_PERF_REGS_SUPPORT
 #include <perf_regs.h>
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
+
 #else
 #define PERF_REGS_MASK 0
 
@@ -10,5 +16,12 @@ static inline const char *perf_reg_name(int id __maybe_unused)
 {
        return NULL;
 }
+
+static inline int perf_reg_value(u64 *valp __maybe_unused,
+                                struct regs_dump *regs __maybe_unused,
+                                int id __maybe_unused)
+{
+       return 0;
+}
 #endif /* HAVE_PERF_REGS_SUPPORT */
 #endif /* __PERF_REGS_H */
index b752ecb40d86af6245b7f8646bb3607992bcd9f6..00a7dcb2f55cb0d7734e7eb331384d00aa42809c 100644 (file)
@@ -3,7 +3,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <dirent.h>
-#include "fs.h"
+#include <api/fs/fs.h>
 #include <locale.h>
 #include "util.h"
 #include "pmu.h"
index d8b048c20cdee51ac894b5394b15c70a1897c106..0d1542f33d879a6f761fe6f1fbd61b6299635237 100644 (file)
@@ -70,34 +70,32 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
-static int convert_name_to_addr(struct perf_probe_event *pev,
-                               const char *exec);
 static void clear_probe_trace_event(struct probe_trace_event *tev);
-static struct machine machine;
+static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
-static int init_vmlinux(void)
+static int init_symbol_maps(bool user_only)
 {
        int ret;
 
        symbol_conf.sort_by_name = true;
-       if (symbol_conf.vmlinux_name == NULL)
-               symbol_conf.try_vmlinux_path = true;
-       else
-               pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
        ret = symbol__init();
        if (ret < 0) {
                pr_debug("Failed to init symbol map.\n");
                goto out;
        }
 
-       ret = machine__init(&machine, "", HOST_KERNEL_ID);
-       if (ret < 0)
-               goto out;
+       if (host_machine || user_only)  /* already initialized */
+               return 0;
 
-       if (machine__create_kernel_maps(&machine) < 0) {
-               pr_debug("machine__create_kernel_maps() failed.\n");
-               goto out;
+       if (symbol_conf.vmlinux_name)
+               pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+
+       host_machine = machine__new_host();
+       if (!host_machine) {
+               pr_debug("machine__new_host() failed.\n");
+               symbol__exit();
+               ret = -1;
        }
 out:
        if (ret < 0)
@@ -105,21 +103,66 @@ out:
        return ret;
 }
 
+static void exit_symbol_maps(void)
+{
+       if (host_machine) {
+               machine__delete(host_machine);
+               host_machine = NULL;
+       }
+       symbol__exit();
+}
+
 static struct symbol *__find_kernel_function_by_name(const char *name,
                                                     struct map **mapp)
 {
-       return machine__find_kernel_function_by_name(&machine, name, mapp,
+       return machine__find_kernel_function_by_name(host_machine, name, mapp,
                                                     NULL);
 }
 
+static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
+{
+       return machine__find_kernel_function(host_machine, addr, mapp, NULL);
+}
+
+static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
+{
+       /* kmap->ref_reloc_sym should be set if host_machine is initialized */
+       struct kmap *kmap;
+
+       if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+               return NULL;
+
+       kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+       return kmap->ref_reloc_sym;
+}
+
+static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
+{
+       struct ref_reloc_sym *reloc_sym;
+       struct symbol *sym;
+       struct map *map;
+
+       /* ref_reloc_sym is just a label. Need a special fix*/
+       reloc_sym = kernel_get_ref_reloc_sym();
+       if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
+               return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
+       else {
+               sym = __find_kernel_function_by_name(name, &map);
+               if (sym)
+                       return map->unmap_ip(map, sym->start) -
+                               (reloc) ? 0 : map->reloc;
+       }
+       return 0;
+}
+
 static struct map *kernel_get_module_map(const char *module)
 {
        struct rb_node *nd;
-       struct map_groups *grp = &machine.kmaps;
+       struct map_groups *grp = &host_machine->kmaps;
 
        /* A file path -- this is an offline module */
        if (module && strchr(module, '/'))
-               return machine__new_module(&machine, 0, module);
+               return machine__new_module(host_machine, 0, module);
 
        if (!module)
                module = "kernel";
@@ -141,7 +184,7 @@ static struct dso *kernel_get_module_dso(const char *module)
        const char *vmlinux_name;
 
        if (module) {
-               list_for_each_entry(dso, &machine.kernel_dsos, node) {
+               list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
                        if (strncmp(dso->short_name + 1, module,
                                    dso->short_name_len - 2) == 0)
                                goto found;
@@ -150,7 +193,7 @@ static struct dso *kernel_get_module_dso(const char *module)
                return NULL;
        }
 
-       map = machine.vmlinux_maps[MAP__FUNCTION];
+       map = host_machine->vmlinux_maps[MAP__FUNCTION];
        dso = map->dso;
 
        vmlinux_name = symbol_conf.vmlinux_name;
@@ -173,20 +216,6 @@ const char *kernel_get_module_path(const char *module)
        return (dso) ? dso->long_name : NULL;
 }
 
-static int init_user_exec(void)
-{
-       int ret = 0;
-
-       symbol_conf.try_vmlinux_path = false;
-       symbol_conf.sort_by_name = true;
-       ret = symbol__init();
-
-       if (ret < 0)
-               pr_debug("Failed to init symbol map.\n");
-
-       return ret;
-}
-
 static int convert_exec_to_group(const char *exec, char **result)
 {
        char *ptr1, *ptr2, *exec_copy;
@@ -218,32 +247,23 @@ out:
        return ret;
 }
 
-static int convert_to_perf_probe_point(struct probe_trace_point *tp,
-                                       struct perf_probe_point *pp)
+static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 {
-       pp->function = strdup(tp->symbol);
-
-       if (pp->function == NULL)
-               return -ENOMEM;
-
-       pp->offset = tp->offset;
-       pp->retprobe = tp->retprobe;
+       int i;
 
-       return 0;
+       for (i = 0; i < ntevs; i++)
+               clear_probe_trace_event(tevs + i);
 }
 
 #ifdef HAVE_DWARF_SUPPORT
+
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
 {
-       const char *path;
+       const char *path = module;
 
-       /* A file path -- this is an offline module */
-       if (module && strchr(module, '/'))
-               path = module;
-       else {
+       if (!module || !strchr(module, '/')) {
                path = kernel_get_module_path(module);
-
                if (!path) {
                        pr_err("Failed to find path of %s module.\n",
                               module ?: "kernel");
@@ -253,46 +273,6 @@ static struct debuginfo *open_debuginfo(const char *module)
        return debuginfo__new(path);
 }
 
-/*
- * Convert trace point to probe point with debuginfo
- * Currently only handles kprobes.
- */
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-                                       struct perf_probe_point *pp)
-{
-       struct symbol *sym;
-       struct map *map;
-       u64 addr;
-       int ret = -ENOENT;
-       struct debuginfo *dinfo;
-
-       sym = __find_kernel_function_by_name(tp->symbol, &map);
-       if (sym) {
-               addr = map->unmap_ip(map, sym->start + tp->offset);
-               pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
-                        tp->offset, addr);
-
-               dinfo = debuginfo__new_online_kernel(addr);
-               if (dinfo) {
-                       ret = debuginfo__find_probe_point(dinfo,
-                                                (unsigned long)addr, pp);
-                       debuginfo__delete(dinfo);
-               } else {
-                       pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
-                                addr);
-                       ret = -ENOENT;
-               }
-       }
-       if (ret <= 0) {
-               pr_debug("Failed to find corresponding probes from "
-                        "debuginfo. Use kprobe event information.\n");
-               return convert_to_perf_probe_point(tp, pp);
-       }
-       pp->retprobe = tp->retprobe;
-
-       return 0;
-}
-
 static int get_text_start_address(const char *exec, unsigned long *address)
 {
        Elf *elf;
@@ -321,12 +301,62 @@ out:
        return ret;
 }
 
+/*
+ * Convert trace point to probe point with debuginfo
+ */
+static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
+                                           struct perf_probe_point *pp,
+                                           bool is_kprobe)
+{
+       struct debuginfo *dinfo = NULL;
+       unsigned long stext = 0;
+       u64 addr = tp->address;
+       int ret = -ENOENT;
+
+       /* convert the address to dwarf address */
+       if (!is_kprobe) {
+               if (!addr) {
+                       ret = -EINVAL;
+                       goto error;
+               }
+               ret = get_text_start_address(tp->module, &stext);
+               if (ret < 0)
+                       goto error;
+               addr += stext;
+       } else {
+               addr = kernel_get_symbol_address_by_name(tp->symbol, false);
+               if (addr == 0)
+                       goto error;
+               addr += tp->offset;
+       }
+
+       pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
+                tp->module ? : "kernel");
+
+       dinfo = open_debuginfo(tp->module);
+       if (dinfo) {
+               ret = debuginfo__find_probe_point(dinfo,
+                                                (unsigned long)addr, pp);
+               debuginfo__delete(dinfo);
+       } else {
+               pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+               ret = -ENOENT;
+       }
+
+       if (ret > 0) {
+               pp->retprobe = tp->retprobe;
+               return 0;
+       }
+error:
+       pr_debug("Failed to find corresponding probes from debuginfo.\n");
+       return ret ? : -ENOENT;
+}
+
 static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
                                          int ntevs, const char *exec)
 {
        int i, ret = 0;
-       unsigned long offset, stext = 0;
-       char buf[32];
+       unsigned long stext = 0;
 
        if (!exec)
                return 0;
@@ -337,15 +367,9 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 
        for (i = 0; i < ntevs && ret >= 0; i++) {
                /* point.address is the addres of point.symbol + point.offset */
-               offset = tevs[i].point.address - stext;
-               tevs[i].point.offset = 0;
-               zfree(&tevs[i].point.symbol);
-               ret = e_snprintf(buf, 32, "0x%lx", offset);
-               if (ret < 0)
-                       break;
+               tevs[i].point.address -= stext;
                tevs[i].point.module = strdup(exec);
-               tevs[i].point.symbol = strdup(buf);
-               if (!tevs[i].point.symbol || !tevs[i].point.module) {
+               if (!tevs[i].point.module) {
                        ret = -ENOMEM;
                        break;
                }
@@ -388,12 +412,40 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
        return ret;
 }
 
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+/* Post processing the probe events */
+static int post_process_probe_trace_events(struct probe_trace_event *tevs,
+                                          int ntevs, const char *module,
+                                          bool uprobe)
 {
+       struct ref_reloc_sym *reloc_sym;
+       char *tmp;
        int i;
 
-       for (i = 0; i < ntevs; i++)
-               clear_probe_trace_event(tevs + i);
+       if (uprobe)
+               return add_exec_to_probe_trace_events(tevs, ntevs, module);
+
+       /* Note that currently ref_reloc_sym based probe is not for drivers */
+       if (module)
+               return add_module_to_probe_trace_events(tevs, ntevs, module);
+
+       reloc_sym = kernel_get_ref_reloc_sym();
+       if (!reloc_sym) {
+               pr_warning("Relocated base symbol is not found!\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ntevs; i++) {
+               if (tevs[i].point.address) {
+                       tmp = strdup(reloc_sym->name);
+                       if (!tmp)
+                               return -ENOMEM;
+                       free(tevs[i].point.symbol);
+                       tevs[i].point.symbol = tmp;
+                       tevs[i].point.offset = tevs[i].point.address -
+                                              reloc_sym->unrelocated_addr;
+               }
+       }
+       return 0;
 }
 
 /* Try to find perf_probe_event with debuginfo */
@@ -416,21 +468,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
                return 0;
        }
 
+       pr_debug("Try to find probe point from debuginfo.\n");
        /* Searching trace events corresponding to a probe event */
        ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
 
        debuginfo__delete(dinfo);
 
        if (ntevs > 0) {        /* Succeeded to find trace events */
-               pr_debug("find %d probe_trace_events.\n", ntevs);
-               if (target) {
-                       if (pev->uprobes)
-                               ret = add_exec_to_probe_trace_events(*tevs,
-                                                ntevs, target);
-                       else
-                               ret = add_module_to_probe_trace_events(*tevs,
-                                                ntevs, target);
-               }
+               pr_debug("Found %d probe_trace_events.\n", ntevs);
+               ret = post_process_probe_trace_events(*tevs, ntevs,
+                                                       target, pev->uprobes);
                if (ret < 0) {
                        clear_probe_trace_events(*tevs, ntevs);
                        zfree(tevs);
@@ -563,20 +610,16 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr, const char *module)
+static int __show_line_range(struct line_range *lr, const char *module)
 {
        int l = 1;
-       struct line_node *ln;
+       struct int_node *ln;
        struct debuginfo *dinfo;
        FILE *fp;
        int ret;
        char *tmp;
 
        /* Search a line range */
-       ret = init_vmlinux();
-       if (ret < 0)
-               return ret;
-
        dinfo = open_debuginfo(module);
        if (!dinfo) {
                pr_warning("Failed to open debuginfo file.\n");
@@ -623,8 +666,8 @@ int show_line_range(struct line_range *lr, const char *module)
                        goto end;
        }
 
-       list_for_each_entry(ln, &lr->line_list, list) {
-               for (; ln->line > l; l++) {
+       intlist__for_each(ln, lr->line_list) {
+               for (; ln->i > l; l++) {
                        ret = show_one_line(fp, l - lr->offset);
                        if (ret < 0)
                                goto end;
@@ -646,6 +689,19 @@ end:
        return ret;
 }
 
+int show_line_range(struct line_range *lr, const char *module)
+{
+       int ret;
+
+       ret = init_symbol_maps(false);
+       if (ret < 0)
+               return ret;
+       ret = __show_line_range(lr, module);
+       exit_symbol_maps();
+
+       return ret;
+}
+
 static int show_available_vars_at(struct debuginfo *dinfo,
                                  struct perf_probe_event *pev,
                                  int max_vls, struct strfilter *_filter,
@@ -707,14 +763,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
        int i, ret = 0;
        struct debuginfo *dinfo;
 
-       ret = init_vmlinux();
+       ret = init_symbol_maps(false);
        if (ret < 0)
                return ret;
 
        dinfo = open_debuginfo(module);
        if (!dinfo) {
                pr_warning("Failed to open debuginfo file.\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto out;
        }
 
        setup_pager();
@@ -724,23 +781,19 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
                                             externs);
 
        debuginfo__delete(dinfo);
+out:
+       exit_symbol_maps();
        return ret;
 }
 
 #else  /* !HAVE_DWARF_SUPPORT */
 
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-                                       struct perf_probe_point *pp)
+static int
+find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
+                                struct perf_probe_point *pp __maybe_unused,
+                                bool is_kprobe __maybe_unused)
 {
-       struct symbol *sym;
-
-       sym = __find_kernel_function_by_name(tp->symbol, NULL);
-       if (!sym) {
-               pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
-               return -ENOENT;
-       }
-
-       return convert_to_perf_probe_point(tp, pp);
+       return -ENOSYS;
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -776,24 +829,22 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
 
 void line_range__clear(struct line_range *lr)
 {
-       struct line_node *ln;
-
        free(lr->function);
        free(lr->file);
        free(lr->path);
        free(lr->comp_dir);
-       while (!list_empty(&lr->line_list)) {
-               ln = list_first_entry(&lr->line_list, struct line_node, list);
-               list_del(&ln->list);
-               free(ln);
-       }
+       intlist__delete(lr->line_list);
        memset(lr, 0, sizeof(*lr));
 }
 
-void line_range__init(struct line_range *lr)
+int line_range__init(struct line_range *lr)
 {
        memset(lr, 0, sizeof(*lr));
-       INIT_LIST_HEAD(&lr->line_list);
+       lr->line_list = intlist__new(NULL);
+       if (!lr->line_list)
+               return -ENOMEM;
+       else
+               return 0;
 }
 
 static int parse_line_num(char **ptr, int *val, const char *what)
@@ -1267,16 +1318,21 @@ static int parse_probe_trace_command(const char *cmd,
        } else
                p = argv[1];
        fmt1_str = strtok_r(p, "+", &fmt);
-       tp->symbol = strdup(fmt1_str);
-       if (tp->symbol == NULL) {
-               ret = -ENOMEM;
-               goto out;
+       if (fmt1_str[0] == '0') /* only the address started with 0x */
+               tp->address = strtoul(fmt1_str, NULL, 0);
+       else {
+               /* Only the symbol-based probe has offset */
+               tp->symbol = strdup(fmt1_str);
+               if (tp->symbol == NULL) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               fmt2_str = strtok_r(NULL, "", &fmt);
+               if (fmt2_str == NULL)
+                       tp->offset = 0;
+               else
+                       tp->offset = strtoul(fmt2_str, NULL, 10);
        }
-       fmt2_str = strtok_r(NULL, "", &fmt);
-       if (fmt2_str == NULL)
-               tp->offset = 0;
-       else
-               tp->offset = strtoul(fmt2_str, NULL, 10);
 
        tev->nargs = argc - 2;
        tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1518,20 +1574,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
        if (buf == NULL)
                return NULL;
 
+       len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
+                        tev->group, tev->event);
+       if (len <= 0)
+               goto error;
+
+       /* Uprobes must have tp->address and tp->module */
+       if (tev->uprobes && (!tp->address || !tp->module))
+               goto error;
+
+       /* Use the tp->address for uprobes */
        if (tev->uprobes)
-               len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
-                                tp->retprobe ? 'r' : 'p',
-                                tev->group, tev->event,
-                                tp->module, tp->symbol);
+               ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
+                                tp->module, tp->address);
        else
-               len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-                                tp->retprobe ? 'r' : 'p',
-                                tev->group, tev->event,
+               ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
                                 tp->module ?: "", tp->module ? ":" : "",
                                 tp->symbol, tp->offset);
 
-       if (len <= 0)
+       if (ret <= 0)
                goto error;
+       len += ret;
 
        for (i = 0; i < tev->nargs; i++) {
                ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -1547,6 +1610,79 @@ error:
        return NULL;
 }
 
+static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
+                                         struct perf_probe_point *pp,
+                                         bool is_kprobe)
+{
+       struct symbol *sym = NULL;
+       struct map *map;
+       u64 addr;
+       int ret = -ENOENT;
+
+       if (!is_kprobe) {
+               map = dso__new_map(tp->module);
+               if (!map)
+                       goto out;
+               addr = tp->address;
+               sym = map__find_symbol(map, addr, NULL);
+       } else {
+               addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+               if (addr) {
+                       addr += tp->offset;
+                       sym = __find_kernel_function(addr, &map);
+               }
+       }
+       if (!sym)
+               goto out;
+
+       pp->retprobe = tp->retprobe;
+       pp->offset = addr - map->unmap_ip(map, sym->start);
+       pp->function = strdup(sym->name);
+       ret = pp->function ? 0 : -ENOMEM;
+
+out:
+       if (map && !is_kprobe) {
+               dso__delete(map->dso);
+               map__delete(map);
+       }
+
+       return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+                                       struct perf_probe_point *pp,
+                                       bool is_kprobe)
+{
+       char buf[128];
+       int ret;
+
+       ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
+       if (!ret)
+               return 0;
+       ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
+       if (!ret)
+               return 0;
+
+       pr_debug("Failed to find probe point from both of dwarf and map.\n");
+
+       if (tp->symbol) {
+               pp->function = strdup(tp->symbol);
+               pp->offset = tp->offset;
+       } else if (!tp->module && !is_kprobe) {
+               ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
+               if (ret < 0)
+                       return ret;
+               pp->function = strdup(buf);
+               pp->offset = 0;
+       }
+       if (pp->function == NULL)
+               return -ENOMEM;
+
+       pp->retprobe = tp->retprobe;
+
+       return 0;
+}
+
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
                               struct perf_probe_event *pev, bool is_kprobe)
 {
@@ -1560,11 +1696,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
                return -ENOMEM;
 
        /* Convert trace_point to probe_point */
-       if (is_kprobe)
-               ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
-       else
-               ret = convert_to_perf_probe_point(&tev->point, &pev->point);
-
+       ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
        if (ret < 0)
                return ret;
 
@@ -1731,7 +1863,8 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
 }
 
 /* Show an event */
-static int show_perf_probe_event(struct perf_probe_event *pev)
+static int show_perf_probe_event(struct perf_probe_event *pev,
+                                const char *module)
 {
        int i, ret;
        char buf[128];
@@ -1747,6 +1880,8 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
                return ret;
 
        printf("  %-20s (on %s", buf, place);
+       if (module)
+               printf(" in %s", module);
 
        if (pev->nargs > 0) {
                printf(" with");
@@ -1784,7 +1919,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
                        ret = convert_to_perf_probe_event(&tev, &pev,
                                                                is_kprobe);
                        if (ret >= 0)
-                               ret = show_perf_probe_event(&pev);
+                               ret = show_perf_probe_event(&pev,
+                                                           tev.point.module);
                }
                clear_perf_probe_event(&pev);
                clear_probe_trace_event(&tev);
@@ -1807,7 +1943,7 @@ int show_perf_probe_events(void)
        if (fd < 0)
                return fd;
 
-       ret = init_vmlinux();
+       ret = init_symbol_maps(false);
        if (ret < 0)
                return ret;
 
@@ -1820,6 +1956,7 @@ int show_perf_probe_events(void)
                close(fd);
        }
 
+       exit_symbol_maps();
        return ret;
 }
 
@@ -1982,7 +2119,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
                group = pev->group;
                pev->event = tev->event;
                pev->group = tev->group;
-               show_perf_probe_event(pev);
+               show_perf_probe_event(pev, tev->point.module);
                /* Trick here - restore current event/group */
                pev->event = (char *)event;
                pev->group = (char *)group;
@@ -2008,113 +2145,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
        return ret;
 }
 
-static int convert_to_probe_trace_events(struct perf_probe_event *pev,
-                                         struct probe_trace_event **tevs,
-                                         int max_tevs, const char *target)
+static char *looking_function_name;
+static int num_matched_functions;
+
+static int probe_function_filter(struct map *map __maybe_unused,
+                                     struct symbol *sym)
 {
+       if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
+           strcmp(looking_function_name, sym->name) == 0) {
+               num_matched_functions++;
+               return 0;
+       }
+       return 1;
+}
+
+#define strdup_or_goto(str, label)     \
+       ({ char *__p = strdup(str); if (!__p) goto label; __p; })
+
+/*
+ * Find probe function addresses from map.
+ * Return an error or the number of found probe_trace_event
+ */
+static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
+                                           struct probe_trace_event **tevs,
+                                           int max_tevs, const char *target)
+{
+       struct map *map = NULL;
+       struct kmap *kmap = NULL;
+       struct ref_reloc_sym *reloc_sym = NULL;
        struct symbol *sym;
-       int ret, i;
+       struct rb_node *nd;
        struct probe_trace_event *tev;
+       struct perf_probe_point *pp = &pev->point;
+       struct probe_trace_point *tp;
+       int ret, i;
 
-       if (pev->uprobes && !pev->group) {
-               /* Replace group name if not given */
-               ret = convert_exec_to_group(target, &pev->group);
-               if (ret != 0) {
-                       pr_warning("Failed to make a group name.\n");
-                       return ret;
-               }
+       /* Init maps of given executable or kernel */
+       if (pev->uprobes)
+               map = dso__new_map(target);
+       else
+               map = kernel_get_module_map(target);
+       if (!map) {
+               ret = -EINVAL;
+               goto out;
        }
 
-       /* Convert perf_probe_event with debuginfo */
-       ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
-       if (ret != 0)
-               return ret;     /* Found in debuginfo or got an error */
-
-       if (pev->uprobes) {
-               ret = convert_name_to_addr(pev, target);
-               if (ret < 0)
-                       return ret;
+       /*
+        * Load matched symbols: Since the different local symbols may have
+        * same name but different addresses, this lists all the symbols.
+        */
+       num_matched_functions = 0;
+       looking_function_name = pp->function;
+       ret = map__load(map, probe_function_filter);
+       if (ret || num_matched_functions == 0) {
+               pr_err("Failed to find symbol %s in %s\n", pp->function,
+                       target ? : "kernel");
+               ret = -ENOENT;
+               goto out;
+       } else if (num_matched_functions > max_tevs) {
+               pr_err("Too many functions matched in %s\n",
+                       target ? : "kernel");
+               ret = -E2BIG;
+               goto out;
        }
 
-       /* Allocate trace event buffer */
-       tev = *tevs = zalloc(sizeof(struct probe_trace_event));
-       if (tev == NULL)
-               return -ENOMEM;
+       if (!pev->uprobes) {
+               kmap = map__kmap(map);
+               reloc_sym = kmap->ref_reloc_sym;
+               if (!reloc_sym) {
+                       pr_warning("Relocated base symbol is not found!\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
 
-       /* Copy parameters */
-       tev->point.symbol = strdup(pev->point.function);
-       if (tev->point.symbol == NULL) {
+       /* Setup result trace-probe-events */
+       *tevs = zalloc(sizeof(*tev) * num_matched_functions);
+       if (!*tevs) {
                ret = -ENOMEM;
-               goto error;
+               goto out;
        }
 
-       if (target) {
-               tev->point.module = strdup(target);
-               if (tev->point.module == NULL) {
-                       ret = -ENOMEM;
-                       goto error;
+       ret = 0;
+       map__for_each_symbol(map, sym, nd) {
+               tev = (*tevs) + ret;
+               tp = &tev->point;
+               if (ret == num_matched_functions) {
+                       pr_warning("Too many symbols are listed. Skip it.\n");
+                       break;
                }
-       }
-
-       tev->point.offset = pev->point.offset;
-       tev->point.retprobe = pev->point.retprobe;
-       tev->nargs = pev->nargs;
-       tev->uprobes = pev->uprobes;
+               ret++;
 
-       if (tev->nargs) {
-               tev->args = zalloc(sizeof(struct probe_trace_arg)
-                                  * tev->nargs);
-               if (tev->args == NULL) {
-                       ret = -ENOMEM;
-                       goto error;
+               if (pp->offset > sym->end - sym->start) {
+                       pr_warning("Offset %ld is bigger than the size of %s\n",
+                                  pp->offset, sym->name);
+                       ret = -ENOENT;
+                       goto err_out;
+               }
+               /* Add one probe point */
+               tp->address = map->unmap_ip(map, sym->start) + pp->offset;
+               if (reloc_sym) {
+                       tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
+                       tp->offset = tp->address - reloc_sym->addr;
+               } else {
+                       tp->symbol = strdup_or_goto(sym->name, nomem_out);
+                       tp->offset = pp->offset;
+               }
+               tp->retprobe = pp->retprobe;
+               if (target)
+                       tev->point.module = strdup_or_goto(target, nomem_out);
+               tev->uprobes = pev->uprobes;
+               tev->nargs = pev->nargs;
+               if (tev->nargs) {
+                       tev->args = zalloc(sizeof(struct probe_trace_arg) *
+                                          tev->nargs);
+                       if (tev->args == NULL)
+                               goto nomem_out;
                }
                for (i = 0; i < tev->nargs; i++) {
-                       if (pev->args[i].name) {
-                               tev->args[i].name = strdup(pev->args[i].name);
-                               if (tev->args[i].name == NULL) {
-                                       ret = -ENOMEM;
-                                       goto error;
-                               }
-                       }
-                       tev->args[i].value = strdup(pev->args[i].var);
-                       if (tev->args[i].value == NULL) {
-                               ret = -ENOMEM;
-                               goto error;
-                       }
-                       if (pev->args[i].type) {
-                               tev->args[i].type = strdup(pev->args[i].type);
-                               if (tev->args[i].type == NULL) {
-                                       ret = -ENOMEM;
-                                       goto error;
-                               }
-                       }
+                       if (pev->args[i].name)
+                               tev->args[i].name =
+                                       strdup_or_goto(pev->args[i].name,
+                                                       nomem_out);
+
+                       tev->args[i].value = strdup_or_goto(pev->args[i].var,
+                                                           nomem_out);
+                       if (pev->args[i].type)
+                               tev->args[i].type =
+                                       strdup_or_goto(pev->args[i].type,
+                                                       nomem_out);
                }
        }
 
-       if (pev->uprobes)
-               return 1;
+out:
+       if (map && pev->uprobes) {
+               /* Only when using uprobe(exec) map needs to be released */
+               dso__delete(map->dso);
+               map__delete(map);
+       }
+       return ret;
 
-       /* Currently just checking function name from symbol map */
-       sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
-       if (!sym) {
-               pr_warning("Kernel symbol \'%s\' not found.\n",
-                          tev->point.symbol);
-               ret = -ENOENT;
-               goto error;
-       } else if (tev->point.offset > sym->end - sym->start) {
-               pr_warning("Offset specified is greater than size of %s\n",
-                          tev->point.symbol);
-               ret = -ENOENT;
-               goto error;
+nomem_out:
+       ret = -ENOMEM;
+err_out:
+       clear_probe_trace_events(*tevs, num_matched_functions);
+       zfree(tevs);
+       goto out;
+}
+
+static int convert_to_probe_trace_events(struct perf_probe_event *pev,
+                                         struct probe_trace_event **tevs,
+                                         int max_tevs, const char *target)
+{
+       int ret;
 
+       if (pev->uprobes && !pev->group) {
+               /* Replace group name if not given */
+               ret = convert_exec_to_group(target, &pev->group);
+               if (ret != 0) {
+                       pr_warning("Failed to make a group name.\n");
+                       return ret;
+               }
        }
 
-       return 1;
-error:
-       clear_probe_trace_event(tev);
-       free(tev);
-       *tevs = NULL;
-       return ret;
+       /* Convert perf_probe_event with debuginfo */
+       ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
+       if (ret != 0)
+               return ret;     /* Found in debuginfo or got an error */
+
+       return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
 }
 
 struct __event_package {
@@ -2135,12 +2334,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
        if (pkgs == NULL)
                return -ENOMEM;
 
-       if (!pevs->uprobes)
-               /* Init vmlinux path */
-               ret = init_vmlinux();
-       else
-               ret = init_user_exec();
-
+       ret = init_symbol_maps(pevs->uprobes);
        if (ret < 0) {
                free(pkgs);
                return ret;
@@ -2174,6 +2368,7 @@ end:
                zfree(&pkgs[i].tevs);
        }
        free(pkgs);
+       exit_symbol_maps();
 
        return ret;
 }
@@ -2323,159 +2518,51 @@ static struct strfilter *available_func_filter;
 static int filter_available_functions(struct map *map __maybe_unused,
                                      struct symbol *sym)
 {
-       if (sym->binding == STB_GLOBAL &&
+       if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
            strfilter__compare(available_func_filter, sym->name))
                return 0;
        return 1;
 }
 
-static int __show_available_funcs(struct map *map)
-{
-       if (map__load(map, filter_available_functions)) {
-               pr_err("Failed to load map.\n");
-               return -EINVAL;
-       }
-       if (!dso__sorted_by_name(map->dso, map->type))
-               dso__sort_by_name(map->dso, map->type);
-
-       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
-       return 0;
-}
-
-static int available_kernel_funcs(const char *module)
+int show_available_funcs(const char *target, struct strfilter *_filter,
+                                       bool user)
 {
        struct map *map;
        int ret;
 
-       ret = init_vmlinux();
+       ret = init_symbol_maps(user);
        if (ret < 0)
                return ret;
 
-       map = kernel_get_module_map(module);
+       /* Get a symbol map */
+       if (user)
+               map = dso__new_map(target);
+       else
+               map = kernel_get_module_map(target);
        if (!map) {
-               pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+               pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
                return -EINVAL;
        }
-       return __show_available_funcs(map);
-}
-
-static int available_user_funcs(const char *target)
-{
-       struct map *map;
-       int ret;
-
-       ret = init_user_exec();
-       if (ret < 0)
-               return ret;
-
-       map = dso__new_map(target);
-       ret = __show_available_funcs(map);
-       dso__delete(map->dso);
-       map__delete(map);
-       return ret;
-}
 
-int show_available_funcs(const char *target, struct strfilter *_filter,
-                                       bool user)
-{
-       setup_pager();
+       /* Load symbols with given filter */
        available_func_filter = _filter;
-
-       if (!user)
-               return available_kernel_funcs(target);
-
-       return available_user_funcs(target);
-}
-
-/*
- * uprobe_events only accepts address:
- * Convert function and any offset to address
- */
-static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
-{
-       struct perf_probe_point *pp = &pev->point;
-       struct symbol *sym;
-       struct map *map = NULL;
-       char *function = NULL;
-       int ret = -EINVAL;
-       unsigned long long vaddr = 0;
-
-       if (!pp->function) {
-               pr_warning("No function specified for uprobes");
-               goto out;
-       }
-
-       function = strdup(pp->function);
-       if (!function) {
-               pr_warning("Failed to allocate memory by strdup.\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       map = dso__new_map(exec);
-       if (!map) {
-               pr_warning("Cannot find appropriate DSO for %s.\n", exec);
-               goto out;
-       }
-       available_func_filter = strfilter__new(function, NULL);
        if (map__load(map, filter_available_functions)) {
-               pr_err("Failed to load map.\n");
-               goto out;
-       }
-
-       sym = map__find_symbol_by_name(map, function, NULL);
-       if (!sym) {
-               pr_warning("Cannot find %s in DSO %s\n", function, exec);
-               goto out;
-       }
-
-       if (map->start > sym->start)
-               vaddr = map->start;
-       vaddr += sym->start + pp->offset + map->pgoff;
-       pp->offset = 0;
-
-       if (!pev->event) {
-               pev->event = function;
-               function = NULL;
-       }
-       if (!pev->group) {
-               char *ptr1, *ptr2, *exec_copy;
-
-               pev->group = zalloc(sizeof(char *) * 64);
-               exec_copy = strdup(exec);
-               if (!exec_copy) {
-                       ret = -ENOMEM;
-                       pr_warning("Failed to copy exec string.\n");
-                       goto out;
-               }
-
-               ptr1 = strdup(basename(exec_copy));
-               if (ptr1) {
-                       ptr2 = strpbrk(ptr1, "-._");
-                       if (ptr2)
-                               *ptr2 = '\0';
-                       e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
-                                       ptr1);
-                       free(ptr1);
-               }
-               free(exec_copy);
-       }
-       free(pp->function);
-       pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
-       if (!pp->function) {
-               ret = -ENOMEM;
-               pr_warning("Failed to allocate memory by zalloc.\n");
-               goto out;
+               pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
+               goto end;
        }
-       e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
-       ret = 0;
+       if (!dso__sorted_by_name(map->dso, map->type))
+               dso__sort_by_name(map->dso, map->type);
 
-out:
-       if (map) {
+       /* Show all (filtered) symbols */
+       setup_pager();
+       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+end:
+       if (user) {
                dso__delete(map->dso);
                map__delete(map);
        }
-       if (function)
-               free(function);
+       exit_symbol_maps();
+
        return ret;
 }
+
index fcaf7273e85a35f41ac465c2f343ec07cbd0f1a4..776c9347a3b64252e2f4c9b30b4710b580923b72 100644 (file)
@@ -2,6 +2,7 @@
 #define _PROBE_EVENT_H
 
 #include <stdbool.h>
+#include "intlist.h"
 #include "strlist.h"
 #include "strfilter.h"
 
@@ -76,13 +77,6 @@ struct perf_probe_event {
        struct perf_probe_arg   *args;  /* Arguments */
 };
 
-
-/* Line number container */
-struct line_node {
-       struct list_head        list;
-       int                     line;
-};
-
 /* Line range */
 struct line_range {
        char                    *file;          /* File name */
@@ -92,7 +86,7 @@ struct line_range {
        int                     offset;         /* Start line offset */
        char                    *path;          /* Real path name */
        char                    *comp_dir;      /* Compile directory */
-       struct list_head        line_list;      /* Visible lines */
+       struct intlist          *line_list;     /* Visible lines */
 };
 
 /* List of variables */
@@ -124,7 +118,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 extern void line_range__clear(struct line_range *lr);
 
 /* Initialize line range */
-extern void line_range__init(struct line_range *lr);
+extern int line_range__init(struct line_range *lr);
 
 /* Internal use: Return kernel/module path */
 extern const char *kernel_get_module_path(const char *module);
index 061edb162b5ba03f9b4f883543faa5c0f27e371d..df0238654698d8967120f538a68b6aec5da18426 100644 (file)
@@ -34,7 +34,9 @@
 
 #include <linux/bitops.h>
 #include "event.h"
+#include "dso.h"
 #include "debug.h"
+#include "intlist.h"
 #include "util.h"
 #include "symbol.h"
 #include "probe-finder.h"
 /* Kprobe tracer basic type is up to u64 */
 #define MAX_BASIC_TYPE_BITS    64
 
-/* Line number list operations */
-
-/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, int line)
-{
-       struct line_node *ln;
-       struct list_head *p;
-
-       /* Reverse search, because new line will be the last one */
-       list_for_each_entry_reverse(ln, head, list) {
-               if (ln->line < line) {
-                       p = &ln->list;
-                       goto found;
-               } else if (ln->line == line)    /* Already exist */
-                       return 1;
-       }
-       /* List is empty, or the smallest entry */
-       p = head;
-found:
-       pr_debug("line list: add a line %u\n", line);
-       ln = zalloc(sizeof(struct line_node));
-       if (ln == NULL)
-               return -ENOMEM;
-       ln->line = line;
-       INIT_LIST_HEAD(&ln->list);
-       list_add(&ln->list, p);
-       return 0;
-}
-
-/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, int line)
-{
-       struct line_node *ln;
-
-       /* Reverse search, because new line will be the last one */
-       list_for_each_entry(ln, head, list)
-               if (ln->line == line)
-                       return 1;
-
-       return 0;
-}
-
-/* Init line number list */
-static void line_list__init(struct list_head *head)
-{
-       INIT_LIST_HEAD(head);
-}
-
-/* Free line number list */
-static void line_list__free(struct list_head *head)
-{
-       struct line_node *ln;
-       while (!list_empty(head)) {
-               ln = list_first_entry(head, struct line_node, list);
-               list_del(&ln->list);
-               free(ln);
-       }
-}
-
 /* Dwarf FL wrappers */
 static char *debuginfo_path;   /* Currently dummy */
 
@@ -147,80 +90,7 @@ error:
        return -ENOENT;
 }
 
-#if _ELFUTILS_PREREQ(0, 148)
-/* This method is buggy if elfutils is older than 0.148 */
-static int __linux_kernel_find_elf(Dwfl_Module *mod,
-                                  void **userdata,
-                                  const char *module_name,
-                                  Dwarf_Addr base,
-                                  char **file_name, Elf **elfp)
-{
-       int fd;
-       const char *path = kernel_get_module_path(module_name);
-
-       pr_debug2("Use file %s for %s\n", path, module_name);
-       if (path) {
-               fd = open(path, O_RDONLY);
-               if (fd >= 0) {
-                       *file_name = strdup(path);
-                       return fd;
-               }
-       }
-       /* If failed, try to call standard method */
-       return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
-                                         file_name, elfp);
-}
-
-static const Dwfl_Callbacks kernel_callbacks = {
-       .find_debuginfo = dwfl_standard_find_debuginfo,
-       .debuginfo_path = &debuginfo_path,
-
-       .find_elf = __linux_kernel_find_elf,
-       .section_address = dwfl_linux_kernel_module_section_address,
-};
-
-/* Get a Dwarf from live kernel image */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-                                              Dwarf_Addr addr)
-{
-       dbg->dwfl = dwfl_begin(&kernel_callbacks);
-       if (!dbg->dwfl)
-               return -EINVAL;
-
-       /* Load the kernel dwarves: Don't care the result here */
-       dwfl_linux_kernel_report_kernel(dbg->dwfl);
-       dwfl_linux_kernel_report_modules(dbg->dwfl);
-
-       dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
-       /* Here, check whether we could get a real dwarf */
-       if (!dbg->dbg) {
-               pr_debug("Failed to find kernel dwarf at %lx\n",
-                        (unsigned long)addr);
-               dwfl_end(dbg->dwfl);
-               memset(dbg, 0, sizeof(*dbg));
-               return -ENOENT;
-       }
-
-       return 0;
-}
-#else
-/* With older elfutils, this just support kernel module... */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-                                              Dwarf_Addr addr __maybe_unused)
-{
-       const char *path = kernel_get_module_path("kernel");
-
-       if (!path) {
-               pr_err("Failed to find vmlinux path\n");
-               return -ENOENT;
-       }
-
-       pr_debug2("Use file %s for debuginfo\n", path);
-       return debuginfo__init_offline_dwarf(dbg, path);
-}
-#endif
-
-struct debuginfo *debuginfo__new(const char *path)
+static struct debuginfo *__debuginfo__new(const char *path)
 {
        struct debuginfo *dbg = zalloc(sizeof(*dbg));
        if (!dbg)
@@ -228,21 +98,44 @@ struct debuginfo *debuginfo__new(const char *path)
 
        if (debuginfo__init_offline_dwarf(dbg, path) < 0)
                zfree(&dbg);
-
+       if (dbg)
+               pr_debug("Open Debuginfo file: %s\n", path);
        return dbg;
 }
 
-struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
-{
-       struct debuginfo *dbg = zalloc(sizeof(*dbg));
+enum dso_binary_type distro_dwarf_types[] = {
+       DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+       DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+       DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+       DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+       DSO_BINARY_TYPE__NOT_FOUND,
+};
 
-       if (!dbg)
-               return NULL;
+struct debuginfo *debuginfo__new(const char *path)
+{
+       enum dso_binary_type *type;
+       char buf[PATH_MAX], nil = '\0';
+       struct dso *dso;
+       struct debuginfo *dinfo = NULL;
+
+       /* Try to open distro debuginfo files */
+       dso = dso__new(path);
+       if (!dso)
+               goto out;
 
-       if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
-               zfree(&dbg);
+       for (type = distro_dwarf_types;
+            !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
+            type++) {
+               if (dso__read_binary_type_filename(dso, *type, &nil,
+                                                  buf, PATH_MAX) < 0)
+                       continue;
+               dinfo = __debuginfo__new(buf);
+       }
+       dso__delete(dso);
 
-       return dbg;
+out:
+       /* if failed to open all distro debuginfo, open given binary */
+       return dinfo ? : __debuginfo__new(path);
 }
 
 void debuginfo__delete(struct debuginfo *dbg)
@@ -880,7 +773,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
 }
 
 /* Find lines which match lazy pattern */
-static int find_lazy_match_lines(struct list_head *head,
+static int find_lazy_match_lines(struct intlist *list,
                                 const char *fname, const char *pat)
 {
        FILE *fp;
@@ -901,7 +794,7 @@ static int find_lazy_match_lines(struct list_head *head,
                        line[len - 1] = '\0';
 
                if (strlazymatch(line, pat)) {
-                       line_list__add_line(head, linenum);
+                       intlist__add(list, linenum);
                        count++;
                }
                linenum++;
@@ -924,7 +817,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
        Dwarf_Die *sc_die, die_mem;
        int ret;
 
-       if (!line_list__has_line(&pf->lcache, lineno) ||
+       if (!intlist__has_entry(pf->lcache, lineno) ||
            strtailcmp(fname, pf->fname) != 0)
                return 0;
 
@@ -952,9 +845,9 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
        int ret = 0;
 
-       if (list_empty(&pf->lcache)) {
+       if (intlist__empty(pf->lcache)) {
                /* Matching lazy line pattern */
-               ret = find_lazy_match_lines(&pf->lcache, pf->fname,
+               ret = find_lazy_match_lines(pf->lcache, pf->fname,
                                            pf->pev->point.lazy_line);
                if (ret <= 0)
                        return ret;
@@ -1096,7 +989,9 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
 #endif
 
        off = 0;
-       line_list__init(&pf->lcache);
+       pf->lcache = intlist__new(NULL);
+       if (!pf->lcache)
+               return -ENOMEM;
 
        /* Fastpath: lookup by function name from .debug_pubnames section */
        if (pp->function) {
@@ -1149,7 +1044,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
        }
 
 found:
-       line_list__free(&pf->lcache);
+       intlist__delete(pf->lcache);
+       pf->lcache = NULL;
 
        return ret;
 }
@@ -1537,7 +1433,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
                if (lr->path == NULL)
                        return -ENOMEM;
        }
-       return line_list__add_line(&lr->line_list, lineno);
+       return intlist__add(lr->line_list, lineno);
 }
 
 static int line_range_walk_cb(const char *fname, int lineno,
@@ -1565,7 +1461,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
        /* Update status */
        if (ret >= 0)
-               if (!list_empty(&lf->lr->line_list))
+               if (!intlist__empty(lf->lr->line_list))
                        ret = lf->found = 1;
                else
                        ret = 0;        /* Lines are not found */
index ffc33cdd25cc343816fd9e05586832bf48b82205..92590b2c7e1ce650080652839e5506bf98d9093c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "util.h"
+#include "intlist.h"
 #include "probe-event.h"
 
 #define MAX_PROBE_BUFFER       1024
@@ -29,8 +30,8 @@ struct debuginfo {
        Dwarf_Addr      bias;
 };
 
+/* This also tries to open distro debuginfo */
 extern struct debuginfo *debuginfo__new(const char *path);
-extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
 extern void debuginfo__delete(struct debuginfo *dbg);
 
 /* Find probe_trace_events specified by perf_probe_event from debuginfo */
@@ -66,7 +67,7 @@ struct probe_finder {
        const char              *fname;         /* Real file name */
        Dwarf_Die               cu_die;         /* Current CU */
        Dwarf_Die               sp_die;
-       struct list_head        lcache;         /* Line cache for lazy match */
+       struct intlist          *lcache;        /* Line cache for lazy match */
 
        /* For variable searching */
 #if _ELFUTILS_PREREQ(0, 142)
index 595bfc73d2ed28cf14feee7daf73c76d92527223..16a475a7d492177623062143434488116cdf2a38 100644 (file)
@@ -17,6 +17,6 @@ util/xyarray.c
 util/cgroup.c
 util/rblist.c
 util/strlist.c
-util/fs.c
+../lib/api/fs/fs.c
 util/trace-event.c
 ../../lib/rbtree.c
index 373762501dadced6c476235ad8170a5241e72801..049e0a09ccd362b6f79192fe769f75648f3730b1 100644 (file)
@@ -2,7 +2,7 @@
 #include "evsel.h"
 #include "cpumap.h"
 #include "parse-events.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include "util.h"
 
 typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
index 5da6ce74c676722ff13ae858c1bb579ba353edbf..55960f22233c4c994feff352d2e458113a4f1db4 100644 (file)
@@ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs)
        }
 }
 
-static void regs_user__printf(struct perf_sample *sample, u64 mask)
+static void regs_user__printf(struct perf_sample *sample)
 {
        struct regs_dump *user_regs = &sample->user_regs;
 
        if (user_regs->regs) {
+               u64 mask = user_regs->mask;
                printf("... user regs: mask 0x%" PRIx64 "\n", mask);
                regs_dump__printf(mask, user_regs->regs);
        }
@@ -793,7 +794,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
        if (!dump_trace)
                return;
 
-       printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
+       printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
               event->header.misc, sample->pid, sample->tid, sample->ip,
               sample->period, sample->addr);
 
@@ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
                branch_stack__printf(sample);
 
        if (sample_type & PERF_SAMPLE_REGS_USER)
-               regs_user__printf(sample, evsel->attr.sample_regs_user);
+               regs_user__printf(sample);
 
        if (sample_type & PERF_SAMPLE_STACK_USER)
                stack_user__printf(&sample->user_stack);
index 3e9f336740fa8699b2bdd16669e05cd8f8f6dede..3b7dbf51d4a93bd425fc41363d98a47acd7288ff 100644 (file)
@@ -151,15 +151,15 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 
                gelf_getshdr(sec, shp);
                str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
-               if (!strcmp(name, str)) {
+               if (str && !strcmp(name, str)) {
                        if (idx)
                                *idx = cnt;
-                       break;
+                       return sec;
                }
                ++cnt;
        }
 
-       return sec;
+       return NULL;
 }
 
 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
@@ -506,6 +506,8 @@ int filename__read_debuglink(const char *filename, char *debuglink,
        /* the start of this section is a zero-terminated string */
        strncpy(debuglink, data->d_buf, size);
 
+       err = 0;
+
 out_elf_end:
        elf_end(elf);
 out_close:
index e89afc097d8ad2d4b818f07e02321084110e6ddc..95e249779931216f5cbeb5b09c26ea0655a0fcf7 100644 (file)
@@ -410,7 +410,7 @@ struct symbol *dso__find_symbol(struct dso *dso,
        return symbols__find(&dso->symbols[type], addr);
 }
 
-struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
+static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
 {
        return symbols__first(&dso->symbols[type]);
 }
@@ -1251,6 +1251,46 @@ out_failure:
        return -1;
 }
 
+static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
+                                          enum dso_binary_type type)
+{
+       switch (type) {
+       case DSO_BINARY_TYPE__JAVA_JIT:
+       case DSO_BINARY_TYPE__DEBUGLINK:
+       case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
+       case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
+       case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
+       case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
+       case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
+               return !kmod && dso->kernel == DSO_TYPE_USER;
+
+       case DSO_BINARY_TYPE__KALLSYMS:
+       case DSO_BINARY_TYPE__VMLINUX:
+       case DSO_BINARY_TYPE__KCORE:
+               return dso->kernel == DSO_TYPE_KERNEL;
+
+       case DSO_BINARY_TYPE__GUEST_KALLSYMS:
+       case DSO_BINARY_TYPE__GUEST_VMLINUX:
+       case DSO_BINARY_TYPE__GUEST_KCORE:
+               return dso->kernel == DSO_TYPE_GUEST_KERNEL;
+
+       case DSO_BINARY_TYPE__GUEST_KMODULE:
+       case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+               /*
+                * kernel modules know their symtab type - it's set when
+                * creating a module dso in machine__new_module().
+                */
+               return kmod && dso->symtab_type == type;
+
+       case DSO_BINARY_TYPE__BUILD_ID_CACHE:
+               return true;
+
+       case DSO_BINARY_TYPE__NOT_FOUND:
+       default:
+               return false;
+       }
+}
+
 int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 {
        char *name;
@@ -1261,6 +1301,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        int ss_pos = 0;
        struct symsrc ss_[2];
        struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
+       bool kmod;
 
        dso__set_loaded(dso, map->type);
 
@@ -1301,7 +1342,11 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        if (!name)
                return -1;
 
-       /* Iterate over candidate debug images.
+       kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+
+       /*
+        * Iterate over candidate debug images.
         * Keep track of "interesting" ones (those which have a symtab, dynsym,
         * and/or opd section) for processing.
         */
@@ -1311,6 +1356,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
                enum dso_binary_type symtab_type = binary_type_symtab[i];
 
+               if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
+                       continue;
+
                if (dso__read_binary_type_filename(dso, symtab_type,
                                                   root_dir, name, PATH_MAX))
                        continue;
@@ -1353,15 +1401,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        if (!runtime_ss && syms_ss)
                runtime_ss = syms_ss;
 
-       if (syms_ss) {
-               int km;
-
-               km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
-                    dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
-               ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
-       } else {
+       if (syms_ss)
+               ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
+       else
                ret = -1;
-       }
 
        if (ret > 0) {
                int nr_plt;
index fffe2888a1c7c123d6e7de3f11eb74dfd4f4ebf8..501e4e722e8e853258e3e06b8448cc5792005971 100644 (file)
@@ -79,6 +79,17 @@ struct symbol {
 void symbol__delete(struct symbol *sym);
 void symbols__delete(struct rb_root *symbols);
 
+/* symbols__for_each_entry - iterate over symbols (rb_root)
+ *
+ * @symbols: the rb_root of symbols
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @nd: the 'struct rb_node *' to use as a temporary storage
+ */
+#define symbols__for_each_entry(symbols, pos, nd)                      \
+       for (nd = rb_first(symbols);                                    \
+            nd && (pos = rb_entry(nd, struct symbol, rb_node));        \
+            nd = rb_next(nd))
+
 static inline size_t symbol__size(const struct symbol *sym)
 {
        return sym->end - sym->start + 1;
@@ -175,7 +186,7 @@ struct addr_location {
        struct symbol *sym;
        u64           addr;
        char          level;
-       bool          filtered;
+       u8            filtered;
        u8            cpumode;
        s32           cpu;
 };
@@ -223,7 +234,6 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
                                u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
                                        const char *name);
-struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
 
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
index 0358882c89108723616c4eca0431fed0aa6be200..3ce0498bdae60bb24fe558006e1e02b4ed9ba2b9 100644 (file)
@@ -142,3 +142,24 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
 
        return 0;
 }
+
+void thread__find_cpumode_addr_location(struct thread *thread,
+                                       struct machine *machine,
+                                       enum map_type type, u64 addr,
+                                       struct addr_location *al)
+{
+       size_t i;
+       const u8 const cpumodes[] = {
+               PERF_RECORD_MISC_USER,
+               PERF_RECORD_MISC_KERNEL,
+               PERF_RECORD_MISC_GUEST_USER,
+               PERF_RECORD_MISC_GUEST_KERNEL
+       };
+
+       for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
+               thread__find_addr_location(thread, machine, cpumodes[i], type,
+                                          addr, al);
+               if (al->map)
+                       break;
+       }
+}
index 5b856bf942e11fa9691c28551a88b53b4ac3d5f2..9b29f085aedeaa637da7bb25e571c07a19697cd0 100644 (file)
@@ -44,12 +44,6 @@ void thread__insert_map(struct thread *thread, struct map *map);
 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
 size_t thread__fprintf(struct thread *thread, FILE *fp);
 
-static inline struct map *thread__find_map(struct thread *thread,
-                                          enum map_type type, u64 addr)
-{
-       return thread ? map_groups__find(&thread->mg, type, addr) : NULL;
-}
-
 void thread__find_addr_map(struct thread *thread, struct machine *machine,
                           u8 cpumode, enum map_type type, u64 addr,
                           struct addr_location *al);
@@ -58,6 +52,11 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
                                u8 cpumode, enum map_type type, u64 addr,
                                struct addr_location *al);
 
+void thread__find_cpumode_addr_location(struct thread *thread,
+                                       struct machine *machine,
+                                       enum map_type type, u64 addr,
+                                       struct addr_location *al);
+
 static inline void *thread__priv(struct thread *thread)
 {
        return thread->priv;
index e0d6d07f68485167f2b05260fd932a288b42eec9..c36636fd825b46481dfcadbc745014ed94f38650 100644 (file)
@@ -126,6 +126,7 @@ void event_format__print(struct event_format *event,
        trace_seq_init(&s);
        pevent_event_info(&s, event, &record);
        trace_seq_do_printf(&s);
+       trace_seq_destroy(&s);
 }
 
 void parse_proc_kallsyms(struct pevent *pevent,
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
new file mode 100644 (file)
index 0000000..67db73e
--- /dev/null
@@ -0,0 +1,210 @@
+#include <linux/compiler.h>
+#include <elfutils/libdw.h>
+#include <elfutils/libdwfl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "unwind.h"
+#include "unwind-libdw.h"
+#include "machine.h"
+#include "thread.h"
+#include "types.h"
+#include "event.h"
+#include "perf_regs.h"
+
+static char *debuginfo_path;
+
+static const Dwfl_Callbacks offline_callbacks = {
+       .find_debuginfo         = dwfl_standard_find_debuginfo,
+       .debuginfo_path         = &debuginfo_path,
+       .section_address        = dwfl_offline_section_address,
+};
+
+static int __report_module(struct addr_location *al, u64 ip,
+                           struct unwind_info *ui)
+{
+       Dwfl_Module *mod;
+       struct dso *dso = NULL;
+
+       thread__find_addr_location(ui->thread, ui->machine,
+                                  PERF_RECORD_MISC_USER,
+                                  MAP__FUNCTION, ip, al);
+
+       if (al->map)
+               dso = al->map->dso;
+
+       if (!dso)
+               return 0;
+
+       mod = dwfl_addrmodule(ui->dwfl, ip);
+       if (!mod)
+               mod = dwfl_report_elf(ui->dwfl, dso->short_name,
+                                     dso->long_name, -1, al->map->start,
+                                     false);
+
+       return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
+}
+
+static int report_module(u64 ip, struct unwind_info *ui)
+{
+       struct addr_location al;
+
+       return __report_module(&al, ip, ui);
+}
+
+static int entry(u64 ip, struct unwind_info *ui)
+
+{
+       struct unwind_entry e;
+       struct addr_location al;
+
+       if (__report_module(&al, ip, ui))
+               return -1;
+
+       e.ip  = ip;
+       e.map = al.map;
+       e.sym = al.sym;
+
+       pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+                al.sym ? al.sym->name : "''",
+                ip,
+                al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
+
+       return ui->cb(&e, ui->arg);
+}
+
+static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
+{
+       /* We want only single thread to be processed. */
+       if (*thread_argp != NULL)
+               return 0;
+
+       *thread_argp = arg;
+       return dwfl_pid(dwfl);
+}
+
+static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
+                         Dwarf_Word *data)
+{
+       struct addr_location al;
+       ssize_t size;
+
+       thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+                             MAP__FUNCTION, addr, &al);
+       if (!al.map) {
+               pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+               return -1;
+       }
+
+       if (!al.map->dso)
+               return -1;
+
+       size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+                                  addr, (u8 *) data, sizeof(*data));
+
+       return !(size == sizeof(*data));
+}
+
+static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
+                       void *arg)
+{
+       struct unwind_info *ui = arg;
+       struct stack_dump *stack = &ui->sample->user_stack;
+       u64 start, end;
+       int offset;
+       int ret;
+
+       ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+       if (ret)
+               return false;
+
+       end = start + stack->size;
+
+       /* Check overflow. */
+       if (addr + sizeof(Dwarf_Word) < addr)
+               return false;
+
+       if (addr < start || addr + sizeof(Dwarf_Word) > end) {
+               ret = access_dso_mem(ui, addr, result);
+               if (ret) {
+                       pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
+                                " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+                               addr, start, end);
+                       return false;
+               }
+               return true;
+       }
+
+       offset  = addr - start;
+       *result = *(Dwarf_Word *)&stack->data[offset];
+       pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
+                addr, (unsigned long)*result, offset);
+       return true;
+}
+
+static const Dwfl_Thread_Callbacks callbacks = {
+       .next_thread            = next_thread,
+       .memory_read            = memory_read,
+       .set_initial_registers  = libdw__arch_set_initial_registers,
+};
+
+static int
+frame_callback(Dwfl_Frame *state, void *arg)
+{
+       struct unwind_info *ui = arg;
+       Dwarf_Addr pc;
+
+       if (!dwfl_frame_pc(state, &pc, NULL)) {
+               pr_err("%s", dwfl_errmsg(-1));
+               return DWARF_CB_ABORT;
+       }
+
+       return entry(pc, ui) || !(--ui->max_stack) ?
+              DWARF_CB_ABORT : DWARF_CB_OK;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+                       struct machine *machine, struct thread *thread,
+                       struct perf_sample *data,
+                       int max_stack)
+{
+       struct unwind_info ui = {
+               .sample         = data,
+               .thread         = thread,
+               .machine        = machine,
+               .cb             = cb,
+               .arg            = arg,
+               .max_stack      = max_stack,
+       };
+       Dwarf_Word ip;
+       int err = -EINVAL;
+
+       if (!data->user_regs.regs)
+               return -EINVAL;
+
+       ui.dwfl = dwfl_begin(&offline_callbacks);
+       if (!ui.dwfl)
+               goto out;
+
+       err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
+       if (err)
+               goto out;
+
+       err = report_module(ip, &ui);
+       if (err)
+               goto out;
+
+       if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
+               goto out;
+
+       err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
+
+       if (err && !ui.max_stack)
+               err = 0;
+
+ out:
+       if (err)
+               pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
+
+       dwfl_end(ui.dwfl);
+       return 0;
+}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
new file mode 100644 (file)
index 0000000..417a142
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __PERF_UNWIND_LIBDW_H
+#define __PERF_UNWIND_LIBDW_H
+
+#include <elfutils/libdwfl.h>
+#include "event.h"
+#include "thread.h"
+#include "unwind.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
+
+struct unwind_info {
+       Dwfl                    *dwfl;
+       struct perf_sample      *sample;
+       struct machine          *machine;
+       struct thread           *thread;
+       unwind_entry_cb_t       cb;
+       void                    *arg;
+       int                     max_stack;
+};
+
+#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
new file mode 100644 (file)
index 0000000..bd5768d
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
+ *
+ * Lots of this code have been borrowed or heavily inspired from parts of
+ * the libunwind 0.99 code which are (amongst other contributors I may have
+ * forgotten):
+ *
+ * Copyright (C) 2002-2007 Hewlett-Packard Co
+ *     Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * And the bugs have been added by:
+ *
+ * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
+ * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
+ *
+ */
+
+#include <elf.h>
+#include <gelf.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/list.h>
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+#include "thread.h"
+#include "session.h"
+#include "perf_regs.h"
+#include "unwind.h"
+#include "symbol.h"
+#include "util.h"
+
+extern int
+UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
+                                   unw_word_t ip,
+                                   unw_dyn_info_t *di,
+                                   unw_proc_info_t *pi,
+                                   int need_unwind_info, void *arg);
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+extern int
+UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
+                                unw_word_t ip,
+                                unw_word_t segbase,
+                                const char *obj_name, unw_word_t start,
+                                unw_word_t end);
+
+#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
+
+#define DW_EH_PE_FORMAT_MASK   0x0f    /* format of the encoded value */
+#define DW_EH_PE_APPL_MASK     0x70    /* how the value is to be applied */
+
+/* Pointer-encoding formats: */
+#define DW_EH_PE_omit          0xff
+#define DW_EH_PE_ptr           0x00    /* pointer-sized unsigned value */
+#define DW_EH_PE_udata4                0x03    /* unsigned 32-bit value */
+#define DW_EH_PE_udata8                0x04    /* unsigned 64-bit value */
+#define DW_EH_PE_sdata4                0x0b    /* signed 32-bit value */
+#define DW_EH_PE_sdata8                0x0c    /* signed 64-bit value */
+
+/* Pointer-encoding application: */
+#define DW_EH_PE_absptr                0x00    /* absolute value */
+#define DW_EH_PE_pcrel         0x10    /* rel. to addr. of encoded value */
+
+/*
+ * The following are not documented by LSB v1.3, yet they are used by
+ * GCC, presumably they aren't documented by LSB since they aren't
+ * used on Linux:
+ */
+#define DW_EH_PE_funcrel       0x40    /* start-of-procedure-relative */
+#define DW_EH_PE_aligned       0x50    /* aligned pointer */
+
+/* Flags intentionaly not handled, since they're not needed:
+ * #define DW_EH_PE_indirect      0x80
+ * #define DW_EH_PE_uleb128       0x01
+ * #define DW_EH_PE_udata2        0x02
+ * #define DW_EH_PE_sleb128       0x09
+ * #define DW_EH_PE_sdata2        0x0a
+ * #define DW_EH_PE_textrel       0x20
+ * #define DW_EH_PE_datarel       0x30
+ */
+
+struct unwind_info {
+       struct perf_sample      *sample;
+       struct machine          *machine;
+       struct thread           *thread;
+};
+
+#define dw_read(ptr, type, end) ({     \
+       type *__p = (type *) ptr;       \
+       type  __v;                      \
+       if ((__p + 1) > (type *) end)   \
+               return -EINVAL;         \
+       __v = *__p++;                   \
+       ptr = (typeof(ptr)) __p;        \
+       __v;                            \
+       })
+
+static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
+                                  u8 encoding)
+{
+       u8 *cur = *p;
+       *val = 0;
+
+       switch (encoding) {
+       case DW_EH_PE_omit:
+               *val = 0;
+               goto out;
+       case DW_EH_PE_ptr:
+               *val = dw_read(cur, unsigned long, end);
+               goto out;
+       default:
+               break;
+       }
+
+       switch (encoding & DW_EH_PE_APPL_MASK) {
+       case DW_EH_PE_absptr:
+               break;
+       case DW_EH_PE_pcrel:
+               *val = (unsigned long) cur;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if ((encoding & 0x07) == 0x00)
+               encoding |= DW_EH_PE_udata4;
+
+       switch (encoding & DW_EH_PE_FORMAT_MASK) {
+       case DW_EH_PE_sdata4:
+               *val += dw_read(cur, s32, end);
+               break;
+       case DW_EH_PE_udata4:
+               *val += dw_read(cur, u32, end);
+               break;
+       case DW_EH_PE_sdata8:
+               *val += dw_read(cur, s64, end);
+               break;
+       case DW_EH_PE_udata8:
+               *val += dw_read(cur, u64, end);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+ out:
+       *p = cur;
+       return 0;
+}
+
+#define dw_read_encoded_value(ptr, end, enc) ({                        \
+       u64 __v;                                                \
+       if (__dw_read_encoded_value(&ptr, end, &__v, enc)) {    \
+               return -EINVAL;                                 \
+       }                                                       \
+       __v;                                                    \
+       })
+
+static u64 elf_section_offset(int fd, const char *name)
+{
+       Elf *elf;
+       GElf_Ehdr ehdr;
+       GElf_Shdr shdr;
+       u64 offset = 0;
+
+       elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+       if (elf == NULL)
+               return 0;
+
+       do {
+               if (gelf_getehdr(elf, &ehdr) == NULL)
+                       break;
+
+               if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
+                       break;
+
+               offset = shdr.sh_offset;
+       } while (0);
+
+       elf_end(elf);
+       return offset;
+}
+
+struct table_entry {
+       u32 start_ip_offset;
+       u32 fde_offset;
+};
+
+struct eh_frame_hdr {
+       unsigned char version;
+       unsigned char eh_frame_ptr_enc;
+       unsigned char fde_count_enc;
+       unsigned char table_enc;
+
+       /*
+        * The rest of the header is variable-length and consists of the
+        * following members:
+        *
+        *      encoded_t eh_frame_ptr;
+        *      encoded_t fde_count;
+        */
+
+       /* A single encoded pointer should not be more than 8 bytes. */
+       u64 enc[2];
+
+       /*
+        * struct {
+        *    encoded_t start_ip;
+        *    encoded_t fde_addr;
+        * } binary_search_table[fde_count];
+        */
+       char data[0];
+} __packed;
+
+static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
+                              u64 offset, u64 *table_data, u64 *segbase,
+                              u64 *fde_count)
+{
+       struct eh_frame_hdr hdr;
+       u8 *enc = (u8 *) &hdr.enc;
+       u8 *end = (u8 *) &hdr.data;
+       ssize_t r;
+
+       r = dso__data_read_offset(dso, machine, offset,
+                                 (u8 *) &hdr, sizeof(hdr));
+       if (r != sizeof(hdr))
+               return -EINVAL;
+
+       /* We dont need eh_frame_ptr, just skip it. */
+       dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
+
+       *fde_count  = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
+       *segbase    = offset;
+       *table_data = (enc - (u8 *) &hdr) + offset;
+       return 0;
+}
+
+static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
+                                    u64 *table_data, u64 *segbase,
+                                    u64 *fde_count)
+{
+       int ret = -EINVAL, fd;
+       u64 offset;
+
+       fd = dso__data_fd(dso, machine);
+       if (fd < 0)
+               return -EINVAL;
+
+       /* Check the .eh_frame section for unwinding info */
+       offset = elf_section_offset(fd, ".eh_frame_hdr");
+       close(fd);
+
+       if (offset)
+               ret = unwind_spec_ehframe(dso, machine, offset,
+                                         table_data, segbase,
+                                         fde_count);
+
+       return ret;
+}
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+static int read_unwind_spec_debug_frame(struct dso *dso,
+                                       struct machine *machine, u64 *offset)
+{
+       int fd = dso__data_fd(dso, machine);
+
+       if (fd < 0)
+               return -EINVAL;
+
+       /* Check the .debug_frame section for unwinding info */
+       *offset = elf_section_offset(fd, ".debug_frame");
+       close(fd);
+
+       if (*offset)
+               return 0;
+
+       return -EINVAL;
+}
+#endif
+
+static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
+{
+       struct addr_location al;
+
+       thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+                             MAP__FUNCTION, ip, &al);
+       return al.map;
+}
+
+static int
+find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+              int need_unwind_info, void *arg)
+{
+       struct unwind_info *ui = arg;
+       struct map *map;
+       unw_dyn_info_t di;
+       u64 table_data, segbase, fde_count;
+
+       map = find_map(ip, ui);
+       if (!map || !map->dso)
+               return -EINVAL;
+
+       pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
+
+       /* Check the .eh_frame section for unwinding info */
+       if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
+                                      &table_data, &segbase, &fde_count)) {
+               memset(&di, 0, sizeof(di));
+               di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
+               di.start_ip = map->start;
+               di.end_ip   = map->end;
+               di.u.rti.segbase    = map->start + segbase;
+               di.u.rti.table_data = map->start + table_data;
+               di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
+                                     / sizeof(unw_word_t);
+               return dwarf_search_unwind_table(as, ip, &di, pi,
+                                                need_unwind_info, arg);
+       }
+
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+       /* Check the .debug_frame section for unwinding info */
+       if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
+               memset(&di, 0, sizeof(di));
+               if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
+                                          map->start, map->end))
+                       return dwarf_search_unwind_table(as, ip, &di, pi,
+                                                        need_unwind_info, arg);
+       }
+#endif
+
+       return -EINVAL;
+}
+
+static int access_fpreg(unw_addr_space_t __maybe_unused as,
+                       unw_regnum_t __maybe_unused num,
+                       unw_fpreg_t __maybe_unused *val,
+                       int __maybe_unused __write,
+                       void __maybe_unused *arg)
+{
+       pr_err("unwind: access_fpreg unsupported\n");
+       return -UNW_EINVAL;
+}
+
+static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
+                                 unw_word_t __maybe_unused *dil_addr,
+                                 void __maybe_unused *arg)
+{
+       return -UNW_ENOINFO;
+}
+
+static int resume(unw_addr_space_t __maybe_unused as,
+                 unw_cursor_t __maybe_unused *cu,
+                 void __maybe_unused *arg)
+{
+       pr_err("unwind: resume unsupported\n");
+       return -UNW_EINVAL;
+}
+
+static int
+get_proc_name(unw_addr_space_t __maybe_unused as,
+             unw_word_t __maybe_unused addr,
+               char __maybe_unused *bufp, size_t __maybe_unused buf_len,
+               unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
+{
+       pr_err("unwind: get_proc_name unsupported\n");
+       return -UNW_EINVAL;
+}
+
+static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
+                         unw_word_t *data)
+{
+       struct addr_location al;
+       ssize_t size;
+
+       thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+                             MAP__FUNCTION, addr, &al);
+       if (!al.map) {
+               pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+               return -1;
+       }
+
+       if (!al.map->dso)
+               return -1;
+
+       size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+                                  addr, (u8 *) data, sizeof(*data));
+
+       return !(size == sizeof(*data));
+}
+
+static int access_mem(unw_addr_space_t __maybe_unused as,
+                     unw_word_t addr, unw_word_t *valp,
+                     int __write, void *arg)
+{
+       struct unwind_info *ui = arg;
+       struct stack_dump *stack = &ui->sample->user_stack;
+       u64 start, end;
+       int offset;
+       int ret;
+
+       /* Don't support write, probably not needed. */
+       if (__write || !stack || !ui->sample->user_regs.regs) {
+               *valp = 0;
+               return 0;
+       }
+
+       ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+       if (ret)
+               return ret;
+
+       end = start + stack->size;
+
+       /* Check overflow. */
+       if (addr + sizeof(unw_word_t) < addr)
+               return -EINVAL;
+
+       if (addr < start || addr + sizeof(unw_word_t) >= end) {
+               ret = access_dso_mem(ui, addr, valp);
+               if (ret) {
+                       pr_debug("unwind: access_mem %p not inside range"
+                                " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+                                (void *) addr, start, end);
+                       *valp = 0;
+                       return ret;
+               }
+               return 0;
+       }
+
+       offset = addr - start;
+       *valp  = *(unw_word_t *)&stack->data[offset];
+       pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
+                (void *) addr, (unsigned long)*valp, offset);
+       return 0;
+}
+
+static int access_reg(unw_addr_space_t __maybe_unused as,
+                     unw_regnum_t regnum, unw_word_t *valp,
+                     int __write, void *arg)
+{
+       struct unwind_info *ui = arg;
+       int id, ret;
+       u64 val;
+
+       /* Don't support write, I suspect we don't need it. */
+       if (__write) {
+               pr_err("unwind: access_reg w %d\n", regnum);
+               return 0;
+       }
+
+       if (!ui->sample->user_regs.regs) {
+               *valp = 0;
+               return 0;
+       }
+
+       id = libunwind__arch_reg_id(regnum);
+       if (id < 0)
+               return -EINVAL;
+
+       ret = perf_reg_value(&val, &ui->sample->user_regs, id);
+       if (ret) {
+               pr_err("unwind: can't read reg %d\n", regnum);
+               return ret;
+       }
+
+       *valp = (unw_word_t) val;
+       pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
+       return 0;
+}
+
+static void put_unwind_info(unw_addr_space_t __maybe_unused as,
+                           unw_proc_info_t *pi __maybe_unused,
+                           void *arg __maybe_unused)
+{
+       pr_debug("unwind: put_unwind_info called\n");
+}
+
+static int entry(u64 ip, struct thread *thread, struct machine *machine,
+                unwind_entry_cb_t cb, void *arg)
+{
+       struct unwind_entry e;
+       struct addr_location al;
+
+       thread__find_addr_location(thread, machine,
+                                  PERF_RECORD_MISC_USER,
+                                  MAP__FUNCTION, ip, &al);
+
+       e.ip = ip;
+       e.map = al.map;
+       e.sym = al.sym;
+
+       pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+                al.sym ? al.sym->name : "''",
+                ip,
+                al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
+
+       return cb(&e, arg);
+}
+
+static void display_error(int err)
+{
+       switch (err) {
+       case UNW_EINVAL:
+               pr_err("unwind: Only supports local.\n");
+               break;
+       case UNW_EUNSPEC:
+               pr_err("unwind: Unspecified error.\n");
+               break;
+       case UNW_EBADREG:
+               pr_err("unwind: Register unavailable.\n");
+               break;
+       default:
+               break;
+       }
+}
+
+static unw_accessors_t accessors = {
+       .find_proc_info         = find_proc_info,
+       .put_unwind_info        = put_unwind_info,
+       .get_dyn_info_list_addr = get_dyn_info_list_addr,
+       .access_mem             = access_mem,
+       .access_reg             = access_reg,
+       .access_fpreg           = access_fpreg,
+       .resume                 = resume,
+       .get_proc_name          = get_proc_name,
+};
+
+static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
+                      void *arg, int max_stack)
+{
+       unw_addr_space_t addr_space;
+       unw_cursor_t c;
+       int ret;
+
+       addr_space = unw_create_addr_space(&accessors, 0);
+       if (!addr_space) {
+               pr_err("unwind: Can't create unwind address space.\n");
+               return -ENOMEM;
+       }
+
+       ret = unw_init_remote(&c, addr_space, ui);
+       if (ret)
+               display_error(ret);
+
+       while (!ret && (unw_step(&c) > 0) && max_stack--) {
+               unw_word_t ip;
+
+               unw_get_reg(&c, UNW_REG_IP, &ip);
+               ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
+       }
+
+       unw_destroy_addr_space(addr_space);
+       return ret;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+                       struct machine *machine, struct thread *thread,
+                       struct perf_sample *data, int max_stack)
+{
+       u64 ip;
+       struct unwind_info ui = {
+               .sample       = data,
+               .thread       = thread,
+               .machine      = machine,
+       };
+       int ret;
+
+       if (!data->user_regs.regs)
+               return -EINVAL;
+
+       ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
+       if (ret)
+               return ret;
+
+       ret = entry(ip, thread, machine, cb, arg);
+       if (ret)
+               return -ENOMEM;
+
+       return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
+}
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
deleted file mode 100644 (file)
index 742f23b..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
- *
- * Lots of this code have been borrowed or heavily inspired from parts of
- * the libunwind 0.99 code which are (amongst other contributors I may have
- * forgotten):
- *
- * Copyright (C) 2002-2007 Hewlett-Packard Co
- *     Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * And the bugs have been added by:
- *
- * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
- * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
- *
- */
-
-#include <elf.h>
-#include <gelf.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <linux/list.h>
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-#include "thread.h"
-#include "session.h"
-#include "perf_regs.h"
-#include "unwind.h"
-#include "symbol.h"
-#include "util.h"
-
-extern int
-UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
-                                   unw_word_t ip,
-                                   unw_dyn_info_t *di,
-                                   unw_proc_info_t *pi,
-                                   int need_unwind_info, void *arg);
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
-                                unw_word_t ip,
-                                unw_word_t segbase,
-                                const char *obj_name, unw_word_t start,
-                                unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-#define DW_EH_PE_FORMAT_MASK   0x0f    /* format of the encoded value */
-#define DW_EH_PE_APPL_MASK     0x70    /* how the value is to be applied */
-
-/* Pointer-encoding formats: */
-#define DW_EH_PE_omit          0xff
-#define DW_EH_PE_ptr           0x00    /* pointer-sized unsigned value */
-#define DW_EH_PE_udata4                0x03    /* unsigned 32-bit value */
-#define DW_EH_PE_udata8                0x04    /* unsigned 64-bit value */
-#define DW_EH_PE_sdata4                0x0b    /* signed 32-bit value */
-#define DW_EH_PE_sdata8                0x0c    /* signed 64-bit value */
-
-/* Pointer-encoding application: */
-#define DW_EH_PE_absptr                0x00    /* absolute value */
-#define DW_EH_PE_pcrel         0x10    /* rel. to addr. of encoded value */
-
-/*
- * The following are not documented by LSB v1.3, yet they are used by
- * GCC, presumably they aren't documented by LSB since they aren't
- * used on Linux:
- */
-#define DW_EH_PE_funcrel       0x40    /* start-of-procedure-relative */
-#define DW_EH_PE_aligned       0x50    /* aligned pointer */
-
-/* Flags intentionaly not handled, since they're not needed:
- * #define DW_EH_PE_indirect      0x80
- * #define DW_EH_PE_uleb128       0x01
- * #define DW_EH_PE_udata2        0x02
- * #define DW_EH_PE_sleb128       0x09
- * #define DW_EH_PE_sdata2        0x0a
- * #define DW_EH_PE_textrel       0x20
- * #define DW_EH_PE_datarel       0x30
- */
-
-struct unwind_info {
-       struct perf_sample      *sample;
-       struct machine          *machine;
-       struct thread           *thread;
-       u64                     sample_uregs;
-};
-
-#define dw_read(ptr, type, end) ({     \
-       type *__p = (type *) ptr;       \
-       type  __v;                      \
-       if ((__p + 1) > (type *) end)   \
-               return -EINVAL;         \
-       __v = *__p++;                   \
-       ptr = (typeof(ptr)) __p;        \
-       __v;                            \
-       })
-
-static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
-                                  u8 encoding)
-{
-       u8 *cur = *p;
-       *val = 0;
-
-       switch (encoding) {
-       case DW_EH_PE_omit:
-               *val = 0;
-               goto out;
-       case DW_EH_PE_ptr:
-               *val = dw_read(cur, unsigned long, end);
-               goto out;
-       default:
-               break;
-       }
-
-       switch (encoding & DW_EH_PE_APPL_MASK) {
-       case DW_EH_PE_absptr:
-               break;
-       case DW_EH_PE_pcrel:
-               *val = (unsigned long) cur;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if ((encoding & 0x07) == 0x00)
-               encoding |= DW_EH_PE_udata4;
-
-       switch (encoding & DW_EH_PE_FORMAT_MASK) {
-       case DW_EH_PE_sdata4:
-               *val += dw_read(cur, s32, end);
-               break;
-       case DW_EH_PE_udata4:
-               *val += dw_read(cur, u32, end);
-               break;
-       case DW_EH_PE_sdata8:
-               *val += dw_read(cur, s64, end);
-               break;
-       case DW_EH_PE_udata8:
-               *val += dw_read(cur, u64, end);
-               break;
-       default:
-               return -EINVAL;
-       }
-
- out:
-       *p = cur;
-       return 0;
-}
-
-#define dw_read_encoded_value(ptr, end, enc) ({                        \
-       u64 __v;                                                \
-       if (__dw_read_encoded_value(&ptr, end, &__v, enc)) {    \
-               return -EINVAL;                                 \
-       }                                                       \
-       __v;                                                    \
-       })
-
-static u64 elf_section_offset(int fd, const char *name)
-{
-       Elf *elf;
-       GElf_Ehdr ehdr;
-       GElf_Shdr shdr;
-       u64 offset = 0;
-
-       elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
-       if (elf == NULL)
-               return 0;
-
-       do {
-               if (gelf_getehdr(elf, &ehdr) == NULL)
-                       break;
-
-               if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
-                       break;
-
-               offset = shdr.sh_offset;
-       } while (0);
-
-       elf_end(elf);
-       return offset;
-}
-
-struct table_entry {
-       u32 start_ip_offset;
-       u32 fde_offset;
-};
-
-struct eh_frame_hdr {
-       unsigned char version;
-       unsigned char eh_frame_ptr_enc;
-       unsigned char fde_count_enc;
-       unsigned char table_enc;
-
-       /*
-        * The rest of the header is variable-length and consists of the
-        * following members:
-        *
-        *      encoded_t eh_frame_ptr;
-        *      encoded_t fde_count;
-        */
-
-       /* A single encoded pointer should not be more than 8 bytes. */
-       u64 enc[2];
-
-       /*
-        * struct {
-        *    encoded_t start_ip;
-        *    encoded_t fde_addr;
-        * } binary_search_table[fde_count];
-        */
-       char data[0];
-} __packed;
-
-static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
-                              u64 offset, u64 *table_data, u64 *segbase,
-                              u64 *fde_count)
-{
-       struct eh_frame_hdr hdr;
-       u8 *enc = (u8 *) &hdr.enc;
-       u8 *end = (u8 *) &hdr.data;
-       ssize_t r;
-
-       r = dso__data_read_offset(dso, machine, offset,
-                                 (u8 *) &hdr, sizeof(hdr));
-       if (r != sizeof(hdr))
-               return -EINVAL;
-
-       /* We dont need eh_frame_ptr, just skip it. */
-       dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
-
-       *fde_count  = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
-       *segbase    = offset;
-       *table_data = (enc - (u8 *) &hdr) + offset;
-       return 0;
-}
-
-static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
-                                    u64 *table_data, u64 *segbase,
-                                    u64 *fde_count)
-{
-       int ret = -EINVAL, fd;
-       u64 offset;
-
-       fd = dso__data_fd(dso, machine);
-       if (fd < 0)
-               return -EINVAL;
-
-       /* Check the .eh_frame section for unwinding info */
-       offset = elf_section_offset(fd, ".eh_frame_hdr");
-       close(fd);
-
-       if (offset)
-               ret = unwind_spec_ehframe(dso, machine, offset,
-                                         table_data, segbase,
-                                         fde_count);
-
-       return ret;
-}
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
-static int read_unwind_spec_debug_frame(struct dso *dso,
-                                       struct machine *machine, u64 *offset)
-{
-       int fd = dso__data_fd(dso, machine);
-
-       if (fd < 0)
-               return -EINVAL;
-
-       /* Check the .debug_frame section for unwinding info */
-       *offset = elf_section_offset(fd, ".debug_frame");
-       close(fd);
-
-       if (*offset)
-               return 0;
-
-       return -EINVAL;
-}
-#endif
-
-static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
-{
-       struct addr_location al;
-
-       thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
-                             MAP__FUNCTION, ip, &al);
-       return al.map;
-}
-
-static int
-find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
-              int need_unwind_info, void *arg)
-{
-       struct unwind_info *ui = arg;
-       struct map *map;
-       unw_dyn_info_t di;
-       u64 table_data, segbase, fde_count;
-
-       map = find_map(ip, ui);
-       if (!map || !map->dso)
-               return -EINVAL;
-
-       pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
-
-       /* Check the .eh_frame section for unwinding info */
-       if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
-                                      &table_data, &segbase, &fde_count)) {
-               memset(&di, 0, sizeof(di));
-               di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
-               di.start_ip = map->start;
-               di.end_ip   = map->end;
-               di.u.rti.segbase    = map->start + segbase;
-               di.u.rti.table_data = map->start + table_data;
-               di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
-                                     / sizeof(unw_word_t);
-               return dwarf_search_unwind_table(as, ip, &di, pi,
-                                                need_unwind_info, arg);
-       }
-
-#ifndef NO_LIBUNWIND_DEBUG_FRAME
-       /* Check the .debug_frame section for unwinding info */
-       if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
-               memset(&di, 0, sizeof(di));
-               if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
-                                          map->start, map->end))
-                       return dwarf_search_unwind_table(as, ip, &di, pi,
-                                                        need_unwind_info, arg);
-       }
-#endif
-
-       return -EINVAL;
-}
-
-static int access_fpreg(unw_addr_space_t __maybe_unused as,
-                       unw_regnum_t __maybe_unused num,
-                       unw_fpreg_t __maybe_unused *val,
-                       int __maybe_unused __write,
-                       void __maybe_unused *arg)
-{
-       pr_err("unwind: access_fpreg unsupported\n");
-       return -UNW_EINVAL;
-}
-
-static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
-                                 unw_word_t __maybe_unused *dil_addr,
-                                 void __maybe_unused *arg)
-{
-       return -UNW_ENOINFO;
-}
-
-static int resume(unw_addr_space_t __maybe_unused as,
-                 unw_cursor_t __maybe_unused *cu,
-                 void __maybe_unused *arg)
-{
-       pr_err("unwind: resume unsupported\n");
-       return -UNW_EINVAL;
-}
-
-static int
-get_proc_name(unw_addr_space_t __maybe_unused as,
-             unw_word_t __maybe_unused addr,
-               char __maybe_unused *bufp, size_t __maybe_unused buf_len,
-               unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
-{
-       pr_err("unwind: get_proc_name unsupported\n");
-       return -UNW_EINVAL;
-}
-
-static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
-                         unw_word_t *data)
-{
-       struct addr_location al;
-       ssize_t size;
-
-       thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
-                             MAP__FUNCTION, addr, &al);
-       if (!al.map) {
-               pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
-               return -1;
-       }
-
-       if (!al.map->dso)
-               return -1;
-
-       size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
-                                  addr, (u8 *) data, sizeof(*data));
-
-       return !(size == sizeof(*data));
-}
-
-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
-                    u64 sample_regs)
-{
-       int i, idx = 0;
-
-       if (!(sample_regs & (1 << id)))
-               return -EINVAL;
-
-       for (i = 0; i < id; i++) {
-               if (sample_regs & (1 << i))
-                       idx++;
-       }
-
-       *valp = regs->regs[idx];
-       return 0;
-}
-
-static int access_mem(unw_addr_space_t __maybe_unused as,
-                     unw_word_t addr, unw_word_t *valp,
-                     int __write, void *arg)
-{
-       struct unwind_info *ui = arg;
-       struct stack_dump *stack = &ui->sample->user_stack;
-       unw_word_t start, end;
-       int offset;
-       int ret;
-
-       /* Don't support write, probably not needed. */
-       if (__write || !stack || !ui->sample->user_regs.regs) {
-               *valp = 0;
-               return 0;
-       }
-
-       ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
-                       ui->sample_uregs);
-       if (ret)
-               return ret;
-
-       end = start + stack->size;
-
-       /* Check overflow. */
-       if (addr + sizeof(unw_word_t) < addr)
-               return -EINVAL;
-
-       if (addr < start || addr + sizeof(unw_word_t) >= end) {
-               ret = access_dso_mem(ui, addr, valp);
-               if (ret) {
-                       pr_debug("unwind: access_mem %p not inside range %p-%p\n",
-                               (void *)addr, (void *)start, (void *)end);
-                       *valp = 0;
-                       return ret;
-               }
-               return 0;
-       }
-
-       offset = addr - start;
-       *valp  = *(unw_word_t *)&stack->data[offset];
-       pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
-                (void *)addr, (unsigned long)*valp, offset);
-       return 0;
-}
-
-static int access_reg(unw_addr_space_t __maybe_unused as,
-                     unw_regnum_t regnum, unw_word_t *valp,
-                     int __write, void *arg)
-{
-       struct unwind_info *ui = arg;
-       int id, ret;
-
-       /* Don't support write, I suspect we don't need it. */
-       if (__write) {
-               pr_err("unwind: access_reg w %d\n", regnum);
-               return 0;
-       }
-
-       if (!ui->sample->user_regs.regs) {
-               *valp = 0;
-               return 0;
-       }
-
-       id = unwind__arch_reg_id(regnum);
-       if (id < 0)
-               return -EINVAL;
-
-       ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
-       if (ret) {
-               pr_err("unwind: can't read reg %d\n", regnum);
-               return ret;
-       }
-
-       pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
-       return 0;
-}
-
-static void put_unwind_info(unw_addr_space_t __maybe_unused as,
-                           unw_proc_info_t *pi __maybe_unused,
-                           void *arg __maybe_unused)
-{
-       pr_debug("unwind: put_unwind_info called\n");
-}
-
-static int entry(u64 ip, struct thread *thread, struct machine *machine,
-                unwind_entry_cb_t cb, void *arg)
-{
-       struct unwind_entry e;
-       struct addr_location al;
-
-       thread__find_addr_location(thread, machine,
-                                  PERF_RECORD_MISC_USER,
-                                  MAP__FUNCTION, ip, &al);
-
-       e.ip = ip;
-       e.map = al.map;
-       e.sym = al.sym;
-
-       pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
-                al.sym ? al.sym->name : "''",
-                ip,
-                al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
-
-       return cb(&e, arg);
-}
-
-static void display_error(int err)
-{
-       switch (err) {
-       case UNW_EINVAL:
-               pr_err("unwind: Only supports local.\n");
-               break;
-       case UNW_EUNSPEC:
-               pr_err("unwind: Unspecified error.\n");
-               break;
-       case UNW_EBADREG:
-               pr_err("unwind: Register unavailable.\n");
-               break;
-       default:
-               break;
-       }
-}
-
-static unw_accessors_t accessors = {
-       .find_proc_info         = find_proc_info,
-       .put_unwind_info        = put_unwind_info,
-       .get_dyn_info_list_addr = get_dyn_info_list_addr,
-       .access_mem             = access_mem,
-       .access_reg             = access_reg,
-       .access_fpreg           = access_fpreg,
-       .resume                 = resume,
-       .get_proc_name          = get_proc_name,
-};
-
-static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
-                      void *arg, int max_stack)
-{
-       unw_addr_space_t addr_space;
-       unw_cursor_t c;
-       int ret;
-
-       addr_space = unw_create_addr_space(&accessors, 0);
-       if (!addr_space) {
-               pr_err("unwind: Can't create unwind address space.\n");
-               return -ENOMEM;
-       }
-
-       ret = unw_init_remote(&c, addr_space, ui);
-       if (ret)
-               display_error(ret);
-
-       while (!ret && (unw_step(&c) > 0) && max_stack--) {
-               unw_word_t ip;
-
-               unw_get_reg(&c, UNW_REG_IP, &ip);
-               ret = entry(ip, ui->thread, ui->machine, cb, arg);
-       }
-
-       unw_destroy_addr_space(addr_space);
-       return ret;
-}
-
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
-                       struct machine *machine, struct thread *thread,
-                       u64 sample_uregs, struct perf_sample *data,
-                       int max_stack)
-{
-       unw_word_t ip;
-       struct unwind_info ui = {
-               .sample       = data,
-               .sample_uregs = sample_uregs,
-               .thread       = thread,
-               .machine      = machine,
-       };
-       int ret;
-
-       if (!data->user_regs.regs)
-               return -EINVAL;
-
-       ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
-       if (ret)
-               return ret;
-
-       ret = entry(ip, thread, machine, cb, arg);
-       if (ret)
-               return -ENOMEM;
-
-       return get_entries(&ui, cb, arg, max_stack);
-}
index d5966f49e22cc24fb91e8f53307504cfed7e290d..b031316f221a7de76c1930d8289ba03300748672 100644 (file)
@@ -13,24 +13,25 @@ struct unwind_entry {
 
 typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                        struct machine *machine,
                        struct thread *thread,
-                       u64 sample_uregs,
                        struct perf_sample *data, int max_stack);
-int unwind__arch_reg_id(int regnum);
+/* libunwind specific */
+#ifdef HAVE_LIBUNWIND_SUPPORT
+int libunwind__arch_reg_id(int regnum);
+#endif
 #else
 static inline int
 unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
                    void *arg __maybe_unused,
                    struct machine *machine __maybe_unused,
                    struct thread *thread __maybe_unused,
-                   u64 sample_uregs __maybe_unused,
                    struct perf_sample *data __maybe_unused,
                    int max_stack __maybe_unused)
 {
        return 0;
 }
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
index 42ad667bb317570e6f22216598181d1e2a8c9798..9f66549562bd6959907323573edcb91badd97380 100644 (file)
@@ -1,6 +1,6 @@
 #include "../perf.h"
 #include "util.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include <sys/mman.h>
 #ifdef HAVE_BACKTRACE_SUPPORT
 #include <execinfo.h>
index d66418237d21522df42e33a316b808c1e5962ffd..aa290c0de6f56d9e3f142d46124ee5d0688dd68d 100644 (file)
@@ -201,6 +201,7 @@ int main(int argc, char **argv)
 
        msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
        if (msgque.msq_id == -1) {
+               err = -errno;
                printf("Can't create queue\n");
                goto err_out;
        }
index 587561d7c035a053f590fe8d33a591f8ee78c477..9b17e810ddc39c96f4b7f7e2fead951455bb9c8e 100644 (file)
@@ -96,6 +96,7 @@ identify_qemu () {
                echo qemu-system-ppc64
        else
                echo Cannot figure out what qemu command to use! 1>&2
+               echo file $1 output: $u
                # Usually this will be one of /usr/bin/qemu-system-*
                # Use RCU_QEMU_CMD environment variable or appropriate
                # argument to top-level script.
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
new file mode 100755 (executable)
index 0000000..829186e
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Analyze a given results directory for locktorture progress.
+#
+# Usage: sh kvm-recheck-lock.sh resdir
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2014
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+i="$1"
+if test -d $i
+then
+       :
+else
+       echo Unreadable results directory: $i
+       exit 1
+fi
+
+configfile=`echo $i | sed -e 's/^.*\///'`
+ncs=`grep "Writes:  Total:" $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* Total: //' -e 's/ .*$//'`
+if test -z "$ncs"
+then
+       echo $configfile
+else
+       title="$configfile ------- $ncs acquisitions/releases"
+       dur=`sed -e 's/^.* locktorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null`
+       if test -z "$dur"
+       then
+               :
+       else
+               ncsps=`awk -v ncs=$ncs -v dur=$dur '
+                       BEGIN { print ncs / dur }' < /dev/null`
+               title="$title ($ncsps per second)"
+       fi
+       echo $title
+fi
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
new file mode 100755 (executable)
index 0000000..d75b1dc
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Analyze a given results directory for rcutorture progress.
+#
+# Usage: sh kvm-recheck-rcu.sh resdir
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2014
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+i="$1"
+if test -d $i
+then
+       :
+else
+       echo Unreadable results directory: $i
+       exit 1
+fi
+
+configfile=`echo $i | sed -e 's/^.*\///'`
+ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'`
+if test -z "$ngps"
+then
+       echo $configfile
+else
+       title="$configfile ------- $ngps grace periods"
+       dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null`
+       if test -z "$dur"
+       then
+               :
+       else
+               ngpsps=`awk -v ngps=$ngps -v dur=$dur '
+                       BEGIN { print ngps / dur }' < /dev/null`
+               title="$title ($ngpsps per second)"
+       fi
+       echo $title
+fi
index baef09f3469b1dbb914ad0459076adbd027a1cd0..a44daaa259a912e91837e102e6d35c290a17d21d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Given the results directories for previous KVM runs of rcutorture,
+# Given the results directories for previous KVM-based torture runs,
 # check the build and console output for errors.  Given a directory
 # containing results directories, this recursively checks them all.
 #
 PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
 for rd in "$@"
 do
+       firsttime=1
        dirs=`find $rd -name Make.defconfig.out -print | sort | sed -e 's,/[^/]*$,,' | sort -u`
        for i in $dirs
        do
-               configfile=`echo $i | sed -e 's/^.*\///'`
-               echo $configfile
+               if test -n "$firsttime"
+               then
+                       firsttime=""
+                       resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'`
+                       head -1 $resdir/log
+               fi
+               TORTURE_SUITE="`cat $i/../TORTURE_SUITE`"
+               kvm-recheck-${TORTURE_SUITE}.sh $i
                configcheck.sh $i/.config $i/ConfigFragment
                parse-build.sh $i/Make.out $configfile
                parse-rcutorture.sh $i/console.log $configfile
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh
deleted file mode 100755 (executable)
index 151b237..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-#!/bin/bash
-#
-# Run a kvm-based test of the specified tree on the specified configs.
-# Fully automated run and error checking, no graphics console.
-#
-# Execute this in the source tree.  Do not run it as a background task
-# because qemu does not seem to like that much.
-#
-# Usage: sh kvm-test-1-rcu.sh config builddir resdir minutes qemu-args bootargs
-#
-# qemu-args defaults to "" -- you will want "-nographic" if running headless.
-# bootargs defaults to "root=/dev/sda noapic selinux=0 console=ttyS0"
-#                      "initcall_debug debug rcutorture.stat_interval=15"
-#                      "rcutorture.shutdown_secs=$((minutes * 60))"
-#                      "rcutorture.rcutorture_runnable=1"
-#
-# Anything you specify for either qemu-args or bootargs is appended to
-# the default values.  The "-smp" value is deduced from the contents of
-# the config fragment.
-#
-# More sophisticated argument parsing is clearly needed.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2011
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-grace=120
-
-T=/tmp/kvm-test-1-rcu.sh.$$
-trap 'rm -rf $T' 0
-
-. $KVM/bin/functions.sh
-. $KVPATH/ver_functions.sh
-
-config_template=${1}
-title=`echo $config_template | sed -e 's/^.*\///'`
-builddir=${2}
-if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir"
-then
-       echo "kvm-test-1-rcu.sh :$builddir: Not a writable directory, cannot build into it"
-       exit 1
-fi
-resdir=${3}
-if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir"
-then
-       echo "kvm-test-1-rcu.sh :$resdir: Not a writable directory, cannot build into it"
-       exit 1
-fi
-cp $config_template $resdir/ConfigFragment
-echo ' ---' `date`: Starting build
-echo ' ---' Kconfig fragment at: $config_template >> $resdir/log
-cat << '___EOF___' >> $T
-CONFIG_RCU_TORTURE_TEST=y
-___EOF___
-# Optimizations below this point
-# CONFIG_USB=n
-# CONFIG_SECURITY=n
-# CONFIG_NFS_FS=n
-# CONFIG_SOUND=n
-# CONFIG_INPUT_JOYSTICK=n
-# CONFIG_INPUT_TABLET=n
-# CONFIG_INPUT_TOUCHSCREEN=n
-# CONFIG_INPUT_MISC=n
-# CONFIG_INPUT_MOUSE=n
-# # CONFIG_NET=n # disables console access, so accept the slower build.
-# CONFIG_SCSI=n
-# CONFIG_ATA=n
-# CONFIG_FAT_FS=n
-# CONFIG_MSDOS_FS=n
-# CONFIG_VFAT_FS=n
-# CONFIG_ISO9660_FS=n
-# CONFIG_QUOTA=n
-# CONFIG_HID=n
-# CONFIG_CRYPTO=n
-# CONFIG_PCCARD=n
-# CONFIG_PCMCIA=n
-# CONFIG_CARDBUS=n
-# CONFIG_YENTA=n
-if kvm-build.sh $config_template $builddir $T
-then
-       cp $builddir/Make*.out $resdir
-       cp $builddir/.config $resdir
-       cp $builddir/arch/x86/boot/bzImage $resdir
-       parse-build.sh $resdir/Make.out $title
-else
-       cp $builddir/Make*.out $resdir
-       echo Build failed, not running KVM, see $resdir.
-       exit 1
-fi
-minutes=$4
-seconds=$(($minutes * 60))
-qemu_args=$5
-boot_args=$6
-
-cd $KVM
-kstarttime=`awk 'BEGIN { print systime() }' < /dev/null`
-echo ' ---' `date`: Starting kernel
-
-# Determine the appropriate flavor of qemu command.
-QEMU="`identify_qemu $builddir/vmlinux.o`"
-
-# Generate -smp qemu argument.
-cpu_count=`configNR_CPUS.sh $config_template`
-vcpus=`identify_qemu_vcpus`
-if test $cpu_count -gt $vcpus
-then
-       echo CPU count limited from $cpu_count to $vcpus
-       touch $resdir/Warnings
-       echo CPU count limited from $cpu_count to $vcpus >> $resdir/Warnings
-       cpu_count=$vcpus
-fi
-qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`"
-
-# Generate architecture-specific and interaction-specific qemu arguments
-qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`"
-
-# Generate qemu -append arguments
-qemu_append="`identify_qemu_append "$QEMU"`"
-
-# Pull in Kconfig-fragment boot parameters
-boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
-# Generate CPU-hotplug boot parameters
-boot_args="`rcutorture_param_onoff "$boot_args" $builddir/.config`"
-# Generate rcu_barrier() boot parameter
-boot_args="`rcutorture_param_n_barrier_cbs "$boot_args"`"
-# Pull in standard rcutorture boot arguments
-boot_args="$boot_args rcutorture.stat_interval=15 rcutorture.shutdown_secs=$seconds rcutorture.rcutorture_runnable=1"
-
-echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
-if test -n "$RCU_BUILDONLY"
-then
-       echo Build-only run specified, boot/test omitted.
-       exit 0
-fi
-$QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append "$qemu_append $boot_args" &
-qemu_pid=$!
-commandcompleted=0
-echo Monitoring qemu job at pid $qemu_pid
-for ((i=0;i<$seconds;i++))
-do
-       if kill -0 $qemu_pid > /dev/null 2>&1
-       then
-               sleep 1
-       else
-               commandcompleted=1
-               kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
-               if test $kruntime -lt $seconds
-               then
-                       echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1
-               else
-                       echo ' ---' `date`: Kernel done
-               fi
-               break
-       fi
-done
-if test $commandcompleted -eq 0
-then
-       echo Grace period for qemu job at pid $qemu_pid
-       for ((i=0;i<=$grace;i++))
-       do
-               if kill -0 $qemu_pid > /dev/null 2>&1
-               then
-                       sleep 1
-               else
-                       break
-               fi
-               if test $i -eq $grace
-               then
-                       kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }'`
-                       echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
-                       kill -KILL $qemu_pid
-               fi
-       done
-fi
-
-cp $builddir/console.log $resdir
-parse-rcutorture.sh $resdir/console.log $title
-parse-console.sh $resdir/console.log $title
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
new file mode 100755 (executable)
index 0000000..94b28bb
--- /dev/null
@@ -0,0 +1,203 @@
+#!/bin/bash
+#
+# Run a kvm-based test of the specified tree on the specified configs.
+# Fully automated run and error checking, no graphics console.
+#
+# Execute this in the source tree.  Do not run it as a background task
+# because qemu does not seem to like that much.
+#
+# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
+#
+# qemu-args defaults to "-nographic", along with arguments specifying the
+#                      number of CPUs and other options generated from
+#                      the underlying CPU architecture.
+# boot_args defaults to value returned by the per_version_boot_params
+#                      shell function.
+#
+# Anything you specify for either qemu-args or boot_args is appended to
+# the default values.  The "-smp" value is deduced from the contents of
+# the config fragment.
+#
+# More sophisticated argument parsing is clearly needed.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2011
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+grace=120
+
+T=/tmp/kvm-test-1-run.sh.$$
+trap 'rm -rf $T' 0
+
+. $KVM/bin/functions.sh
+. $KVPATH/ver_functions.sh
+
+config_template=${1}
+config_dir=`echo $config_template | sed -e 's,/[^/]*$,,'`
+title=`echo $config_template | sed -e 's/^.*\///'`
+builddir=${2}
+if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir"
+then
+       echo "kvm-test-1-run.sh :$builddir: Not a writable directory, cannot build into it"
+       exit 1
+fi
+resdir=${3}
+if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir"
+then
+       echo "kvm-test-1-run.sh :$resdir: Not a writable directory, cannot store results into it"
+       exit 1
+fi
+cp $config_template $resdir/ConfigFragment
+echo ' ---' `date`: Starting build
+echo ' ---' Kconfig fragment at: $config_template >> $resdir/log
+if test -r "$config_dir/CFcommon"
+then
+       cat < $config_dir/CFcommon >> $T
+fi
+# Optimizations below this point
+# CONFIG_USB=n
+# CONFIG_SECURITY=n
+# CONFIG_NFS_FS=n
+# CONFIG_SOUND=n
+# CONFIG_INPUT_JOYSTICK=n
+# CONFIG_INPUT_TABLET=n
+# CONFIG_INPUT_TOUCHSCREEN=n
+# CONFIG_INPUT_MISC=n
+# CONFIG_INPUT_MOUSE=n
+# # CONFIG_NET=n # disables console access, so accept the slower build.
+# CONFIG_SCSI=n
+# CONFIG_ATA=n
+# CONFIG_FAT_FS=n
+# CONFIG_MSDOS_FS=n
+# CONFIG_VFAT_FS=n
+# CONFIG_ISO9660_FS=n
+# CONFIG_QUOTA=n
+# CONFIG_HID=n
+# CONFIG_CRYPTO=n
+# CONFIG_PCCARD=n
+# CONFIG_PCMCIA=n
+# CONFIG_CARDBUS=n
+# CONFIG_YENTA=n
+if kvm-build.sh $config_template $builddir $T
+then
+       cp $builddir/Make*.out $resdir
+       cp $builddir/.config $resdir
+       cp $builddir/arch/x86/boot/bzImage $resdir
+       parse-build.sh $resdir/Make.out $title
+       if test -f $builddir.wait
+       then
+               mv $builddir.wait $builddir.ready
+       fi
+else
+       cp $builddir/Make*.out $resdir
+       echo Build failed, not running KVM, see $resdir.
+       if test -f $builddir.wait
+       then
+               mv $builddir.wait $builddir.ready
+       fi
+       exit 1
+fi
+while test -f $builddir.ready
+do
+       sleep 1
+done
+minutes=$4
+seconds=$(($minutes * 60))
+qemu_args=$5
+boot_args=$6
+
+cd $KVM
+kstarttime=`awk 'BEGIN { print systime() }' < /dev/null`
+echo ' ---' `date`: Starting kernel
+
+# Determine the appropriate flavor of qemu command.
+QEMU="`identify_qemu $builddir/vmlinux`"
+
+# Generate -smp qemu argument.
+qemu_args="-nographic $qemu_args"
+cpu_count=`configNR_CPUS.sh $config_template`
+vcpus=`identify_qemu_vcpus`
+if test $cpu_count -gt $vcpus
+then
+       echo CPU count limited from $cpu_count to $vcpus
+       touch $resdir/Warnings
+       echo CPU count limited from $cpu_count to $vcpus >> $resdir/Warnings
+       cpu_count=$vcpus
+fi
+qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`"
+
+# Generate architecture-specific and interaction-specific qemu arguments
+qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`"
+
+# Generate qemu -append arguments
+qemu_append="`identify_qemu_append "$QEMU"`"
+
+# Pull in Kconfig-fragment boot parameters
+boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
+# Generate kernel-version-specific boot parameters
+boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`"
+
+echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
+if test -n "$RCU_BUILDONLY"
+then
+       echo Build-only run specified, boot/test omitted.
+       exit 0
+fi
+$QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append "$qemu_append $boot_args" &
+qemu_pid=$!
+commandcompleted=0
+echo Monitoring qemu job at pid $qemu_pid
+for ((i=0;i<$seconds;i++))
+do
+       if kill -0 $qemu_pid > /dev/null 2>&1
+       then
+               sleep 1
+       else
+               commandcompleted=1
+               kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
+               if test $kruntime -lt $seconds
+               then
+                       echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1
+               else
+                       echo ' ---' `date`: Kernel done
+               fi
+               break
+       fi
+done
+if test $commandcompleted -eq 0
+then
+       echo Grace period for qemu job at pid $qemu_pid
+       for ((i=0;i<=$grace;i++))
+       do
+               if kill -0 $qemu_pid > /dev/null 2>&1
+               then
+                       sleep 1
+               else
+                       break
+               fi
+               if test $i -eq $grace
+               then
+                       kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }'`
+                       echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
+                       kill -KILL $qemu_pid
+               fi
+       done
+fi
+
+cp $builddir/console.log $resdir
+parse-${TORTURE_SUITE}torture.sh $resdir/console.log $title
+parse-console.sh $resdir/console.log $title
index 1b7923bf6a702a921040c86970cbe8d9dc47a2a6..5a78cbf55f066dd3a657e9bfd210d4129e002f83 100644 (file)
 scriptname=$0
 args="$*"
 
+T=/tmp/kvm.sh.$$
+trap 'rm -rf $T' 0
+mkdir $T
+
 dur=30
+dryrun=""
 KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
 PATH=${KVM}/bin:$PATH; export PATH
 builddir="${KVM}/b1"
 RCU_INITRD="$KVM/initrd"; export RCU_INITRD
 RCU_KMAKE_ARG=""; export RCU_KMAKE_ARG
+TORTURE_SUITE=rcu
 resdir=""
 configs=""
+cpus=0
 ds=`date +%Y.%m.%d-%H:%M:%S`
 kversion=""
 
@@ -49,7 +56,9 @@ usage () {
        echo "       --builddir absolute-pathname"
        echo "       --buildonly"
        echo "       --configs \"config-file list\""
+       echo "       --cpus N"
        echo "       --datestamp string"
+       echo "       --dryrun sched|script"
        echo "       --duration minutes"
        echo "       --interactive"
        echo "       --kmake-arg kernel-make-arguments"
@@ -58,8 +67,9 @@ usage () {
        echo "       --no-initrd"
        echo "       --qemu-args qemu-system-..."
        echo "       --qemu-cmd qemu-system-..."
-       echo "       --results absolute-pathname"
        echo "       --relbuilddir relative-pathname"
+       echo "       --results absolute-pathname"
+       echo "       --torture rcu"
        exit 1
 }
 
@@ -85,11 +95,21 @@ do
                configs="$2"
                shift
                ;;
+       --cpus)
+               checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--'
+               cpus=$2
+               shift
+               ;;
        --datestamp)
                checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' '^--'
                ds=$2
                shift
                ;;
+       --dryrun)
+               checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--'
+               dryrun=$2
+               shift
+               ;;
        --duration)
                checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error'
                dur=$2
@@ -138,6 +158,11 @@ do
                resdir=$2
                shift
                ;;
+       --torture)
+               checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--'
+               TORTURE_SUITE=$2
+               shift
+               ;;
        *)
                echo Unknown argument $1
                usage
@@ -146,7 +171,7 @@ do
        shift
 done
 
-CONFIGFRAG=${KVM}/configs; export CONFIGFRAG
+CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG
 KVPATH=${CONFIGFRAG}/$kversion; export KVPATH
 
 if test -z "$configs"
@@ -157,54 +182,231 @@ fi
 if test -z "$resdir"
 then
        resdir=$KVM/res
-       if ! test -e $resdir
-       then
-               mkdir $resdir || :
-       fi
-else
+fi
+
+if test "$dryrun" = ""
+then
        if ! test -e $resdir
        then
                mkdir -p "$resdir" || :
        fi
-fi
-mkdir $resdir/$ds
-touch $resdir/$ds/log
-echo $scriptname $args >> $resdir/$ds/log
+       mkdir $resdir/$ds
 
-pwd > $resdir/$ds/testid.txt
-if test -d .git
-then
-       git status >> $resdir/$ds/testid.txt
-       git rev-parse HEAD >> $resdir/$ds/testid.txt
-fi
-builddir=$KVM/b1
-if ! test -e $builddir
-then
-       mkdir $builddir || :
+       # Be noisy only if running the script.
+       echo Results directory: $resdir/$ds
+       echo $scriptname $args
+
+       touch $resdir/$ds/log
+       echo $scriptname $args >> $resdir/$ds/log
+       echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE
+
+       pwd > $resdir/$ds/testid.txt
+       if test -d .git
+       then
+               git status >> $resdir/$ds/testid.txt
+               git rev-parse HEAD >> $resdir/$ds/testid.txt
+       fi
 fi
 
+# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus.
+touch $T/cfgcpu
 for CF in $configs
 do
-       # Running TREE01 multiple times creates TREE01, TREE01.2, TREE01.3, ...
-       rd=$resdir/$ds/$CF
-       if test -d "${rd}"
+       if test -f "$CONFIGFRAG/$kversion/$CF"
        then
-               n="`ls -d "${rd}"* | grep '\.[0-9]\+$' |
-                       sed -e 's/^.*\.\([0-9]\+\)/\1/' |
-                       sort -k1n | tail -1`"
-               if test -z "$n"
-               then
-                       rd="${rd}.2"
-               else
-                       n="`expr $n + 1`"
-                       rd="${rd}.${n}"
-               fi
+               echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu
+       else
+               echo "The --configs file $CF does not exist, terminating."
+               exit 1
        fi
-       mkdir "${rd}"
-       echo Results directory: $rd
-       kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "-nographic $RCU_QEMU_ARG" "rcutorture.test_no_idle_hz=1 rcutorture.verbose=1 $RCU_BOOTARGS"
 done
+sort -k2nr $T/cfgcpu > $T/cfgcpu.sort
+
+# Use a greedy bin-packing algorithm, sorting the list accordingly.
+awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus '
+BEGIN {
+       njobs = 0;
+}
+
+{
+       # Read file of tests and corresponding required numbers of CPUs.
+       cf[njobs] = $1;
+       cpus[njobs] = $2;
+       njobs++;
+}
+
+END {
+       alldone = 0;
+       batch = 0;
+       nc = -1;
+
+       # Each pass through the following loop creates on test batch
+       # that can be executed concurrently given ncpus.  Note that a
+       # given test that requires more than the available CPUs will run in
+       # their own batch.  Such tests just have to make do with what
+       # is available.
+       while (nc != ncpus) {
+               batch++;
+               nc = ncpus;
+
+               # Each pass through the following loop considers one
+               # test for inclusion in the current batch.
+               for (i = 0; i < njobs; i++) {
+                       if (done[i])
+                               continue; # Already part of a batch.
+                       if (nc >= cpus[i] || nc == ncpus) {
+
+                               # This test fits into the current batch.
+                               done[i] = batch;
+                               nc -= cpus[i];
+                               if (nc <= 0)
+                                       break; # Too-big test in its own batch.
+                       }
+               }
+       }
+
+       # Dump out the tests in batch order.
+       for (b = 1; b <= batch; b++)
+               for (i = 0; i < njobs; i++)
+                       if (done[i] == b)
+                               print cf[i], cpus[i];
+}'
+
+# Generate a script to execute the tests in appropriate batches.
+cat << ___EOF___ > $T/script
+TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
+___EOF___
+awk < $T/cfgcpu.pack \
+       -v CONFIGDIR="$CONFIGFRAG/$kversion/" \
+       -v KVM="$KVM" \
+       -v ncpus=$cpus \
+       -v rd=$resdir/$ds/ \
+       -v dur=$dur \
+       -v RCU_QEMU_ARG=$RCU_QEMU_ARG \
+       -v RCU_BOOTARGS=$RCU_BOOTARGS \
+'BEGIN {
+       i = 0;
+}
+
+{
+       cf[i] = $1;
+       cpus[i] = $2;
+       i++;
+}
+
+# Dump out the scripting required to run one test batch.
+function dump(first, pastlast)
+{
+       print "echo ----Start batch: `date`";
+       print "echo ----Start batch: `date` >> " rd "/log";
+       jn=1
+       for (j = first; j < pastlast; j++) {
+               builddir=KVM "/b" jn
+               cpusr[jn] = cpus[j];
+               if (cfrep[cf[j]] == "") {
+                       cfr[jn] = cf[j];
+                       cfrep[cf[j]] = 1;
+               } else {
+                       cfrep[cf[j]]++;
+                       cfr[jn] = cf[j] "." cfrep[cf[j]];
+               }
+               if (cpusr[jn] > ncpus && ncpus != 0)
+                       ovf = "(!)";
+               else
+                       ovf = "";
+               print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date`";
+               print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` >> " rd "/log";
+               print "rm -f " builddir ".*";
+               print "touch " builddir ".wait";
+               print "mkdir " builddir " > /dev/null 2>&1 || :";
+               print "mkdir " rd cfr[jn] " || :";
+               print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " rd cfr[jn]  "/kvm-test-1-run.sh.out 2>&1 &"
+               print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`";
+               print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` >> " rd "/log";
+               print "while test -f " builddir ".wait"
+               print "do"
+               print "\tsleep 1"
+               print "done"
+               print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date`";
+               print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` >> " rd "/log";
+               jn++;
+       }
+       for (j = 1; j < jn; j++) {
+               builddir=KVM "/b" j
+               print "rm -f " builddir ".ready"
+               print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`";
+               print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
+       }
+       print "wait"
+       print "echo ---- All kernel runs complete. `date`";
+       print "echo ---- All kernel runs complete. `date` >> " rd "/log";
+       for (j = 1; j < jn; j++) {
+               builddir=KVM "/b" j
+               print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:";
+               print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: >> " rd "/log";
+               print "cat " rd cfr[j]  "/kvm-test-1-run.sh.out";
+               print "cat " rd cfr[j]  "/kvm-test-1-run.sh.out >> " rd "/log";
+       }
+}
+
+END {
+       njobs = i;
+       nc = ncpus;
+       first = 0;
+
+       # Each pass through the following loop considers one test.
+       for (i = 0; i < njobs; i++) {
+               if (ncpus == 0) {
+                       # Sequential test specified, each test its own batch.
+                       dump(i, i + 1);
+                       first = i;
+               } else if (nc < cpus[i] && i != 0) {
+                       # Out of CPUs, dump out a batch.
+                       dump(first, i);
+                       first = i;
+                       nc = ncpus;
+               }
+               # Account for the CPUs needed by the current test.
+               nc -= cpus[i];
+       }
+       # Dump the last batch.
+       if (ncpus != 0)
+               dump(first, i);
+}' >> $T/script
+
+if test "$dryrun" = script
+then
+       # Dump out the script, but define the environment variables that
+       # it needs to run standalone.
+       echo CONFIGFRAG="$CONFIGFRAG; export CONFIGFRAG"
+       echo KVM="$KVM; export KVM"
+       echo KVPATH="$KVPATH; export KVPATH"
+       echo PATH="$PATH; export PATH"
+       echo RCU_BUILDONLY="$RCU_BUILDONLY; export RCU_BUILDONLY"
+       echo RCU_INITRD="$RCU_INITRD; export RCU_INITRD"
+       echo RCU_KMAKE_ARG="$RCU_KMAKE_ARG; export RCU_KMAKE_ARG"
+       echo RCU_QEMU_CMD="$RCU_QEMU_CMD; export RCU_QEMU_CMD"
+       echo RCU_QEMU_INTERACTIVE="$RCU_QEMU_INTERACTIVE; export RCU_QEMU_INTERACTIVE"
+       echo RCU_QEMU_MAC="$RCU_QEMU_MAC; export RCU_QEMU_MAC"
+       echo "mkdir -p "$resdir" || :"
+       echo "mkdir $resdir/$ds"
+       cat $T/script
+       exit 0
+elif test "$dryrun" = sched
+then
+       # Extract the test run schedule from the script.
+       egrep 'start batch|Starting build\.' $T/script |
+               sed -e 's/:.*$//' -e 's/^echo //'
+       exit 0
+else
+       # Not a dryru, so run the script.
+       sh $T/script
+fi
+
 # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier
 
+echo
+echo
 echo " --- `date` Test summary:"
+echo Results directory: $resdir/$ds
 kvm-recheck.sh $resdir/$ds
diff --git a/tools/testing/selftests/rcutorture/configs/CFLIST b/tools/testing/selftests/rcutorture/configs/CFLIST
deleted file mode 100644 (file)
index cd3d29c..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-TREE01
-TREE02
-TREE03
-TREE04
-TREE05
-TREE06
-TREE07
-TREE08
-TREE09
-SRCU-N
-SRCU-P
-TINY01
-TINY02
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N b/tools/testing/selftests/rcutorture/configs/SRCU-N
deleted file mode 100644 (file)
index 10a0e27..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N.boot b/tools/testing/selftests/rcutorture/configs/SRCU-N.boot
deleted file mode 100644 (file)
index 238bfe3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-rcutorture.torture_type=srcu
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P b/tools/testing/selftests/rcutorture/configs/SRCU-P
deleted file mode 100644 (file)
index 6650e00..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P.boot b/tools/testing/selftests/rcutorture/configs/SRCU-P.boot
deleted file mode 100644 (file)
index 238bfe3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-rcutorture.torture_type=srcu
diff --git a/tools/testing/selftests/rcutorture/configs/TINY01 b/tools/testing/selftests/rcutorture/configs/TINY01
deleted file mode 100644 (file)
index 0c2823f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_TRACE=n
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PREEMPT_COUNT=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TINY02 b/tools/testing/selftests/rcutorture/configs/TINY02
deleted file mode 100644 (file)
index e5072d7..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_HZ_PERIODIC=y
-CONFIG_NO_HZ_IDLE=n
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_LOCK_ALLOC=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PREEMPT_COUNT=y
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE01 b/tools/testing/selftests/rcutorture/configs/TREE01
deleted file mode 100644 (file)
index 141119a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_RCU_TRACE=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_FANOUT=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_ZERO=y
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_RCU_BOOST=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE01.boot b/tools/testing/selftests/rcutorture/configs/TREE01.boot
deleted file mode 100644 (file)
index 0fc8a34..0000000
+++ /dev/null
@@ -1 +0,0 @@
-rcutorture.torture_type=rcu_bh
diff --git a/tools/testing/selftests/rcutorture/configs/TREE02 b/tools/testing/selftests/rcutorture/configs/TREE02
deleted file mode 100644 (file)
index 2d4d096..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=n 
-CONFIG_RCU_TRACE=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_RCU_FANOUT=3
-CONFIG_RCU_FANOUT_LEAF=3
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_RCU_NOCB_CPU=n
-CONFIG_DEBUG_LOCK_ALLOC=y
-CONFIG_PROVE_LOCKING=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=y
-CONFIG_RCU_BOOST=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE03 b/tools/testing/selftests/rcutorture/configs/TREE03
deleted file mode 100644 (file)
index a47de5b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_HZ_PERIODIC=y
-CONFIG_NO_HZ_IDLE=n
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_TRACE=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_FANOUT=4
-CONFIG_RCU_FANOUT_LEAF=4
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_RCU_NOCB_CPU=n
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE04 b/tools/testing/selftests/rcutorture/configs/TREE04
deleted file mode 100644 (file)
index 8d839b8..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=n
-CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_RCU_TRACE=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_RCU_FANOUT=2
-CONFIG_RCU_FANOUT_LEAF=2
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_RCU_NOCB_CPU=n
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_RCU_CPU_STALL_VERBOSE=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE04.boot b/tools/testing/selftests/rcutorture/configs/TREE04.boot
deleted file mode 100644 (file)
index 0fc8a34..0000000
+++ /dev/null
@@ -1 +0,0 @@
-rcutorture.torture_type=rcu_bh
diff --git a/tools/testing/selftests/rcutorture/configs/TREE05 b/tools/testing/selftests/rcutorture/configs/TREE05
deleted file mode 100644 (file)
index b5ba72e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=n
-CONFIG_RCU_TRACE=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_FANOUT=6
-CONFIG_RCU_FANOUT_LEAF=6
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_DEBUG_LOCK_ALLOC=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_PROVE_RCU_DELAY=y
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE05.boot b/tools/testing/selftests/rcutorture/configs/TREE05.boot
deleted file mode 100644 (file)
index 3b42b8b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-rcutorture.torture_type=sched
diff --git a/tools/testing/selftests/rcutorture/configs/TREE06 b/tools/testing/selftests/rcutorture/configs/TREE06
deleted file mode 100644 (file)
index 7c95ab4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=n
-CONFIG_RCU_TRACE=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_RCU_FANOUT=6
-CONFIG_RCU_FANOUT_LEAF=6
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_RCU_NOCB_CPU=n
-CONFIG_DEBUG_LOCK_ALLOC=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE07 b/tools/testing/selftests/rcutorture/configs/TREE07
deleted file mode 100644 (file)
index 1467404..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=16
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=n
-CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=y
-CONFIG_NO_HZ_FULL_SYSIDLE=y
-CONFIG_RCU_FAST_NO_HZ=n
-CONFIG_RCU_TRACE=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_FANOUT=2
-CONFIG_RCU_FANOUT_LEAF=2
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_RCU_NOCB_CPU=n
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE08 b/tools/testing/selftests/rcutorture/configs/TREE08
deleted file mode 100644 (file)
index 7d097a6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=16
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=n
-CONFIG_RCU_TRACE=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_RCU_FANOUT=3
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_RCU_FANOUT_LEAF=2
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_ALL=y
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_RCU_BOOST=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE08-T b/tools/testing/selftests/rcutorture/configs/TREE08-T
deleted file mode 100644 (file)
index 442c4e4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-CONFIG_SMP=y
-CONFIG_NR_CPUS=16
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=n
-CONFIG_RCU_TRACE=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_RCU_FANOUT=3
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_RCU_FANOUT_LEAF=2
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_ALL=y
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_RCU_BOOST=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE09 b/tools/testing/selftests/rcutorture/configs/TREE09
deleted file mode 100644 (file)
index 0d1ec0d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-CONFIG_SMP=n
-CONFIG_NR_CPUS=1
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_HZ_PERIODIC=n
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_TRACE=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_RCU_NOCB_CPU=n
-CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
-CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
-CONFIG_RCU_BOOST=n
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/BUSTED b/tools/testing/selftests/rcutorture/configs/lock/BUSTED
new file mode 100644 (file)
index 0000000..1d1da14
--- /dev/null
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot
new file mode 100644 (file)
index 0000000..6386c15
--- /dev/null
@@ -0,0 +1 @@
+locktorture.torture_type=lock_busted
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
new file mode 100644 (file)
index 0000000..a061b22
--- /dev/null
@@ -0,0 +1 @@
+LOCK01
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFcommon b/tools/testing/selftests/rcutorture/configs/lock/CFcommon
new file mode 100644 (file)
index 0000000..e372dc2
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_LOCK_TORTURE_TEST=y
+CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK01 b/tools/testing/selftests/rcutorture/configs/lock/LOCK01
new file mode 100644 (file)
index 0000000..a9625e3
--- /dev/null
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
new file mode 100644 (file)
index 0000000..9746ea1
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Kernel-version-dependent shell functions for the rest of the scripts.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2014
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+# locktorture_param_onoff bootparam-string config-file
+#
+# Adds onoff locktorture module parameters to kernels having it.
+locktorture_param_onoff () {
+       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
+       then
+               echo CPU-hotplug kernel, adding locktorture onoff. 1>&2
+               echo locktorture.onoff_interval=3 locktorture.onoff_holdoff=30
+       fi
+}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+       echo $1 `locktorture_param_onoff "$1" "$2"` \
+               locktorture.stat_interval=15 \
+               locktorture.shutdown_secs=$3 \
+               locktorture.locktorture_runnable=1 \
+               locktorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED
new file mode 100644 (file)
index 0000000..48d8a24
--- /dev/null
@@ -0,0 +1,7 @@
+CONFIG_RCU_TRACE=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot
new file mode 100644 (file)
index 0000000..6804f9d
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=rcu_busted
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
new file mode 100644 (file)
index 0000000..cd3d29c
--- /dev/null
@@ -0,0 +1,13 @@
+TREE01
+TREE02
+TREE03
+TREE04
+TREE05
+TREE06
+TREE07
+TREE08
+TREE09
+SRCU-N
+SRCU-P
+TINY01
+TINY02
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFcommon b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon
new file mode 100644 (file)
index 0000000..d2d2a86
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_RCU_TORTURE_TEST=y
+CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N
new file mode 100644 (file)
index 0000000..9fbb41b
--- /dev/null
@@ -0,0 +1,7 @@
+CONFIG_RCU_TRACE=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot
new file mode 100644 (file)
index 0000000..238bfe3
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=srcu
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P
new file mode 100644 (file)
index 0000000..4b6f272
--- /dev/null
@@ -0,0 +1,7 @@
+CONFIG_RCU_TRACE=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot
new file mode 100644 (file)
index 0000000..238bfe3
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=srcu
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY01 b/tools/testing/selftests/rcutorture/configs/rcu/TINY01
new file mode 100644 (file)
index 0000000..0a63e07
--- /dev/null
@@ -0,0 +1,12 @@
+CONFIG_SMP=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_PREEMPT_COUNT=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
new file mode 100644 (file)
index 0000000..f4feaee
--- /dev/null
@@ -0,0 +1,12 @@
+CONFIG_SMP=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_PREEMPT_COUNT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
new file mode 100644 (file)
index 0000000..9c827ec
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ZERO=y
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
new file mode 100644 (file)
index 0000000..0fc8a34
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=rcu_bh
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
new file mode 100644 (file)
index 0000000..1a777b5
--- /dev/null
@@ -0,0 +1,25 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=3
+CONFIG_RCU_FANOUT_LEAF=3
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
new file mode 100644 (file)
index 0000000..c1f111c
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=4
+CONFIG_RCU_FANOUT_LEAF=4
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
new file mode 100644 (file)
index 0000000..7dbd27c
--- /dev/null
@@ -0,0 +1,24 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ_FULL_ALL=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=2
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
new file mode 100644 (file)
index 0000000..0fc8a34
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=rcu_bh
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
new file mode 100644 (file)
index 0000000..d0f32e5
--- /dev/null
@@ -0,0 +1,24 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=6
+CONFIG_RCU_FANOUT_LEAF=6
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_NONE=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot
new file mode 100644 (file)
index 0000000..3b42b8b
--- /dev/null
@@ -0,0 +1 @@
+rcutorture.torture_type=sched
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
new file mode 100644 (file)
index 0000000..2e477df
--- /dev/null
@@ -0,0 +1,25 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=6
+CONFIG_RCU_FANOUT_LEAF=6
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
new file mode 100644 (file)
index 0000000..042f86e
--- /dev/null
@@ -0,0 +1,23 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ_FULL_ALL=y
+CONFIG_NO_HZ_FULL_SYSIDLE=y
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=2
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
new file mode 100644 (file)
index 0000000..3438cee
--- /dev/null
@@ -0,0 +1,25 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=3
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
new file mode 100644 (file)
index 0000000..bf4523d
--- /dev/null
@@ -0,0 +1,25 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_FANOUT=3
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
new file mode 100644 (file)
index 0000000..81e4f7c
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_SMP=n
+CONFIG_NR_CPUS=1
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_RCU_DELAY=n
+CONFIG_RCU_CPU_STALL_INFO=n
+CONFIG_RCU_CPU_STALL_VERBOSE=n
+CONFIG_RCU_BOOST=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST
new file mode 100644 (file)
index 0000000..1822394
--- /dev/null
@@ -0,0 +1,14 @@
+P1-S-T-NH-SD-SMP-HP
+P2-2-t-nh-sd-SMP-hp
+P3-3-T-nh-SD-SMP-hp
+P4-A-t-NH-sd-SMP-HP
+P5-U-T-NH-sd-SMP-hp
+N1-S-T-NH-SD-SMP-HP
+N2-2-t-nh-sd-SMP-hp
+N3-3-T-nh-SD-SMP-hp
+N4-A-t-NH-sd-SMP-HP
+N5-U-T-NH-sd-SMP-hp
+PT1-nh
+PT2-NH
+NT1-nh
+NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..d3ef873
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..02e4185
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b3100f6
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..c56b445
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..90d924f
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh
new file mode 100644 (file)
index 0000000..023f312
--- /dev/null
@@ -0,0 +1,23 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH
new file mode 100644 (file)
index 0000000..6fd0235
--- /dev/null
@@ -0,0 +1,20 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..f72402d
--- /dev/null
@@ -0,0 +1,19 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..0f3b667
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b035e14
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..3ccf6a9
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..ef624ce
--- /dev/null
@@ -0,0 +1,28 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh
new file mode 100644 (file)
index 0000000..e3361c3
--- /dev/null
@@ -0,0 +1,23 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH
new file mode 100644 (file)
index 0000000..64abfc3
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh
new file mode 100644 (file)
index 0000000..5ace37a
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Kernel-version-dependent shell functions for the rest of the scripts.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2013
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+# Which old kernels do not.
+per_version_boot_params () {
+       echo    rcutorture.stat_interval=15 \
+               rcutorture.shutdown_secs=$3 \
+               rcutorture.rcutorture_runnable=1 \
+               rcutorture.test_no_idle_hz=1 \
+               rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST
new file mode 100644 (file)
index 0000000..da4cbc6
--- /dev/null
@@ -0,0 +1,17 @@
+sysidleY.2013.06.19a
+sysidleN.2013.06.19a
+P1-S-T-NH-SD-SMP-HP
+P2-2-t-nh-sd-SMP-hp
+P3-3-T-nh-SD-SMP-hp
+P4-A-t-NH-sd-SMP-HP
+P5-U-T-NH-sd-SMP-hp
+P6---t-nh-SD-smp-hp
+N1-S-T-NH-SD-SMP-HP
+N2-2-t-nh-sd-SMP-hp
+N3-3-T-nh-SD-SMP-hp
+N4-A-t-NH-sd-SMP-HP
+N5-U-T-NH-sd-SMP-hp
+PT1-nh
+PT2-NH
+NT1-nh
+NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..d81e11d
--- /dev/null
@@ -0,0 +1,19 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..02e4185
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b3100f6
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..c56b445
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..90d924f
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp
new file mode 100644 (file)
index 0000000..0ccc36d
--- /dev/null
@@ -0,0 +1,19 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=1
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..3f640cf
--- /dev/null
@@ -0,0 +1,26 @@
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=16
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_NONE=y
+CONFIG_RCU_NOCB_CPU_ZERO=n
+CONFIG_RCU_NOCB_CPU_ALL=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..285da2d
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=14
+CONFIG_NR_CPUS=16
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh
new file mode 100644 (file)
index 0000000..023f312
--- /dev/null
@@ -0,0 +1,23 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH
new file mode 100644 (file)
index 0000000..6fd0235
--- /dev/null
@@ -0,0 +1,20 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..9647c44
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..0f3b667
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b035e14
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..3ccf6a9
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..ef624ce
--- /dev/null
@@ -0,0 +1,28 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp
new file mode 100644 (file)
index 0000000..f4c9175
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=n
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..77a8c5b
--- /dev/null
@@ -0,0 +1,30 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=16
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_NONE=n
+CONFIG_RCU_NOCB_CPU_ZERO=n
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SLUB=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all
new file mode 100644 (file)
index 0000000..0eecebc
--- /dev/null
@@ -0,0 +1,30 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=16
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_NONE=y
+CONFIG_RCU_NOCB_CPU_ZERO=n
+CONFIG_RCU_NOCB_CPU_ALL=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SLUB=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none
new file mode 100644 (file)
index 0000000..0eecebc
--- /dev/null
@@ -0,0 +1,30 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=16
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_NONE=y
+CONFIG_RCU_NOCB_CPU_ZERO=n
+CONFIG_RCU_NOCB_CPU_ALL=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SLUB=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp
new file mode 100644 (file)
index 0000000..588bc70
--- /dev/null
@@ -0,0 +1,30 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=16
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_NONE=n
+CONFIG_RCU_NOCB_CPU_ZERO=y
+CONFIG_RCU_NOCB_CPU_ALL=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SLUB=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh
new file mode 100644 (file)
index 0000000..e3361c3
--- /dev/null
@@ -0,0 +1,23 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH
new file mode 100644 (file)
index 0000000..64abfc3
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST
new file mode 100644 (file)
index 0000000..1822394
--- /dev/null
@@ -0,0 +1,14 @@
+P1-S-T-NH-SD-SMP-HP
+P2-2-t-nh-sd-SMP-hp
+P3-3-T-nh-SD-SMP-hp
+P4-A-t-NH-sd-SMP-HP
+P5-U-T-NH-sd-SMP-hp
+N1-S-T-NH-SD-SMP-HP
+N2-2-t-nh-sd-SMP-hp
+N3-3-T-nh-SD-SMP-hp
+N4-A-t-NH-sd-SMP-HP
+N5-U-T-NH-sd-SMP-hp
+PT1-nh
+PT2-NH
+NT1-nh
+NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..d81e11d
--- /dev/null
@@ -0,0 +1,19 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..02e4185
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b3100f6
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..c56b445
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..90d924f
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh
new file mode 100644 (file)
index 0000000..023f312
--- /dev/null
@@ -0,0 +1,23 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH
new file mode 100644 (file)
index 0000000..6fd0235
--- /dev/null
@@ -0,0 +1,20 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..9647c44
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..0f3b667
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b035e14
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..3ccf6a9
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..ef624ce
--- /dev/null
@@ -0,0 +1,28 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh
new file mode 100644 (file)
index 0000000..e3361c3
--- /dev/null
@@ -0,0 +1,23 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH
new file mode 100644 (file)
index 0000000..64abfc3
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh
new file mode 100644 (file)
index 0000000..bae5569
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+#
+# Kernel-version-dependent shell functions for the rest of the scripts.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2013
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+# rcutorture_param_onoff bootparam-string config-file
+#
+# Adds onoff rcutorture module parameters to kernels having it.
+rcutorture_param_onoff () {
+       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
+       then
+               echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
+               echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
+       fi
+}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+       echo $1 `rcutorture_param_onoff "$1" "$2"` \
+               rcutorture.stat_interval=15 \
+               rcutorture.shutdown_secs=$3 \
+               rcutorture.rcutorture_runnable=1 \
+               rcutorture.test_no_idle_hz=1 \
+               rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST
new file mode 100644 (file)
index 0000000..1822394
--- /dev/null
@@ -0,0 +1,14 @@
+P1-S-T-NH-SD-SMP-HP
+P2-2-t-nh-sd-SMP-hp
+P3-3-T-nh-SD-SMP-hp
+P4-A-t-NH-sd-SMP-HP
+P5-U-T-NH-sd-SMP-hp
+N1-S-T-NH-SD-SMP-HP
+N2-2-t-nh-sd-SMP-hp
+N3-3-T-nh-SD-SMP-hp
+N4-A-t-NH-sd-SMP-HP
+N5-U-T-NH-sd-SMP-hp
+PT1-nh
+PT2-NH
+NT1-nh
+NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..d81e11d
--- /dev/null
@@ -0,0 +1,19 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..02e4185
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b3100f6
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..c56b445
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..90d924f
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh
new file mode 100644 (file)
index 0000000..023f312
--- /dev/null
@@ -0,0 +1,23 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH
new file mode 100644 (file)
index 0000000..6fd0235
--- /dev/null
@@ -0,0 +1,20 @@
+#CHECK#CONFIG_TINY_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP
new file mode 100644 (file)
index 0000000..9647c44
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=8
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp
new file mode 100644 (file)
index 0000000..0f3b667
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=4
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp
new file mode 100644 (file)
index 0000000..b035e14
--- /dev/null
@@ -0,0 +1,20 @@
+CONFIG_RCU_TRACE=y
+CONFIG_NO_HZ=n
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=2
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP
new file mode 100644 (file)
index 0000000..3ccf6a9
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_RCU_TRACE=n
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=n
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
new file mode 100644 (file)
index 0000000..ef624ce
--- /dev/null
@@ -0,0 +1,28 @@
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_RCU_FANOUT=6
+CONFIG_NR_CPUS=8
+CONFIG_RCU_FANOUT_EXACT=y
+CONFIG_HOTPLUG_CPU=n
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_RT_MUTEXES=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh
new file mode 100644 (file)
index 0000000..e3361c3
--- /dev/null
@@ -0,0 +1,23 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_TRACE=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=n
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH
new file mode 100644 (file)
index 0000000..64abfc3
--- /dev/null
@@ -0,0 +1,22 @@
+CONFIG_TINY_PREEMPT_RCU=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_MODULE_UNLOAD=y
+CONFIG_SUSPEND=n
+CONFIG_HIBERNATION=n
+#
+CONFIG_SMP=n
+#
+CONFIG_HOTPLUG_CPU=n
+#
+CONFIG_NO_HZ=y
+#
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_PRINTK_TIME=y
+
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh
new file mode 100644 (file)
index 0000000..8977d8d
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# Kernel-version-dependent shell functions for the rest of the scripts.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2013
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+# rcutorture_param_n_barrier_cbs bootparam-string
+#
+# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
+rcutorture_param_n_barrier_cbs () {
+       if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
+       then
+               :
+       else
+               echo rcutorture.n_barrier_cbs=4
+       fi
+}
+
+# rcutorture_param_onoff bootparam-string config-file
+#
+# Adds onoff rcutorture module parameters to kernels having it.
+rcutorture_param_onoff () {
+       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
+       then
+               echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
+               echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
+       fi
+}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+       echo $1 `rcutorture_param_onoff "$1" "$2"` \
+               `rcutorture_param_n_barrier_cbs "$1"` \
+               rcutorture.stat_interval=15 \
+               rcutorture.shutdown_secs=$3 \
+               rcutorture.rcutorture_runnable=1 \
+               rcutorture.test_no_idle_hz=1 \
+               rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
new file mode 100644 (file)
index 0000000..8977d8d
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# Kernel-version-dependent shell functions for the rest of the scripts.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2013
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+# rcutorture_param_n_barrier_cbs bootparam-string
+#
+# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
+rcutorture_param_n_barrier_cbs () {
+       if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
+       then
+               :
+       else
+               echo rcutorture.n_barrier_cbs=4
+       fi
+}
+
+# rcutorture_param_onoff bootparam-string config-file
+#
+# Adds onoff rcutorture module parameters to kernels having it.
+rcutorture_param_onoff () {
+       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
+       then
+               echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
+               echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
+       fi
+}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+       echo $1 `rcutorture_param_onoff "$1" "$2"` \
+               `rcutorture_param_n_barrier_cbs "$1"` \
+               rcutorture.stat_interval=15 \
+               rcutorture.shutdown_secs=$3 \
+               rcutorture.rcutorture_runnable=1 \
+               rcutorture.test_no_idle_hz=1 \
+               rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST b/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST
deleted file mode 100644 (file)
index 1822394..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index d3ef873..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 02e4185..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b3100f6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index c56b445..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index 90d924f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh b/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh
deleted file mode 100644 (file)
index 023f312..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH b/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH
deleted file mode 100644 (file)
index 6fd0235..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index f72402d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 0f3b667..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b035e14..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index 3ccf6a9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index ef624ce..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh b/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh
deleted file mode 100644 (file)
index e3361c3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH b/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH
deleted file mode 100644 (file)
index 64abfc3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh
deleted file mode 100644 (file)
index e805253..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
-       echo $1
-}
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
-       echo $1
-}
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST b/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST
deleted file mode 100644 (file)
index da4cbc6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-sysidleY.2013.06.19a
-sysidleN.2013.06.19a
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-P6---t-nh-SD-smp-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index d81e11d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 02e4185..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b3100f6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index c56b445..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index 90d924f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp
deleted file mode 100644 (file)
index 0ccc36d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_NR_CPUS=1
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index 3f640cf..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index 285da2d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=14
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh b/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh
deleted file mode 100644 (file)
index 023f312..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH b/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH
deleted file mode 100644 (file)
index 6fd0235..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index 9647c44..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 0f3b667..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b035e14..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index 3ccf6a9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index ef624ce..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp
deleted file mode 100644 (file)
index f4c9175..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=n
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index 77a8c5b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=n
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all
deleted file mode 100644 (file)
index 0eecebc..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none
deleted file mode 100644 (file)
index 0eecebc..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp
deleted file mode 100644 (file)
index 588bc70..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=n
-CONFIG_RCU_NOCB_CPU_ZERO=y
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh b/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh
deleted file mode 100644 (file)
index e3361c3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH b/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH
deleted file mode 100644 (file)
index 64abfc3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST b/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST
deleted file mode 100644 (file)
index 1822394..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index d81e11d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 02e4185..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b3100f6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index c56b445..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index 90d924f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh b/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh
deleted file mode 100644 (file)
index 023f312..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH b/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH
deleted file mode 100644 (file)
index 6fd0235..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index 9647c44..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 0f3b667..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b035e14..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index 3ccf6a9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index ef624ce..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh b/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh
deleted file mode 100644 (file)
index e3361c3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH b/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH
deleted file mode 100644 (file)
index 64abfc3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh
deleted file mode 100644 (file)
index c37432f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
-       echo $1
-}
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
-       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
-       then
-               echo CPU-hotplug kernel, adding rcutorture onoff.
-               echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
-       else
-               echo $1
-       fi
-}
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST b/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST
deleted file mode 100644 (file)
index 1822394..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index d81e11d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 02e4185..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b3100f6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index c56b445..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index 90d924f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh b/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh
deleted file mode 100644 (file)
index 023f312..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH b/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH
deleted file mode 100644 (file)
index 6fd0235..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644 (file)
index 9647c44..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644 (file)
index 0f3b667..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644 (file)
index b035e14..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644 (file)
index 3ccf6a9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644 (file)
index ef624ce..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh b/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh
deleted file mode 100644 (file)
index e3361c3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH b/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH
deleted file mode 100644 (file)
index 64abfc3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh
deleted file mode 100644 (file)
index 6a5f13a..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
-       if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
-       then
-               echo $1
-       else
-               echo $1 rcutorture.n_barrier_cbs=4
-       fi
-}
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
-       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
-       then
-               echo CPU-hotplug kernel, adding rcutorture onoff.
-               echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
-       else
-               echo $1
-       fi
-}
diff --git a/tools/testing/selftests/rcutorture/configs/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/ver_functions.sh
deleted file mode 100644 (file)
index 5e40ead..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
-       if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
-       then
-               echo $1
-       else
-               echo $1 rcutorture.n_barrier_cbs=4
-       fi
-}
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
-       if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
-       then
-               echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
-               echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
-       else
-               echo $1
-       fi
-}
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt
deleted file mode 100644 (file)
index adbb76c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-This document gives a brief rationale for the TREE_RCU-related test
-cases, a group that includes TREE_PREEMPT_RCU.
-
-
-Kconfig Parameters:
-
-CONFIG_DEBUG_LOCK_ALLOC -- Do three, covering CONFIG_PROVE_LOCKING & not.
-CONFIG_DEBUG_OBJECTS_RCU_HEAD -- Do one.
-CONFIG_HOTPLUG_CPU -- Do half.  (Every second.)
-CONFIG_HZ_PERIODIC -- Do one.
-CONFIG_NO_HZ_IDLE -- Do those not otherwise specified. (Groups of two.)
-CONFIG_NO_HZ_FULL -- Do two, one with CONFIG_NO_HZ_FULL_SYSIDLE.
-CONFIG_NO_HZ_FULL_SYSIDLE -- Do one.
-CONFIG_PREEMPT -- Do half.  (First three and #8.)
-CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not.
-CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING.
-CONFIG_PROVE_RCU_DELAY -- Do one.
-CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU.
-CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing.
-CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE.
-CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO.
-CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others.
-CONFIG_RCU_FANOUT_EXACT -- Do one.
-CONFIG_RCU_FANOUT_LEAF -- Do one non-default.
-CONFIG_RCU_FAST_NO_HZ -- Do one, but not with CONFIG_RCU_NOCB_CPU_ALL.
-CONFIG_RCU_NOCB_CPU -- Do three, see below.
-CONFIG_RCU_NOCB_CPU_ALL -- Do one.
-CONFIG_RCU_NOCB_CPU_NONE -- Do one.
-CONFIG_RCU_NOCB_CPU_ZERO -- Do one.
-CONFIG_RCU_TRACE -- Do half.
-CONFIG_SMP -- Need one !SMP for TREE_PREEMPT_RCU.
-RCU-bh: Do one with PREEMPT and one with !PREEMPT.
-RCU-sched: Do one with PREEMPT but not BOOST.
-
-
-Hierarchy:
-
-TREE01.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=8, CONFIG_RCU_FANOUT_EXACT=n.
-TREE02.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=n,
-       CONFIG_RCU_FANOUT_LEAF=3.
-TREE03.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=4, CONFIG_RCU_FANOUT_EXACT=n,
-       CONFIG_RCU_FANOUT_LEAF=4.
-TREE04.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n,
-       CONFIG_RCU_FANOUT_LEAF=2.
-TREE05.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=n
-       CONFIG_RCU_FANOUT_LEAF=6.
-TREE06.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=y
-       CONFIG_RCU_FANOUT_LEAF=6.
-TREE07.        CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n,
-       CONFIG_RCU_FANOUT_LEAF=2.
-TREE08.        CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=y,
-       CONFIG_RCU_FANOUT_LEAF=2.
-TREE09.        CONFIG_NR_CPUS=1.
-
-
-Kconfig Parameters Ignored:
-
-CONFIG_64BIT
-
-       Used only to check CONFIG_RCU_FANOUT value, inspection suffices.
-
-CONFIG_NO_HZ_FULL_SYSIDLE_SMALL
-
-       Defer until Frederic uses this.
-
-CONFIG_PREEMPT_COUNT
-CONFIG_PREEMPT_RCU
-
-       Redundant with CONFIG_PREEMPT, ignore.
-
-CONFIG_RCU_BOOST_DELAY
-
-       Inspection suffices, ignore.
-
-CONFIG_RCU_CPU_STALL_TIMEOUT
-
-       Inspection suffices, ignore.
-
-CONFIG_RCU_STALL_COMMON
-
-       Implied by TREE_RCU and TREE_PREEMPT_RCU.
-
-CONFIG_RCU_TORTURE_TEST
-CONFIG_RCU_TORTURE_TEST_RUNNABLE
-
-       Always used in KVM testing.
-
-CONFIG_RCU_USER_QS
-
-       Redundant with CONFIG_NO_HZ_FULL.
-
-CONFIG_TREE_PREEMPT_RCU
-CONFIG_TREE_RCU
-
-       These are controlled by CONFIG_PREEMPT.
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
new file mode 100644 (file)
index 0000000..adbb76c
--- /dev/null
@@ -0,0 +1,95 @@
+This document gives a brief rationale for the TREE_RCU-related test
+cases, a group that includes TREE_PREEMPT_RCU.
+
+
+Kconfig Parameters:
+
+CONFIG_DEBUG_LOCK_ALLOC -- Do three, covering CONFIG_PROVE_LOCKING & not.
+CONFIG_DEBUG_OBJECTS_RCU_HEAD -- Do one.
+CONFIG_HOTPLUG_CPU -- Do half.  (Every second.)
+CONFIG_HZ_PERIODIC -- Do one.
+CONFIG_NO_HZ_IDLE -- Do those not otherwise specified. (Groups of two.)
+CONFIG_NO_HZ_FULL -- Do two, one with CONFIG_NO_HZ_FULL_SYSIDLE.
+CONFIG_NO_HZ_FULL_SYSIDLE -- Do one.
+CONFIG_PREEMPT -- Do half.  (First three and #8.)
+CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not.
+CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING.
+CONFIG_PROVE_RCU_DELAY -- Do one.
+CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU.
+CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing.
+CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE.
+CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO.
+CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others.
+CONFIG_RCU_FANOUT_EXACT -- Do one.
+CONFIG_RCU_FANOUT_LEAF -- Do one non-default.
+CONFIG_RCU_FAST_NO_HZ -- Do one, but not with CONFIG_RCU_NOCB_CPU_ALL.
+CONFIG_RCU_NOCB_CPU -- Do three, see below.
+CONFIG_RCU_NOCB_CPU_ALL -- Do one.
+CONFIG_RCU_NOCB_CPU_NONE -- Do one.
+CONFIG_RCU_NOCB_CPU_ZERO -- Do one.
+CONFIG_RCU_TRACE -- Do half.
+CONFIG_SMP -- Need one !SMP for TREE_PREEMPT_RCU.
+RCU-bh: Do one with PREEMPT and one with !PREEMPT.
+RCU-sched: Do one with PREEMPT but not BOOST.
+
+
+Hierarchy:
+
+TREE01.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=8, CONFIG_RCU_FANOUT_EXACT=n.
+TREE02.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=n,
+       CONFIG_RCU_FANOUT_LEAF=3.
+TREE03.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=4, CONFIG_RCU_FANOUT_EXACT=n,
+       CONFIG_RCU_FANOUT_LEAF=4.
+TREE04.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n,
+       CONFIG_RCU_FANOUT_LEAF=2.
+TREE05.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=n
+       CONFIG_RCU_FANOUT_LEAF=6.
+TREE06.        CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=y
+       CONFIG_RCU_FANOUT_LEAF=6.
+TREE07.        CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n,
+       CONFIG_RCU_FANOUT_LEAF=2.
+TREE08.        CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=y,
+       CONFIG_RCU_FANOUT_LEAF=2.
+TREE09.        CONFIG_NR_CPUS=1.
+
+
+Kconfig Parameters Ignored:
+
+CONFIG_64BIT
+
+       Used only to check CONFIG_RCU_FANOUT value, inspection suffices.
+
+CONFIG_NO_HZ_FULL_SYSIDLE_SMALL
+
+       Defer until Frederic uses this.
+
+CONFIG_PREEMPT_COUNT
+CONFIG_PREEMPT_RCU
+
+       Redundant with CONFIG_PREEMPT, ignore.
+
+CONFIG_RCU_BOOST_DELAY
+
+       Inspection suffices, ignore.
+
+CONFIG_RCU_CPU_STALL_TIMEOUT
+
+       Inspection suffices, ignore.
+
+CONFIG_RCU_STALL_COMMON
+
+       Implied by TREE_RCU and TREE_PREEMPT_RCU.
+
+CONFIG_RCU_TORTURE_TEST
+CONFIG_RCU_TORTURE_TEST_RUNNABLE
+
+       Always used in KVM testing.
+
+CONFIG_RCU_USER_QS
+
+       Redundant with CONFIG_NO_HZ_FULL.
+
+CONFIG_TREE_PREEMPT_RCU
+CONFIG_TREE_RCU
+
+       These are controlled by CONFIG_PREEMPT.
index 03a0381b1cb79a2b09a565d43883bb89c5855950..b5ec7fb986f6a560a258c99b8af3977aff936c2d 100644 (file)
@@ -102,7 +102,7 @@ static void kvm_release_pfn_dirty(pfn_t pfn);
 static void mark_page_dirty_in_slot(struct kvm *kvm,
                                    struct kvm_memory_slot *memslot, gfn_t gfn);
 
-bool kvm_rebooting;
+__visible bool kvm_rebooting;
 EXPORT_SYMBOL_GPL(kvm_rebooting);
 
 static bool largepages_enabled = true;